这里首先说下客户端拦截器。
这里要实现的效果
这里的打印都是在拦截器中打印的!
下面要介绍如下的东西,如何在拦截器中打印这些东西,其次是在拦截器中添加一个head
对应的Maven
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.1.16.RELEASE
com.example
demo
0.0.1-SNAPSHOT
demo
Demo project for Spring Boot
1.8
org.springframework.boot
spring-boot-starter-web
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
wsdl4j
wsdl4j
1.6.1
org.springframework.ws
spring-ws-core
3.0.8.RELEASE
org.springframework.ws
spring-ws-security
junit
junit
4.12
org.apache.ws.security
wss4j
1.6.19
org.springframework.boot
spring-boot-maven-plugin
org.jvnet.jaxb2.maven2
maven-jaxb2-plugin
0.14.0
generate
WSDL
com.example.demo.wsdl
http://127.0.0.1:8080/ws/countries.wsdl
在客户端中连接器要实现ClientInterceptor接口:
@Component
public class GlobalInterceptor implements ClientInterceptor {
public final QName SessionID_QNAME = new QName("http://xml.example.com/ws/session", "sessionID");
@Override
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
HttpLoggingUtils.logMessage("Client Request Message start", messageContext.getRequest());
SoapMessage soapMessage = (SoapMessage) messageContext.getRequest();
SoapHeaderElement soapHeaderElement = soapMessage.getSoapHeader().addHeaderElement(SessionID_QNAME);
HttpLoggingUtils.logMessage("Client Request Message end", messageContext.getRequest());
return true;
}
@Override
public boolean handleResponse(MessageContext messageContext) throws WebServiceClientException {
HttpLoggingUtils.logMessage("Client Response Message", messageContext.getResponse());
return true;
}
@Override
public boolean handleFault(MessageContext messageContext) throws WebServiceClientException {
System.out.println("handleFault");
return true;
}
@Override
public void afterCompletion(MessageContext messageContext, Exception e) throws WebServiceClientException {
System.out.println("afterCompletion");
}
}
这里可以在两个地方加,如果仅仅是HTTP协议的,可以直接加。
如CountryClient.java
public class CountryClient extends WebServiceGatewaySupport {
@Bean
public Wss4jSecurityInterceptor securityInterceptor(){
Wss4jSecurityInterceptor wss4jSecurityInterceptor = new Wss4jSecurityInterceptor();
wss4jSecurityInterceptor.setSecurementActions("Timestamp UsernameToken");
wss4jSecurityInterceptor.setSecurementUsername("admin");
wss4jSecurityInterceptor.setSecurementPassword("secret");
return wss4jSecurityInterceptor;
}
private static final Logger log = LoggerFactory.getLogger(CountryClient.class);
public GetCountryResponse getCountry(String country) {
GetCountryRequest request = new GetCountryRequest();
request.setName(country);
log.info("Requesting location for " + country);
ClientInterceptor[] interceptors = new ClientInterceptor[] {
new GlobalInterceptor()
};
getWebServiceTemplate().setInterceptors(interceptors);
GetCountryResponse response = (GetCountryResponse) getWebServiceTemplate()
.marshalSendAndReceive("http://localhost:8080/ws/countries", request,
new SoapActionCallback(
"http://spring.io/guides/gs-producing-web-service/GetCountryRequest"));
return response;
}
}
如果是要SSL双向认证的建议在@Configuration中进行配置
@Configuration
public class SoapConfig {
private static final Resource KEYSTORE_LOCATION = new ClassPathResource("client.jks");
private static final String KEYSTORE_PASSWORD = "cccccc";
private static final String KEY_ALIAS = "client";
@Bean
Jaxb2Marshaller marshaller(){
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("com.example.myData");
return marshaller;
}
@Bean
KeyStoreFactoryBean keyStore(){
KeyStoreFactoryBean factoryBean = new KeyStoreFactoryBean();
factoryBean.setLocation(KEYSTORE_LOCATION);
factoryBean.setPassword(KEYSTORE_PASSWORD);
return factoryBean;
}
@Bean
TrustManagersFactoryBean trustManagers(KeyStoreFactoryBean keyStore){
TrustManagersFactoryBean factoryBean = new TrustManagersFactoryBean();
factoryBean.setKeyStore(keyStore.getObject());
return factoryBean;
}
@Bean
HttpsUrlConnectionMessageSender messageSender(
KeyStoreFactoryBean keyStore,
TrustManagersFactoryBean trustManagers
) throws Exception{
HttpsUrlConnectionMessageSender sender = new HttpsUrlConnectionMessageSender();
KeyManagersFactoryBean keyManagersFactoryBean = new KeyManagersFactoryBean();
keyManagersFactoryBean.setKeyStore(keyStore.getObject());
keyManagersFactoryBean.setPassword(KEYSTORE_PASSWORD);
keyManagersFactoryBean.afterPropertiesSet();
sender.setKeyManagers(keyManagersFactoryBean.getObject());
sender.setTrustManagers(trustManagers.getObject());
return sender;
}
@Bean
CryptoFactoryBean cryptoFactoryBean() throws IOException{
CryptoFactoryBean cryptoFactoryBean = new CryptoFactoryBean();
cryptoFactoryBean.setKeyStoreLocation(KEYSTORE_LOCATION);
cryptoFactoryBean.setKeyStorePassword(KEYSTORE_PASSWORD);
return cryptoFactoryBean;
}
@Bean
Wss4jSecurityInterceptor securityInterceptor(CryptoFactoryBean cryptoFactoryBean) throws Exception {
Wss4jSecurityInterceptor securityInterceptor = new Wss4jSecurityInterceptor();
securityInterceptor.setSecurementActions("Signature");
securityInterceptor.setSecurementUsername(KEY_ALIAS);
securityInterceptor.setSecurementPassword(KEYSTORE_PASSWORD);
securityInterceptor.setSecurementSignatureKeyIdentifier("DirectReference");
securityInterceptor.setSecurementSignatureAlgorithm(WSS4JConstants.RSA_SHA1);
securityInterceptor.setSecurementSignatureDigestAlgorithm(WSS4JConstants.SHA1);
securityInterceptor.setSecurementSignatureCrypto(cryptoFactoryBean.getObject());
return securityInterceptor;
}
@Bean
MyDataClient myDataClient(
Jaxb2Marshaller marshaller,
HttpsUrlConnectionMessageSender messageSender,
Wss4jSecurityInterceptor securityInterceptor
){
MyDataClient myDataClient = new MyDataClient();
myDataClient.setInterceptors(new ClientInterceptor[]{securityInterceptor, new GlobalInterceptor()});
myDataClient.setMessageSender(messageSender);
myDataClient.setMarshaller(marshaller);
myDataClient.setUnmarshaller(marshaller);
return myDataClient;
}
@Bean
MyUserClient myUserClient(
Jaxb2Marshaller marshaller,
HttpsUrlConnectionMessageSender messageSender,
Wss4jSecurityInterceptor securityInterceptor
){
MyUserClient myUserClient = new MyUserClient();
myUserClient.setInterceptors(new ClientInterceptor[]{securityInterceptor});
myUserClient.setMessageSender(messageSender);
myUserClient.setMarshaller(marshaller);
myUserClient.setUnmarshaller(marshaller);
return myUserClient;
}
}
其中Client有2个!
一个是MyDataClient.java
public class MyDataClient extends WebServiceGatewaySupport {
public GetMyDataResponse getMyDataResponse(Integer id){
GetMyDataRequest request = new GetMyDataRequest();
request.setId(id);
return (GetMyDataResponse) getWebServiceTemplate().marshalSendAndReceive("https://localhost:8080/ws/myData", request);
}
}
一个是MyUserClient.java
public class MyUserClient extends WebServiceGatewaySupport {
public GetUserResponse getUserResponse(String usrName, String password){
GetUserRequest request = new GetUserRequest();
request.setName(usrName);
request.setPassword(password);
return (GetUserResponse) getWebServiceTemplate().marshalSendAndReceive("https://localhost:8080/ws/myData", request);
}
}
下面是关于与在拦截器中对每次发送添加一个头:
@Override
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
HttpLoggingUtils.logMessage("Client Request Message start", messageContext.getRequest());
SoapMessage soapMessage = (SoapMessage) messageContext.getRequest();
SoapHeaderElement soapHeaderElement = soapMessage.getSoapHeader().addHeaderElement(SessionID_QNAME);
soapHeaderElement.setText("12345678");
HttpLoggingUtils.logMessage("Client Request Message end", messageContext.getRequest());
return true;
}
首先将messageContext.getRequest()转成SoapMessage。
随后getSoapHeader()获取头,再addHeaderElement()添加头部这里需要QName。
目前我这边是这么填写QName的:
public final QName SessionID_QNAME = new QName("http://xml.example.com/ws/session", "sessionID");
如果要里面填写值,addHeaderElement()后返回一个SoapHeaderElement,只需要调用其setText()即可。
下面是如何打印那些数据,这里我用了工具类:
@Override
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
HttpLoggingUtils.logMessage("Client Request Message start", messageContext.getRequest());
....
....
....
....
HttpLoggingUtils.logMessage("Client Request Message end", messageContext.getRequest());
return true;
}
其中代码如下:
public class HttpLoggingUtils extends TransformerObjectSupport {
private static final Logger LOGGER = LoggerFactory.getLogger(HttpLoggingUtils.class);
private static final String NEW_LINE = System.getProperty("line.separator");
private HttpLoggingUtils() {}
public static void logMessage(String id, WebServiceMessage webServiceMessage) {
try {
ByteArrayTransportOutputStream byteArrayTransportOutputStream =
new ByteArrayTransportOutputStream();
webServiceMessage.writeTo(byteArrayTransportOutputStream);
String httpMessage = new String(byteArrayTransportOutputStream.toByteArray());
LOGGER.info(NEW_LINE + "----------------------------" + NEW_LINE + id + NEW_LINE
+ "----------------------------" + NEW_LINE + httpMessage + NEW_LINE);
} catch (Exception e) {
LOGGER.error("Unable to log HTTP message.", e);
}
}
}
这里的ByteArrayTransportOutputStream为:
public class ByteArrayTransportOutputStream extends TransportOutputStream {
private static final String NEW_LINE = System.getProperty("line.separator");
private ByteArrayOutputStream byteArrayOutputStream;
@Override
public void addHeader(String name, String value) throws IOException {
createOutputStream();
String header = name + ": " + value + NEW_LINE;
byteArrayOutputStream.write(header.getBytes());
}
@Override
protected OutputStream createOutputStream() throws IOException {
if (byteArrayOutputStream == null) {
byteArrayOutputStream = new ByteArrayOutputStream();
}
return byteArrayOutputStream;
}
public byte[] toByteArray() {
return byteArrayOutputStream.toByteArray();
}
}
下面是服务端的拦截器。
构造服务端连接器要实现EndpointInterceptor类
@Component
public class GlobalEndpointInterceptor implements EndpointInterceptor {
private static final Log LOG = LogFactory.getLog(GlobalEndpointInterceptor.class);
@Override
public boolean handleRequest(MessageContext messageContext, Object o) throws Exception {
LOG.info("GlobalEndpointInterceptor handleRequest");
System.out.println("GlobalEndpointInterceptor handleRequest");
return true;
}
@Override
public boolean handleResponse(MessageContext messageContext, Object o) throws Exception {
LOG.info("GlobalEndpointInterceptor handleResponse");
System.out.println("GlobalEndpointInterceptor handleResponse");
return true;
}
@Override
public boolean handleFault(MessageContext messageContext, Object o) throws Exception {
LOG.info("GlobalEndpointInterceptor handleFault");
System.out.println("GlobalEndpointInterceptor handleFault");
return true;
}
@Override
public void afterCompletion(MessageContext messageContext, Object o, Exception e) throws Exception {
LOG.info("GlobalEndpointInterceptor afterCompletion");
System.out.println("GlobalEndpointInterceptor afterCompletion");
}
}
在config中配置即可
@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
@Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, "/ws/*");
}
@Bean(name = "countries")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("CountriesPort");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setTargetNamespace("http://it1995.com/example/demo");
wsdl11Definition.setSchema(countriesSchema);
return wsdl11Definition;
}
@Bean
public XsdSchema countriesSchema() {
return new SimpleXsdSchema(new ClassPathResource("countries.xsd"));
}
@Override
public void addInterceptors(List interceptors) {
interceptors.add(new GlobalEndpointInterceptor());
}
}
下面提下,如何在拦截器中获取客户端发来的头
这里给出一个例子:
@Override
public boolean handleRequest(MessageContext messageContext, Object o) throws Exception {
SoapMessage soapMessage = (SoapMessage) messageContext.getRequest();
......
......
......
......
......
SoapHeader soapHeader = soapMessage.getSoapHeader();
Iterator qn = soapHeader.examineAllHeaderElements();
while (qn.hasNext()) {
SoapElement elem = qn.next();
QName name = elem.getName();
String localPart = name.getLocalPart();
if(localPart.equals("userToken")){
String text = ((SoapHeaderElement) elem).getText();
......
......
......
......
}
}
throw new Exception("无UserToken");
}