英文:
Pass data from a SOAP handler to a webservice server Class
问题
以下是您提供的代码翻译部分:
@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);
}
}
@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;
}
}
@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;
}
英文:
I have a Spring boot SOAP services with cxf, and my Consumers are passing me SSO token in http header.. I am able to retrieve the SSO token using JAX-WS handler. I am saving that SSO token into handler class level variable, and after control going through various classes it reaches to a point where I have to make a request to another service and have to pass the same SSO token, but in my Connection class the SSO token value is 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);
}
}
In my Connection class I have to set this SSO token as a header and make a call to another service but SSO token value is NULL.
Connection 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;
}
}
This is how I set the handler chain in my 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;
}
答案1
得分: 4
我认为,就在我发布了最后一段代码之后,我立刻找到了一个解决方案,当我注意到在将其添加到处理程序链时使用了 new EndPointHandler()
.. 我尝试使用 @Autowired
,这对我起了作用。
英文:
I think, I got a solution right after posting the last piece of code here when I noticed that I used new EndPointHandler() while adding it into handler chain.. I tried using Autowired it and it worked for me.
答案2
得分: 2
<sub>*据我所知,`jax-ws`上下文和`spring-ws`上下文彼此不相交。因此,这不是一个解决方案,而是一个变通方法。作为另一种变通方法,您可以使用一些单例的[`synchronizedMap`][1],或者使用`jax-ws`的`Handler`将请求重定向到具有扩展API的另一个端点。*</sub>
---
### 使用JAX-WS处理程序访问SOAP消息的HTTP头
如果您为`JAX-WS`的`WebService`配置了[`SOAPHandler`][2],那么您可以访问HTTP头并将它们作为[`SOAPElement`][5]类型的字段传递到[`SOAPBody`][4]中,反之亦然。为此,您必须使用这些字段扩展消息POJO,并对其进行[`XmlElement`][6]注释。然后您可以从您的[`WebService`][3]中访问它们。
*注意:*如果您的动态生成的WSDL基于Java类,那么它也会发生变化。但无论如何,旧的请求和响应都会被接受,因为这些字段默认不是必需的。
---
**示例:** `UserService` - 输入消息有一个`String`类型的字段,输出消息有一个`int`类型的字段。让我们分别使用一个`String`类型的`ssoToken`字段扩展它们。我们将从传入消息的HTTP头中读取此令牌,并在传出消息的HTTP头中将其发送回去。
GetUserRequest.java:
```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) {
// 请求消息
return processIncomingMessage(soapMessageContext);
} else {
// 响应消息
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进行测试:
请求头:
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>
响应头:
HTTP/1.1 200
SSOToken: 6cd506ac-738a-43ca-aee8-d13b78180605
Content-Type: text/xml;charset=utf-8
Transfer-Encoding:
<details>
<summary>英文:</summary>
<sub>*As far as I know, `jax-ws` context and `spring-ws` context don't intersect with each other. So this is not a solution but a workaround. As another workaround, you can use some singleton [`synchronizedMap`][1], or use a `jax-ws` `Handler` to redirect requests to another endpoint with extended api.*</sub>
---
### Access HTTP headers of SOAP messages using JAX-WS handler
If you have configured [`SOAPHandler`][2] for your `JAX-WS` [`WebService`][3], then you can access the HTTP headers and pass them on inside the [`SOAPBody`][4] as fields of the [`SOAPElement`][5] type, and vice versa. To do this you have to extend the messages POJOs with these fields annotated as [`XmlElement`][6]. Then you can access them from your [`WebService`][3].
*Note:* If you have a dynamically generated WSDL schema based on Java classes, then it changes too. But anyway, the old requests and responses are accepted, because these fields are not required by default.
---
**Example:** `UserService` - the incoming message has one field of `String` type and outgoing message has one field of `int` type. Let's extend each of them with one `ssoToken` field of `String` type. We'll read this token from HTTP headers of incoming message and send it back in HTTP headers of outgoing message.
GetUserRequest.java:
```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;
}
}
Testing with SoapUI:
Request 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)
Request message:
<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>
Response 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
Response message:
<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>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论