经过前段时间的学习,已经实现一个有返回值的spring-ws服务,那接下来,就要试试能不能通过不同方式的调用,要实现一下几种方式的测试:

  • spring-ws服务端测试

  • spring-ws客户端测试

  • httpclient

spring-ws服务端测试

我对spring-test 和spring-ws-test,几乎没有什么了解,只好按照文档来写spring-ws服务端测试的,这是测试代码:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("spring-ws-servlet.xml")
public class WebserviceTest {
    
    @Autowired
    private ApplicationContext applicationContext;
    
    private MockWebServiceClient client;
    
    @Before
    public void createClient() {
        client = MockWebServiceClient.createClient(applicationContext);
    }
    
    
    @Test
    public void holidayTest() {
    
        Source requestPayload = new StringSource(
            
                "<holidayRequest xmlns='http://mycompany.com/hr/webservice'>" +
                    
                        "<name>旺财</name>" +
                    
                        "</holidayRequest>");
    
        Source responsePayload = new StringSource(
            
                "<holidayResponse xmlns='http://mycompany.com/hr/webservice'>" +
                        "<name>中华田园犬</name>" +
                        "<age>5</age>" +
                       "</holidayResponse>");
    
    
        client.sendRequest(RequestCreators.withPayload(requestPayload)).andExpect(ResponseMatchers
                .payload
                (responsePayload));
        
    }
}

需要添加jar包:

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.ws</groupId>
            <artifactId>spring-ws-test</artifactId>
            <version>2.4.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>4.2.7.RELEASE</version>
        </dependency>

执行测试方法,一直报下面这个错误:

failed to load applicationcontext

因为我没有配置日志,所以不知道具体错误是什么,只好又去配置log4j2,配置完之后,具体的错误信息可以看到了:

Caused by: java.io.FileNotFoundException: class path resource [spring-ws-servlet.xml] cannot be opened because it does not exist
    at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:172)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:330)
    ... 36 more

可以看到,是因为找不到配置文件【spring-ws-servlet.xml】,我找到了出错的代码:

public URL getResource(String name) {
        URL url;
        if (parent != null) {
            url = parent.getResource(name);
        } else {
            url = getBootstrapResource(name);
        }
        if (url == null) {
            url = findResource(name);
        }
        return url;
    }

name就是spring-ws-servlet.xml, parent就是Classloader,只是不知道为什么找不到;

我只好把路径修改为@ContextConfiguration("classpath:spring-ws-servlet.xml"),为了能够在classpath下找到这个文件,又把spring-ws-servlet.xml 和hr.xsd文件复制到src/main/resource下面,可能有人会疑惑为什么是复制过去一份,而不是把WEB-INF下的文件转移到src/main/resource下面,因为spring 的默认加载位置就是wWEB-INF下的文件,而我又没有找到读取classpath路径文件的配置,就是这个:

<servlet>
    <servlet-name>spring-ws</servlet-name>
    <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
    <init-param>
      <param-name>transformWsdlLocations</param-name>
      <param-value>true</param-value>
    </init-param>
  </servlet>

所以只好改成这样,虽然看着奇怪,但是不再报找不到文件的错误了。

改完之后,继续测试,可是又有报错了:

[different] Expected namespace URI 'http://mycompany.com/hr/webservice' but was 'null' - comparing <holidayResponse...> at /holidayResponse[1] to <holidayResponse...> at /holidayResponse[1]

Payload: <holidayResponse><name>中华田园犬</name><age>5</age></holidayResponse>

起初,以为是哪里错了,后来,认真看了下信息,才发现,报错是因为期望返回值中有xmlns='http://mycompany.com/hr/webse...',但是实际返回值是:

<holidayResponse><name>中华田园犬</name><age>5</age></holidayResponse>

和期望的值不一样,所以才报了这个错,把期望值修改了一下:

Source responsePayload = new StringSource(
            
                "<holidayResponse >" +
                        "<name>中华田园犬</name>" +
                        "<age>5</age>" +
                       "</holidayResponse>");

这样再测试,就不报错了。
至此,spring-ws服务端测试通过。

spring-ws客户端测试

spring-ws参考文档上关于服务端测试,给出了几种方式,有http、jms、eamil等,因为我的测试服务端是http的,所以就使用http的测试;

关于http测试webservice的方式,spring-ws首先给出的要求是要有消息工厂【messageFactory】,就像下面的配置一样:

<beans>

<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>

<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate"> <constructor-arg ref="messageFactory"/>

<property name="defaultUri" value="http://example.com/WebService"/> </bean>

</beans>

spring-ws提供了两种消息工厂,分别为:

  • SaajSoapMessageFactory ------saaj 支持多

  • AxiomSoapMessageFactory ------axis2 适合数据多

我参考文档写的测试代码是:

import org.junit.Test;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.xml.transform.StringSource;

import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

/**
 * Created by nyl
 * 2017/6/23
 */
public class SpringClient {
    
    private final WebServiceTemplate client = new WebServiceTemplate();
    
    
    @Test
    public void sptingTest() {
        
        client.setDefaultUri("http://www.ningyongli.site:8080/webservicelearn/holidayService");
    
        StreamSource source =  new StringSource(
        
                "<holidayRequest xmlns='http://mycompany.com/hr/webservice'>" +
                
                        "<name>旺财</name>" +
                
                        "</holidayRequest>");
    
        try {
            JAXBContext unmarshaller = JAXBContext.newInstance(HolidayResponse.class);
            JAXBResult jaxbResult = new JAXBResult(unmarshaller);
            
            //StreamResult result = new StreamResult(System.out);
            client.sendSourceAndReceiveToResult(source, jaxbResult);
            HolidayResponse holidayResponse = (HolidayResponse) jaxbResult.getResult();
            System.out.println(holidayResponse.toString());
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    
        
        
    }
    
}

代码中并没有设置messageFactory,于是我去看源码,发现:

public WebServiceTemplate() {
        initDefaultStrategies();
    }

    /**
     * Creates a new {@code WebServiceTemplate} based on the given message factory.
     *
     * @param messageFactory the message factory to use
     */
    public WebServiceTemplate(WebServiceMessageFactory messageFactory) {
        setMessageFactory(messageFactory);
        initDefaultStrategies();
    }

 还有···········

WebServiceTemplate 提供了很多中构造方法,无参构造方法会加载默认的配置(initDefaultStrategies),默认配置如下:

org.springframework.ws.client.core.FaultMessageResolver=org.springframework.ws.soap.client.core.SoapFaultMessageResolver
org.springframework.ws.WebServiceMessageFactory=org.springframework.ws.soap.saaj.SaajSoapMessageFactory
org.springframework.ws.transport.WebServiceMessageSender=org.springframework.ws.transport.http.HttpUrlConnectionMessageSender

也就是说,默认的就是SaajSoapMessageFactory这个,知道了,我就不管这个了。

WebServiceTemplate 有很多用于请求的方法
请求方法

我用的是这个sendSourceAndReceiveToResult(source, result),这些方法的参数请求参数顶级接口Source ,返回数据顶级接口Result,回调方法等;只要根据接口要求,实现子类,放进方法里执行即可。
执行结果如下:

HolidayResponse{ name=中华田园犬, age=5}

httpclient测试

我认为所有使用http协议的,都能使用httpclient测试。
我在学习spring-ws之前遇到了几次webservice的问题,其中一个让我印象深刻,第三方公司给我一个wsdl文件,我根据文件生成客户端代码,发现返回值是boolean类型的数据,但是他给我的soap ui测试截图上,返回的是一个复杂的对象,我以为我客户端代码生成错了,于是尝试了axis 、axis2 、cxf等jar包,生成的返回值都一样,于是我就去看wsdl文件(那时候基本上还看不懂),发现wsdl中返回值就是boolean类型,于是和对接人员沟通希望给出正确的wsdl文件,结果对方不认为wsdl有问题,反正soap ui 测通了,让我自己想办法。
于是就有了httpclient调用webservice的经历。

下面是我写的测试代码:

    @Test
    public void httpclientTest() {
        CloseableHttpClient closeableHttpClient = null;
        CloseableHttpResponse closeableHttpResponse = null;
        String  result = null;
        try {
            
            String requestStr = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" " +
                    "xmlns:web=\"http://mycompany.com/hr/webservice\">" +
                    "<soapenv:Header/>" +
                    "<soapenv:Body>"+
                    "<web:holidayRequest>" +
                    "<web:name>旺财</web:name>" +
                    "</web:holidayRequest>" +
                    "</soapenv:Body>" +
                    "</soapenv:Envelope>";
                
            HttpPost httpPost = new HttpPost("http://www.ningyongli.site:8080/webservicelearn/holidayService");
            httpPost.setHeader("Content-Type", "text/xml;charset=utf-8");
            //httpPost.setHeader("SOAPAction", "hollidayService");
    
            System.out.println(requestStr);
            StringEntity entity = new StringEntity(requestStr, "UTF-8");
            httpPost.setEntity(entity);
        
            closeableHttpClient = HttpClients.createDefault();
            closeableHttpResponse = closeableHttpClient.execute(httpPost);
            result = EntityUtils.toString(closeableHttpResponse.getEntity());
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                closeableHttpResponse.close();
                closeableHttpClient.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

需要增加一个jar包:

   <dependency>
      <groupId>org.apache.httpcomponents</groupId>
      <artifactId>httpclient</artifactId>
      <version>4.5.3</version>
    </dependency>

测试结果返回值如下:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Header/>
    <SOAP-ENV:Body>
        <holidayResponse>
            <name>中华田园犬</name>
            <age>5</age>
        </holidayResponse>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

写法稍微有点麻烦的是,需要拼接请求参数,参数少的话还好,多的话就很烦;不过这种方法不用生成一大堆客户端代码。

总结

总体而言,测试实现要比服务端实现要简单一些,基本都很快调通了。

本来还想用axis、axis2调用测试一下的,但是突然发现spring-ws生成的wsdl路径和它们要求的有点不一样,这两种要求路径都是这样的http://ip:port/name/servicena...,和我用spring-ws有点不一样,尝试了一下常用的调用方式都无法实现。以后对axis和axis2有一定了解了,再来看这个问题

客户端测试源码在这里


流浪的神明
226 声望9 粉丝