SpringBoot集成 WebService
- 概述
- SpringBoot集成WebService
-
- 服务端
-
- pom
- 部分注解
- 编码
-
- 实体类
- 接口
- 实现类
- 配置类
- yaml配置
- 启动
- 客户端
-
- pom
- 编码
-
- 测试代码(动态调用)
-
- 运行测试
- 测试代码(静态调用)
-
- webservice转java插件
- 运行Maven代码可以通过编译生成
- 运行测试
- 部分日志
概述
第三方需要使用最近维护的项目对接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
启动
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'