概述

最近维护的项目对接第三方需要用到WebService,工作好几年了,实际项目中还是第一次用到,去网上翻了翻,大都是抄来抄去,并且已经过时的版本了,趁这个机会去了解了解,分享出来,希望能帮到大家。

WebService,诞生于SOAP时期,简单来说是一种服务间通讯手段,以下来自百科。

Web服务是一种服务导向架构的技术,通过标准的Web协议提供服务,目的是保证不同平台的应用服务可以互操作。

根据W3C的定义,Web服务(Web service)应当是一个软件系统,用以支持网络间不同机器的互动操作。网络服务通常是许多应用程序接口(API)所组成的,它们透过网络,例如国际互联网(Internet)的远程服务器端,执行客户所提交服务的请求。

尽管W3C的定义涵盖诸多相异且无法介分的系统,不过通常我们指有关于主从式架构(Client-server)之间根据SOAP协议进行传递XML格式消息。无论定义还是实现,Web服务过程中会由服务器提供一个机器可读的描述(通常基于WSDL)以辨识服务器所提供的WEB服务。另外,虽然WSDL不是SOAP服务端点的必要条件,但目前基于Java的主流Web服务开发框架往往需要WSDL实现客户端的源代码生成。一些工业标准化组织,比如WS-I,就在Web服务定义中强制包含SOAP和WSDL。

SpringBoot集成WebService

服务端

pom

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web-services</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-spring-boot-starter-jaxws</artifactId>
            <version>3.5.2</version>
        </dependency>

部分注解

@WebService 声明为WebService服务
@WebResult 定义返回值信息		不指定时 默认为 return
@WebParam 定义参数信息		不指定时 默认为 arg0 arg1....
@WebMethod 对指定方法进行个性化设置 如:不向外暴露某个方法


@WebService 实现类上声明
其他的 WebResult WebMethod WebParam 可以声明在接口中也可以声明在实现类中
而且 WebResult WebMethod WebParam 声明所在的类中必须声明 @WebService

默认情况下会将WebService下所有方法暴露为WebService 服务,可以在实现类中 使用 @WebMethod 标记指定方法不对外暴露

一句话总结
	- 所有声明在实现类可以
    - 接口中声明所有资源 + 实现类中声明 @WebService

编码

实体类
@Data
public class User {

    private Long id;
    private String name;
    private Integer age;
    private String birthday;
    // WebService 对参数类型有限制 无法直接使用 LocalDate
//    private LocalDate birthday;
    private List<String> hobbies;
}
接口
public interface UserService {

    User getById(User User);
}
实现类
@Service
@WebService(targetNamespace = "http://springboot.kalpana.top")
public class UserServiceImpl implements UserService {
    private final Map<Long, User> userMap = new HashMap<>();

    {
        User user = new User();
        user.setId(1L);
        user.setName("张三");
        user.setAge(18);
        user.setBirthday("1987-12-15");
        user.setHobbies(Arrays.asList("吃饭", "睡觉"));
        userMap.put(1L, user);

        user = new User();
        user.setId(2L);
        user.setName("李四");
        user.setAge(15);
        user.setBirthday("1991-03-03");
        user.setHobbies(Arrays.asList("游泳", "下棋"));
        userMap.put(2L, user);

        user = new User();
        user.setId(3L);
        user.setName("王五");
        user.setAge(12);
        user.setBirthday("1994-03-03");
        user.setHobbies(Arrays.asList("打游戏", "读书"));
        userMap.put(3L, user);
    }

    @Override
    //    @WebMethod 不对方法单独设置,则无需加此注解,以默认配置暴露该方法
    @WebResult(name = "res")
    public User getById(@WebParam(name = "req") User user) {
        User res = userMap.get(user.getId());
        Assert.notNull(res, user.getId() + " 用户不存在");
        return res;
    }
}

配置类
@Configuration
public class WebServiceConfig {
    @Autowired
    private Bus bus;
    @Autowired
    private UserService userService;
    
 	/**
     * 如果有多个服务需要暴露,需定义多个EndpointImpl 的Bean,并关联到对应的 服务 ,绑定到指定路径
     * @return
     */
    
    @Bean
    public Endpoint endpoint() {
        EndpointImpl endpoint = new EndpointImpl(bus, userService);
        // 设置入口拦截器,拦截器实现 org.apache.cxf.interceptor.Interceptor 接口即可
//        endpoint.getInInterceptors().add(new CustomInterceptor());
        endpoint.publish("/user");
        return endpoint;
    }
}
yaml配置
cxf:
# 必须以 / 开头
  path: /student-service
启动

访问路径为 ip:port/student-service/user?wsdl
http://localhost:8080/student-service/user?wsdl
在这里插入图片描述

客户端

pom

		<dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-spring-boot-starter-jaxws</artifactId>
            <version>3.5.2</version>
        </dependency>

编码

测试代码(动态调用)
public static void main(String[] args) {
        JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
        Client client = dcf.createClient("http://localhost:8080/student-service/user?wsdl");
        // 设置出口拦截器,拦截器实现 org.apache.cxf.interceptor.Interceptor 接口即可
//        client.getOutInterceptors().add(new CustomInterceptor());
        Object[] objects;
        try {
        // p1:服务所在命名空间,p2:方法名
            QName opName = new QName("http://springboot.kalpana.top", "getById");
            User user = new User();
            user.setId(3L);
            objects = client.invoke(opName, user);
            System.out.println("响应 : " + objects[0]);
        } catch (java.lang.Exception e) {
            e.printStackTrace();
        }
    }
运行测试

部分日志

15:22:29.299 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Chain org.apache.cxf.phase.PhaseInterceptorChain@4acc5dff was modified. Current flow:
  receive [PolicyInInterceptor, AttachmentInInterceptor]
  post-stream [StaxInInterceptor]
  read [ReadHeadersInterceptor, SoapActionInInterceptor, StartBodyInterceptor]
  pre-protocol [MustUnderstandInterceptor]
  post-protocol [CheckFaultInterceptor]
  unmarshal [DocLiteralInInterceptor, SoapHeaderInterceptor]
  post-logical [WrapperClassInInterceptor]
  pre-invoke [StaxInEndingInterceptor, SwAInInterceptor, HolderInInterceptor, PolicyVerificationInInterceptor]

15:22:29.299 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.binding.soap.interceptor.ReadHeadersInterceptor@3650d4fc
15:22:29.309 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.binding.soap.interceptor.SoapActionInInterceptor@7e5843db
15:22:29.309 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.binding.soap.interceptor.StartBodyInterceptor@aaa0f76
15:22:29.309 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.binding.soap.interceptor.MustUnderstandInterceptor@7a8b9166
15:22:29.309 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.binding.soap.interceptor.CheckFaultInterceptor@340a8894
15:22:29.309 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.wsdl.interceptors.DocLiteralInInterceptor@459f703f
15:22:29.324 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.binding.soap.interceptor.SoapHeaderInterceptor@188ac8a3
15:22:29.324 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.jaxws.interceptors.WrapperClassInInterceptor@31dfc6f5
15:22:29.328 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.interceptor.StaxInEndingInterceptor@2264ea32
15:22:29.328 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.jaxws.interceptors.SwAInInterceptor@663bb8ef
15:22:29.328 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.jaxws.interceptors.HolderInInterceptor@37b52340
15:22:29.328 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.ws.policy.PolicyVerificationInInterceptor@44b29496
15:22:29.328 [main] DEBUG org.apache.cxf.ws.policy.PolicyVerificationInInterceptor - Verified policies for inbound message.
返回数据:User{id=3, name='王五', age=12, birthday='1994-03-03', hobbies=[打游戏, 读书]}
测试代码(静态调用)

静态调用需预先将webservice翻译成Java代码,然后以本地Java方法的方式调用

webservice转java插件
<plugin>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-codegen-plugin</artifactId>
    <version>3.5.2</version>
    <executions>
        <execution>
            <id>generate-sources</id>
            <phase>generate-sources</phase>
            <configuration>
            <!-- 代码生成的目录 -->
                <sourceRoot>src/main/resources/cxf</sourceRoot>
                <wsdlOptions>
                    <wsdlOption>
                    <!-- wsdl地址 -->
                        <wsdl>http://localhost:8080/student-service/user?wsdl</wsdl>
                    </wsdlOption>
                </wsdlOptions>
            </configuration>
            <goals>
                <goal>wsdl2java</goal>
            </goals>
        </execution>
    </executions>
</plugin>
运行Maven编译即可生成代码

在这里插入图片描述

运行测试
public static void main(String[] args) {
        UserServiceImplService userServiceImplService = new UserServiceImplService();

        UserServiceImpl userServiceImplPort = userServiceImplService.getUserServiceImplPort();
        User user = new User();
        user.setId(3L);
        User byId = userServiceImplPort.getById(user);
        System.out.println("静态测试返回的数据: " + byId);
    }
部分日志
15:47:56.727 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Chain org.apache.cxf.phase.PhaseInterceptorChain@3ecedf21 was modified. Current flow:
  receive [PolicyInInterceptor, AttachmentInInterceptor]
  post-stream [StaxInInterceptor]
  read [WSDLGetInterceptor, ReadHeadersInterceptor, SoapActionInInterceptor, StartBodyInterceptor]
  pre-protocol [MustUnderstandInterceptor]
  post-protocol [CheckFaultInterceptor, JAXBAttachmentSchemaValidationHack]
  unmarshal [DocLiteralInInterceptor, SoapHeaderInterceptor]
  post-logical [WrapperClassInInterceptor]
  pre-invoke [StaxInEndingInterceptor, SwAInInterceptor, HolderInInterceptor, PolicyVerificationInInterceptor]

15:47:56.727 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.frontend.WSDLGetInterceptor@3c1e23ff
15:47:56.727 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.binding.soap.interceptor.ReadHeadersInterceptor@2ba45490
15:47:56.739 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.binding.soap.interceptor.SoapActionInInterceptor@1bf0f6f6
15:47:56.739 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.binding.soap.interceptor.StartBodyInterceptor@37ff4054
15:47:56.739 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.binding.soap.interceptor.MustUnderstandInterceptor@7af707e0
15:47:56.740 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.binding.soap.interceptor.CheckFaultInterceptor@894858
15:47:56.740 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.jaxb.attachment.JAXBAttachmentSchemaValidationHack@737edcfa
15:47:56.740 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.wsdl.interceptors.DocLiteralInInterceptor@56bc3fac
15:47:56.760 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.binding.soap.interceptor.SoapHeaderInterceptor@df4b72
15:47:56.760 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.jaxws.interceptors.WrapperClassInInterceptor@18151a14
15:47:56.764 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.interceptor.StaxInEndingInterceptor@4943defe
15:47:56.765 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.jaxws.interceptors.SwAInInterceptor@169da7f2
15:47:56.765 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.jaxws.interceptors.HolderInInterceptor@64711bf2
15:47:56.765 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on interceptor org.apache.cxf.ws.policy.PolicyVerificationInInterceptor@125c082e
15:47:56.765 [main] DEBUG org.apache.cxf.ws.policy.PolicyVerificationInInterceptor - Verified policies for inbound message.
静态测试返回的数据: User{age=15, birthday='1991-03-03', hobbies=[游泳, 下棋], id=2, name='李四'}
Disconnected from the target VM, address: '127.0.0.1:13468', transport: 'socket'
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐