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

140 篇文章 4 订阅
21 篇文章 3 订阅

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

这里要实现的效果

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

下面要介绍如下的东西,如何在拦截器中打印这些东西,其次是在拦截器中添加一个head

 

对应的Maven

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.16.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>wsdl4j</groupId>
            <artifactId>wsdl4j</artifactId>
            <version>1.6.1</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.ws</groupId>
            <artifactId>spring-ws-core</artifactId>
            <version>3.0.8.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.ws</groupId>
            <artifactId>spring-ws-security</artifactId>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

        <dependency>
            <groupId>org.apache.ws.security</groupId>
            <artifactId>wss4j</artifactId>
            <version>1.6.19</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

            <plugin>
                <groupId>org.jvnet.jaxb2.maven2</groupId>
                <artifactId>maven-jaxb2-plugin</artifactId>
                <version>0.14.0</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <schemaLanguage>WSDL</schemaLanguage>
                    <generatePackage>com.example.demo.wsdl</generatePackage>
                    <schemas>
                        <schema>
                            <url>http://127.0.0.1:8080/ws/countries.wsdl</url>
                        </schema>
                    </schemas>
                </configuration>
            </plugin>

        </plugins>
    </build>

</project>

在客户端中连接器要实现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<EndpointInterceptor> 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<SoapHeaderElement> 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");
    }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT1995

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值