spring boot 集成 cxf 实现 webservice
就可以生成客户端代码,将其 copy 到自己的包内。使用 jax-ws 注解。在 idea 中执行。
·
spring boot 集成 cxf 实现 webservice
服务端实现
引入依赖
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-spring-boot-starter-jaxws</artifactId>
<version>3.5.5</version>
</dependency>
<dependency>
<groupId>jakarta.xml.ws</groupId>
<artifactId>jakarta.xml.ws-api</artifactId>
</dependency>
服务类
使用 jax-ws 注解
@WebService(name = "UserService")
public interface UserService {
@WebMethod
String getUser(@WebParam(name = "userId")String userId);
}
@Service
@WebService(
serviceName = "UserService",
targetNamespace = "http://ws.bootintegration.example.com/",
// 需要填targetName,不然报错, No operation was found with the name, 一般为接口所在包名倒序,不是实现类的包名
endpointInterface = "com.example.bootintegration.client.ws.UserService"
//一般是接口所在包名
)
@WebPath(path = "/userService")
@Slf4j
public class UserServiceImpl implements UserService {
@Override
public String getUser(String userId) {
log.info("ws server recv: {}", userId);
return userId + " hello";
}
}
服务发布
- 自定义
@WebPath
实现webservice自动注册 - 实现 webservice 指定专门端口(一般的,
endpoint.publish
默认将 webservice服务发布在和web端口一致)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface WebPath {
/**
* 发布地址
* @return
*/
String path();
}
@Configuration
@Slf4j
public class CxfConfig {
@Autowired
private SpringBus bus;
@Autowired
private ApplicationContext applicationContext;
@Value("${cxf.port:9999}")
private int webServicePort = 9999;
@Value("${cxf.context:/soap-api}")
private String webServiceContextPath;
@Value("${cxf.schema:http}")
private String webServiceSchema;
/* *
* 设置 webservice 上下文根路径
*
* @return*/
@Bean
public ServletRegistrationBean<CXFServlet> registrationBean() {
return new ServletRegistrationBean<>(new CXFServlet(), webServiceContextPath + "/*");
}
@PostConstruct
public void userServiceEndPoint() {
String[] beanNames = applicationContext.getBeanNamesForAnnotation(WebPath.class);
for (String beanName : beanNames) {
Object bean = applicationContext.getBean(beanName);
WebPath annotation = bean.getClass().getAnnotation(WebPath.class);
if (!Objects.isNull(annotation)) {
String path = annotation.path();
//默认端口,这种是使用cxf注册
Endpoint endpoint = new EndpointImpl(bus, applicationContext.getBean(beanName));
endpoint.publish(path);
//这种是使用jax-ws java 原生注册
// Endpoint.publish("http://localhost:8080/cxfbt/userService?wsdl", applicationContext.getBean(beanName));
log.info("auto publish webservice: {}", path);
}
}
log.info("webservice starts at port: {}, path: {}", webServicePort, webServiceContextPath);
}
/*
@Bean
public Endpoint userServiceEndPoint() {
EndpointImpl endpoint = new EndpointImpl(bus, userService);
//自动绑定 server.port 端口
endpoint.publish("/userService");
return endpoint;
}*/
//一般的,webservice 端口和 web 端口一致: server.port
//======================以下是给 webservice服务提供 指定端口=============//
// WebService 专用端口(如 9999)
/**
* 这种方式是同时启动tomcat 多个端口,如8080,9999,但是这两个都可以访问wsdl
*
* @return
*/
@Bean
public TomcatServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
// 添加额外连接器
tomcat.addAdditionalTomcatConnectors(createWebServiceConnector());
return tomcat;
}
private Connector createWebServiceConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setPort(webServicePort);
connector.setScheme(webServiceSchema);
return connector;
}
/**
* 1. 给tomcat 启一个额外的端口,这里是 9999
* 2.通过 filter 强制 9999 给 webservice专门使用
*/
@Component
public class CxfFilter extends HttpFilter {
@Override
protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
if (request.getRequestURI().startsWith(webServiceContextPath) && request.getLocalPort()!=webServicePort){
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return;
}
chain.doFilter(request, response);
}
}
}
cxf 客户端
cxf 调用分两种
- 代理对象
- 动态客户端
生成客户端代码
使用 cxf-codegen-plugin
插件生成,引入依赖
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>3.5.5</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<sourceRoot>${project.basedir}/src/main/java</sourceRoot>
<encoding>UTF-8</encoding>
<wsdlOptions>
<!-- 指定wsdl文件 -->
<wsdlOption>
<!-- 也可以指定 http-->
<wsdl>http://localhost:9999/soap-api/userService?wsdl</wsdl>
<!-- <wsdl>src/main/resources/wsdl/userService.wsdl</wsdl>-->
<!-- <wsdlLocation>classpath:wsdl/userService.wsdl</wsdlLocation>-->
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
在 idea 中执行 clean generate-sources
, 就可以生成客户端代码,将其 copy 到自己的包内
代理调用
public interface WsServiceConst {
String SOAP_USER = "http://localhost:9999/soap-api/userService?wsdl";
}
@Configuration
public class CxfClientConfig {
/**
* 通过 cxf-codegen-plugin 插件生成客户端代码,创建代理
* 每个 wsdl 都需要创建一个代码
* @return
*/
@Bean("userServiceProxy")
public UserService userServiceProxy(){
JaxWsProxyFactoryBean factoryBean = new JaxWsProxyFactoryBean();
//UserService 客户端生成的服务名称,注意不要引错
factoryBean.setServiceClass(UserService.class);
factoryBean.setAddress(SOAP_USER);
return (UserService) factoryBean.create();
}
}
动态 client 调用
public class DynamicClient {
private static Map<String, Client> clientMap = new ConcurrentHashMap<>();
/**
* 使用动态工厂
*
* @param serviceName
* @return
*/
public static Client getClient(String serviceName) {
if (clientMap.containsKey(serviceName)) {
return clientMap.get(serviceName);
}
return clientMap.computeIfAbsent(serviceName, s -> {
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
return dcf.createClient(SOAP_USER);
});
}
}
测试
@RestController
@Slf4j
public class CxfClientController {
@Resource(name = "userServiceProxy")
private UserService userService;
/**
* 使用代理对象
*
* @return
*/
@GetMapping("/ws/hello")
public String invoke() {
String user = userService.getUser("tom");
log.info("ws result: {}", user);
return "success";
}
/**
* 使用动态工厂
*
* @return
*/
@GetMapping("/ws/hello2")
public String invoke2() throws Exception {
Client client = DynamicClient.getClient(WsServiceConst.SOAP_USER);
Object[] response = client.invoke("getUser", "tom");
if (response != null && response.length > 0) {
log.info("ws result: {}", response[0]);
} else {
log.info("ws client invoke error: {}", JSON.toJSONString(response));
}
return "success";
}
}
结果:
c.e.b.ws.impl.UserServiceImpl : ws server recv: tom
c.e.b.controller.CxfClientController : ws result: tom hello

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐
所有评论(0)