您的位置:首页 > 编程语言 > Java开发

Java for Web学习笔记(八五):SOAP(2)小例子

2017-10-03 09:39 549 查看

加入soap上下文

soap上下文配置

和spring framework不同,spring web service不支持代码配置,小例子中,我们采用了混合配制的方式,通过SoapServletContextConfiguration扫描@org.springframework.ws.server.endpoint.annotation.Endpoint标记,同时导入ws的soapServletContext.xml配置文件。
//... ...
import org.springframework.ws.server.endpoint.annotation.Endpoint;

@Configuration
@ComponentScan(
basePackages = "cn.wei.flowingflying.customer_support.site",
useDefaultFilters = false,
includeFilters = @ComponentScan.Filter(Endpoint.class)
)
@ImportResource("classpath:cn/wei/flowingflying/customer_support/config/soapServletContext.xml")
public class SoapServletContextConfiguration {
/* The explicit messageFactory bean (the name is important) overrides the default message factory so
* that the supported SOAP version is 1.2 instead of the default 1.1. */
@Bean
public WebServiceMessageFactory messageFactory(){
SaajSoapMessageFactory factory = new SaajSoapMessageFactory();
factory.setSoapVersion(SoapVersion.SOAP_12);
return factory;
}
}
我们在src/main/resources下,建立cn/wei/flowingflying/customer_support/config/soapServletContext.xml文件,用于告诉spring
web service使用哪个XSD schema文件来生成WSDL。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sws="http://www.springframework.org/schema/web-services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/web-services http://www.springframework.org/schema/web-services/web-services-2.0.xsd"> 
<sws:annotation-driven marshaller="jaxb2Marshaller"
unmarshaller="jaxb2Marshaller" />
<sws:dynamic-wsdl id="support" portTypeName="Support"
locationUri="/services/Soap/" createSoap11Binding="false"
createSoap12Binding="true"
targetNamespace="http://www.example.org/support">
<sws:xsd location="/WEB-INF/xsd/soap/support.xsd" />
</sws:dynamic-wsdl>
</beans>
这里targetNamespace是定义自动生成wdsl的targetNamespace,可以和我们在xsd schema中定义的不一样,例如http://www.example.org/support123,那么生成的wsdl为:
<wsdl:definitions targetNamespace="http://www.example.org/support123">
<wsdl:types>
<schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://www.example.org/support">
<element name="ticketsRequest" type="support:ticketsRequestType"/>
<complexType name="ticketsRequestType"/>
......
虽然这是允许的,但是就代码的可读性和可维护性而言,我们应当将两者设置为相同。

root上下文中不扫描@Endpoint

@ComponentScan(
basePackages = "cn.wei.chapter16.site",
excludeFilters = @ComponentScan.Filter({Controller.class, ControllerAdvice.class, Endpoint.class})
)
public class RootContextConfiguration

启动时加载soap dispatcher servlet

AnnotationConfigWebApplicationContext soapContext = new AnnotationConfigWebApplicationContext();
soapContext.register(SoapServletContextConfiguration.class);
//Spring Web Service提供了一个Dispather MessageDispatcherServlet来处理soap请求
MessageDispatcherServlet soapServlet = new MessageDispatcherServlet(soapContext);
soapServlet.setTransformWsdlLocations(true);
dispatcher = container.addServlet("springSoapDispatcher", soapServlet);
dispatcher.setLoadOnStartup(3);
dispatcher.addMapping("/services/Soap/","/services/Soap/support.wsdl");

我们注意到在启动时,为dispatcher设置了mapping "/services/Soap/",当然我们也可以写成"/services/Soap/*",这涉及到soap消息如何定位。

在配置文件soapServletContext.xml文件中,有
locationUri="/services/Soap/"
,但经过我们测试,并不实际起作用。但如果不提供,启动时会报错,虽然不起作用,我们应保持配置文件中的设置和启动代码的一致。
ws区分soap消息,依靠的消息中的namespace,也即依赖于soap消息里面的内容,而不是底层承载的http的url。因此对于soap接口,指定一个url即可。
如果使用了"/services/Soap/*",那么对于某个SOAP消息,访问/services/Soap/可以得到正确的结果,访问/services/Soap/123也可以,这可能不是我们需要的。
处理提供soap接口外,还提供查看wsdl的接口,例如http://localhost:8080/customer-support/services/Soap/support.wsdl,我们必须允许这个链接是soap上下文的。如果有很多的xsd schema文件,且可能在开发过程中进行调整,这是使用
/services/Soap/*
可能会更为方便。

实现SOAP Endpoint

@Endpoint //ws的标记
public class TicketSoapEndpoint {
private static final Logger logger = LogManager.getLogger();
private static final String NAMESPACE = "http://www.example.org/support";
@Inject private TicketService ticketService;

// Spring Web Service提供了@PayloadRoot、@SoapAction和@Action来过滤请求
//@PayloadRoot中namespace配置很重要,这是soap消息的匹配。在soapServletContext.xml的配置文件中有targetNamespace,在wsdl文件support.xsd中有targetNamespace。而这里的namespace是检查请求消息中的namespace,并进行过滤,虽然可以和配置文件以及wsdl文件中设置得不一样,不影响其找到相应的wsdl接口定义,但是我们仍应三处保持一致。
// @ResponsePayload或者RequestPayload表示soapbody中的净荷。
@PayloadRoot(namespace = NAMESPACE, localPart = "ticketsRequest")
@ResponsePayload
public TicketWebServiceList read(){
TicketWebServiceList list = new TicketWebServiceList();
list.setValue(this.ticketService.getAllTickets());
return list;
}

/* 这里prefix设置为s,只是将s作为prefix的标记,用于在@XPathParam进行标识,并发要求真的为s。
下面合法的匹配消息:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header/>
<soap:Body>
<support:ticketRequest xmlns:support="http://www.example.org/support">
<id>1</id>
</support:ticketRequest>
</soap:Body>
</soap:Envelope>
soap body也可以写成
<ticketRequest xmlns="http://www.example.org/support">
<id>1</id>
</ticketRequest>
或者
<a:ticketRequest xmlns:a="http://www.example.org/support">
<id>1</id>
</a:ticketRequest> */
@PayloadRoot(namespace = NAMESPACE, localPart = "ticketRequest")
@Namespace(uri = NAMESPACE, prefix = "s")
@ResponsePayload
public Ticket read(@XPathParam("/s:ticketRequest/id") long id) {
Ticket ticket = this.ticketService.getTicket(id);
logger.info("ticket create time : {}", ticket.getDateCreated());
return ticket;
}

/* 将soap消息体整个作为对象传递进来 */
@PayloadRoot(namespace = NAMESPACE, localPart = "createTicket")
@ResponsePayload
public Ticket create(@RequestPayload CreateTicket form) {
......
}
......
}

我们看看消息的交互,需要注意,请求消息中应该设置Content-type和Accept为application/soap+xml,否则会返回500的错误,ws认为不是合法的soap消息。



相关链接:
我的Professional Java for Web Applications相关文章
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: