二、参考文献
4. 共享组件
本章探讨了客户端和服务器端 Spring-WS 开发共享的组件。这些接口和类代表了 Spring-WS 的构建模块,因此即使你不直接使用它们,也需要理解它们的作用。
4.1. 网络服务消息
本节介绍了Spring-WS使用的消息和消息工厂。
4.1.1.WebServiceMessage
Spring-WS 的核心接口之一是WebServiceMessage. 该接口表示一个与协议无关的XML消息。该接口包含提供访问消息有效载荷的方法,形式为javax.xml.transform.来源或者javax.xml.变换.结果.源和结果是表示对XML输入和输出抽象的标签接口。具体实现会包裹各种XML表示,如下表所示:
| 源代码或结果实现 | 封装XML表示 |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
除了读取和写入负载外,网络服务消息还可以写入输出流。
4.1.2.肥皂信息
肥皂信息是 的子类WebServiceMessage. 它包含 SOAP 特定的方法,比如获取 SOAP 头部、SOAP 错误等。一般来说,你的代码不应依赖于肥皂信息,因为SOAP主体(消息的有效载荷)的内容可以通过以下方式获得getPayloadSource()和getPayloadResult()在WebServiceMessage. 只有在需要执行SOAP特定的作(比如添加头部、获取附件等)时,才需要投射WebServiceMessage自肥皂信息.
4.1.3. 消息工厂
具体消息实现由WebServiceMessageFactory. 该工厂可以创建空消息或从输入流读取消息。一个具体的实现WebServiceMessageFactory基于SAAJ(Java的SOAP附件API)提供。
SaajSoapMessageFactory(Saaj肥皂信息工厂)
这SaajSoapMessageFactory(Saaj肥皂信息工厂)使用 Java 的 SOAP 附件 API(SAAJ)来创建肥皂信息实现。 SAAJ 是 J2EE 1.4 的一部分,因此大多数现代应用服务器应支持它。以下是通用应用服务器提供的 SAAJ 版本概述:
| 应用服务器 | SAAJ版本 |
|---|---|
BEA WebLogic 8 |
1.1 |
BEA WebLogic 9 |
1.1/1.21 |
IBM WebSphere 6 |
1.2 |
太阳玻璃鱼1号 |
1.3 |
1Weblogic 9 在 SAAJ 1.2 实现中存在一个已知的错误:它实现了所有 1.2 接口,但抛出了 |
|
此外,Java SE 6 包含了 SAAJ 1.3。你可以接线SaajSoapMessageFactory(Saaj肥皂信息工厂)如下:
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory" />
| SAAJ基于DOM,即文档对象模型。这意味着所有SOAP消息都存储在内存中。对于较大的SOAP消息,这种性能可能不佳。 |
SOAP 1.1 或 1.2
SaajSoapMessageFactory(Saaj肥皂信息工厂)有肥皂剧版本性质,其中你可以注入一个肥皂剧版本不断。 默认版本是1.1,但你可以设置为1.2:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util"
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-2.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.0.xsd">
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory">
<property name="soapVersion">
<util:constant static-field="org.springframework.ws.soap.SoapVersion.SOAP_12"/>
</property>
</bean>
</beans>
在前面的例子中,我们定义了一个SaajSoapMessageFactory(Saaj肥皂信息工厂)它只接受 SOAP 1.2 消息。
|
尽管两个版本的SOAP格式非常相似,但1.2版本与1.1不兼容,因为它使用了不同的XML命名空间。SOAP 1.1和1.2的其他主要区别包括故障结构的不同以及 关于SOAP版本号(或WS-*规范版本号)需要注意的一个重要点是,规范的最新版本通常不是最受欢迎的版本。对于SOAP来说,这意味着目前最好的版本是1.1。1.2版本未来可能会更受欢迎,但目前1.1是最安全的选择。 |
4.1.4.消息上下文
通常,消息成对出现:请求和响应。请求在客户端创建,通过某种传输方式发送到服务器端,响应由此生成。该响应会返回客户端,客户端读取。
在Spring-WS中,这样的对话包含在消息上下文,具有获取请求和响应消息的属性。在客户端,消息上下文由WebService模板. 在服务器端,消息上下文是从传输专用输入流中读取的。例如,在HTTP中,消息是从以下HttpServletRequest,响应写回HttpServletResponse(服务服务响应).
4.2.运输语境
SOAP协议的一个关键特性是它试图实现传输无关性。这也是为什么例如,Spring-WS不支持通过HTTP请求URL将消息映射到端点,而是按消息内容。
然而,有时需要在客户端或服务器端访问底层传输。为此,Spring-WS 具有运输语境. 传输上下文允许访问底层WebServiceConnection,通常为HttpServlet连接在服务器端或HttpUrl连接或共享HttpConnection在客户端。例如,你可以在服务器端端点或拦截器中获取当前请求的IP地址:
TransportContext context = TransportContextHolder.getTransportContext();
HttpServletConnection connection = (HttpServletConnection )context.getConnection();
HttpServletRequest request = connection.getHttpServletRequest();
String ipAddress = request.getRemoteAddr();
4.3. 用 XPath 处理 XML
处理XML的最佳方法之一是使用XPath。引用[effective-xml],第35条:
XPath 是第四代声明式语言,允许你指定想处理的节点,而无需具体说明处理器如何导航到这些节点。XPath 的数据模型设计得非常好,几乎所有开发者都希望 XML 实现。例如,它合并所有相邻文本,包括 CDATA 部分的文本,允许计算跳过注释和处理指令的值,包含子元素和后代元素的文本,并要求所有外部实体引用都必须解析。实际上,XPath 表达式对输入文档中意外但可能无关紧要的变化通常更为稳健。
Spring-WS 在应用中使用 XPath 有两种方式:更快XPath表达式或者更灵活的XPathOperations(十字架运营).
4.3.1.XPath表达式
这XPath表达式是对已编译的XPath表达式(如Java 5)的抽象javax.xml.xpath.XPath表达式接口或JaxenXPath类。 在应用上下文中构造表达式,你可以使用XPathExpressionFactoryBean. 以下示例使用了这种工厂豆子:
<beans xmlns="http://www.springframework.org/schema/beans"
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-2.0.xsd">
<bean id="nameExpression" class="org.springframework.xml.xpath.XPathExpressionFactoryBean">
<property name="expression" value="/Contacts/Contact/Name"/>
</bean>
<bean id="myEndpoint" class="sample.MyXPathClass">
<constructor-arg ref="nameExpression"/>
</bean>
</beans>
前面的表达式没有使用命名空间,但我们可以通过使用命名空间工厂豆的属性。该表达式可在代码中使用如下:
package sample;
public class MyXPathClass {
private final XPathExpression nameExpression;
public MyXPathClass(XPathExpression nameExpression) {
this.nameExpression = nameExpression;
}
public void doXPath(Document document) {
String name = nameExpression.evaluateAsString(document.getDocumentElement());
System.out.println("Name: " + name);
}
}
如果想要更灵活的方法,你可以使用节点映射器,类似于行图仪在Spring的JDBC支持中。以下示例展示了如何使用它:
package sample;
public class MyXPathClass {
private final XPathExpression contactExpression;
public MyXPathClass(XPathExpression contactExpression) {
this.contactExpression = contactExpression;
}
public void doXPath(Document document) {
List contacts = contactExpression.evaluate(document,
new NodeMapper() {
public Object mapNode(Node node, int nodeNum) throws DOMException {
Element contactElement = (Element) node;
Element nameElement = (Element) contactElement.getElementsByTagName("Name").item(0);
Element phoneElement = (Element) contactElement.getElementsByTagName("Phone").item(0);
return new Contact(nameElement.getTextContent(), phoneElement.getTextContent());
}
});
PlainText Section qName; // do something with the list of Contact objects
}
}
类似于春季JDBC中的行映射行图仪每个结果节点都通过匿名内类映射。在这种情况下,我们创建联系我们稍后会用到的对象。
4.3.2.XPathOperations(十字架运营)
这XPath表达式你可以只评估一个预编译表达式。一个更灵活但较慢的替代方案是XPathOperations(十字架运营). 本课程遵循整个春季期间常用的模板模式(Jdbc模板,Jms模板,以及其他。
以下列表展示了一个示例:
package sample;
public class MyXPathClass {
private XPathOperations template = new Jaxp13XPathTemplate();
public void doXPath(Source source) {
String name = template.evaluateAsString("/Contacts/Contact/Name", request);
// do something with name
}
}
4.4. 消息记录与追踪
在开发或调试Web服务时,查看(SOAP)消息到达时或发送前的内容会非常有用。 Spring-WS通过标准的Commons日志接口提供此功能。
要记录所有服务器端消息,设置org.springframework.ws.server.MessageTracingLogging器电平到调试或跟踪.
在调试级别,只有有效载荷根元素被记录。
在跟踪在 Level,所有消息内容都会被记录。
如果你只想记录已发送的消息,可以使用org.springframework.ws.server.MessageTracing.sent记录。
同样,你可以使用org.springframework.ws.server.MessageTracing.received只记录收到的消息。
在客户端,存在类似的日志记录器:org.springframework.ws.client.MessageTracing.sent和org.springframework.ws.client.MessageTracing.received.
以下示例为log4j2.properties配置文件记录客户端发送消息的全部内容,客户端接收消息仅记录有效载荷根元素。
在服务器端,有效载荷根会记录发送和接收的消息:
appender.console.name=STDOUT
appender.console.type=Console
appender.console.layout.type=PatternLayout
appender.console.layout.pattern=%-5p [%c{3}] %m%n
rootLogger=DEBUG,STDOUT
logger.org.springframework.ws.client.MessageTracing.sent=TRACE
logger.org.springframework.ws.client.MessageTracing.received=DEBUG
logger.org.springframework.ws.server.MessageTracing=DEBUG
在此配置下,典型输出为:
TRACE [client.MessageTracing.sent] Sent request [<SOAP-ENV:Envelope xmlns:SOAP-ENV="...
DEBUG [server.MessageTracing.received] Received request [SaajSoapMessage {http://example.com}request] ...
DEBUG [server.MessageTracing.sent] Sent response [SaajSoapMessage {http://example.com}response] ...
DEBUG [client.MessageTracing.received] Received response [SaajSoapMessage {http://example.com}response] ...
5. 使用 Spring-WS 创建 Web 服务
Spring-WS 服务器端支持是围绕消息调度器它将收到的消息发送到端点,并可配置端点映射、响应生成和端点拦截。
端点通常会用@Endpoint注释并具有一种或多种处理方法。
这些方法通过检查消息的部分(通常是有效载荷)来处理接收的 XML 请求消息,并生成某种响应。
通常你可以用另一个注释来注释方法。@PayloadRoot,用来表示它能处理什么类型的消息。
Spring-WS 的 XML 处理极其灵活。 端点可以从Spring-WS支持的大量XML处理库中选择,包括:
-
DOM家族:W3C DOM、JDOM、DOM4j和XOM。
-
SAX或StAX:为了更快的表现。
-
XPath:从信息中提取信息。
-
编组技术(JAXB、Castor、XMLBeans、JiBX 或 XStream):将 XML 转换为对象,反之亦然。
5.1. 该消息调度器
Spring-WS 的服务器端围绕一个中心类设计,该类将收到的 XML 消息调度到端点。
春季-WS消息调度器非常灵活,允许你使用任何类型的类作为端点,只要能在 Spring IoC 容器中配置即可。
在某种程度上,消息调度员类似于斯普林的调度器服务,即春季网页MVC中使用的“前端控制器”。
下图展示了消息调度器:
当消息调度器是设置为使用,并且会收到针对该特定调度器的请求,消息调度器开始处理请求。
以下过程描述了如何进行消息调度器处理以下请求:
-
配置
端点映射搜索合适的端点。 如果找到端点,会调用与该端点相关的调用链(预处理器、后处理器和端点)来生成响应。 -
会找到适合端点的适配器。 这
消息调度器委托给该适配器调用端点。 -
如果收到回复,它就会被发送。 如果没有返回响应(这可能是由于前置处理器或后处理器出于安全原因拦截了请求),则不会发送任何响应。
在处理请求过程中抛出的异常会被应用上下文中声明的端点异常解析器捕获。 使用这些异常解析器可以定义自定义行为(例如返回SOAP错误),以防此类异常被抛出。
消息调度器在消息上下文上工作,而非针对特定传输的输入流和输出流。
因此,传输专用请求需要读取消息上下文.
对于HTTP,这通过一个WebServiceMessageReceiverHandlerAdapter(这是一张春季网拦截者),因此消息调度器可以按标准布线调度器服务.
不过,还有一种更方便的方法,如下所示MessageDispatcherServlet.
5.2. 运输舰
Spring-WS支持多种传输协议。 最常见的是HTTP传输,为此提供了自定义的servlet,但你也可以通过JMS甚至电子邮件发送消息。
5.2.1.MessageDispatcherServlet
这MessageDispatcherServlet是标准servlet它方便地从标准的Spring Web延伸出来调度器服务并包裹消息调度器.
因此,它将这些属性合并为一体。
作为消息调度器,它遵循前一节描述的请求处理流程。
作为一个servlet,MessageDispatcherServlet配置在web.xml在你的网页应用中。
您想要的请求MessageDispatcherServlet处理 必须通过同一中的 URL 映射来映射web.xml文件。
这是标准的 JavaEE servlet 配置。
以下示例展示了这样的MessageDispatcherServlet声明与映射:
<web-app>
<servlet>
<servlet-name>spring-ws</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-ws</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
在上述示例中,所有请求均由春-Ws MessageDispatcherServlet.
这只是构建 Spring-WS 的第一步,因为 Spring-WS 框架使用的各种组件豆也需要配置。
该配置由标准的 Spring XML 组成<豆/>定义。
因为MessageDispatcherServlet是标准Spring调度器服务,它查找一个名为[servlet-name]-servlet.xml在网内在你Web应用的目录中创建Spring容器中定义的豆子。
在前述例子中,它寻找/网-INF/spring-ws-servlet.xml.
该文件包含所有 Spring-WS 的 Beans,如端点、编组器等。
作为 的替代方案web.xml你可以编程配置 Spring-WS。
为此,Spring-WS 提供了若干抽象基类,用于扩展WebApplicationInitializer该接口存在于 Spring 框架中。
如果你也使用,也要使用。@Configuration对于你的Beans定义,你应该扩展AbstractAnnotationConfigMessageDispatcherServletInitializer:
public class MyServletInitializer
extends AbstractAnnotationConfigMessageDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{MyRootConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{MyEndpointConfig.class};
}
}
在前面的例子中,我们告诉Spring端点豆的定义可以在MyEndpointConfig类(该类为@Configuration班级)。
其他Beans定义(通常是服务、仓库等)可以在我的根配置类。
默认情况下,AbstractAnnotationConfigMessageDispatcherServletInitializer将 servlet 映射到两个模式:/服务业和*.WSDL,不过你可以通过覆盖getServletMappings()方法。
关于程序配置的更多细节MessageDispatcherServlet,参考 的 Javadoc抽象消息调度器ServletInitializer和AbstractAnnotationConfigMessageDispatcherServletInitializer.
自动WSDL曝光
这MessageDispatcherServlet自动检测任何WSDL定义Beans定义在其春季容器中。
所有的WSDL定义检测到的豆子也通过WsdlDefinitionHandlerAdapter.
这是一种方便的方式,通过定义一些豆子,将你的WSDL暴露给客户。
举个例子,考虑以下情况<静态-WSDL>定义,定义在 Spring-WS 配置文件中(/WEB-INF/[servlet-name]-servlet.xml).
注意身份证属性,因为它用于暴露WSDL时。
<sws:static-wsdl id="orders" location="orders.wsdl"/>
或者,也可以是@Bean在 A 中的方法@Configuration类:
@Bean
public SimpleWsdl11Definition orders() {
return new SimpleWsdl11Definition(new ClassPathResource("orders.wsdl"));
}
你可以访问定义在命令.WSDL在类路径上的文件获取请求到以下形式的URL(根据需要替换主机、端口和servlet上下文路径):
http://localhost:8080/spring-ws/orders.wsdl
|
都 |
另一个不错的特点MessageDispatcherServlet(或者更准确地说,是WsdlDefinitionHandlerAdapter)是它可以变换位置它暴露的所有WSDL以反映来请求的URL。
请注意位置变形功能默认关闭。
要开启此功能,你需要指定一个初始化参数到MessageDispatcherServlet:
<web-app>
<servlet>
<servlet-name>spring-ws</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>transformWsdlLocations</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>spring-ws</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
如果你使用,AbstractAnnotationConfigMessageDispatcherServletInitializer,实现变换只需覆盖isTransformWsdlLocations()返回方法true.
请查阅类级Javadoc中的WsdlDefinitionHandlerAdapter课程内容是了解整个转变过程。
作为手写WSDL和曝光的替代方案<静态-WSDL>Spring-WS 还可以从 XSD 模式生成 WSDL。
这就是《WSDL的出版》中所展示的方法。
下一个应用上下文摘要展示了如何创建这样一个动态的WSDL文件:
<sws:dynamic-wsdl id="orders"
portTypeName="Orders"
locationUri="http://localhost:8080/ordersService/">
<sws:xsd location="Orders.xsd"/>
</sws:dynamic-wsdl>
或者,你也可以用 Java@Bean方法:
@Bean
public DefaultWsdl11Definition orders() {
DefaultWsdl11Definition definition = new DefaultWsdl11Definition();
definition.setPortTypeName("Orders");
definition.setLocationUri("http://localhost:8080/ordersService/");
definition.setSchema(new SimpleXsdSchema(new ClassPathResource("Orders.xsd")));
return definition;
}
这<dynamic-wsdl>元素依赖于DefaultWsdl11定义类。
该定义类在org.springframework.ws.wsdl.wsdl11.provider包裹和ProviderBasedWsdl4jDefinition在首次请求时生成WSDL。
查看这些类的类级 Javadoc,了解如何扩展这种机制(如有必要)。
这DefaultWsdl11定义(因此,<dynamic-wsdl>tag)通过使用约定从XSD模式构建WSDL。
它会对整体进行迭代元素在模式中发现的元素,并创建消息对所有元素。
接下来,它生成一个WSDL操作对于所有以定义的请求或响应后缀结尾的消息。
默认请求后缀为请求.
默认的响应后缀为响应,尽管这些可以通过设置请求后缀和回复后缀属性<dynamic-wsdl />分别。
它还建造了端口类型,捆绑和服务根据手术情况。
例如,如果我们Orders.xsd模式定义了获取订单请求和获取命令响应元素<dynamic-wsdl>生成一个获取订单请求和获取命令响应信息和获取订单该作被置于订单端口类型。
如果想使用多个模式,无论是通过包含还是导入,你可以把 Commons XMLSchema 放在类路径上。
如果 Commons XMLSchema 在类路径上,则<dynamic-wsdl>element 跟随所有 XSD 导入,并将其作为一个 XSD 在 WSDL 中内嵌。
用 Java 配置,你可以使用CommonsXsdSchemaCollection如下例所示:
@Bean
public DefaultWsdl11Definition ordersWsdlDefinition() throws Exception {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
// ... configuration
CommonsXsdSchemaCollection schemas = new CommonsXsdSchemaCollection(
new ClassPathResource("xsd/order/main.xsd"));
schemas.setInline(true);
wsdl11Definition.setSchemaCollection(schemas);
return wsdl11Definition;
}
这大大简化了模式的部署,同时仍允许单独编辑它们。
|
虽然在运行时用XSD创建WSDL很方便,但这种方法也有一些缺点。 首先,虽然我们努力保持WSDL生成过程在不同版本间的一致性,但仍有可能(略有变化)。 其次,生成速度稍慢,不过生成后会缓存WSDL以便后续调用。 |
因此,你应该使用<dynamic-wsdl>仅限于项目开发阶段。
我们建议使用浏览器下载生成的WSDL,存储在项目中,并用以下方式暴露<静态-WSDL>.
这是唯一能真正确定WSDL不会随时间变化的方法。
5.2.2. 在 a 中接线 Spring-WS调度器服务
作为MessageDispatcherServlet,你可以接线消息调度器在标准的Spring-Web MVC中调度器服务.
默认情况下,调度器服务只能委派给控制器但我们可以指示它委派给消息调度器通过添加一个WebServiceMessageReceiverHandlerAdapter对于 Servlet 的 Web 应用上下文:
<beans>
<bean class="org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter"/>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="defaultHandler" ref="messageDispatcher"/>
</bean
<bean id="messageDispatcher" class="org.springframework.ws.soap.server.SoapMessageDispatcher"/>
...
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
</beans>
注意,通过明确添加WebServiceMessageReceiverHandlerAdapter调度器servlet不加载默认适配器,无法处理标准的Spring-MVC@Controllers.
因此,我们添加RequestMappingHandlerAdapter在最后。
类似地,你可以接线WsdlDefinitionHandlerAdapter以确保调度器服务可以处理WSDL定义接口:
<beans>
<bean class="org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter"/>
<bean class="org.springframework.ws.transport.http.WsdlDefinitionHandlerAdapter"/>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="*.wsdl">myServiceDefinition</prop>
</props>
</property>
<property name="defaultHandler" ref="messageDispatcher"/>
</bean>
<bean id="messageDispatcher" class="org.springframework.ws.soap.server.SoapMessageDispatcher"/>
<bean id="myServiceDefinition" class="org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition">
<prop name="wsdl" value="/WEB-INF/myServiceDefinition.wsdl"/>
</bean>
...
</beans>
5.2.3. JMS 运输
Spring-WS 通过 Spring 框架提供的 JMS 功能支持服务器端 JMS 处理。
Spring-WS 提供WebServiceMessageListener插入MessageListenerContainer.
该消息监听器需要WebServiceMessageFactory和消息调度器去作。
以下配置示例展示了这一点:
<beans>
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="vm://localhost?broker.persistent=false"/>
</bean>
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>
<bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destinationName" value="RequestQueue"/>
<property name="messageListener">
<bean class="org.springframework.ws.transport.jms.WebServiceMessageListener">
<property name="messageFactory" ref="messageFactory"/>
<property name="messageReceiver" ref="messageDispatcher"/>
</bean>
</property>
</bean>
<bean id="messageDispatcher" class="org.springframework.ws.soap.server.SoapMessageDispatcher">
<property name="endpointMappings">
<bean
class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping">
<property name="defaultEndpoint">
<bean class="com.example.MyEndpoint"/>
</property>
</bean>
</property>
</bean>
</beans>
5.2.4. 电子邮件传输
除了HTTP和JMS,Spring-WS还提供服务器端电子邮件处理。
此功能通过邮件消息接收器类。
这个班级监控POP3或IMAP文件夹,把邮件转换成WebServiceMessage,并通过SMTP发送任何响应。
你可以通过以下方式配置主机名storeUri,表示要监控请求的邮件文件夹(通常是 POP3 或 IMAP 文件夹),以及交通Uri,指示用于发送响应的服务器(通常是SMTP服务器)。
你可以配置如何邮件消息接收器通过可插拔策略监控入信:该监测策略.
默认情况下,采用轮询策略,每五分钟轮询一次新邮件。
你可以通过设置轮询间隔策略上的财产。
默认情况下,全部监测策略实现会删除已处理的消息。
你可以通过设置deleteMessages(删除信息)财产。
作为效率较低的轮询方法的替代方案,有一种使用IMAP IDLE的监测策略。
IDLE 命令是 IMAP 邮件协议的一个可选扩展,允许邮件服务器向邮件消息接收器异步。
如果你使用的是支持 IDLE 命令的 IMAP 服务器,你可以插入ImapIdleMonitoringStrategy进入监测策略财产。
以下配置展示了如何使用服务器端电子邮件支持,覆盖默认轮询间隔,每30秒(30,000毫秒)检查一次:
<beans>
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>
<bean id="messagingReceiver" class="org.springframework.ws.transport.mail.MailMessageReceiver">
<property name="messageFactory" ref="messageFactory"/>
<property name="from" value="Spring-WS SOAP Server <[email protected]>"/>
<property name="storeUri" value="imap://server:[email protected]/INBOX"/>
<property name="transportUri" value="smtp://smtp.example.com"/>
<property name="messageReceiver" ref="messageDispatcher"/>
<property name="monitoringStrategy">
<bean class="org.springframework.ws.transport.mail.monitor.PollingMonitoringStrategy">
<property name="pollingInterval" value="30000"/>
</bean>
</property>
</bean>
<bean id="messageDispatcher" class="org.springframework.ws.soap.server.SoapMessageDispatcher">
<property name="endpointMappings">
<bean
class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping">
<property name="defaultEndpoint">
<bean class="com.example.MyEndpoint"/>
</property>
</bean>
</property>
</bean>
</beans>
5.2.5. 嵌入式HTTP服务器传输
| 这只应用于测试目的。 |
Spring-WS 提供基于 Sun JRE HTTP 服务器的传输方式。 嵌入式 HTTP 服务器是一个独立服务器,配置简单。 它为传统餐具容器提供了更轻便的选择。
使用嵌入式 HTTP 服务器时,不需要外部部署描述符(web.xml).
你只需定义一个服务器实例,并配置它来处理来电请求。SimpleHttpServerFactoryBean连接电路,而最重要的属性是上下文,该路径将上下文路径映射到对应的路径HttpHandler实例。
Spring-WS 提供了两种实现HttpHandler接口:WsdlDefinitionHttpHandler和WebServiceMessageReceiverHttpHandler.
前者将收到的GET请求映射到一个WSDL定义.
后者负责处理Web服务消息的POST请求,因此需要WebServiceMessageFactory(通常是SaajSoapMessageFactory(Saaj肥皂信息工厂)) 以及WebServiceMessageReceiver(通常是肥皂消息调度员)以完成其任务。
为了与servlet世界进行类比,以下为上下文属性在 中扮演着 servlet 映射的作用web.xml以及WebServiceMessageReceiverHttpHandler是等价于MessageDispatcherServlet.
以下摘录展示了HTTP服务器传输的配置示例:
<beans>
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>
<bean id="messageReceiver" class="org.springframework.ws.soap.server.SoapMessageDispatcher">
<property name="endpointMappings" ref="endpointMapping"/>
</bean>
<bean id="endpointMapping" class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping">
<property name="defaultEndpoint" ref="stockEndpoint"/>
</bean>
<bean id="httpServer" class="org.springframework.ws.transport.http.SimpleHttpServerFactoryBean">
<property name="contexts">
<map>
<entry key="/StockService.wsdl" value-ref="wsdlHandler"/>
<entry key="/StockService" value-ref="soapHandler"/>
</map>
</property>
</bean>
<bean id="soapHandler" class="org.springframework.ws.transport.http.WebServiceMessageReceiverHttpHandler">
<property name="messageFactory" ref="messageFactory"/>
<property name="messageReceiver" ref="messageReceiver"/>
</bean>
<bean id="wsdlHandler" class="org.springframework.ws.transport.http.WsdlDefinitionHttpHandler">
<property name="definition" ref="wsdlDefinition"/>
</bean>
</beans>
5.2.6. XMPP 运输
Spring-WS 支持 XMPP,也称为 Jabber。 支持基于Smack库。
Spring-WS 对 XMPP 的支持与其他传输非常相似:有一个Xmpp消息发送器对于WebService模板以及一个XmppMessage接收器用于消息调度器.
以下示例展示了如何设置服务器端XMPP组件:
<beans>
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>
<bean id="connection" class="org.springframework.ws.transport.xmpp.support.XmppConnectionFactoryBean">
<property name="host" value="jabber.org"/>
<property name="username" value="username"/>
<property name="password" value="password"/>
</bean>
<bean id="messagingReceiver" class="org.springframework.ws.transport.xmpp.XmppMessageReceiver">
<property name="messageFactory" ref="messageFactory"/>
<property name="connection" ref="connection"/>
<property name="messageReceiver" ref="messageDispatcher"/>
</bean>
<bean id="messageDispatcher" class="org.springframework.ws.soap.server.SoapMessageDispatcher">
<property name="endpointMappings">
<bean
class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping">
<property name="defaultEndpoint">
<bean class="com.example.MyEndpoint"/>
</property>
</bean>
</property>
</bean>
</beans>
5.3. 终点
端点是 Spring-WS 服务器端支持的核心概念。 端点提供对应用行为的访问,通常由业务服务接口定义。 端点解释XML请求消息,并利用该输入(通常)调用业务服务中的某个方法。 该服务调用的结果以响应消息表示。 Spring-WS 拥有多种端点,并采用多种方式处理 XML 消息和生成响应。
你可以通过用@Endpoint注解。
在该类中,你通过使用多种参数类型(如DOM元素、JAXB2对象等)定义一个或多个处理来电XML请求的方法。
你可以通过使用另一种注释(通常)来表示方法能处理的消息类型(通常是@PayloadRoot).
考虑以下样本端点:
package samples;
@Endpoint (1)
public class AnnotationOrderEndpoint {
private final OrderService orderService;
public AnnotationOrderEndpoint(OrderService orderService) {
this.orderService = orderService;
}
@PayloadRoot(localPart = "order", namespace = "http://samples") (4)
public void order(@RequestPayload Element orderElement) { (2)
Order order = createOrder(orderElement);
orderService.createOrder(order);
}
@PayloadRoot(localPart = "orderRequest", namespace = "http://samples") (4)
@ResponsePayload
public Order getOrder(@RequestPayload OrderRequest orderRequest, SoapHeader header) { (3)
checkSoapHeaderForSomething(header);
return orderService.getOrder(orderRequest.getId());
}
}
| 1 | 该类被注释为@Endpoint,标记为Spring-WS端点。 |
| 2 | 这次序方法元素(注释为@RequestPayload)作为参数。
这意味着消息的有效载荷作为DOM元素传递到该方法上。
该方法具有无效返回类型,表示没有发送任何响应消息。
关于端点方法的更多信息,请参见@Endpoint搬运方法. |
| 3 | 这getOrder方法订单请求(也注释为@RequestPayload)作为参数。
该参数是 JAXB2 支持的对象(注释为@XmlRootElement).
这意味着消息的有效载荷作为未编组对象传递给该方法。
这肥皂标题类型也作为参数给出。
调用时,该参数包含请求消息的SOAP头部。
该方法还注释为@ResponsePayload,表示返回值(次序)作为响应消息的有效载荷。
关于端点方法的更多信息,请参见@Endpoint搬运方法. |
| 4 | 该端点的两种处理方法分别标记为@PayloadRoot,表示该方法可处理哪种请求消息:该方法。getOrder对于带有orderRequest本地名称及http://samples命名空间 URI。
对于具有次序俗名。
欲了解更多信息@PayloadRoot,参见端点映射。 |
以支持以下内容@Endpoint以及相关的 Spring-WS 注释,你需要在 Spring 应用上下文中添加以下内容:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sws="http://www.springframework.org/schema/web-services"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
*http://www.springframework.org/schema/web-services
http://www.springframework.org/schema/web-services/web-services.xsd">
<sws:annotation-driven />
</beans>
或者,如果你使用@Configuration类 代替 Spring XML,你可以用 来注释你的配置类@EnableWs:
@EnableWs
@Configuration
public class EchoConfig {
// @Bean definitions go here
}
以定制@EnableWs配置,你可以实现WsConfigurer并覆盖各个方法:
@Configuration
@EnableWs
public class EchoConfig extends WsConfigurerAdapter {
@Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
interceptors.add(new MyInterceptor());
}
@Override
public void addArgumentResolvers(List<MethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new MyArgumentResolver());
}
}
如果WsConfigurer不会暴露需要配置的更高级设置,考虑移除@EnableWs并且直接从WsConfigurationSupport或DelegatingWsConfiguration.
@Configuration
public class EchoConfig extends WsConfigurationSupport {
@Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
interceptors.add(new MyInterceptor());
}
@Bean
@Override
public PayloadRootAnnotationMethodEndpointMapping payloadRootAnnotationMethodEndpointMapping() {
// Create or delegate to "super" to create and
// customize properties of PayloadRootAnnotationMethodEndpointMapping
}
}
接下来的几个章节,将对@Endpoint给出了编程模型。
|
端点,和其他 Spring Bean 一样,默认是单例的范围。 也就是说,每个容器创建一个豆子定义的实例。 单例意味着多个线程可以同时使用,因此端点必须是线程安全的。 如果你想使用不同的作用域,比如原型,请参见 Spring Framework 参考文档。 |
注意,除非类级 Javadoc 另有说明,否则 Spring-WS 提供的所有抽象基类均为线程安全。
5.4.@Endpoint搬运方法
要让端点真正处理收到的XML消息,它需要有一个或多个处理方法。 处理方法可以采用广泛的参数和返回类型。 然而,它们通常有一个包含消息有效载荷的参数,并返回响应消息的有效载荷(如果有的话)。 本节介绍支持哪些参数类型和返回类型。
为了表示方法能够处理哪种消息,通常会对该方法进行注释,以以下@PayloadRoot或者@SoapAction注解。
你可以在端点映射中了解更多关于这些注释的信息。
以下示例展示了一种处理方法:
@PayloadRoot(localPart = "order", namespace = "http://samples")
public void order(@RequestPayload Element orderElement) {
Order order = createOrder(orderElement);
orderService.createOrder(order);
}
这次序方法元素(注释为@RequestPayload)作为参数。
这意味着消息的有效载荷作为DOM元素传递到该方法上。
该方法具有无效返回类型,表示没有发送任何响应消息。
5.4.1. 处理方法参数
处理方法通常包含一个或多个参数,指向接收XML消息的各个部分。 最常见的处理方法有一个参数,映射到消息的有效载荷,但它也可以映射到请求消息的其他部分,比如SOAP头部。 本节描述了你可以在处理方法签名中使用的参数。
要将参数映射到请求消息的有效载荷,你需要用@RequestPayload注解。
该注释告诉 Spring-WS 参数需要绑定到请求有效载荷。
下表描述了支持的参数类型。
它显示支持的类型,以及参数是否应用@RequestPayload,以及任何附加注释。
| 名称 | 支持的参数类型 | @RequestPayload必填? |
附加注释 |
|---|---|---|---|
TrAX |
|
是的 |
默认启用。 |
W3C DOM |
|
是的 |
默认启用 |
dom4j |
|
是的 |
当 dom4j 在类路径上时启用。 |
JDOM |
|
是的 |
当JDOM在类路径上时启用。 |
XOM |
|
是的 |
当XOM在类路径上时启用。 |
StAX |
|
是的 |
当 StAX 在类路径上时启用。 |
XPath |
任意布尔值,双倍, |
不 |
默认启用,参见该部分称为 |
消息上下文 |
|
不 |
默认启用。 |
肥皂 |
|
不 |
默认启用。 |
JAXB2 |
任何标注为 |
是的 |
当JAXB2在类路径上时启用。 |
OXM |
任何由Spring OXM支持的类型 |
是的 |
当 |
接下来的几个示例展示了可能的方法签名。以下方法以请求消息的有效载荷作为DOM调用org.w3c.dom.Element:
public void handle(@RequestPayload Element element)
以下方法在请求消息的有效载荷作为javax.xml.transform.dom.DOMSource.
这页眉参数绑定在请求消息的SOAP头部。
public void handle(@RequestPayload DOMSource domSource, SoapHeader header)
以下方法在请求消息的有效载荷未封组为我的Jaxb2对象(注释为@XmlRootElement). 消息的有效载荷也以DOM形式给出元素. 整个消息上下文作为第三个参数传递。
public void handle(@RequestPayload MyJaxb2Object requestObject, @RequestPayload Element element, Message messageContext)
如你所见,在定义方法签名处理方面有很多可能性。你甚至可以扩展这种机制,支持你自己的参数类型。参见 的 JavadocDefaultMethodEndpointAdapter和方法参数解析器看看怎么样。
@XPathParam
有一种参数类型需要额外解释:@XPathParam. 这里的思路是用XPath表达式注释一个或多个方法参数,并将每个注释参数绑定到表达式的求值上。以下示例展示了如何实现:
package samples;
@Endpoint
public class AnnotationOrderEndpoint {
private final OrderService orderService;
public AnnotationOrderEndpoint(OrderService orderService) {
this.orderService = orderService;
}
@PayloadRoot(localPart = "orderRequest", namespace = "http://samples")
@Namespace(prefix = "s", uri="http://samples")
public Order getOrder(@XPathParam("/s:orderRequest/@id") int orderId) {
Order order = orderService.getOrder(orderId);
// create Source from order and return it
}
}
由于我们使用s在我们的XPath表达式中,必须将其绑定为http://samplesNamespace。 这是通过@Namespace注解。 或者,我们也可以将该注释放在类型层级,以便所有处理方法或包级(在package-info.java)以便用于多个端点。
通过使用@XPathParam,你可以绑定到XPath支持的所有数据类型:
-
布尔或布尔. -
双或双. -
字符串. -
节点. -
节点列表.
除了这个列表外,你还可以使用任何可以从字符串由春季改装服务提供。
5.4.2. 处理方法返回类型
要发送响应消息,处理需要指定返回类型。如果不需要响应消息,方法可以声明无效返回类型。返回类型最常用来创建响应消息的有效载荷。不过,你也可以映射到响应消息的其他部分。本节介绍了你可以在处理方法签名中使用的返回类型。
要将返回值映射到响应消息的有效载荷,你需要用@ResponsePayload注解。 该注释告诉 Spring-WS,返回值需要绑定到响应有效载荷。
下表描述了支持的返回类型。它显示了支持的类型,以及参数是否应用@ResponsePayload,以及任何附加注释。
| 名称 | 支持的返回类型 | @ResponsePayload必填? |
附加注释 |
|---|---|---|---|
没有回应 |
|
不 |
默认启用。 |
TrAX |
|
是的 |
默认启用。 |
W3C DOM |
|
是的 |
默认启用 |
dom4j |
|
是的 |
当 dom4j 在类路径上时启用。 |
JDOM |
|
是的 |
当JDOM在类路径上时启用。 |
XOM |
|
是的 |
当XOM在类路径上时启用。 |
JAXB2 |
任何标注为 |
是的 |
当JAXB2在类路径上时启用。 |
OXM |
任何由Spring OXM支持的类型 |
是的 |
当 |
在定义处理方法签名方面有很多可能性。甚至可以将这一机制扩展到支持你自己的参数类型。参见 的类级 JavadocDefaultMethodEndpointAdapter和方法返回值处理程序看看怎么样。
5.5. 端点映射
端点映射负责将收到的消息映射到相应的端点。
某些端点映射默认启用——例如,PayloadRootAnnotationMethodEndpointMapping或者SoapActionAnnotationMethodEndpointMapping.
然而,我们首先需要考察一个端点映射.
一端点映射传递端点调用链,包含与来电请求匹配的端点,并且可能包含应用于请求和响应的端点拦截器列表。
当有请求进来时,消息调度器把它交给端点映射,让它检查请求并推导出合适的请求端点调用链.
然后消息调度器调用端点和链中的任何拦截器。
可配置端点映射的概念极其强大,这些映射可以选择包含拦截器(拦截器可以作请求、响应或两者兼有)。
很多辅助功能都可以内置在自定义中端点映射实现。
例如,自定义端点映射不仅可以根据消息内容选择端点,还基于特定的SOAP头(甚至多个SOAP头)。
大多数端点映射继承自摘要端点映射,该系统提供了“拦截器”属性,即可使用拦截器的列表。端点拦截器在拦截请求——终端拦截者接口.
正如《端点》中所述,@EndpointStyle 允许你在一个端点类中处理多个请求。
这是方法端点映射.
该映射决定了对收到的请求消息应调用哪种方法。
有两种端点映射可以将请求导向方法:PayloadRootAnnotationMethodEndpointMapping以及SoapActionAnnotationMethodEndpointMapping你可以通过以下方式启用这两种方法<sws:注释驱动/>在你的应用背景下。
这PayloadRootAnnotationMethodEndpointMapping使用@PayloadRoot注释,其中本地部分和Namespace元素,用特定限定名称标记方法。
每当带有该限定名称的消息进入有效载荷根元素时,该方法就会被调用。
或者,SoapActionAnnotationMethodEndpointMapping使用@SoapAction注释用于标记带有特定SOAP动作的方法。
每当有消息出现时肥皂剧该方法被调用。
摘要端点映射实现提供了defaultEndpoint该属性用于配置端点,当配置的映射未生成匹配端点时使用。
5.5.1. 世界定位
WS-寻址规定了一种传输中性路由机制。
它基于自和行动SOAP 头,分别表示 SOAP 消息的目的地和意图。
此外,Way-Addressing 允许你定义返回地址(用于普通消息和错误)和唯一消息标识符,用于关联。
有关WS-寻址的更多信息,请参见 https://en.wikipedia.org/wiki/WS-Addressing。
以下示例展示了WS-寻址消息:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope"
xmlns:wsa="http://www.w3.org/2005/08/addressing">
<SOAP-ENV:Header>
<wsa:MessageID>urn:uuid:21363e0d-2645-4eb7-8afd-2f5ee1bb25cf</wsa:MessageID>
<wsa:ReplyTo>
<wsa:Address>http://example.com/business/client1</wsa:Address>
</wsa:ReplyTo>
<wsa:To S:mustUnderstand="true">http://example/com/fabrikam</wsa:To>
<wsa:Action>http://example.com/fabrikam/mail/Delete</wsa:Action>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<f:Delete xmlns:f="http://example.com/fabrikam">
<f:maxCount>42</f:maxCount>
</f:Delete>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
在上述示例中,目标设置为http://example/com/fabrikam,而作用 设为http://example.com/fabrikam/mail/Delete.
此外,还有消息标识符和回复地址。
默认情况下,该地址是“匿名”地址,表示响应应使用与请求相同的通道(即HTTP响应),但也可以是另一个地址,如本例所示。
在 Spring-WS 中,WS-寻址被实现为端点映射。
通过使用这种映射,你可以将 WS-Addressing 动作与端点关联起来,类似于SoapActionAnnotationMethodEndpointMapping前面描述过。
用AnnotationActionEndpointMapping
这AnnotationActionEndpointMapping与SoapActionAnnotationMethodEndpointMapping但使用 WS-Addressing 头部,而非 SOAP Action 传输头。
使用AnnotationActionEndpointMapping,用@Action注释,类似于@PayloadRoot和@SoapAction注释描述于@Endpoint搬运方法以及端点映射。
以下示例展示了如何实现:
package samples;
@Endpoint
public class AnnotationOrderEndpoint {
private final OrderService orderService;
public AnnotationOrderEndpoint(OrderService orderService) {
this.orderService = orderService;
}
@Action("http://samples/RequestOrder")
public Order getOrder(OrderRequest orderRequest) {
return orderService.getOrder(orderRequest.getId());
}
@Action("http://samples/CreateOrder")
public void order(Order order) {
orderService.createOrder(order);
}
}
前述映射路由具有WS-Addressing的请求行动之http://samples/RequestOrder前往getOrder方法。
请求http://samples/CreateOrder被路由到次序方法。
默认情况下,AnnotationActionEndpointMapping支持1.0版本(2006年5月版)和2004年8月版的WS-Addressing。
这两个版本最受欢迎,并且与轴1和2、JAX-WS、XFire、Windows通信基础(WCF)以及Windows服务增强(WSE)3.0兼容。
如有必要,可以将特定版本的规范注入版本财产。
此外@Action注释,你可以用@Address注解。
如果设,则该值与自收到消息的头部属性。
最后,还有消息发送者属性,是向非匿名、越界地址发送响应消息所必需的。
你可以设置消息发送器在该属性中的实现,与你在WebService模板.
参见URI和传输。
5.5.2. 拦截请求——终端拦截者接口
端点映射机制具有端点拦截器的概念。 当你想为某些请求应用特定功能时,这些工具非常有用——例如处理与安全相关的SOAP头或请求和响应消息的日志记录。
端点拦截器通常通过使用<SWS:拦截机>在你的应用上下文中。
在这个元素中,你可以定义适用于该应用上下文中定义的所有端点的截点 BEAN。
或者,你可以使用<sws:payloadRoot>或<sws:soapAction(肥皂动作)>用于指定拦截器应应用于哪个有效载荷根名或SOAP动作。
以下示例展示了如何实现:
<sws:interceptors>
<bean class="samples.MyGlobalInterceptor"/>
<sws:payloadRoot namespaceUri="http://www.example.com">
<bean class="samples.MyPayloadRootInterceptor"/>
</sws:payloadRoot>
<sws:soapAction value="http://www.example.com/SoapAction">
<bean class="samples.MySoapActionInterceptor1"/>
<ref bean="mySoapActionInterceptor2"/>
</sws:soapAction>
</sws:interceptors>
<bean id="mySoapActionInterceptor2" class="samples.MySoapActionInterceptor2"/>
在前述例子中,我们定义了一个“全局”拦截器(我的全球拦截者)该系统拦截所有请求和响应。
我们还定义了一个拦截器,仅适用于具有http://www.example.com作为有效载荷根命名空间。
我们可以定义一个本地部分属性除了命名空间Uri进一步限制拦截器适用的消息范围。
最后,我们定义两个拦截器,适用于消息具有http://www.example.com/SoapAction肥皂剧行动。
注意第二个拦截器实际上是对豆子定义的引用,而非<拦截机>元素。
你可以在<拦截机>元素。
当你使用@Configuration类,你可以从WsConfigurerAdapter新增拦截机:
@Configuration
@EnableWs
public class MyWsConfiguration extends WsConfigurerAdapter {
@Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
interceptors.add(new MyPayloadRootInterceptor());
}
}
拦截机必须实现终端拦截者.
该接口定义了三种方法,一种用于处理实际端点前的请求消息,一种用于处理普通响应消息,另一种用于处理故障消息。
后面两个是在端点处理完毕后调用的。
这三种方法应能提供足够的灵活性,进行各种前后处理。
这handleRequest(..)拦截器上的方法返回一个布尔值。
你可以用这种方法中断或继续调用链的处理。
当该方法回归时true,端点处理链将继续。
当它回归时false这消息调度器解释为拦截器本身已经处理了相关事务,不再继续处理其他拦截器和调用链中的实际端点。
这handleResponse(..)和handleFault(..)方法也有布尔返回值。
当这些方法回归时false,响应不会返回给客户端。
有若干标准终端拦截者你可以在你的Web服务中使用的实现。
此外,还有Xws安全拦截者,描述为Xws安全拦截者.
有效载荷记录拦截者和肥皂信封记录拦截者
在开发网络服务时,记录收发XML消息是很有用的。
春季 WS 通过有效载荷记录拦截者和肥皂信封记录拦截者类。
前者只记录消息的有效载荷。
后者记录整个SOAP包絡,包括SOAP头部。
以下示例展示了如何定义有效载荷记录拦截者在端点映射中:
<sws:interceptors>
<bean class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor"/>
</sws:interceptors>
这两种拦截器都有两个特性,logRequest和logResponse(日志响应),可以设为false禁用请求或响应消息的日志。
你可以用WsConfigurerAdapter如前所述,适用于有效载荷记录拦截者也。
有效载荷验证拦截器
采用合同优先开发风格的一个好处是,我们可以利用该模式验证进出的XML消息。
Spring-WS通过有效载荷验证拦截器.
该拦截器需要引用一个或多个 W3C XML 或 RELAX NG 模式,并可设置为验证请求、响应或两者兼有。
|
虽然请求验证听起来是个好主意,但它会使最终的 Web 服务非常严格。 通常,请求是否验证并不重要,重要的是端点是否能获得足够的信息来满足请求。 验证响应是个好主意,因为端点应遵守其模式。 记住波斯特尔定律:“做事要保守;对他人的接受要宽容。” |
以下示例使用了有效载荷验证拦截器.
在这个例子中,我们使用了 模式/WEB-INF/orders.xsd用来验证回复,但不验证请求。
注意有效载荷验证拦截器也可以通过设置模式财产。
<bean id="validatingInterceptor"
class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
<property name="schema" value="/WEB-INF/orders.xsd"/>
<property name="validateRequest" value="false"/>
<property name="validateResponse" value="true"/>
</bean>
当然,你可以使用WsConfigurerAdapter如前所述,适用于有效载荷验证拦截器也。
用有效载荷拦截器变换
为了将有效载荷转换为另一种 XML 格式,Spring-WS 提供有效载荷拦截器变换.
该端点拦截器基于XSLT样式表,尤其适用于支持多个版本的Web服务,因为你可以将旧消息格式转换为新格式。
以下示例使用了有效载荷拦截器变换:
<bean id="transformingInterceptor"
class="org.springframework.ws.server.endpoint.interceptor.PayloadTransformingInterceptor">
<property name="requestXslt" value="/WEB-INF/oldRequests.xslt"/>
<property name="responseXslt" value="/WEB-INF/oldResponses.xslt"/>
</bean>
在前面的例子中,我们通过以下方式转换请求/WEB-INF/oldRequests.xslt响应消息则使用/WEB-INF/oldResponses.xslt.
注意,由于端点拦截器注册在端点映射层面,你可以创建一个端点映射,适用于“旧式”消息,并将拦截器添加到该映射中。
因此,这种转变仅适用于这些“老派”信息。
你可以用WsConfigurerAdapter如前所述,适用于有效载荷拦截器变换也。
5.6. 处理异常
Spring-WS 提供EndpointExceptionResolver这些实现是为了缓解在消息被匹配请求的端点处理时出现意外异常的痛苦。
端点异常解析器在某种程度上类似于可以在网页应用描述符中定义的异常映射web.xml.
然而,它们提供了更灵活的方式来处理异常情况。
它们提供了抛出异常时调用的端点信息。
此外,程序化处理异常的方式为你提供了更多恰当响应的选项。
你不必通过设置异常和栈跟踪来暴露应用内部,而是可以用任何你想要的方式处理异常——例如,返回带有特定故障代码和字符串的SOAP错误。
端点异常解析器会自动被消息调度器,因此无需显式配置。
除了实施EndpointExceptionResolver接口,这仅仅是实现resolveException(MessageContext, endpoint, Exception)你也可以使用提供的实现之一。
最简单的实现是SimpleSoapExceptionResolver,该错误生成一个SOAP 1.1服务器或SOAP 1.2接收端故障,并使用异常消息作为故障字符串。
你可以将其子类化以自定义故障,如下示例所示:
public class CustomSoapExceptionResolver extends SimpleSoapExceptionResolver {
private final Transformer transformer;
public CustomSoapExceptionResolver(Transformer transformer) {
this.transformer = transformer;
}
@Override
protected void customizeFault(MessageContext messageContext, Object endpoint, Exception exception,
SoapFault fault) {
SoapFaultDetail faultDetail = fault.addFaultDetail();
try {
this.transformer.transform(new StringSource("""
<ns2:YourCustomException xmlns:ns2="http://serviceendpoint/">
<errorCode>Your custom error code</errorCode>
<systemMessage>A system message</systemMessage>
</ns2:YourCustomException >
"""), faultDetail.getResult());
}
catch (TransformerException ex) {
throw new IllegalArgumentException("Failed to write detail", ex);
}
}
}
这SimpleSoapExceptionResolver是默认,但可以通过显式添加另一个解析器来覆盖。
5.6.1.SoapFaultMappingExceptionResolver
这SoapFaultMappingExceptionResolver是更复杂的实现。
这个解析器允许你将任何可能抛出的异常的类名映射到一个SOAP故障:
<beans>
<bean id="exceptionResolver"
class="org.springframework.ws.soap.server.endpoint.SoapFaultMappingExceptionResolver">
<property name="defaultFault" value="SERVER"/>
<property name="exceptionMappings">
<value>
org.springframework.oxm.ValidationFailureException=CLIENT,Invalid request
</value>
</property>
</bean>
</beans>
关键值和默认端点使用格式为faultCode,faultString,locale,只需故障代码。
如果错误字符串未被设置,则默认为异常消息。
如果语言未设置,默认为英语。
上述配置映射为 的例外ValidationFailureException对客户端SOAP故障,且故障字符串为无效请求如下:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Client</faultcode>
<faultstring>Invalid request</faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
如果发生其他异常,则返回默认错误:服务器端故障,异常消息作为故障字符串。
5.6.2. 使用SoapFaultAnnotationExceptionResolver
你也可以用@SoapFault注释,用以表示每次抛出该异常时应返回的SOAP错误。
为了让这些注释被拾取,你需要添加SoapFaultAnnotationExceptionResolver切换到你的应用上下文。注释的元素包括故障代码枚举、错误字符串或理由以及语言。
以下示例展示了此类例外:
package samples;
@SoapFault(faultCode = FaultCode.SERVER)
public class MyBusinessException extends Exception {
public MyClientException(String message) {
super(message);
}
}
每当我的业务例外是用构造子串抛出的“哎呀!”在终点调用过程中,它会产生以下响应:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Server</faultcode>
<faultstring>Oops!</faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
5.7. 服务器端测试
在测试你的Web服务端点时,你有两种可能的方法:
-
写单元测试,提供(模拟)参数让终端调用。 这种方法的优点是相当容易实现(尤其是对于标注为
@Endpoint). 缺点是你实际上并不会测试通过线路发送的XML消息的具体内容。 -
编写集成测试,这些测试会测试消息的内容。
第一种方法可以通过Mockito、EasyMock等模拟框架轻松实现。 下一部分专注于写积分测试。
5.7.1. 编写服务器端集成测试
Spring-WS 支持创建端点集成测试。 在此语境中,端点是处理(SOAP)消息的类(参见端点)。
积分测试支持存在于org.springframework.ws.test.server包。
该包的核心类是MockWebServiceClient.
其基本思想是,客户端创建请求消息,然后发送给标准配置的端点MessageDispatcherServlet应用上下文(参见MessageDispatcherServlet).
这些端点负责处理消息并生成响应。
客户随后收到该回复,并根据注册预期进行核实。
典型的用法MockWebServiceClient是:。
-
创建一个
MockWebServiceClient通过调用实例MockWebServiceClient.createClient(ApplicationContext)或MockWebServiceClient.createClient(WebServiceMessageReceiver, WebServiceMessageFactory). -
通过呼叫发送请求消息
sendRequest(RequestCreator),可能通过使用默认请求创建者提供的实现请求创作者(可以静态导入)。 -
通过打电话设定响应预期
andExpect(ResponseMatcher),可能通过使用默认响应匹配器提供的实现响应匹配器(可以静态导入)。 通过链式连接可以设置多重期望andExpect(ResponseMatcher)调用。
|
|
|
你可以依赖 Spring-WS 在单元测试中提供的标准日志功能。 有时,检查请求或响应消息有助于找出某些测试失败的原因。 更多信息请参见消息记录与追踪。 |
例如,考虑以下Web服务端点类:
@Endpoint (1)
public class CustomerEndpoint {
@ResponsePayload (2)
public CustomerCountResponse getCustomerCount(
@RequestPayload CustomerCountRequest request) {
CustomerCountResponse response = new CustomerCountResponse();
response.setCustomerCount(10);
return response;
}
}
| 1 | 这客户终端注释为@Endpoint.
参见端点。 |
| 2 | 这getCustomerCount()方法取客户计数请求作为其参数,返回客户计数响应.
这两类都是由 marshaller 支持的对象。
例如,它们可以有@XmlRootElement注释将由JAXB2支持。 |
以下示例展示了一个典型的测试客户终端:
@RunWith(SpringJUnit4ClassRunner.class) (1)
@ContextConfiguration("spring-ws-servlet.xml")
public class CustomerEndpointIntegrationTest {
@Autowired
private ApplicationContext applicationContext; (2)
private MockWebServiceClient mockClient;
@Before
public void createClient() {
mockClient = MockWebServiceClient.createClient(applicationContext); (3)
}
@Test
public void customerEndpoint() throws Exception {
Source requestPayload = new StringSource("""
<customerCountRequest xmlns='http://springframework.org/spring-ws'>
<customerName>John Doe</customerName>
</customerCountRequest>
""");
Source responsePayload = new StringSource("""
<customerCountResponse xmlns='http://springframework.org/spring-ws'>
<customerCount>10</customerCount>
</customerCountResponse>
""");
mockClient.sendRequest(withPayload(requestPayload)). (4)
andExpect(payload(responsePayload));
}
}
| 1 | 该测试使用了Spring Framework提供的标准测试设施。 这不是必须的,但通常是设置测试最简单的方式。 |
| 2 | 应用上下文是标准的 Spring-WS 应用上下文(参见MessageDispatcherServlet),诵读自spring-ws-servlet.xml.
在这种情况下,应用上下文包含一个豆子定义客户终端(或者说,也许是<上下文:组件扫描 />被使用)。 |
| 3 | 在@Before方法,我们创建一个MockWebServiceClient通过使用createClient工厂方法。 |
| 4 | 我们通过电话发送请求sendRequest()其中withPayload() 请求创建者由静态导入提供请求创作者(参见用请求创建者和请求创作者).
我们还通过打电话来设定响应预期andExpect()其中有效载荷() 响应匹配器由静态导入提供响应匹配器(参见用响应匹配器和响应匹配器). |
这部分测试看起来可能有点复杂,但你IDE的代码补全功能非常有帮助。
打完字后sendRequest(,你的IDE可以为你提供一份可能的请求创建策略列表,前提是你是静态导入的请求创作者.
同样适用于andExpect(), 前提是你是静态导入响应匹配器.
5.7.2. 使用请求创建者和请求创作者
最初,MockWebServiceClient需要为终端创建请求消息以供消费。
客户端使用请求创建者为此目的的策略界面:
public interface RequestCreator {
WebServiceMessage createRequest(WebServiceMessageFactory messageFactory)
throws IOException;
}
你可以自己编写该接口的实现,通过消息工厂创建请求消息,但你当然不必这么做。
这请求创作者类提供了一种创建请求创建者基于给定的有效载荷withPayload()方法。
你通常是静态导入的请求创作者.
5.7.3. 使用响应匹配器和响应匹配器
当请求消息被端点处理并收到响应时,MockWebServiceClient可以验证该回复消息是否符合某些预期。
客户端使用响应匹配器为此目的的策略界面:
public interface ResponseMatcher {
void match(WebServiceMessage request, WebServiceMessage response)
throws IOException, AssertionError;
}
同样,你可以自己编写该接口的实现,投掷断言错误当信息不符合你的预期时,但你当然不必如此,因为响应匹配器类别提供标准响应匹配器为你测试时提供的实现。
通常你会静态导入这个类。
这响应匹配器类提供以下响应匹配器:
响应匹配器方法 |
描述 |
|---|---|
|
期望给定的响应负载。 可能包含XMLUnit占位符。 |
|
期望响应有效载荷能根据给定的 XSD 模式进行验证。 |
|
期望给定的XPath表达式存在、不存在或取值给定值。 |
|
期望响应消息中存在给定的SOAP头。 |
|
期望达到给定的SOAP载荷。 可能包含XMLUnit占位符。 |
|
期望响应消息不包含SOAP故障。 |
|
期望响应消息包含特定的SOAP故障。 |
你可以通过链式设置多重响应预期andExpect()调用:
mockClient.sendRequest(...).
andExpect(payload(expectedResponsePayload)).
andExpect(validPayload(schemaResource));
关于所提供的响应匹配器的更多信息响应匹配器,参见 Javadoc。
6. 在客户端使用 Spring-WS
Spring-WS 提供了一个客户端 Web 服务 API,允许一致的、基于 XML 的访问访问 Web 服务。 它还支持封送程序和非排序程序的使用,使你的服务层代码能够专门处理 Java 对象。
这org.springframework.ws.client.core包提供了使用客户端访问API的核心功能。
它包含简化Web服务使用的模板类,类似于核心SpringJdbc模板这也适用于JDBC。
Spring 模板类共有的设计原则是提供辅助方法来执行常用作,并在更复杂的应用中委托用户实现回调接口。
Web服务模板遵循相同的设计。
这些课程提供了多种便捷的方法
-
发送和接收XML消息。
-
在发送前将对象打组成 XML。
-
允许多种交通方式。
6.1. 使用客户端 API
本节介绍如何使用客户端 API。 关于如何使用服务器端 API,请参见使用 Spring-WS 创建 Web 服务。
6.1.1.WebService模板
这WebService模板是 Spring-WS 客户端 Web 服务访问的核心类。
它包含发送的方法源对象和接收响应消息的对象分别为源或结果.
此外,它可以在通过传输前将对象封组为 XML,并将任何响应 XML 重新封组到对象中。
URI与传输
这WebService模板类使用URI作为消息目的地。
你可以设置默认Uri模板本身的属性,或者在调用模板上的方法时明确提供URI。
URI被解析为WebServiceMessageSender,负责通过传输层发送XML消息。
你可以通过使用消息发送者或消息发送者的性质WebService模板类。
HTTP 传输
有三种实现方式WebServiceMessageSender用于通过HTTP发送消息的接口。
默认实现是HttpUrlConnectionMessageSender该工具使用了 Java 自身提供的设施。
其他选择有两种JdkHttpClientMessageSender该系统使用 JDKHttp客户端或HttpComponents5MessageSender,该系统使用Apache HttpClient。
如果你需要更高级且易用的功能(比如认证、HTTP连接池等),建议使用后者。
要使用 HTTP 传输,可以设置默认Uri变成类似的东西http://example.com/services或提供乌里参数,用于其中一种方法。
以下示例展示了如何使用HTTP传输的默认配置:
<beans>
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory"/>
<property name="defaultUri" value="http://example.com/WebService"/>
</bean>
</beans>
以下示例展示了如何覆盖默认配置以及如何使用 Apache HttpClient 进行 HTTP 认证:
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory"/>
<property name="messageSender">
<bean class="org.springframework.ws.transport.http.HttpComponents5MessageSender">
<property name="credentials">
<bean class="org.apache.hc.client5.http.auth.UsernamePasswordCredentials">
<constructor-arg value="john"/>
<constructor-arg value="secret"/>
</bean>
</property>
</bean>
</property>
<property name="defaultUri" value="http://example.com/WebService"/>
</bean>
JMS运输
对于通过JMS发送消息,Spring-WS提供以下服务JmsMessageSender.
该类利用 Spring 框架的功能来转换WebServiceMessage进入JMS消息,让它踏上队列或主题,并收到回复(如果有的话)。
使用JmsMessageSender,你需要设置默认Uri或乌里参数映射到一个JMS URI,该URI至少包括JMS:前缀和目的地名称。
JMS URI的一些例子包括:jms:SomeQueue,jms:SomeTopic?priority=3&deliveryMode=NON_PERSISTENT和jms:RequestQueue?replyToName=ResponseName.
有关该URI语法的更多信息,请参见Javadoc forJmsMessageSender.
默认情况下,JmsMessageSender发送JMS字节消息但你可以覆盖它来使用短信通过使用消息类型JMS URI上的参数——例如,jms:Queue?messageType=TEXT_MESSAGE.
注意字节消息是首选类型,因为短信不可靠地支持附件和字符编码。
以下示例展示了如何将JMS传输系统与Artemis连接工厂结合使用:
<beans>
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>
<bean id="connectionFactory" class="org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory">
<property name="brokerURL" value="vm://localhost?broker.persistent=false"/>
</bean>
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory"/>
<property name="messageSender">
<bean class="org.springframework.ws.transport.jms.JmsMessageSender">
<property name="connectionFactory" ref="connectionFactory"/>
</bean>
</property>
<property name="defaultUri" value="jms:RequestQueue?deliveryMode=NON_PERSISTENT"/>
</bean>
</beans>
电子邮件传输
Spring-WS还提供电子邮件传输功能,你可以用它通过SMTP发送Web服务消息,并通过POP3或IMAP获取消息。
客户端电子邮件功能包含于邮件消息发送器.
该类会根据请求生成电子邮件WebServiceMessage并通过SMTP发送。
然后等待响应消息到达接收的POP3或IMAP服务器。
使用邮件消息发送器,设默认Uri或乌里参数映射到梅尔托例如,URI,邮件:[email protected]或mailto:server@localhost?subject=SOAP%20Test.
确保消息发送器正确配置为交通Uri,表示用于发送请求的服务器(通常是SMTP服务器),以及storeUri,指示要轮询响应的服务器(通常是POP3或IMAP服务器)。
以下示例展示了如何使用电子邮件传输:
<beans>
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory"/>
<property name="messageSender">
<bean class="org.springframework.ws.transport.mail.MailMessageSender">
<property name="from" value="Spring-WS SOAP Client <[email protected]>"/>
<property name="transportUri" value="smtp://client:[email protected]"/>
<property name="storeUri" value="imap://client:[email protected]/INBOX"/>
</bean>
</property>
<property name="defaultUri" value="mailto:[email protected]?subject=SOAP%20Test"/>
</bean>
</beans>
XMPP交通
Spring-WS 还提供 XMPP(Jabber)传输,您可以通过 XMPP 发送和接收网络服务消息。
客户端XMPP功能包含在Xmpp消息发送器.
该类从请求中创建XMPP消息WebServiceMessage并通过XMPP发送。
然后它监听回复消息的到来。
使用Xmpp消息发送器,设默认Uri或乌里参数映射到XMPP例如,URI,XMPP:[email protected].
发送方还要求XMPP通讯可以方便地通过使用org.springframework.ws.transport.xmpp.support.XmppConnectionFactoryBean.
以下示例展示了如何使用XMPP传输:
<beans>
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>
<bean id="connection" class="org.springframework.ws.transport.xmpp.support.XmppConnectionFactoryBean">
<property name="host" value="jabber.org"/>
<property name="username" value="username"/>
<property name="password" value="password"/>
</bean>
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory"/>
<property name="messageSender">
<bean class="org.springframework.ws.transport.xmpp.XmppMessageSender">
<property name="connection" ref="connection"/>
</bean>
</property>
<property name="defaultUri" value="xmpp:[email protected]"/>
</bean>
</beans>
6.1.2. 发送和接收 aWebServiceMessage
这WebService模板包含许多便捷的发送和接收网络服务消息的方法。
有方法接受并返回源以及返回结果.
此外,还有一些方法可以将对象封组和非封编成 XML。
以下示例向Web服务发送一个简单的XML消息:
public class WebServiceClient {
private static final String MESSAGE =
"<message xmlns=\"http://tempuri.org\">Hello, Web Service World</message>";
private final WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
public void setDefaultUri(String defaultUri) {
webServiceTemplate.setDefaultUri(defaultUri);
}
// send to the configured default URI
public void simpleSendAndReceive() {
StreamSource source = new StreamSource(new StringReader(MESSAGE));
StreamResult result = new StreamResult(System.out);
webServiceTemplate.sendSourceAndReceiveToResult(source, result);
}
// send to an explicit URI
public void customSendAndReceive() {
StreamSource source = new StreamSource(new StringReader(MESSAGE));
StreamResult result = new StreamResult(System.out);
webServiceTemplate.sendSourceAndReceiveToResult("http://localhost:8080/AnotherWebService",
source, result);
}
}
<beans xmlns="http://www.springframework.org/schema/beans">
<bean id="webServiceClient" class="com.example.WebServiceClient">
<property name="defaultUri" value="http://localhost:8080/WebService"/>
</bean>
</beans>
前述示例使用了WebService模板发送“你好,世界”消息给位于http://localhost:8080/WebService(在simpleSendAndReceive()方法)并将结果写入控制台。
这WebService模板注入默认URI,因为Java代码中没有明确提供URI。
注意WebService模板类一旦配置好,便是线程安全的(假设其所有依赖也都是线程安全的,这对所有随Spring-WS自带的依赖都是如此),因此多个对象可以使用同一个共享对象WebService模板实例。
这WebService模板暴露出一个零参数构造子,消息工厂和消息发送者可以用来构建实例的 bean 属性(通过使用 Spring 容器或普通 Java 代码)。
或者,也可以考虑从 Spring-WS 推导WebServiceGatewaySupport方便基类,它会暴露 BEAN 属性以便易于配置。
(你不必扩展这个基础类,它只是作为方便类提供的。)
6.1.3. 发送和接收POJO——编组与解编
为了方便发送纯 Java 对象,WebService模板有若干发送(..)采取对象作为消息数据内容的论证。
方法元警发送和接收(..)在WebService模板类将请求对象转换为 XML 的任务委托到马歇勒以及将响应XML转换为对象的过程Unmarshaller.
(有关编组和unmarshaller的更多信息,请参见Spring Framework参考文档。)
通过使用分组器,你的应用代码可以专注于发送或接收的业务对象,而不用担心它如何以XML形式表示的细节。
要使用编组功能,你需要设置一个编组器和一个非编组组,且马沙勒和安马沙勒的性质WebService模板类。
6.1.4. 使用WebService消息回调
为了方便在消息中设置SOAP头部和其他设置,WebService消息回调界面允许你在消息创建后但发送前访问该信息。
以下示例演示如何在通过封组对象创建的消息上设置SOAP动作头:
public void marshalWithSoapActionHeader(MyObject o) {
webServiceTemplate.marshalSendAndReceive(o, new WebServiceMessageCallback() {
public void doWithMessage(WebServiceMessage message) {
((SoapMessage)message).setSoapAction("http://tempuri.org/Action");
}
});
}
注意你也可以使用org.springframework.ws.soap.client.core.SoapActionCallback设置SOAP动作头。 |
WS-寻址
除了服务器端的WS-Addressing支持外,Spring-WS在客户端也支持该规范。
在客户端设置WS-Addressing头部时,你可以用行动回应.
该回调以所需动作头为参数。
它还包含用于指定WS寻址版本的构造函数,以及一个自页眉。
如果未特别说明,则自头部默认为所建立连接的URL。
以下示例设置行动头部 至http://samples/RequestOrder:
webServiceTemplate.marshalSendAndReceive(o, new ActionCallback("http://samples/RequestOrder"));
6.1.5. 使用WebServiceMessageExtractor
这WebServiceMessageExtractorinterface 是一种低级回调接口,允许你完全控制提取对象来自WebServiceMessage.
这WebService模板引用extractData(..)在提供的WebServiceMessageExtractor而与服务资源的底层连接仍然保持开放。
以下示例展示了WebServiceMessageExtractor实际行动:
public void marshalWithSoapActionHeader(final Source s) {
final Transformer transformer = transformerFactory.newTransformer();
webServiceTemplate.sendAndReceive(new WebServiceMessageCallback() {
public void doWithMessage(WebServiceMessage message) {
transformer.transform(s, message.getPayloadResult());
},
new WebServiceMessageExtractor() {
public Object extractData(WebServiceMessage message) throws IOException {
// do your own transforms with message.getPayloadResult()
// or message.getPayloadSource()
}
}
});
}
6.2. 客户端测试
在测试你的Web服务客户端(即使用以下WebService模板访问Web服务时,你有两种可能的路径:
-
编写单元测试,模拟
WebService模板类WebService运营接口,或完整的客户端类。 这种方法的优点是很容易实现。 缺点是你实际上不会测试通过线路发送的XML消息的具体内容,尤其是在模拟整个客户端类时。 -
写集成测试,这些测试会测试消息的内容。
第一种方法可以通过模拟框架轻松实现,如Mockito、EasyMock等。 下一部分专注于写积分测试。
6.2.1. 编写客户端集成测试
Spring-WS 支持创建和创建 Web 服务客户端集成测试。
在此语境中,客户端是指使用WebService模板访问网络服务。
积分测试支持存在于org.springframework.ws.test.client包。
该包的核心类是MockWebServiceServer.
其基本思想是,Web服务模板连接到这个模拟服务器并发送请求消息,模拟服务器随后根据注册的期望进行验证。
如果期望被满足,模拟服务器会准备一个响应消息,并返回模板。
典型的用法MockWebServiceServer是:。
-
创建一个
MockWebServiceServer通过调用实例MockWebServiceServer.createServer(WebServiceTemplate),MockWebServiceServer.createServer(WebServiceGatewaySupport)或MockWebServiceServer.createServer(ApplicationContext). -
通过电话设定请求期望
expect(请求匹配者),可能通过使用默认请求匹配器提供的实现请求匹配者(可以静态导入)。 通过链式连接可以设置多重期望andExpect(请求匹配者)调用。 -
通过呼叫创建合适的响应消息
andRespond(ResponseCreator),可能通过使用默认响应创造器提供的实现响应创造者(可以静态导入)。 -
使用该
WebService模板像往常一样,要么直接通过客户端代码。 -
叫
MockWebServiceServer.verify()确保所有期望都被满足。
|
|
|
你可以依赖 Spring-WS 在单元测试中提供的标准日志功能。 有时,检查请求或响应消息有助于找出某些测试失败的原因。 更多信息请参见消息记录与追踪。 |
例如,考虑以下Web服务客户端类:
public class CustomerClient extends WebServiceGatewaySupport { (1)
public int getCustomerCount() {
CustomerCountRequest request = new CustomerCountRequest(); (2)
request.setCustomerName("John Doe");
CustomerCountResponse response =
(CustomerCountResponse) getWebServiceTemplate().marshalSendAndReceive(request); (3)
return response.getCustomerCount();
}
}
| 1 | 这客户客户端延伸WebServiceGatewaySupport,这为它提供了webService模板财产。 |
| 2 | 客户计数请求是由分组器支撑的物体。
例如,它可以有@XmlRootElement注释将由JAXB2支持。 |
| 3 | 这客户客户端使用WebService模板提供WebServiceGatewaySupport将请求对象组建成SOAP消息并发送给Web服务。
响应对象被解组为客户计数响应. |
以下示例展示了一个典型的测试客户客户端:
@RunWith(SpringJUnit4ClassRunner.class) (1)
@ContextConfiguration("integration-test.xml")
public class CustomerClientIntegrationTest {
@Autowired
private CustomerClient client; (2)
private MockWebServiceServer mockServer; (3)
@Before
public void createServer() throws Exception {
mockServer = MockWebServiceServer.createServer(client);
}
@Test
public void customerClient() throws Exception {
Source requestPayload = new StringSource("""
<customerCountRequest xmlns='http://springframework.org/spring-ws'>
<customerName>John Doe</customerName>
</customerCountRequest>
""");
Source responsePayload = new StringSource("""
<customerCountResponse xmlns='http://springframework.org/spring-ws'>
<customerCount>10</customerCount>
</customerCountResponse>
""");
mockServer.expect(payload(requestPayload)).andRespond(withPayload(responsePayload));(4)
int result = client.getCustomerCount(); (5)
assertEquals(10, result);
mockServer.verify(); (6)
}
}
| 1 | 该测试使用了Spring Framework提供的标准测试设施。 这不是必须的,但通常是设置测试最简单的方式。 |
| 2 | 这客户客户端配置为integration-test.xml并用以下方式接入此测试@Autowired. |
| 3 | 在@Before方法,我们创建一个MockWebServiceServer通过使用createServer工厂方法。 |
| 4 | 我们通过呼叫来定义期望expect()其中有效载荷() 请求匹配器由静态导入提供请求匹配者(参见用请求匹配器和请求匹配者).
我们还通过打电话设置了响应andRespond()其中withPayload() 响应创造器由静态导入提供响应创造者(参见用响应创造器和响应创造者).
测试的这一部分看起来可能有些混乱,但你的IDE中的代码补全功能非常有帮助。
打完字后期待(,你的IDE可以为你提供一份可能的请求匹配策略列表,前提是你是静态导入的请求匹配者.
同样适用于andRespond(, 前提是你是静态导入响应创造者. |
| 5 | 我们叫getCustomerCount()在客户客户端,因此使用WebService模板.
模板现在已经设置为“测试模式”,因此该方法调用不会建立真正的(HTTP)连接。
我们还基于方法调用的结果做出一些 JUnit 断言。 |
| 6 | 我们叫verify()在MockWebServiceServer,验证预期消息是否真的被接收到了。 |
6.2.2. 使用请求匹配器和请求匹配者
为了验证请求消息是否满足某些期望,MockWebServiceServer使用请求匹配器策略界面。
该接口定义的契约如下:
public interface RequestMatcher {
void match(URI uri, WebServiceMessage request)
throws IOException, AssertionError;
}
你可以自己写一些这个接口的实现,投掷断言错误当信息不符合你的预期时,当然会有例外,但你当然不必如此。
这请求匹配者类别提供标准请求匹配器为你测试时提供的实现。
通常你会静态导入这个类。
这请求匹配者类提供以下请求匹配器:
请求匹配者方法 |
描述 |
|---|---|
|
期待任何请求。 |
|
期望给定的请求有效载荷。 可能包含XMLUnit占位符 |
|
期望请求有效载荷能根据给定的 XSD 模式进行验证。 |
|
期望给定的XPath表达式存在、不存在或取值给定值。 |
|
期望请求消息中存在给定的SOAP头。 |
|
期望达到给定的SOAP载荷。 可能包含XMLUnit占位符 |
|
期望连接到给定的URL。 |
你可以通过串联设置多个请求预期andExpect()调用:
mockServer.expect(connectionTo("http://example.com")).
andExpect(payload(expectedRequestPayload)).
andExpect(validPayload(schemaResource)).
andRespond(...);
关于提供请求匹配器的更多信息请求匹配者,参见 Javadoc。
6.2.3. 使用响应创造器和响应创造者
当请求消息经过验证并符合定义的期望时,MockWebServiceServer为 生成响应消息WebService模板去消费。
服务器使用响应创造器为此目的的策略界面:
public interface ResponseCreator {
WebServiceMessage createResponse(URI uri, WebServiceMessage request,
WebServiceMessageFactory messageFactory)
throws IOException;
}
同样,你也可以自己编写该接口的实现,通过消息工厂创建响应消息,但你当然不必这样做,因为响应创造者类别提供标准响应创造器为你测试时提供的实现。
通常你会静态导入这个类。
这响应创造者类提供以下回答:
响应创造者方法 |
描述 |
|---|---|
|
生成具有特定有效载荷的响应消息。 |
|
会在响应连接中产生错误。 这种方法让你有机会测试自己的错误处理能力。 |
|
读取响应连接时抛出异常。 这种方法让你有机会测试异常处理能力。 |
|
生成带有特定SOAP故障的响应消息。 这种方法可以让你测试故障处理能力。 |
关于提供请求匹配器的更多信息请求匹配者,参见 Javadoc。
7. 通过 Spring-WS 保护您的网络服务
本章将解释如何为您的Web服务添加WS-Security方面。我们重点关注WS-Security的三个不同领域:
-
认证:这是判断主体是否真如其声称的身份的过程。在这里,“主体”通常指的是用户、设备或其他能够在您的应用中执行作的系统。
-
数字签名:消息的数字签名是基于文档和签署者私钥的信息。它通过使用哈希函数和私有签名函数(用签名者的私钥加密)创建。
-
加密与解密:加密是将数据转换为无法读取的形式,除非使用相应密钥。它主要用于隐藏信息,不让不该信息被处理。解密是加密的反向。它是将加密数据转换回可读形式的过程。
这三个方面通过使用Xws安全拦截者或WSS4j安全拦截者,我们在Xws安全拦截者和用WSS4j安全拦截者分别。
|
WS-Security(尤其是加密和签名)需要大量内存,可能会降低性能。如果你很在意性能,可以考虑不使用WS-Security或使用基于HTTP的安全。 |
7.1.Xws安全拦截者
这Xws安全拦截者是终端拦截者(参见拦截请求——终端拦截者接口)基于SUN的XML和Web服务安全包(XWSS)。该WS-Security实现是Java网络服务开发者包(Java WSDP)的一部分。
和其他端点拦截器一样,它在端点映射中定义(参见端点映射)。这意味着你可以选择性地添加WS-Security支持。有些端点映射要求支持,而有些则不需要。
|
XWSS要求SUN SAAJ参考实现。WSS4J拦截器不具备这些要求(参见用 |
这Xws安全拦截者需要一个安全策略文件才能运行。该 XML 文件告诉拦截者应从收到的 SOAP 消息中要求哪些安全方面,以及应向外发消息添加哪些安全方面。策略文件的基本格式将在后续章节中解释,但也有更深入的教程可供参考。你可以用以下方式设置该策略policyConfiguration属性,需要 Spring 资源。策略文件可以包含多个元素——例如,要求对收到的消息使用用户名Tokens,并对所有发出消息进行签名。它包含安全配置元素(非JAXRPC安全元素)作为其词根。
此外,安全拦截器还需要一个或多个回调处理程序实例以进行作。这些处理程序用于获取证书、私钥、验证用户凭证等。Spring-WS 为大多数常见的安全问题提供处理程序——例如,针对 Spring Security 认证管理器进行身份验证,以及基于 X509 证书签署发出消息。以下章节说明应使用哪种回调处理程序处理哪种安全问题。您可以通过使用回调处理程序或回调处理器财产。
以下示例展示了如何接线Xws安全拦截者:
<beans>
<bean id="wsSecurityInterceptor"
class="org.springframework.ws.soap.security.xwss.XwsSecurityInterceptor">
<property name="policyConfiguration" value="classpath:securityPolicy.xml"/>
<property name="callbackHandlers">
<list>
<ref bean="certificateHandler"/>
<ref bean="authenticationHandler"/>
</list>
</property>
</bean>
...
</beans>
该拦截器通过以下方式配置securityPolicy.xml文件在类路径上。它使用两个回调处理程序,这些程序在文件后面定义。
7.1.1. 密钥存储器
对于大多数密码作,你会使用标准java.security.KeyStore对象。 这些作包括证书验证、消息签名、签名验证和加密。它们不包括用户名和时间戳验证。本节旨在为您提供一些关于密钥存储以及用于将密钥和证书存储在密钥存储文件中的 Java 工具的背景知识。这些信息大多与 Spring-WS 无关,而是关于 Java 的通用密码学特性。
这java.security.KeyStore类代表密码密钥和证书的存储设施。
它可以包含三种不同的元素:
-
私钥:这些密钥用于自我认证。 私钥配有对应公钥的证书链。 在WS-Security领域,这涵盖了消息签名和解密。
-
对称密钥:对称(或秘密)密钥也用于消息加密和解密——区别在于发送方和接收方共享相同的密钥。
-
可信证书:这些 X509 证书被称为“可信证书”,因为密钥存储器所有者相信证书中的公钥确实属于证书所有者。 在WS-Security中,这些证书用于证书验证、签名验证和加密。
用关键工具
这关键工具程序是一个密钥和证书管理工具,随你的Java虚拟机一起提供。
你可以用这个工具创建新的密钥库,添加新的私钥和证书,等等。
本文件无法提供完整的参考资料关键工具命令,检查标准引用或调用Keytool -帮助在命令行。
用KeyStoreFactoryBean
为了通过 Spring 配置轻松加载密钥存储,你可以使用KeyStoreFactoryBean.
它有一个资源位置属性,你可以设置它指向要加载密钥存储的路径。
可能会设置密码以检查密钥存储数据的完整性。
如果未输入密码,则不会进行完整性检查。
以下列表配置为KeyStoreFactoryBean:
<bean id="keyStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
<property name="password" value="password"/>
<property name="location" value="classpath:org/springframework/ws/soap/security/xwss/test-keystore.jks"/>
</bean>
| 如果你没有指定位置属性,就会创建一个新的空密钥库,这很可能不是你想要的。 |
KeyStoreCallbackHandler
在Xws安全拦截者,你需要定义一个KeyStoreCallbackHandler.
该回调有三个性质,类型为密钥库: (keyStore,trustStore和symmetricStore).
处理器使用的具体存储取决于该处理器将执行的密码学作。
对于私钥作,以下keyStore被使用。
对于对称密钥作,则symmetricStore被使用。
为了确定信任关系,以下trustStore被使用。
下表说明了这一点:
| 密码学作 | 密钥存储器使用 |
|---|---|
证书验证 |
第一 |
基于私钥的解密 |
|
基于对称密钥的解密 |
|
基于公钥证书的加密 |
|
基于对称密钥的加密 |
|
签署 |
|
签名验证 |
|
此外,KeyStoreCallbackHandler有私人密钥密码属性,应设置为解锁“keyStore”中私钥。
如果symmetricStore不是设置的,它默认为keyStore.
如果密钥或信任存储未被设置,回调处理器会使用标准的 Java 机制来加载或创建它。
看KeyStoreCallbackHandler更多细节请阅读。
例如,如果你想使用KeyStoreCallbackHandler为了验证收到的证书或签名,您可以使用信任存储器:
<beans>
<bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
<property name="trustStore" ref="trustStore"/>
</bean>
<bean id="trustStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
<property name="location" value="classpath:truststore.jks"/>
<property name="password" value="changeit"/>
</bean>
</beans>
如果你想用它解密入站证书或签署出信,可以使用密钥存储:
<beans>
<bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
<property name="keyStore" ref="keyStore"/>
<property name="privateKeyPassword" value="changeit"/>
</bean>
<bean id="keyStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
<property name="location" value="classpath:keystore.jks"/>
<property name="password" value="changeit"/>
</bean>
</beans>
以下章节指出KeyStoreCallbackHandler可以使用这些属性,以及为特定密码作设置哪些属性。
7.1.2. 认证
正如本章引言所述,认证是确定委托人是否真如其声称的身份的任务。 在WS-Security中,认证有两种形式:使用用户名和密码Tokens(使用明文密码或密码摘要)或使用X509证书。
纯文本用户名认证
最简单的用户名认证方式使用纯文本密码。
在这种情况下,SOAP消息包含一个用户名Tokens元素本身包含一个用户名元素和密码该元素包含明文密码。
纯文本认证可以与HTTP服务器提供的基本认证进行比较。
|
纯文本密码安全性不高。 因此,如果你使用传输层,应该始终添加额外的安全措施(比如用 HTTPS 代替普通 HTTP)。 |
要求每个入站消息都包含用户名Tokens使用纯文本密码时,安全策略文件应包含RequireUsernameToken(需要用户名Tokens)元素,其中passwordDigestRequired(密码摘要必需)属性设置为false.
欲了解更多细节,请查看官方可能的子元素参考资料。
以下列表展示了如何包含RequireUsernameToken(需要用户名Tokens)元素:
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
...
<xwss:RequireUsernameToken passwordDigestRequired="false" nonceRequired="false"/>
...
</xwss:SecurityConfiguration>
如果用户名Tokens不存在,则Xws安全拦截者向发送方返回SOAP故障。
如果存在,则发射密码验证回调其中PlainTextPassword请求对注册的控者来说。
在 Spring-WS 中,有三个类负责处理这一特定回调:
用SimplePasswordValidationCallbackHandler
最简单的密码验证处理器是SimplePasswordValidationCallbackHandler.
该处理器会根据内存验证密码性能你可以用用户财产:
<bean id="passwordValidationHandler"
class="org.springframework.ws.soap.security.xwss.callback.SimplePasswordValidationCallbackHandler">
<property name="users">
<props>
<prop key="Bert">Ernie</prop>
</props>
</property>
</bean>
在这种情况下,我们只允许用户“Bert”使用密码“Ernie”登录。
用SpringPlainTextPasswordValidationCallbackHandler
这SpringPlainTextPasswordValidationCallbackHandler使用 Spring Security 来认证用户。
本文超出了对 Spring Security 的描述范围,但它是一个完整的安全框架。
你可以在Spring Security参考文档中了解更多。
这SpringPlainTextPasswordValidationCallbackHandler需要认证管理器去作。
它利用该管理器对用户名密码认证Tokens它创造了。
如果认证成功,Tokens将存储在安全上下文持有者.
你可以通过以下方式设置认证管理器authenticationManager财产:
<beans>
<bean id="springSecurityHandler"
class="org.springframework.ws.soap.security.xwss.callback.SpringPlainTextPasswordValidationCallbackHandler">
<property name="authenticationManager" ref="authenticationManager"/>
</bean>
<bean id="authenticationManager" class=" org.springframework.security.authentication.ProviderManager">
<constructor-arg>
<bean class="org.springframework.security.providers.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userDetailsService"/>
</bean>
</constructor-arg>
</bean>
<bean id="userDetailsService" class="com.mycompany.app.dao.UserDetailService" />
...
</beans>
用JaasPlainTextPasswordValidationCallbackHandler
这JaasPlainTextPasswordValidationCallbackHandler基于标准的Java认证与授权服务。
本文档无法全面介绍JAAS,但已有教程可供参考。
这JaasPlainTextPasswordValidationCallbackHandler只需一个loginContextName去作。
它创建了新的JAAS系统登录上下文使用该名称,并处理标准JAAS信号名称回呼和密码回调通过使用SOAP消息中提供的用户名和密码。
这意味着该回调处理程序可以集成到任何JAAS中登录模块在login()相位,这是标准行为。
你可以接线JaasPlainTextPasswordValidationCallbackHandler如下:
<bean id="jaasValidationHandler"
class="org.springframework.ws.soap.security.xwss.callback.jaas.JaasPlainTextPasswordValidationCallbackHandler">
<property name="loginContextName" value="MyLoginModule" />
</bean>
在这种情况下,回调处理器使用登录上下文叫MyLoginModule.
该模块应在你的jaas.config文件,正如前面教程中所解释的。
摘要用户名认证
使用密码摘要时,SOAP 消息还包含用户名Tokens元素本身包含一个用户名元素和密码元素。
区别在于密码不是以纯文本形式发送,而是以摘要形式发送。
接收者将该摘要与他根据用户已知密码计算出的摘要进行比较,如果两者相同,用户即获得认证。
这种方法类似于HTTP服务器提供的摘要认证。
要求每个入站消息都包含用户名Tokens带有密码摘要的元素,安全策略文件应包含RequireUsernameToken(需要用户名Tokens)元素,其中passwordDigestRequired(密码摘要必需)属性设置为true.
此外,nonceRequired(必要)属性应设置为true.
欲了解更多细节,请查阅官方参考资料中的可能子元素。
以下列表展示了如何定义RequireUsernameToken(需要用户名Tokens)元素:
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
...
<xwss:RequireUsernameToken passwordDigestRequired="true" nonceRequired="true"/>
...
</xwss:SecurityConfiguration>
如果用户名Tokens不存在,则Xws安全拦截者向发送方返回SOAP故障。
如果存在,则发射密码验证回调其中摘要密码请求对注册的控者来说。
在 Spring-WS 中,有两个类处理这种特定的回调:SimplePasswordValidationCallbackHandler和SpringDigestPasswordValidationCallbackHandler.
用SimplePasswordValidationCallbackHandler
这SimplePasswordValidationCallbackHandler既能处理明文密码,也能处理密码摘要。
其描述如下:用SimplePasswordValidationCallbackHandler.
用SpringDigestPasswordValidationCallbackHandler
这SpringDigestPasswordValidationCallbackHandler需要春季安全用户详情服务去作。
它利用该服务获取Tokens中指定的用户密码。
然后将该详细信息对象中包含的密码摘要与消息中的摘要进行比较。
如果它们相等,则表示用户已成功认证,且用户名密码认证Tokens存储在安全上下文持有者.
你可以通过使用用户详情服务财产。
此外,你可以设置用户缓存属性,用于缓存加载的用户信息。
以下示例展示了如何实现:
<beans>
<bean class="org.springframework.ws.soap.security.xwss.callback.SpringDigestPasswordValidationCallbackHandler">
<property name="userDetailsService" ref="userDetailsService"/>
</bean>
<bean id="userDetailsService" class="com.mycompany.app.dao.UserDetailService" />
...
</beans>
证书认证
更安全的认证方式是使用X509证书。
在这种情况下,SOAP消息包含一个二进制安全Tokens,其中包含一个基于 Base 64 编码的 X509 证书版本。
证书由接收方用于认证。
消息中存储的证书也用于消息的签名(参见验证签名)。
为了确保所有收到的SOAP消息都携带“BinarySecurityToken”,安全策略文件应包含要求签名元素。
该元素还可以携带其他元素,这些内容在验证签名中已有介绍。
欲了解更多细节,请查阅官方参考资料中的可能子元素。
以下列表展示了如何定义要求签名元素:
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
...
<xwss:RequireSignature requireTimestamp="false">
...
</xwss:SecurityConfiguration>
当收到一条没有证书的消息时,Xws安全拦截者向发送方返回SOAP故障。
如果存在,则发射证书验证回调.
Spring-WS 中的两个处理器负责此回调以进行认证:
|
在大多数情况下,证书认证应先进行证书验证,因为你只想对有效证书进行认证。 无效证书,比如过期已过或不在你信任证书库中的证书,应被忽略。 用Spring-WS术语来说,这意味着
利用这种设置,拦截者首先通过密钥存储来判断消息中的证书是否有效,然后对其进行认证。 |
用KeyStoreCallbackHandler
这KeyStoreCallbackHandler使用标准的 Java 密钥库来验证证书。
该证书验证过程包括以下步骤:
-
处理器检查证书是否存在私有账户
keyStore. 如果是,那就是有效的。 -
如果证书不在私钥库中,处理程序会检查当前日期和时间是否在证书中给出的有效期内。 如果不合格,证书无效。 如果是,则继续进行最后一步。
-
证书的认证路径会被创建。 这基本上意味着处理者会判断该证书是否由任何证书授权机构在
trustStore. 如果能够成功构建认证路径,证书即有效。 否则,证书无效。
使用KeyStoreCallbackHandler为了验证证书,你很可能只需要设置trustStore财产:
<beans>
<bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
<property name="trustStore" ref="trustStore"/>
</bean>
<bean id="trustStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
<property name="location" value="classpath:truststore.jks"/>
<property name="password" value="changeit"/>
</bean>
</beans>
根据前述示例所示的设置,待验证的证书必须存在于信任存储中,或者信任存储中必须包含颁发该证书的证书颁发机构。
用SpringCertificateValidationCallbackHandler
这SpringCertificateValidationCallbackHandler需要一个春季安全测试认证管理器去作。
它利用该管理器对X509认证Tokens它创造了。
配置的认证管理器应提供一个能够处理该Tokens的提供者(通常是X509认证提供者).
如果认证成功,Tokens将存储在安全上下文持有者.
你可以通过以下方式设置认证管理器authenticationManager财产:
<beans>
<bean id="springSecurityCertificateHandler"
class="org.springframework.ws.soap.security.xwss.callback.SpringCertificateValidationCallbackHandler">
<property name="authenticationManager" ref="authenticationManager"/>
</bean>
<bean id="authenticationManager"
class="org.springframework.security.providers.ProviderManager">
<property name="providers">
<bean class="org.springframework.ws.soap.security.x509.X509AuthenticationProvider">
<property name="x509AuthoritiesPopulator">
<bean class="org.springframework.ws.soap.security.x509.populator.DaoX509AuthoritiesPopulator">
<property name="userDetailsService" ref="userDetailsService"/>
</bean>
</property>
</bean>
</property>
</bean>
<bean id="userDetailsService" class="com.mycompany.app.dao.UserDetailService" />
...
</beans>
在这种情况下,我们使用自定义用户信息服务来获取基于证书的认证信息。 有关针对X509证书认证的更多信息,请参见Spring Security参考文档。
7.1.3. 数字签名
消息的数字签名是基于文档和签署者私钥的信息。 WS-Security 中与签名相关的主要任务有两个:验证签名和签署消息。
验证签名
与基于证书的认证类似,签名消息包含二进制安全Tokens,其中包含用于签署消息的证书。
此外,它还包含一个签名信息block,表示消息的哪部分被签名。
以确保所有收到的SOAP消息都携带二进制安全Tokens安全策略文件应包含要求签名元素。
它也可以包含签名目标元素,指定预期需签名的目标消息部分及其他各种子元素。
你还可以定义私钥别名,是否使用对称密钥而非私钥,以及许多其他属性。
欲了解更多细节,请查阅官方参考资料中的可能子元素。
以下列表配置为要求签名元素:
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<xwss:RequireSignature requireTimestamp="false"/>
</xwss:SecurityConfiguration>
如果没有签名,则Xws安全拦截者向发送方返回SOAP故障。
如果存在,则发射签名验证键回调对注册的控者来说。
在 Spring-WS 中,有一个类负责处理这个特定的回调:KeyStoreCallbackHandler.
用KeyStoreCallbackHandler
正如KeyStoreCallbackHandler中描述的,KeyStoreCallbackHandler使用java.security.KeyStore用于处理各种加密回调,包括签名验证。
对于签名验证,处理器使用trustStore财产:
<beans>
<bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
<property name="trustStore" ref="trustStore"/>
</bean>
<bean id="trustStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
<property name="location" value="classpath:org/springframework/ws/soap/security/xwss/test-truststore.jks"/>
<property name="password" value="changeit"/>
</bean>
</beans>
签署信息
在签署消息时,Xws安全拦截者补充道二进制安全Tokens对信息。
它还增加了一个签名信息block,表示消息的哪部分被签名。
要签署所有发出的SOAP消息,安全策略文件应包含标志元素。
它也可以包含签名目标元素,指定预期需签名的目标消息部分及其他各种子元素。
你还可以定义私钥别名,是否使用对称密钥而非私钥,以及许多其他属性。
欲了解更多细节,请查阅官方参考资料中的可能子元素。
以下示例包括一个标志元素:
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<xwss:Sign includeTimestamp="false" />
</xwss:SecurityConfiguration>
这Xws安全拦截者发射A签名键回调对注册的控者来说。
在春-西区内,KeyStoreCallbackHandler类负责处理这次特定的回调。
用KeyStoreCallbackHandler
正如KeyStoreCallbackHandler中描述的,KeyStoreCallbackHandler使用java.security.KeyStore处理各种密码学回调,包括签名消息。
对于添加签名,处理器使用keyStore财产。
此外,你必须设置私人密钥密码用于解锁用于签名的私钥。
以下示例使用了一个KeyStoreCallbackHandler:
<beans>
<bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
<property name="keyStore" ref="keyStore"/>
<property name="privateKeyPassword" value="changeit"/>
</bean>
<bean id="keyStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
<property name="location" value="classpath:keystore.jks"/>
<property name="password" value="changeit"/>
</bean>
</beans>
7.1.4. 解密与加密
加密时,消息被转换成只能用相应密钥读取的形式。 消息可以解密,以揭示原始且可读的消息。
解密
要解密收到的SOAP消息,安全策略文件应包含要求加密元素。
该元素还可以进一步承载加密目标表示消息中哪部分应加密的元素,以及对称键用来表示解密消息时应使用共享秘密而非普通私钥。
更多细节请查阅其他元素的官方参考资料。
以下示例使用了一个要求加密元素:
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<xwss:RequireEncryption />
</xwss:SecurityConfiguration>
如果收到的消息未加密,则Xws安全拦截者向发送方返回SOAP故障。
如果存在,则发射解密密钥回调对注册的控者来说。
在春-西区内,KeyStoreCallbackHandler类负责处理这次特定的回调。
用KeyStoreCallbackHandler
正如KeyStoreCallbackHandler中描述的,KeyStoreCallbackHandler使用java.security.KeyStore处理各种密码学回调,包括解密。
解密时,处理器使用keyStore财产。
此外,你必须设置私人密钥密码用于解锁用于解密的私钥的属性。
对于基于对称密钥的解密,它使用以下条件symmetricStore.
以下示例使用KeyStoreCallbackHandler:
<beans>
<bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
<property name="keyStore" ref="keyStore"/>
<property name="privateKeyPassword" value="changeit"/>
</bean>
<bean id="keyStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
<property name="location" value="classpath:keystore.jks"/>
<property name="password" value="changeit"/>
</bean>
</beans>
加密
为了加密发出的SOAP消息,安全策略文件应包含加密元素。
该元素还可以进一步承载加密目标表示消息中哪部分应加密的元素,以及对称键表示应使用共享秘密而非普通公钥来加密消息。
更多细节请查阅其他元素的官方参考资料。
以下示例使用了一个加密元素:
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<xwss:Encrypt />
</xwss:SecurityConfiguration>
这Xws安全拦截者发射加密密钥回调发送给注册处理程序以获取加密信息。
在春-西区内,KeyStoreCallbackHandler类负责处理这次特定的回调。
用KeyStoreCallbackHandler
正如KeyStoreCallbackHandler中描述的,KeyStoreCallbackHandler使用java.security.KeyStore处理各种密码学回调,包括加密。
对于基于公钥的加密,处理器使用trustStore财产。
对于基于对称密钥的加密,它使用symmetricStore.
以下示例使用KeyStoreCallbackHandler:
<beans>
<bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
<property name="trustStore" ref="trustStore"/>
</bean>
<bean id="trustStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
<property name="location" value="classpath:truststore.jks"/>
<property name="password" value="changeit"/>
</bean>
</beans>
7.1.5. 安全异常处理
当保障或验证作失败时,Xws安全拦截者掷出WsSecuritySecurementException或WsSecurityValidationException分别。
这些异常绕过标准的异常处理机制,但由拦截器本身处理。
WsSecuritySecurementException异常由以下handleSecurementException方法Xws安全拦截者.
默认情况下,该方法会记录错误并停止消息的进一步处理。
同样地WsSecurityValidationException异常由以下handleValidationException方法Xws安全拦截者.
默认情况下,这种方法会生成一个 SOAP 1.1 客户端或 SOAP 1.2 发送器错误,并作为响应返回。
双handleSecurementException和handleValidationException是受保护的方法,你可以覆盖它们以改变它们的默认行为。 |
7.2. 使用WSS4j安全拦截者
这WSS4j安全拦截者是终端拦截者(参见拦截请求——终端拦截者接口该系统基于Apache的WSS4J。
WSS4J 实现以下标准:
-
OASIS Web Services 安全:SOAP 消息安全 1.0 标准 200401,2004 年 3 月。
-
用户名Tokens配置文件 V1.0。
-
X.509 Tokens配置文件 v1.0。
该拦截器支持由SaajSoapMessageFactory(Saaj肥皂信息工厂).
7.2.1. 配置WSS4j安全拦截者
WSS4J 不使用外部配置文件。
拦截器完全由属性配置。
该拦截器调用的验证和安全作通过以下方式规范验证作和安全作分别是性质。
动作以空格分离字符串的形式传递。
以下列表展示了一个示例配置:
<bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="validationActions" value="UsernameToken Encrypt"/>
...
<property name="securementActions" value="Encrypt"/>
...
</bean>
下表展示了可用的验证作:
| 验证动作 | 描述 |
|---|---|
|
验证用户名Tokens |
|
验证时间戳 |
|
解密消息 |
|
验证签名 |
|
未执行任何动作 |
下表显示了可用的安全作:
| 安全措施 | 描述 |
|---|---|
|
添加用户名Tokens |
|
添加用户名Tokens和签名用户Tokens 密钥 |
|
添加时间戳 |
|
加密响应 |
|
回应的信号 |
|
未执行任何动作 |
行动顺序重要,由拦截器执行。
如果其安全作的执行顺序与以下规定不同验证作拦截器拒绝接收的SOAP消息。
7.2.2. 数字证书的处理
对于需要与密钥存储或证书处理交互的密码作(签名、加密和解密作),WSS4J 要求org.apache.ws.security.components.crypto.Crypto.
加密实例可从 WSS4J 获得加密工厂或者更方便地说,是Spring-WSCryptoFactoryBean.
CryptoFactoryBean
Spring-WS提供了便捷的工厂豆,CryptoFactoryBean,能够构造并配置加密通过强类型属性(优先)或通过性能对象。
默认情况下,CryptoFactoryBean返回 的实例org.apache.ws.security.components.crypto.Merlin.
你可以通过设置加密提供商性质(或其等价物)org.apache.ws.security.crypto.provider字符串属性)。
以下示例配置使用CryptoFactoryBean:
<bean class="org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean">
<property name="keyStorePassword" value="mypassword"/>
<property name="keyStoreLocation" value="file:/path_to_keystore/keystore.jks"/>
</bean>
7.2.3. 认证
本节讲解如何通过WSS4j安全拦截者.
验证用户名Tokens
Spring-WS 提供了一组回调处理程序,用于与 Spring Security 集成。
此外,还有一个简单的回调处理程序,SimplePasswordValidationCallbackHandler,用于配置用户和密码,并带有内存性能对象。
回调处理程序通过以下方式配置验证回调处理程序关于WSS4j安全拦截者财产。
用SimplePasswordValidationCallbackHandler
SimplePasswordValidationCallbackHandler验证纯文本,并对内存用户名Tokens进行解析性能对象。
你可以按以下方式配置:
<bean id="callbackHandler"
class="org.springframework.ws.soap.security.wss4j.callback.SimplePasswordValidationCallbackHandler">
<property name="users">
<props>
<prop key="Bert">Ernie</prop>
</props>
</property>
</bean>
用SpringSecurityPasswordValidationCallbackHandler
这SpringSecurityPasswordValidationCallbackHandler通过使用 Spring Security 验证明文和摘要密码用户详情服务去作。
它利用该服务获取Tokens中指定的用户密码(或密码摘要)。
该详细信息对象中包含的密码(或密码摘要)随后与消息中的摘要进行比较。
如果它们相等,则表示用户已成功认证,且用户名密码认证Tokens存储在安全上下文持有者.
你可以通过使用用户详情服务.
此外,你可以设置用户缓存用于缓存已加载的用户信息的属性,具体如下:
<beans>
<bean class="org.springframework.ws.soap.security.wss4j.callback.SpringDigestPasswordValidationCallbackHandler">
<property name="userDetailsService" ref="userDetailsService"/>
</bean>
<bean id="userDetailsService" class="com.mycompany.app.dao.UserDetailService" />
...
</beans>
添加用户名Tokens
在外发消息中添加用户名Tokens只需添加用户名Tokens前往安全作的属性WSS4j安全拦截者并且securement用户名和securementPassword.
密码类型可以通过设置securementPasswordType财产。
可能的值有密码正文用于纯文本密码或密码摘要对于摘要密码,这是默认的。
以下示例生成一个带有摘要密码的用户名Tokens:
<bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="securementActions" value="UsernameToken"/>
<property name="securementUsername" value="Ernie"/>
<property name="securementPassword" value="Bert"/>
</bean>
如果选择纯文本密码类型,可以指示拦截者添加不和创建通过设置securementUsernameTokenElements财产。
该值必须是一个包含所需元素名称并用空格分隔的列表(大小写区分)。
以下示例生成一个带有明文密码的用户名Tokens,即不,以及一个创建元素:
<bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="securementActions" value="UsernameToken"/>
<property name="securementUsername" value="Ernie"/>
<property name="securementPassword" value="Bert"/>
<property name="securementPasswordType" value="PasswordText"/>
<property name="securementUsernameTokenElements" value="Nonce Created"/>
</bean>
证书认证
由于证书认证类似于数字签名,WSS4J将其作为签名验证和安全的一部分来处理。
具体来说,是securementSignatureKeyIdentifier属性必须设置为直接参考以指示WSS4J生成一个二进制安全Tokens包含X509证书的元素,并将其包含在发出消息中。
证书的名称和密码通过securement用户名和securementPassword如下例所示,分别是性质:
<bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="securementActions" value="Signature"/>
<property name="securementSignatureKeyIdentifier" value="DirectReference"/>
<property name="securementUsername" value="mycert"/>
<property name="securementPassword" value="certpass"/>
<property name="securementSignatureCrypto">
<bean class="org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean">
<property name="keyStorePassword" value="123456"/>
<property name="keyStoreLocation" value="classpath:/keystore.jks"/>
</bean>
</property>
</bean>
对于证书验证,通常采用常规签名验证:
<bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="validationActions" value="Signature"/>
<property name="validationSignatureCrypto">
<bean class="org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean">
<property name="keyStorePassword" value="123456"/>
<property name="keyStoreLocation" value="classpath:/keystore.jks"/>
</bean>
</property>
</bean>
验证结束时,拦截者通过委派给默认的WSS4J实现,自动验证证书的有效性。
如果需要,你可以通过重新定义验证证书信任方法。
更多详情请参见数字签名。
7.2.4. 安全时间戳
本节描述了在WSS4j安全拦截者.
验证时间戳
要验证时间戳,添加时间戳前往验证作财产。
你可以通过设置来覆盖SOAP消息发起者指定的时间戳语义时间戳严格自true并通过设置时间到生命财产。
拦截器总是拒绝已过期的时间戳,无论 值为何时间到生命是。
在以下示例中,拦截者将时间戳有效窗口限制为10秒,拒绝该窗口外的任何有效时间戳Tokens:
<bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="validationActions" value="Timestamp"/>
<property name="timestampStrict" value="true"/>
<property name="timeToLive" value="10"/>
</bean>
添加时间戳
添加时间戳前往安全作property 在发出消息中生成时间戳头。
这时间戳精确度毫秒性质 指定生成时间戳的精度是否以毫秒为单位。
默认值为true.
以下列表添加了时间戳:
<bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="securementActions" value="Timestamp"/>
<property name="timestampPrecisionInMilliseconds" value="true"/>
</bean>
7.2.5. 数字签名
本节介绍了在WSS4j安全拦截者.
验证签名
以指导WSS4j安全拦截者,验证作必须包含签名行动。
此外,验证签名加密属性必须指向包含发起方公开证书的密钥库:
<bean id="wsSecurityInterceptor" class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="validationActions" value="Signature"/>
<property name="validationSignatureCrypto">
<bean class="org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean">
<property name="keyStorePassword" value="123456"/>
<property name="keyStoreLocation" value="classpath:/keystore.jks"/>
</bean>
</property>
</bean>
签署信息
通过添加签名对安全作.
私钥的别名和密码由以下方式指定securement用户名和securementPassword分别是性质。安全签名加密必须指向包含私钥的密钥库:
<bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="securementActions" value="Signature"/>
<property name="securementUsername" value="mykey"/>
<property name="securementPassword" value="123456"/>
<property name="securementSignatureCrypto">
<bean class="org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean">
<property name="keyStorePassword" value="123456"/>
<property name="keyStoreLocation" value="classpath:/keystore.jks"/>
</bean>
</property>
</bean>
此外,你可以通过设置securementSignatureAlgorithm财产。
你可以通过设置securementSignatureKeyIdentifier财产。
只发行序列号和直接参考对于签名有效。
这安全签名部分属性控制消息的哪部分被签名。
该属性的值是一份用分号分隔的元素名称列表,用于标识需要签名的元素。
签名部分的一般形式为{}{namespace}元素.
注意,第一个空括号仅用于加密部分。
默认行为是签署SOAP主体。
以下示例展示了如何签署回声响应Spring-WS回声采样中的元素:
<property name="securementSignatureParts"
value="{}{http://www.springframework.org/spring-ws/samples/echo}echoResponse"/>
要指定一个没有命名空间的元素,可以使用字符串,零(区分大小写),作为命名空间名称。
如果请求中没有其他元素具有本地名称身体,SOAP 命名空间标识符可以为空()。{}
签名确认
签名确认通过设置启用enableSignatureConfirmation自true.
请注意,签名确认动作跨越请求和响应。
这意味着secureResponse和验证请求必须设置为true(这是默认值),即使没有相应的安全作。
以下示例设置enableSignatureConfirmation属性到true:
<bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="validationActions" value="Signature"/>
<property name="enableSignatureConfirmation" value="true"/>
<property name="validationSignatureCrypto">
<bean class="org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean">
<property name="keyStorePassword" value="123456"/>
<property name="keyStoreLocation" value="file:/keystore.jks"/>
</bean>
</property>
</bean>
7.2.6. 解密与加密
本节介绍了在WSS4j安全拦截者.
解密
解密接收的SOAP消息需要加密动作被添加到验证作财产。
其余配置取决于消息中出现的关键信息。
(这是因为WSS4J只需加密密钥的加密密钥,而嵌入密钥名的验证则委托给回调处理程序。)
要解密带有加密对称密钥的消息(xenc:加密密钥元素),验证解密加密需要指向包含解密私钥的密钥存储。
此外验证回调处理程序必须注射KeyStoreCallbackHandler该密钥指定了密码:
<bean class="org.springframework.ws.soap.security.wss4j2.Wss4jSecurityInterceptor">
<property name="validationActions" value="Encrypt"/>
<property name="validationDecryptionCrypto">
<bean class="org.springframework.ws.soap.security.wss4j2.support.CryptoFactoryBean">
<property name="keyStorePassword" value="123456"/>
<property name="keyStoreLocation" value="classpath:/keystore.jks"/>
</bean>
</property>
<property name="validationCallbackHandler">
<bean class="org.springframework.ws.soap.security.wss4j2.callback.KeyStoreCallbackHandler">
<property name="privateKeyPassword" value="mykeypass"/>
</bean>
</property>
</bean>
为支持带有嵌入密钥名的消息解密(ds:KeyName元素),你可以配置一个KeyStoreCallbackHandler指向带有对称密钥的密钥库。
这symmetricKeyPassword属性表示密钥的密码,密钥名由以下方式指定ds:KeyName元素:
<bean class="org.springframework.ws.soap.security.wss4j2.Wss4jSecurityInterceptor">
<property name="validationActions" value="Encrypt"/>
<property name="validationCallbackHandler">
<bean class="org.springframework.ws.soap.security.wss4j2.callback.KeyStoreCallbackHandler">
<property name="keyStore">
<bean class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
<property name="location" value="classpath:keystore.jks"/>
<property name="type" value="JCEKS"/>
<property name="password" value="123456"/>
</bean>
</property>
<property name="symmetricKeyPassword" value="mykeypass"/>
</bean>
</property>
</bean>
加密
添加加密前往安全作支持对外发消息的加密。
你可以通过设置securementEncryptionUser财产。
证书所在的密钥存储是通过安全加密加密财产。
由于加密依赖于公共证书,无需传递密码。
以下示例使用了安全加密加密财产:
<bean class="org.springframework.ws.soap.security.wss4j2.Wss4jSecurityInterceptor">
<property name="securementActions" value="Encrypt"/>
<property name="securementEncryptionUser" value="mycert"/>
<property name="securementEncryptionCrypto">
<bean class="org.springframework.ws.soap.security.wss4j2.support.CryptoFactoryBean">
<property name="keyStorePassword" value="123456"/>
<property name="keyStoreLocation" value="file:/keystore.jks"/>
</bean>
</property>
</bean>
您可以通过多种方式自定义加密:使用的密钥标识符类型由以下securementEncryptionKeyIdentifier财产。
可能的值有发行序列号,X509KeyIdentifier,直接参考,指纹,SKIKey标识符和嵌入键名.
如果你选择嵌入键名类型,你需要指定用于加密的密钥。
密钥的别名设置在securementEncryptionUser属性,以及其他键标识符类型。
然而,WSS4J需要回调处理程序来获取密钥。
因此,你必须提供securementCallbackHandler其中KeyStoreCallbackHandler这指向了相应的密钥存储。
默认情况下,ds:KeyName结果WS-Security头中的元素取值securementEncryptionUser财产。
要表示不同的名字,可以设置securementEncryptionEmbeddedKeyName以所需值。
在下一个例子中,发出消息被加密为一个混淆的密钥秘密密钥而我的钥匙出现在ds:KeyName元素:
<bean class="org.springframework.ws.soap.security.wss4j2.Wss4jSecurityInterceptor">
<property name="securementActions" value="Encrypt"/>
<property name="securementEncryptionKeyIdentifier" value="EmbeddedKeyName"/>
<property name="securementEncryptionUser" value="secretKey"/>
<property name="securementEncryptionEmbeddedKeyName" value="myKey"/>
<property name="securementCallbackHandler">
<bean class="org.springframework.ws.soap.security.wss4j2.callback.KeyStoreCallbackHandler">
<property name="symmetricKeyPassword" value="keypass"/>
<property name="keyStore">
<bean class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
<property name="location" value="file:/keystore.jks"/>
<property name="type" value="jceks"/>
<property name="password" value="123456"/>
</bean>
</property>
</bean>
</property>
</bean>
这安全加密密钥传输算法性质定义了用于加密生成对称密钥的算法。
支持的值有http://www.w3.org/2001/04/xmlenc#rsa-1_5,这是默认值,且http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p.
你可以通过设置securementEncryptionSymAlgorithm财产。
支持的值有http://www.w3.org/2001/04/xmlenc#aes128-cbc(默认),http://www.w3.org/2001/04/xmlenc#tripledes-cbc,http://www.w3.org/2001/04/xmlenc#aes256-cbc和http://www.w3.org/2001/04/xmlenc#aes192-cbc.
最后,是安全加密部分属性定义了消息中哪些部分被加密。
该属性的值是一组用分号分隔的元素名称列表,用于识别需要加密的元素。
加密模式指定符和命名空间标识,分别位于一对大括号内,位于每个元素名称之前。
加密模式的指定符为{内容}或{元素}请参阅 W3C XML 加密规范中关于元素加密与内容加密差异的说明。
以下示例识别了回声响应来自回声采样:
<property name="securementEncryptionParts"
value="{Content}{http://www.springframework.org/spring-ws/samples/echo}echoResponse"/>
请注意,元素名称、命名空间标识符和加密修饰符均区分大小写。
你可以省略加密修饰符和命名空间标识符。
如果这样做,加密模式默认为内容,且命名空间设置为SOAP命名空间。
要指定一个没有命名空间的元素,可以使用零(区分大小写),作为命名空间名称。
如果没有指定列表,处理器会在内容默认模式。
7.2.7. 安全异常处理
例外处理WSS4j安全拦截者与 的 相同Xws安全拦截者.
更多信息请参见安全例外处理。