经过前段时间的学习,已经实现一个有返回值的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有一定了解了,再来看这个问题。
客户端测试源码在这里
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。