资讯专栏INFORMATION COLUMN

实现一个spring webservice服务端三:实现一个有复杂返回值的spring-ws服务

xinhaip / 3021人阅读

摘要:,将类或枚举类型映射到模式类型,控制字段或属性的序列化。表示将自动绑定类中的每个非静态的非瞬态的由标注字段到。,对于数组或集合即包含多个元素的成员变量,生成一个包装该数组或集合的元素称为包装器。

在经过前面两篇文章的学习,我已经能够熟练创建一个正常运行的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 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 , respectively. It also builds a portType, binding, and service based on the operations.

谷歌翻译成中文是:

DefaultWsdl11Definition(因此,标记)通过使用约定从XSD模式构建WSDL。
它迭代在模式中找到的所有元素元素,并为所有元素创建一条消息。 接下来,它为所有以定义的请求或响应后缀结尾的消息创建WSDL操作。
默认请求后缀为Request; 默认响应后缀为Response,但可以通过在/>上分别设置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相关的配置,算是有了比较直观充分地了解。

这是我的最终修改的项目,发布出来的的路径,测试wsdl链接。

源码,我放到码云上了,路径为:https://git.oschina.net/thewa...,有需要的可以下载下来看看。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70165.html

相关文章

  • 实现一个spring webservice服务端四:服务端、客户端以及httpclient调用spr

    摘要:执行结果如下中华田园犬测试我认为所有使用协议的,都能使用测试。下面是我写的测试代码旺财需要增加一个包测试结果返回值如下中华田园犬写法稍微有点麻烦的是,需要拼接请求参数,参数少的话还好,多的话就很烦不过这种方法不用生成一大堆客户端代码。 经过前段时间的学习,已经实现一个有返回值的spring-ws服务,那接下来,就要试试能不能通过不同方式的调用,要实现一下几种方式的测试: spring...

    oneasp 评论0 收藏0
  • 实现一个spring webservice服务端二:创建一个可以访问的webservice

    摘要:把上一篇文章生成的文件另存为,放到下面,没有改,文件也没有修改,只有配置文件改成了下面这个样子按照文档说明,此时访问就可以访问了。 在文章中,我学习了spring-ws基本的知识,在文章最后我也实现一个简单的项目,访问可以看到wsdl文件,但是我也遇到了一个问题,无法通过soap UI的测试,经过这一段业余时间的学习,这个问题解决。 这是上一个学习创建的项目的demo演示链接,打开可以...

    Arno 评论0 收藏0
  • Java系统WebServiceSpring与CXF的集成

    摘要:我们再使用这样的来查看这个服务具体的定义这个用以通过查看服务也就是我们开头所说的用通用格式来描述的功能入参和返回值,使我们的调用者明白服务的使用方法具体详情可以查看我们的这个服务的页面。 WebService是什么呢?顾名思义,是Web系统提供的服务,其目的呢,往大了说:是系统实现多异构模块协同合作,服务实现SOA(Services oriented Architecture面向服务的...

    waterc 评论0 收藏0
  • spring boot开发soap webservice

    摘要:本文介绍如何在中开发接口,以及接口如何同时支持和两种协议。该功能很简单,就是通过一个人的姓名查询这个人的详细信息。就是关键,如本次请求报文如下就是,对应。测试使用进行测试,通过地址导入文件进行测试。测试这样就实现了和同时提供的目的。 介绍spring boot web模块提供了RestController实现restful,第一次看到这个名字的时候以为还有SoapController,...

    Ashin 评论0 收藏0
  • Java 远程通讯技术及原理分析

    摘要:对于与而言,则可以看做是消息传递技术的一种衍生或封装。在生产者通知消费者时,传递的往往是消息或事件,而非生产者自身。通过消息路由,我们可以配置路由规则指定消息传递的路径,以及指定具体的消费者消费对应的生产者。采用和来进行远程对象的通讯。 消息模式 归根结底,企业应用系统就是对数据的处理,而对于一个拥有多个子系统的企业应用系统而言,它的基础支撑无疑就是对消息的处理。与对象不同,消息本质上...

    rozbo 评论0 收藏0

发表评论

0条评论

xinhaip

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<