将数据从 SOAP 处理程序传递到 Web 服务服务器 Class
Pass data from a SOAP handler to a webservice server Class
我有一个 Spring 带有 cxf 的引导 SOAP 服务,我的消费者在 http header 中向我传递 SSO 令牌。我能够使用 JAX-WS 检索 SSO 令牌处理程序。我将该 SSO 令牌保存到处理程序 class 级别变量中,在控制通过各种 classes 之后,它到达了一个点,我必须向另一个服务发出请求并且必须传递相同的 SSO令牌,但在我的连接 class 中,SSO 令牌值为 NULL。
@Component
public class EndPointHandler implements SOAPHandler<SOAPMessageContext> {
private List<String> ssoToken;
private Map<String, List<String>> headers;
@Override
public boolean handleMessage(SOAPMessageContext context) {
Boolean isResponse = (Boolean) context.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (!isResponse) {
headers = ((Map<String, List<String>>) context.get(MessageContext.HTTP_REQUEST_HEADERS));
if (headers != null) {
if (!headers.get("SSOToken").get(0).isEmpty()) {
List<String> ssoToken = headers.get("SSOToken");
LOGGER.info(ssoToken.get(0));
this.ssoToken = ssoToken;
} else {
LOGGER.error("SSO Token value cannot be empty");
return false;
}
}
}
return true;
}
public void setSSOToken() {
headers.put("SSOToken", this.ssoToken);
}
}
在我的连接 class 中,我必须将此 SSO 令牌设置为 header 并调用另一个服务,但 SSO 令牌值为 NULL。
连接Class:
@Component
public class ConnectionManager {
private static final Logger LOGGER = LoggerFactory.getLogger(ConnectionManager.class);
@Autowired
private EndPointHandler handler;
private void establishConnection(String uri) throws FileNetIntegrationException {
handler.ssoToken; // --> I need SSO token here but the value is NULL;
}
}
这就是我在 WebServiceConfig 中设置处理程序链的方式 class:
@Bean
public Endpoint endpoint(Bus bus) {
EndpointImpl endpoint = new EndpointImpl(bus, changeServiceEndpoint);
WebService ws = AnnotationUtils.findAnnotation(endpoint.getImplementorClass(), WebService.class);
endpoint.setAddress("/" + ws.serviceName());
endpoint.publish();
SOAPBinding binding = (SOAPBinding) endpoint.getBinding();
ArrayList<Handler> handlerChain = new ArrayList<>();
handlerChain.add(new EndPointHandler());
binding.setHandlerChain(handlerChain);
return endpoint;
}
我想,当我注意到我在将它添加到处理程序链时使用了 new EndPointHandler() 时,我在此处发布最后一段代码后立即找到了解决方案。我尝试使用 Autowired 它并且它对我有用。
据我所知,jax-ws
上下文和spring-ws
上下文不相交。所以这不是解决方案,而是解决方法。作为另一种解决方法,您可以使用一些单例 synchronizedMap
,或使用 jax-ws
Handler
将请求重定向到具有扩展 api.[=80 的另一个端点=]
使用 JAX-WS 处理程序
访问 SOAP 消息的 HTTP headers
如果您配置了SOAPHandler
for your JAX-WS
WebService
, then you can access the HTTP headers and pass them on inside the SOAPBody
as fields of the SOAPElement
type, and vice versa. To do this you have to extend the messages POJOs with these fields annotated as XmlElement
. Then you can access them from your WebService
.
注意: 如果您有一个基于 Java 类 的动态生成的 WSDL 架构,那么它也会发生变化。但是无论如何,旧的请求和响应都被接受,因为默认情况下不需要这些字段。
示例: UserService
- 传入消息具有一个 String
类型的字段,而传出消息具有一个 int
类型的字段。让我们用一个 String
类型的 ssoToken
字段来扩展它们中的每一个。我们将从传入消息的 HTTP headers 中读取此令牌,并在传出消息的 HTTP headers 中将其发回。
GetUserRequest.java:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType
@XmlRootElement(name = "getUserRequest")
public class GetUserRequest {
@XmlElement
protected String ssoToken;
@XmlElement(required = true)
protected String name;
// getters + setters + constructor
}
GetUserResponse.java:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType
@XmlRootElement(name = "getUserResponse")
public class GetUserResponse {
@XmlElement
protected String ssoToken;
@XmlElement(required = true)
protected int age;
// getters + setters + constructor
}
UserServiceHandler.java
public class UserServiceHandler implements SOAPHandler<SOAPMessageContext> {
@Override
public boolean handleMessage(SOAPMessageContext soapMessageContext) {
Boolean isResponse =
(Boolean) soapMessageContext
.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (!isResponse) {
// Request message
return processIncomingMessage(soapMessageContext);
} else {
// Response message
return processOutgoingMessage(soapMessageContext);
}
}
}
processIncomingMessage:
@SuppressWarnings("unchecked")
private boolean processIncomingMessage(SOAPMessageContext soapMessageContext) {
Map<String, List<String>> headers =
((Map<String, List<String>>) soapMessageContext
.get(MessageContext.HTTP_REQUEST_HEADERS));
if (headers == null || headers.isEmpty()) {
return false;
}
List<String> ssoTokens = headers.get("SSOToken");
if (ssoTokens == null || ssoTokens.size() != 1) {
return false;
}
String ssoToken = ssoTokens.get(0);
if (ssoToken == null || ssoToken.isEmpty()) {
return false;
}
try {
Iterator<Node> iterator =
soapMessageContext.getMessage().getSOAPBody().getChildElements();
while (iterator.hasNext()) {
Node element = iterator.next();
if (element.getNodeName().contains("getUserRequest")) {
((SOAPElement) element)
.addChildElement("ssoToken", element.getPrefix())
.setTextContent(ssoToken);
}
}
} catch (SOAPException e) {
e.printStackTrace();
return false;
}
return true;
}
processOutgoingMessage:
@SuppressWarnings("unchecked")
private boolean processOutgoingMessage(SOAPMessageContext soapMessageContext) {
Map<String, List<String>> headers =
((Map<String, List<String>>) soapMessageContext
.get(MessageContext.HTTP_RESPONSE_HEADERS));
if (headers == null || headers.isEmpty()) {
soapMessageContext
.put(MessageContext.HTTP_RESPONSE_HEADERS, new HashMap<>());
headers = ((Map<String, List<String>>) soapMessageContext
.get(MessageContext.HTTP_RESPONSE_HEADERS));
}
try {
Iterator<Node> iterator = soapMessageContext
.getMessage().getSOAPBody().getChildElements();
while (iterator.hasNext()) {
Node element = iterator.next();
if (element.getNodeName().contains("getUserResponse")) {
Iterator<Node> iteratorResponse =
((SOAPElement) element).getChildElements();
while (iteratorResponse.hasNext()) {
Node childElement = iteratorResponse.next();
if (childElement.getNodeName().contains("ssoToken")) {
String ssoToken = childElement.getTextContent();
headers.put("SSOToken",
Collections.singletonList(ssoToken));
element.removeChild(childElement);
}
}
}
}
} catch (SOAPException e) {
e.printStackTrace();
return false;
}
return true;
}
UserService.java
@WebService(endpointInterface = "com.example.UserPort",
serviceName = "UserService")
@HandlerChain(file="handler-chain.xml")
public class UserService implements UserPort {
public GetUserResponse getUser(GetUserRequest request) {
GetUserResponse response = new GetUserResponse();
response.setAge(23);
response.setSsoToken(request.getSsoToken());
return response;
}
}
使用 SoapUI 进行测试:
请求headers:
POST http://localhost:8080/ws/userService HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: ""
SSOToken: 6cd506ac-738a-43ca-aee8-d13b78180605
Content-Length: 296
Host: localhost:8080
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
请求消息:
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:spr="http://example.com/jax-ws-sample">
<soapenv:Header/>
<soapenv:Body>
<spr:getUserRequest>
<spr:name>John</spr:name>
</spr:getUserRequest>
</soapenv:Body>
</soapenv:Envelope>
响应headers:
HTTP/1.1 200
SSOToken: 6cd506ac-738a-43ca-aee8-d13b78180605
Content-Type: text/xml;charset=utf-8
Transfer-Encoding: chunked
Date: Thu, 27 Aug 2020 15:54:33 GMT
Keep-Alive: timeout=20
Connection: keep-alive
回复消息:
<S:Envelope
xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<S:Body>
<getUserResponse xmlns="http://example.com/jax-ws-sample">
<age>23</age>
</getUserResponse>
</S:Body>
</S:Envelope>
我有一个 Spring 带有 cxf 的引导 SOAP 服务,我的消费者在 http header 中向我传递 SSO 令牌。我能够使用 JAX-WS 检索 SSO 令牌处理程序。我将该 SSO 令牌保存到处理程序 class 级别变量中,在控制通过各种 classes 之后,它到达了一个点,我必须向另一个服务发出请求并且必须传递相同的 SSO令牌,但在我的连接 class 中,SSO 令牌值为 NULL。
@Component
public class EndPointHandler implements SOAPHandler<SOAPMessageContext> {
private List<String> ssoToken;
private Map<String, List<String>> headers;
@Override
public boolean handleMessage(SOAPMessageContext context) {
Boolean isResponse = (Boolean) context.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (!isResponse) {
headers = ((Map<String, List<String>>) context.get(MessageContext.HTTP_REQUEST_HEADERS));
if (headers != null) {
if (!headers.get("SSOToken").get(0).isEmpty()) {
List<String> ssoToken = headers.get("SSOToken");
LOGGER.info(ssoToken.get(0));
this.ssoToken = ssoToken;
} else {
LOGGER.error("SSO Token value cannot be empty");
return false;
}
}
}
return true;
}
public void setSSOToken() {
headers.put("SSOToken", this.ssoToken);
}
}
在我的连接 class 中,我必须将此 SSO 令牌设置为 header 并调用另一个服务,但 SSO 令牌值为 NULL。
连接Class:
@Component
public class ConnectionManager {
private static final Logger LOGGER = LoggerFactory.getLogger(ConnectionManager.class);
@Autowired
private EndPointHandler handler;
private void establishConnection(String uri) throws FileNetIntegrationException {
handler.ssoToken; // --> I need SSO token here but the value is NULL;
}
}
这就是我在 WebServiceConfig 中设置处理程序链的方式 class:
@Bean
public Endpoint endpoint(Bus bus) {
EndpointImpl endpoint = new EndpointImpl(bus, changeServiceEndpoint);
WebService ws = AnnotationUtils.findAnnotation(endpoint.getImplementorClass(), WebService.class);
endpoint.setAddress("/" + ws.serviceName());
endpoint.publish();
SOAPBinding binding = (SOAPBinding) endpoint.getBinding();
ArrayList<Handler> handlerChain = new ArrayList<>();
handlerChain.add(new EndPointHandler());
binding.setHandlerChain(handlerChain);
return endpoint;
}
我想,当我注意到我在将它添加到处理程序链时使用了 new EndPointHandler() 时,我在此处发布最后一段代码后立即找到了解决方案。我尝试使用 Autowired 它并且它对我有用。
据我所知,jax-ws
上下文和spring-ws
上下文不相交。所以这不是解决方案,而是解决方法。作为另一种解决方法,您可以使用一些单例 synchronizedMap
,或使用 jax-ws
Handler
将请求重定向到具有扩展 api.[=80 的另一个端点=]
使用 JAX-WS 处理程序
访问 SOAP 消息的 HTTP headers如果您配置了SOAPHandler
for your JAX-WS
WebService
, then you can access the HTTP headers and pass them on inside the SOAPBody
as fields of the SOAPElement
type, and vice versa. To do this you have to extend the messages POJOs with these fields annotated as XmlElement
. Then you can access them from your WebService
.
注意: 如果您有一个基于 Java 类 的动态生成的 WSDL 架构,那么它也会发生变化。但是无论如何,旧的请求和响应都被接受,因为默认情况下不需要这些字段。
示例: UserService
- 传入消息具有一个 String
类型的字段,而传出消息具有一个 int
类型的字段。让我们用一个 String
类型的 ssoToken
字段来扩展它们中的每一个。我们将从传入消息的 HTTP headers 中读取此令牌,并在传出消息的 HTTP headers 中将其发回。
GetUserRequest.java:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType
@XmlRootElement(name = "getUserRequest")
public class GetUserRequest {
@XmlElement
protected String ssoToken;
@XmlElement(required = true)
protected String name;
// getters + setters + constructor
}
GetUserResponse.java:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType
@XmlRootElement(name = "getUserResponse")
public class GetUserResponse {
@XmlElement
protected String ssoToken;
@XmlElement(required = true)
protected int age;
// getters + setters + constructor
}
UserServiceHandler.java
public class UserServiceHandler implements SOAPHandler<SOAPMessageContext> {
@Override
public boolean handleMessage(SOAPMessageContext soapMessageContext) {
Boolean isResponse =
(Boolean) soapMessageContext
.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (!isResponse) {
// Request message
return processIncomingMessage(soapMessageContext);
} else {
// Response message
return processOutgoingMessage(soapMessageContext);
}
}
}
processIncomingMessage:
@SuppressWarnings("unchecked")
private boolean processIncomingMessage(SOAPMessageContext soapMessageContext) {
Map<String, List<String>> headers =
((Map<String, List<String>>) soapMessageContext
.get(MessageContext.HTTP_REQUEST_HEADERS));
if (headers == null || headers.isEmpty()) {
return false;
}
List<String> ssoTokens = headers.get("SSOToken");
if (ssoTokens == null || ssoTokens.size() != 1) {
return false;
}
String ssoToken = ssoTokens.get(0);
if (ssoToken == null || ssoToken.isEmpty()) {
return false;
}
try {
Iterator<Node> iterator =
soapMessageContext.getMessage().getSOAPBody().getChildElements();
while (iterator.hasNext()) {
Node element = iterator.next();
if (element.getNodeName().contains("getUserRequest")) {
((SOAPElement) element)
.addChildElement("ssoToken", element.getPrefix())
.setTextContent(ssoToken);
}
}
} catch (SOAPException e) {
e.printStackTrace();
return false;
}
return true;
}
processOutgoingMessage:
@SuppressWarnings("unchecked")
private boolean processOutgoingMessage(SOAPMessageContext soapMessageContext) {
Map<String, List<String>> headers =
((Map<String, List<String>>) soapMessageContext
.get(MessageContext.HTTP_RESPONSE_HEADERS));
if (headers == null || headers.isEmpty()) {
soapMessageContext
.put(MessageContext.HTTP_RESPONSE_HEADERS, new HashMap<>());
headers = ((Map<String, List<String>>) soapMessageContext
.get(MessageContext.HTTP_RESPONSE_HEADERS));
}
try {
Iterator<Node> iterator = soapMessageContext
.getMessage().getSOAPBody().getChildElements();
while (iterator.hasNext()) {
Node element = iterator.next();
if (element.getNodeName().contains("getUserResponse")) {
Iterator<Node> iteratorResponse =
((SOAPElement) element).getChildElements();
while (iteratorResponse.hasNext()) {
Node childElement = iteratorResponse.next();
if (childElement.getNodeName().contains("ssoToken")) {
String ssoToken = childElement.getTextContent();
headers.put("SSOToken",
Collections.singletonList(ssoToken));
element.removeChild(childElement);
}
}
}
}
} catch (SOAPException e) {
e.printStackTrace();
return false;
}
return true;
}
UserService.java
@WebService(endpointInterface = "com.example.UserPort",
serviceName = "UserService")
@HandlerChain(file="handler-chain.xml")
public class UserService implements UserPort {
public GetUserResponse getUser(GetUserRequest request) {
GetUserResponse response = new GetUserResponse();
response.setAge(23);
response.setSsoToken(request.getSsoToken());
return response;
}
}
使用 SoapUI 进行测试:
请求headers:
POST http://localhost:8080/ws/userService HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: ""
SSOToken: 6cd506ac-738a-43ca-aee8-d13b78180605
Content-Length: 296
Host: localhost:8080
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
请求消息:
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:spr="http://example.com/jax-ws-sample">
<soapenv:Header/>
<soapenv:Body>
<spr:getUserRequest>
<spr:name>John</spr:name>
</spr:getUserRequest>
</soapenv:Body>
</soapenv:Envelope>
响应headers:
HTTP/1.1 200
SSOToken: 6cd506ac-738a-43ca-aee8-d13b78180605
Content-Type: text/xml;charset=utf-8
Transfer-Encoding: chunked
Date: Thu, 27 Aug 2020 15:54:33 GMT
Keep-Alive: timeout=20
Connection: keep-alive
回复消息:
<S:Envelope
xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<S:Body>
<getUserResponse xmlns="http://example.com/jax-ws-sample">
<age>23</age>
</getUserResponse>
</S:Body>
</S:Envelope>