Java笔记-springframework.ws中拦截器的使用(SOAP)

这里首先说下客户端拦截器。

这里要实现的效果

Java笔记-springframework.ws中拦截器的使用(SOAP)_第1张图片

这里的打印都是在拦截器中打印的!

下面要介绍如下的东西,如何在拦截器中打印这些东西,其次是在拦截器中添加一个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;
    }
}

Java笔记-springframework.ws中拦截器的使用(SOAP)_第2张图片

如果是要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");
    }

 

你可能感兴趣的:(webservice,Java,Spring,Boot,spring,webservice,java,spring,boot,interceptor)