Spring Boot中@RestController与Apache CXF SOAP服务共存配置求助
你的问题核心在于*CXFServlet拦截了所有/ws/路径的请求,导致原本由Spring MVC DispatcherServlet处理的REST接口请求被CXF接管,从而失效。下面提供几种可行的解决方案,按推荐程度排序:
方案一:使用CXF与Spring MVC集成(推荐)
这种方式让CXF服务和REST服务共享Spring的DispatcherServlet,无需单独注册CXFServlet,从根本上避免了Servlet映射冲突。
步骤1:添加必要依赖
如果用Maven,在pom.xml中添加CXF的Spring MVC集成依赖(确保版本和你的CXF starter一致):
<dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-spring-boot-starter-jaxws</artifactId> <version>3.6.2</version> <!-- 替换为你的CXF版本 --> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http-spring-mvc</artifactId> <version>3.6.2</version> </dependency>
步骤2:配置CXF Endpoint
编写CXF配置类,使用SpringMvcEndpointServletRegistration替代普通的ServletRegistrationBean:
import org.apache.cxf.jaxws.EndpointImpl; import org.apache.cxf.transport.http.spring.SpringMvcEndpointServletRegistration; import org.apache.cxf.transport.servlet.CXFServlet; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.xml.ws.Endpoint; @Configuration public class CxfSoapConfig { // 注入你的SOAP服务实现类 @Autowired private FindPersonService findPersonService; @Bean public Endpoint soapEndpoint() { EndpointImpl endpoint = new EndpointImpl(findPersonService); // 这里设置的地址会拼接在/ws/后面,最终SOAP地址是/ws/findPerson endpoint.publish("/findPerson"); return endpoint; } @Bean public SpringMvcEndpointServletRegistration cxfMvcRegistration() { // 将CXF服务绑定到/ws/*路径,由Spring MVC DispatcherServlet统一处理 return new SpringMvcEndpointServletRegistration(new CXFServlet(), "/ws/*"); } }
这样配置后,你的REST接口(比如@GetMapping("/ws/person"))和SOAP接口(/ws/findPerson)会由同一个DispatcherServlet处理,不会再出现冲突。
方案二:精确映射CXFServlet到SOAP服务路径
如果你不想修改依赖或集成方式,可以调整CXFServlet的映射规则,只让它处理SOAP服务的精确路径,而非整个/ws/*:
修改你的CXFServlet注册代码:
@Bean public ServletRegistrationBean cxfServletRegistration() { ServletRegistrationBean<CXFServlet> registration = new ServletRegistrationBean<>(new CXFServlet()); // 只精确匹配SOAP服务的路径,有多个SOAP服务就添加多个映射 registration.addUrlMappings("/ws/findPerson"); // 如果还有其他SOAP服务,比如/ws/createPerson,继续添加 // registration.addUrlMappings("/ws/createPerson"); return registration; }
这种方式下,只有请求精确匹配/ws/findPerson时才会被CXFServlet处理,其他/ws前缀的请求(比如/ws/person)会正常被Spring MVC处理,REST服务就能恢复。
方案三:拆分路径前缀(扩展性好)
如果你的服务数量较多,推荐将REST和SOAP服务的路径前缀拆分,让结构更清晰:
步骤1:调整CXFServlet映射
@Bean public ServletRegistrationBean cxfServletRegistration() { // 让CXF处理/ws/soap/*下的所有SOAP请求 return new ServletRegistrationBean(new CXFServlet(), "/ws/soap/*"); }
步骤2:配置SOAP Endpoint
@Bean public Endpoint soapEndpoint() { EndpointImpl endpoint = new EndpointImpl(findPersonService); // SOAP服务地址最终为/ws/soap/findPerson endpoint.publish("/findPerson"); return endpoint; }
步骤3:调整REST接口路径
将REST接口的路径调整为/ws/rest/person(保持和SOAP路径区分):
@RestController @RequestMapping("/ws/rest") public class PersonRestController { @GetMapping("/person") public Person getPerson() { // 实现逻辑 } }
这种方式不仅解决了冲突,还让两种服务的路径结构更清晰,后期维护和扩展更方便。
内容的提问来源于stack exchange,提问作者NAZEHA

