Spring Web Service 简明教程(二) —— 测试篇
程序员文章站
2022-03-17 16:53:46
...
其实这是一篇很水的文章,因为我并没有打算讲spring-ws-test包里提供的测试API,只是为了简单讲述一下client的API的使用而借用了junit,就像前一篇最后说的,实际使用webserviceTemplate时不会一次一次去new,而是依赖注入,所以,这篇就是例子。
在编写测试代码之前,首先做一点准备,首先我在我的项目架构里添加了这么些东西。高亮显示的test目录(好吧,高亮的下面一行)以下级别的东西。
我是使用maven来编写的,所以会有这样的结构,总之不管是什么样的目录结构,你都需要将这里的java目录和resources目录设置为classpath,在eclipse里是classpath,在intelliJ里设置为test sources和test resources。
注意: 图里看到的spring-ws-servlet.xml和user.xsd及存放路径并不是前文使用到的,这是拷贝过来,由于想将测试环境和开发环境的spring配置文件区分开,所以将这两个文件拷贝到test的resources目录下……好吧,其实是骗人的,因为直接使用开发环境(即/WEB-INF/)目录下的配置文件,请求发送时抛错了。。。。
额,题外话了,具体原因还得找时间深入源码去看,现在不管它。
首先修改下spring-ws-servlet.xml,当然,是用于测试的那个xml,正式的xml不需要改变。将
改为
添加一段配置,我们要将webserviceTemplate配置在spring里,也是同一个文件,但是这一段最好在正式的配置文件里也加上去,尽管我们现在是用不到:
说明 :还记得上一篇配置的marshaller吗,其实在上一篇中并没有作用,我们要在这里将它注入进WebServiceTemplate中,这样我们取到的template实例将能够使用转型+发送合二为一的方法marshalSendAndReceive()。在template中分别注入了由Object到XML的转换器marshaller,和由XML到Object的转换器unmarshaller,但是有趣的是两者是同一个bean,这是一个的简化之处。
然后,简单的测试代码:
说明:因为配置文件放在classpath目录下了,所以@ContextConfiguration("classpath:spring-ws-servlet.xml")这样就可以了。测试代码是上一篇文章最后的例子,但是因为有了依赖注入而简化了大量代码。应该比较好理解。
再来看一个使用基本的发送方法的例子 :
说明:请先直接看发送方法sendSourceAndReceiveToResult,它需要的参数是Source类型的requestPayload和Result类型的result,前者是发送的参数,后者是返回的结果。
区域#a是将User对象转换为Xml字符串, 区域#b是发送,区域#c是取到返回的结果,包括返回的值ret(true/false)以及填充后的sw变量,即返回的xml字符串。
再来看一种方法,使用场景比较少。
这里主要展示了WebServiceMessageCallback的简单使用。回调函数,顾名思义,请求发送返回后执行的方法。内部实现一个方法doWithMessage,参数message对我们而言感觉用处不大。这个方法最坑爹的是作为一个同步顺序执行的send方法,在回掉函数内实现的逻辑完全可以写在send之后吧…… 除非send是异步的...
还有另一种方法,是利用SourceExtractor这个参数,和callback类似的编码方式,也是自己实现方法的匿名内部类,不过实现方法中能取到的参数信息量比上面那种多,但是我没仔细研究过,就不列出来了。
好吧,这其实不是个严谨的单元测试篇章,所有的结果都是以sout的方式打印出来。而对于spring-ws-test包提供的更专业的sws单元测试API以后看心情再去研究吧。。。
源码同在上一篇提供的Github repo里,直接传送门:
https://github.com/chenzhouce/spring-webservice-demo/blob/master/src/test/java/ClientTest.java
在编写测试代码之前,首先做一点准备,首先我在我的项目架构里添加了这么些东西。高亮显示的test目录(好吧,高亮的下面一行)以下级别的东西。
我是使用maven来编写的,所以会有这样的结构,总之不管是什么样的目录结构,你都需要将这里的java目录和resources目录设置为classpath,在eclipse里是classpath,在intelliJ里设置为test sources和test resources。
注意: 图里看到的spring-ws-servlet.xml和user.xsd及存放路径并不是前文使用到的,这是拷贝过来,由于想将测试环境和开发环境的spring配置文件区分开,所以将这两个文件拷贝到test的resources目录下……好吧,其实是骗人的,因为直接使用开发环境(即/WEB-INF/)目录下的配置文件,请求发送时抛错了。。。。
Caused by: java.io.FileNotFoundException: class path resource [WEB-INF/spring-ws-servlet.xml] cannot be opened because it does not exist
Caused by: java.lang.IllegalArgumentException: xsd 'class path resource [WEB-INF/user.xsd]' does not exist
额,题外话了,具体原因还得找时间深入源码去看,现在不管它。
首先修改下spring-ws-servlet.xml,当然,是用于测试的那个xml,正式的xml不需要改变。将
<sws:xsd location="/WEB-INF/user.xsd" />
改为
<sws:xsd location="classpath:user.xsd" />
添加一段配置,我们要将webserviceTemplate配置在spring里,也是同一个文件,但是这一段最好在正式的配置文件里也加上去,尽管我们现在是用不到:
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate"> <property name="marshaller" ref="jaxbMarshallerBean"/> <property name="unmarshaller" ref="jaxbMarshallerBean"/> </bean>
说明 :还记得上一篇配置的marshaller吗,其实在上一篇中并没有作用,我们要在这里将它注入进WebServiceTemplate中,这样我们取到的template实例将能够使用转型+发送合二为一的方法marshalSendAndReceive()。在template中分别注入了由Object到XML的转换器marshaller,和由XML到Object的转换器unmarshaller,但是有趣的是两者是同一个bean,这是一个的简化之处。
然后,简单的测试代码:
import com.zchen.User; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.ws.WebServiceMessage; import org.springframework.ws.client.core.SourceExtractor; import org.springframework.ws.client.core.WebServiceMessageCallback; import org.springframework.ws.client.core.WebServiceMessageExtractor; import org.springframework.ws.client.core.WebServiceTemplate; import org.springframework.ws.support.MarshallingUtils; import org.springframework.xml.transform.StringSource; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; import javax.xml.transform.stream.StreamResult; import java.io.IOException; import java.io.StringWriter; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:spring-ws-servlet.xml") public class ClientTest { private String uri = "http://127.0.0.1:8080/userService/user.wsdl"; @Autowired private WebServiceTemplate webServiceTemplate; @Test public void testMarshalSend() throws Exception { User user = new User(1, "chenzhouce"); User returnUser =(User)webServiceTemplate.marshalSendAndReceive(uri, user); System.out.println(returnUser); } }
说明:因为配置文件放在classpath目录下了,所以@ContextConfiguration("classpath:spring-ws-servlet.xml")这样就可以了。测试代码是上一篇文章最后的例子,但是因为有了依赖注入而简化了大量代码。应该比较好理解。
再来看一个使用基本的发送方法的例子 :
@Test public void testSourceSend() throws Exception { User user = new User(1, "chenzhouce"); StringWriter prepareData = new StringWriter(); webServiceTemplate.getMarshaller().marshal(user, new StreamResult(prepareData)); String userString = prepareData.toString(); // #a Source requestPayload = new StringSource(userString); StringWriter sw = new StringWriter(); StreamResult result = new StreamResult(sw); boolean ret = webServiceTemplate.sendSourceAndReceiveToResult(uri, requestPayload, result); //#b System.out.println("Return :" + ret); System.out.println(sw); Source resultSource = new StringSource(sw.toString()); User user = (User) webServiceTemplate.getUnmarshaller() .unmarshal(resultSource); System.out.println(user); //#c }
说明:请先直接看发送方法sendSourceAndReceiveToResult,它需要的参数是Source类型的requestPayload和Result类型的result,前者是发送的参数,后者是返回的结果。
区域#a是将User对象转换为Xml字符串, 区域#b是发送,区域#c是取到返回的结果,包括返回的值ret(true/false)以及填充后的sw变量,即返回的xml字符串。
再来看一种方法,使用场景比较少。
@Test public void testSendCallback() throws Exception { User user = new User(1, "chenzhouce"); User returnUser = (User) webServiceTemplate .marshalSendAndReceive(uri, user, new WebServiceMessageCallback() { public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException { System.out.println(message); } }); System.out.println(returnUser); }
这里主要展示了WebServiceMessageCallback的简单使用。回调函数,顾名思义,请求发送返回后执行的方法。内部实现一个方法doWithMessage,参数message对我们而言感觉用处不大。这个方法最坑爹的是作为一个同步顺序执行的send方法,在回掉函数内实现的逻辑完全可以写在send之后吧…… 除非send是异步的...
还有另一种方法,是利用SourceExtractor这个参数,和callback类似的编码方式,也是自己实现方法的匿名内部类,不过实现方法中能取到的参数信息量比上面那种多,但是我没仔细研究过,就不列出来了。
好吧,这其实不是个严谨的单元测试篇章,所有的结果都是以sout的方式打印出来。而对于spring-ws-test包提供的更专业的sws单元测试API以后看心情再去研究吧。。。
源码同在上一篇提供的Github repo里,直接传送门:
https://github.com/chenzhouce/spring-webservice-demo/blob/master/src/test/java/ClientTest.java