博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
实现一个spring webservice服务端三:实现一个有复杂返回值的spring-ws服务
阅读量:6967 次
发布时间:2019-06-27

本文共 8121 字,大约阅读时间需要 27 分钟。

在经过前面两篇文章的学习,我已经能够熟练创建一个正常运行的spring-ws的webservice服务,大多数接口,都是要有返回数据,所以这篇文章就是学习spring-ws怎么实现返回数据

实现一个常规的返回数据

一个接口返回的数据一般都是对象,那就看看怎么返回一个对象数据。

首先,还是要看spring-ws文档的,在参考文档,在这一节中,开始就提出了,要使用@ResponsePayload注解,实现返回数据。支持类型如下:

支持类型

从上面表格可以看出,spring-ws的得demo中,使用的是jdom类型的,先不管其它类型,在此基础上,实现一个返回值,

修改代码:

加上注解

@PayloadRoot(namespace = NAMESPACE_URI, localPart = "HolidayRequest")    @ResponsePayload    public Dog handleHolidayRequest(@RequestPayload Element holidayRequest) throws Exception {            System.out.println("请求进来了");                Date startDate = parseDate(startDateExpression, holidayRequest);        Date endDate = parseDate(endDateExpression, holidayRequest);        String name = firstNameExpression.evaluateFirst(holidayRequest).getText() + " " + lastNameExpression.evaluateFirst(holidayRequest).getText();                humanResourceService.bookHoliday(startDate, endDate, name);                Dog dog = new Dog("中华田园犬", 5);                return dog;    }

第一个返回类:

public class Dog {    private String name;    private Integer age;        public Dog (String name, Integer age) {        this.name = name;        this.age = age;    }        public String getName () {        return name;    }        public void setName (String name) {        this.name = name;    }        public Integer getAge () {        return age;    }        public void setAge (Integer age) {        this.age = age;    }

启动测试,soap ui 测试结果:

SOAP-ENV:Server
No adapter for endpoint [public com.nyl.learn.hr.model.Dog com.nyl.learn.hr.ws.HolidayEndpoint.handleHolidayRequest(org.jdom2.Element) throws java.lang.Exception]: Is your endpoint annotated with @Endpoint, or does it implement a supported interface like MessageHandler or PayloadEndpoint?

后台输出结果:

六月 19, 2017 6:08:13 下午 org.springframework.ws.transport.http.MessageDispatcherServlet initServletBean信息: FrameworkServlet 'spring-ws': initialization completed in 502 ms

没有输出信息,可以看出请求根本没有进来

从错误信息,可以看到适配到返回值为Dog的端点,这么说来,肯定是我配错了。

可是spring-ws的参考文档上也没说需要给Dog加注解或者实现某个类。

重新打开新生成wsdl文件,发现是这样的:

wsdl:portType name="HumanResource">

也就是说,spring-ws会查找名字为Holiday参数为HolidayRequest,返回值为void的方法,所以找不到我写的,可是按理说,我既然写返回值了,为什么生成还没有返回值的port。

我突然想到,上面写的那个返回值支持类型,我写的dog好像不是表格中任何一种类型,因为我只对jaxb2有点印象,所以就按照jaxb2类型修改,修改如下:

@XmlAccessorType(XmlAccessType.FIELD)@XmlRootElement(name = "dog")public class Dog {        private String name;    private Integer age;        public Dog () {    }        public Dog (String name, Integer age) {        this.name = name;        this.age = age;    }        public String getName () {        return name;    }        public void setName (String name) {        this.name = name;    }        public Integer getAge () {        return age;    }        public void setAge (Integer age) {        this.age = age;    }}

相比前面,多了两个注释和一个空构造方法,先不解释,看一下测试结果:

中华田园犬
5

总而言之,现在得到返回值了。

因为我用的是jdk自带的jaxb2,所以不需要增加额外的jar包就可以使用,这个jar包提供了一下几个注释用于xml和对象的转化,我从网上找了一段感觉非常不错的说明:

JAXBContext类,是应用的入口,用于管理XML/Java绑定信息。Marshaller接口,将Java对象序列化为XML数据。Unmarshaller接口,将XML数据反序列化为Java对象。 @XmlType,将Java类或枚举类型映射到XML模式类型@XmlAccessorType(XmlAccessType.FIELD) ,控制字段或属性的序列化。FIELD表示JAXB将自动绑定Java类中的每个非静态的(static)、非瞬态的(由@XmlTransient标 注)字段到XML。其他值还有XmlAccessType.PROPERTY和XmlAccessType.NONE。@XmlAccessorOrder,控制JAXB 绑定类中属性和字段的排序。@XmlJavaTypeAdapter,使用定制的适配器(即扩展抽象类XmlAdapter并覆盖marshal()和unmarshal()方法),以序列化Java类为XML。@XmlElementWrapper ,对于数组或集合(即包含多个元素的成员变量),生成一个包装该数组或集合的XML元素(称为包装器)。@XmlRootElement,将Java类或枚举类型映射到XML元素。@XmlElement,将Java类的一个属性映射到与属性同名的一个XML元素。@XmlAttribute,将Java类的一个属性映射到与属性同名的一个XML属性。

原文是个博客,地址为,有兴趣的可以看看。

此时,再次查看生成的wsdl文件,发现并不是我想象中的样子:

···
···

soap UI 测试都返回数据了,为什么wsdl文件上却没有返回值,不知道该搜索什么,只好去看spring-ws的参考文档,最终在找到了答案:

The DefaultWsdl11Definition (and therefore, the <dynamic-wsdl> tag) builds a WSDL from a XSD schema by using conventions. It iterates over all element elements found in the schema, and creates a message for all elements. Next, it creates WSDL operation for all messages that end with the defined request or response suffix. The default request suffix is Request; the default response suffix is Response, though these can be changed by setting the requestSuffix and responseSuffix attributes on <dynamic-wsdl />, respectively. It also builds a portType, binding, and service based on the operations.

谷歌翻译成中文是:

DefaultWsdl11Definition(因此,<dynamic-wsdl>标记)通过使用约定从XSD模式构建WSDL。

它迭代在模式中找到的所有元素元素,并为所有元素创建一条消息。 接下来,它为所有以定义的请求或响应后缀结尾的消息创建WSDL操作。
默认请求后缀为Request; 默认响应后缀为Response,但可以通过在<dynamic-wsdl
/>上分别设置requestSuffix和responseSuffix属性来更改。 它还基于操作构建portType,绑定和服务。

也就是说,只有带有指定的后缀,才能正确的生成wsdl文件,那么再改一下代码,如下:

1、把Dog类改成DogResponse

@XmlAccessorType(XmlAccessType.FIELD)@XmlRootElement(name = "DogResponse")@XmlType(name = "", propOrder = {        "name","age"})public class DogResponse {        @XmlElement(required = true)    protected String name;        protected Integer age;                public String getName () {        return name;    }        public void setName (String name) {        this.name = name;    }        public Integer getAge () {        return age;    }        public void setAge (Integer age) {        this.age = age;    }}

2、xsd修改

3、现在的HolidayEndpoint是这样的:

@PayloadRoot(namespace = NAMESPACE_URI, localPart = "holidayRequest")    @ResponsePayload    public DogResponse handleHolidayRequest(@RequestPayload HolidayRequest holidayRequest) throws Exception {            System.out.println("请求进来了");                DogResponse dogResponse = new DogResponse();        dogResponse.setName("中华田园犬");        dogResponse.setAge(5);                return dogResponse;    }

重启测试,新生成的wsdl结果如下:

soap ui 测试结果仍然是对的,生成的wsdl仍然是错的;

继续修改,把DogResponse,改成HolidayResponse,修改后,重新测试,结果如下:

终于生成的是正确的wsdl文件了,现在我把HolidayRequest和HolidayResponse都改成DogRequest和DogResponse,再测试一下,结果如下:

可以看出,请求和返回的名字是有要求的,两个名字前面要一样,后缀分别是固定的配置,默认为Request和Response;

把名字改回HolidayRequest和HolidayResponse, 现在生成wsdl没有错误了,那继续测试soap ui。

但是很不幸是,soap ui测试无法通过了,因为生成的service是这样的:

测试时,认为我的访问路径是/holidayService/,这样肯定是无法访问的,因为这个location是相对路径,需要动态转化为真实路径,需要在web.xml中配置下面的init内容,如下:

spring-ws
org.springframework.ws.transport.http.MessageDispatcherServlet
transformWsdlLocations
true

应该是我改代码的时候,误删了。加回来继续测试,测试请求如下:

旺财

返回的信息是:

SOAP-ENV:Server
意外的元素 (uri:"http://mycompany.com/hr/webservice", local:"holidayRequest")。所需元素为<{}holidayRequest>

明显可以看出报错了,百度了一下,看到有人说,要在请求参数上,所有的请求参数的元素加上namespace,于是改成下面这个样子:

@XmlAccessorType(XmlAccessType.FIELD)@XmlType(name = "", propOrder = {        "name"})@XmlRootElement(name = "holidayRequest", namespace = "http://mycompany.com/hr/webservice")public class HolidayRequest {        @XmlElement(namespace = "http://mycompany.com/hr/webservice")    protected String name;        public String getName () {        return name;    }        public void setName (String name) {        this.name = name;    }}

重新测试,结果如下:

中华田园犬
5

总结

刚开始觉得挺简单的,下载下来spring-ws的demo,非常顺利的运行起来了,可是自己搞一遍的时候,错误百出,网上搜索的话,大多是求解决方法的,很少有提出有用的解决方案的,在上面,我把自己的解决过程写了出来,希望对和我一样刚开始学这个东西的朋友有点帮助。

总得来讲,经过这一段闲暇时间的学习对webservice相关的概念,对spring-ws相关的配置,算是有了比较直观充分地了解。

这是我的最终修改的项目,发布出来的的路径,。

源码,我放到码云上了,路径为:,有需要的可以下载下来看看。

转载地址:http://mtbsl.baihongyu.com/

你可能感兴趣的文章
VirtualBox6.0中CentOS7.6 网络配置
查看>>
Windows下MySQL安装
查看>>
Apache Falcon数据集管理和数据处理平台
查看>>
React Native 项目简单整理-组件优化
查看>>
Quartz2.2.1开发问题
查看>>
Win8 快捷键
查看>>
ORACLE11G 将dataguard的rman备份恢复到测试环境的单机oracle中的详细过程
查看>>
import static和import的区别
查看>>
从MyEclipse到IntelliJ IDEA ——让你脱键盘,全键盘操作
查看>>
Python-字典
查看>>
Android Studio ndk-Jni开发详细
查看>>
我的网站搭建 (第十七天) celery 定时刷新缓存
查看>>
dubbo的provider和consumer的demo
查看>>
倒计时效果
查看>>
杨辉三角(C++)
查看>>
前端框架
查看>>
在linux上配置JDK环境变量
查看>>
Maven学习(六):灵活的构建
查看>>
对Linux Kernel 4.15的支持的VirtualBox 5.2.8发布
查看>>
Eclipse快捷键 10个最有用的快捷键
查看>>