我有一个 Spring MVC 项目。我写了一段类似的代码
@Controller
@RequestMapping("CallBack")
@WebService(name = "NotificationToCP", targetNamespace = "http://SubscriptionEngine.ibm.com")
public class CallbackController {
@RequestMapping("")
@ResponseBody
@WebMethod(action = "notificationToCP")
@RequestWrapper(localName = "notificationToCP", targetNamespace = "http://SubscriptionEngine.ibm.com", className = "in.co.mobiz.airtelVAS.model.NotificationToCP_Type")
@ResponseWrapper(localName = "notificationToCPResponse", targetNamespace = "http://SubscriptionEngine.ibm.com", className = "in.co.mobiz.airtelVAS.model.NotificationToCPResponse")
public NotificationToCPResponse index(
@WebParam(name = "notificationRespDTO", targetNamespace = "") CPNotificationRespDTO notificationRespDTO) {
return new NotificationToCPResponse();
}
}
我可以一起使用Spring MVC + Webservices吗?我想要的只是一个接受 SOAP 请求并处理它的控制器。 url 必须是 /CallBack。作为一个新手,我仍然感到困惑。像上面这样的东西会起作用吗?否则我该如何让它继续下去。
我不会将 Spring MVC 和 SOAP Web 服务 (JAX-WS) 混合在一起,因为它们有不同的用途。
更好的做法是将业务操作封装在服务类中,并使用 MVC 控制器和 JAX-WS 公开它。例如:
您好服务
@Service
public class HelloService {
public String sayHello() {
return "hello world";
}
}
HelloController 通过自动装配注入了 HelloService 引用。这是标准 Spring MVC 控制器,它调用服务并将结果作为模型传递给视图(例如:hello.jsp 视图)
@Controller
@RequestMapping("/hello")
public class HelloController {
@Autowired private HelloService helloService;
@RequestMapping(method = RequestMethod.GET)
public String get(Model model) {
model.addAttribute("message", helloService.sayHello());
return "hello";
}
}
JAX-WS 端点也调用相同的服务。不同之处在于该服务作为 SOAP Web 服务公开
@WebService(serviceName="HelloService")
public class HelloServiceEndpoint {
@Autowired private HelloService helloService;
@WebMethod
public String sayHello() {
return helloService.sayHello();
}
}
请注意,上面的 JAX-WS 风格的 Web 服务不能保证在所有 Spring 部署上自动工作,特别是部署在非 Java EE 环境 (tomcat) 上时。可能需要额外的设置。
是的,您可能出于某些原因想要向现有 Spring MVC 应用程序添加 Web 服务端点。问题是您可能需要为每个路径设置不同的路径,这很好。
您将需要两个 servlet,一个用于处理 HTTP/MVC 的标准调度程序 servlet 和一个用于处理 SOAP 调用的 MessageDispatcherServlet。
配置可能很棘手。首先要明白,当您添加 Spring-ws 依赖项时,您将与 Spring MVC 存在依赖项不匹配的情况。您需要在 pom 中排除 Spring-web,如下所示:
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-core</artifactId>
<version>2.2.1.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</exclusion>
</exclusions>
</dependency>
完成此操作后,您将需要添加两个 servlet,一个用于通过 Spring MVC 处理 Web 请求,另一个用于处理 SOAP。
我假设使用 Spring 4 进行 no-xml 配置,SpringBoot 也是可能的。
这是您将添加到 Web 初始化程序中的关键代码:
DispatcherServlet servlet = new DispatcherServlet();
// no explicit configuration reference here: everything is configured in the root container for simplicity
servlet.setContextConfigLocation("");
/* TMT From Java EE 6 API Docs:
* Registers the given servlet instance with this ServletContext under the given servletName.
* The registered servlet may be further configured via the returned ServletRegistration object.
*/
ServletRegistration.Dynamic appServlet = servletContext.addServlet("appServlet", servlet);
appServlet.setLoadOnStartup(1);
appServlet.setAsyncSupported(true);
Set<String> mappingConflicts = appServlet.addMapping("/web/*");
MessageDispatcherServlet mds = new MessageDispatcherServlet();
mds.setTransformWsdlLocations(true);
mds.setApplicationContext(context);
mds.setTransformWsdlLocations(true);
ServletRegistration.Dynamic mdsServlet = servletContext.addServlet("mdsServlet", mds);
mdsServlet.addMapping("/wsep/*");
mdsServlet.setLoadOnStartup(2);
mdsServlet.setAsyncSupported(true);
这就是全部内容了。其余的配置是标准的东西,可以在许多示例中找到。
例如,您可以轻松地将 Spring MVC 和 Spring-WS 的 Spring IO 示例混合作为测试床。只需确保相应地设置
WebMvcConfigurerAdapter
和 WsConfigurerAdapter
即可。它们将是两个独立的类,分别用 @Configuration @EnableWebMvc
和 @EnableWs @Configuration
单独注释。它们必须与您的 @Endpoint
类一起添加到组件扫描中。
使用浏览器通过
/web/*
编译、运行和测试根上下文中的 MVC 内容,并通过导入 WSDL 并点击根中的 /wsep/*
使用 SoapUI 进行 SOAP 调用。每个 servlet 处理的每个路径。
在看到 stackoverflow 中的所有建议后,我觉得我需要创建两个调度程序 servlet,一个用于 SOAP 端点,另一个用于 REST 端点,以便 SOAP 和 REST 端点可以构建到同一个项目中。但这里的关键点是调度程序 servlet 应该指向它自己的 URL 映射。我们可以将每个 servlet 配置为拥有自己的 URL 映射。 我正在使用 Spring Boot,下面的内容似乎适用于我的情况。我希望它可以帮助其他人。
第一步: 您可以禁用 Spring Boot 的自动配置调度程序 servlet,或者我们可以使用默认的自动配置调度程序来保持其原始行为。 经过多次组合测试后,我意识到将自动配置的调度程序保留其原始行为会更容易。
但是如果您有兴趣调整该调度程序 servlet,您可以执行以下操作:
@SpringBootApplication(exclude = DispatcherServletAutoConfiguration.class) -> 在你的主类中。
在新班级,
@配置 公共类 RestWebConfig {
@Bean
public DispatcherServlet dispatcherServlet() {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
//dispatcherServlet.setThreadContextInheritable(true);
//dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
return dispatcherServlet;
}
@Bean
public ServletRegistrationBean dispatcherServletRegistration() {
ServletRegistrationBean registration = new ServletRegistrationBean(dispatcherServlet());
registration.setName(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME);
return registration;
}
@Bean
public DispatcherServletPath dispatcherServletPath() {
return () -> "/rest";
}
}
第二步: 我尝试自定义 DispatcherServlet,使我的第二个 SOAP 调度程序 servlet 指向“/”,但我无法让它工作。 因此,我默认为原始行为,所有 REST 请求都将路由到 Spring Boot 的自动配置的 DispatcherServlet。 然后我创建了下面的 Message DispatcherServlet,它实际上构建在 DispatcherServlet 之上,具有不同的 URL 映射 - “/soap/”。
@EnableWs
@Configuration
public class WebConfig extends WsConfigurerAdapter{
@Bean
public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean<>(servlet, "/soap/*");
}
@Bean(name = "app")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchemaCollection appserviceSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("AppservicePort");
wsdl11Definition.setLocationUri("/soap/appservice");
wsdl11Definition.setTargetNamespace("http://xmlns.fedex.com/appservice");
wsdl11Definition.setSchemaCollection(appserviceSchema);
return wsdl11Definition;
}
@Bean
public XsdSchemaCollection appserviceSchema() {
return new CommonsXsdSchemaCollection(new ClassPathResource("xsds/CommonServices.xsd"));
}
}
有了以上配置,