【问题标题】:Spring Web-Service unmarshalling not workingSpring Web-Service 解组不起作用
【发布时间】:2011-10-17 07:22:28
【问题描述】:

我已经像这样配置了我的 WebService:

应用上下文:

<sws:annotation-driven />    
 <bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping" >
<property name="interceptors">
 <list>
    <bean class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor"/>
</list>
</property>

注意:拦截器在启动时加载,但如果有请求进来,则不会写入任何内容。

我有一个带有方法 addPersonRequest() 的 PersonServiceImpl 类。一切正常,如果我使用 org.dom4j.Element 作为方法参数;

@Endpoint
public class PersonServiceImpl {
     @PayloadRoot(namespace = "http://www.example.org/person/schema", localPart = "AddPersonRequest")
     @ResponsePayload
       public AddPersonRequest addPersonRequest(@RequestPayload Element element) {
        System.out.println(element.asXML());
        Person response = new Person();
        response.setId(2);
        response.setFirstName("Mad");
        response.setLastName("Mike");
        return response;
     }
}

但是,如果我更改我的方法参数,如下所示(因此应该使用 spring-ws 的自动编组),request.getFirstName() 将打印 null。 (JAXB2 在类路径上)。

Person 类使用@XMLType 和@XMLRootElement 进行注释。

注意:编组工作正常。

@Endpoint
public class PersonServiceImpl {
     @PayloadRoot(namespace = "http://www.example.org/person/schema", localPart = "AddPersonRequest")
     @ResponsePayload
       public AddPersonRequest addPersonRequest(@RequestPayload Person request, SoapHeader header) {
        System.out.println(header.getName());
        System.out.println(request.getFirstName());
        Person response = new Person();
        response.setId(2);
        response.setFirstName("Mad");
        response.setLastName("Mike");
        return response;
     }
}

Person.java:

@XmlType
@XmlRootElement(namespace="http://www.example.org/person/schema", name="Person")
public class Person implements Serializable {

    private int id;
    private String firstName;
    private String lastName;

    @XmlElement
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    @XmlElement
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    @XmlAttribute
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
}

通过soapUI 发送的测试请求(从wsdl 生成):

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sch="http://www.example.org/person/schema"> 
<soapenv:Header/>
<soapenv:Body>

  <sch:AddPersonRequest>

     <sch:Person sch:Id="1">

        <sch:FirstName>firstname</sch:FirstName>

        <sch:LastName>lastname</sch:LastName>

     </sch:Person>

  </sch:AddPersonRequest>

</soapenv:Body>
</soapenv:Envelope>

【问题讨论】:

  • 你有日志拦截器吗?
  • 不,我没有让它工作。在春季教程教程之后,我更改了我的 applicationContext 中的 Bean-Definition。(在原始帖子中所做的更改)。但是我的 Spring-WS 的 Logging-Level 设置为 TRACE,它告诉我:o.s.w.s.e.a.m.j.XmlRootElementPayloadMethodProcessor - Unmarshalled payload request to [mypackages.AddPersonRequest@a1557b],所以一切似乎都正常......
  • 玩了一会儿之后,我得到了一个新异常:javax.xml.bind.UnmarshalException:意外元素(uri:“example.org/person/schema”,本地:“AddPersonRequest”)。预期的元素是 example.org/person/schema}Person> 也许有一个命名空间或本地部分问题,我没有看到?!

标签: web-services spring spring-ws


【解决方案1】:

阅读您的最新评论,我不确定您是否还需要答案。我对您的请求和响应有效负载有点困惑。他们似乎被交换了。无论如何,如果没有 Person 类,这很难说。

虽然我之前处理过类似的问题,但通过在实际类周围添加 JAXBElement 解决了这些问题。像这个sn-p:

@PayloadRoot(
    localPart = "PutOrganisationUnitRequest", 
    namespace = DEFAULT_NAMESPACE
)
@ResponsePayload public JAXBElement<Response> putOrganisationUnits (
    @RequestPayload JAXBElement<PutOrganisationUnitRequest> organisations,
    MessageContext messageContext) {

您可以检查的另一件事是 jaxb 类和端点定义中的命名空间。

【讨论】:

  • 仍然需要一个答案 :) 你到底对什么感到困惑?注释似乎是对的?!我将通过添加人员类来更新我的问题。我已经尝试在我的班级周围使用 JAXBElement,但没有成功。 XML-File 中的命名空间等于 java-classes 中映射的命名空间。
  • 我对响应和请求有效负载感到困惑。我想你想收到一个 AddPersonRequest 并用一个人回应。如果这是真的,您可能希望在方法签名中切换它们。 (特别是因为您在昨天的评论中说“解组器似乎试图将 解析为 Person-Object”。
【解决方案2】:

您提到编组正在工作我看不出解组不起作用的任何原因,您是否在隔离中测试了 marshall 和 unmarshall?

只是为了确保soap请求是好的,你可以添加日志拦截器并打印来自客户端访问Web服务的实际请求,将此sn-p添加到你的上下文文件中

  <sws:interceptors>
    <bean class="org.springframework.ws.soap.server.endpoint.interceptor.SoapEnvelopeLoggingInterceptor">
        <property name="logRequest" value="true"></property>
        <property name="logResponse" value="true"></property>
    </bean>
</sws:interceptors>

您应该会看到这样的日志消息,其中包含整个soap 请求,我正在将来自saop UI 的日志消息请求添加到

   DEBUG [http-8080-2]:endpoint.interceptor.SoapEnvelopeLoggingInterceptor.logMessage - Request:
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sch="http://hoost:port/context/patient/schemas">
      <soapenv:Header/>
         <soapenv:Body>
            <sch:addRequest>
              <sch:patient>
                  <sch:id>?</sch:id>
                     <sch:lastname>Joe</sch:lastname>
                </sch:patient>
             </sch:addRequest>
        </soapenv:Body>
      </soapenv:Envelope>

答案更新

这可能是你的肥皂请求不确定

        <sch:FirstName>firstname</sch:FirstName> (this should be)

        <sch:firstName>firstname</sch:firstName>

另一个更新

例外是由于您定义端点的方式,在您的soap请求(sch:AddPersonRequest)中,您发送的是addPersonRequest而不是Person作为有效负载,因此请更改端点以反映这一点, @RequestPayload 应该是 AddPersonRequest 而不是 Person

     @PayloadRoot(namespace = "http://www.example.org/person/schema", localPart = "AddPersonRequest")
     @ResponsePayload
      public AddPersonRequest addPersonRequest(@RequestPayload AddPersonRequest request, SoapHeader header) {

【讨论】:

  • 我激活了 LoggingInterceptor。它准确记录了我通过soapUI发送的请求(我用测试请求更新了问题)。
  • 请阅读我对原始问题的最后评论。我得到一个解组异常。似乎解组器尝试将 解析为 Person-Object。也许我没有理解命名空间/本地部分的想法?!
  • @Lodger,迟到了...但是好的,是的,Unmarshaller 无法将有效负载映射到 java bean。将 @XmlRootElement(name="Person") 更改为 @XmlRootElement(name="AddPersonRequest")
【解决方案3】:

这个 Spring webservice 实现完全是垃圾。一个脑残的白痴可以比那些“专业人士”做得更好。

仅仅遵循 JSON 原则并按照提供的根类型恢复对象树是多么困难。

没有人需要这些命名空间。永远不会发生相同的请求有两个具有相同名称但来自不同名称空间的元素。但是这些命名空间是无尽的痛苦。

只需将 XML 元素与对象字段匹配即可。这只是需要的。如果有人在检索结束时关心它们,则在生成响应时从 WSDL 分配命名空间,但在解组请求时完全忽略它们。

当我看到所有这些时,我真的很想花一个月时间做一个带有 XML 序列化/反序列化的 NORMAL SOAP Web 服务框架,只要 XML 树匹配对象,它只关心元素名称和自动实例化请求/响应对象树。

【讨论】:

  • 我同意 Soap 协议很混乱,但 Spring 只是简单地实现了它的规则。您对“普通soap web 服务框架”的定义根本不尊重soap 协议,您将无法向其他尊重soap 标准的应用程序发送有效请求。
猜你喜欢
  • 2018-01-27
  • 2013-02-03
  • 2014-08-14
  • 2016-09-13
  • 2012-10-28
  • 2016-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多