Spring 使用JAXB在RestController中接受SOAP消息

Spring 使用JAXB在RestController中接受SOAP消息,spring,soap,jaxb,Spring,Soap,Jaxb,我们创建了一个springboot@RestController,它将使用SOAP接受XML请求,但我无法让它工作 示例消息: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap

我们创建了一个springboot@RestController,它将使用SOAP接受XML请求,但我无法让它工作

示例消息:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
    <PostPayload xmlns="http://mynamespace/">
      <Message>
        <Header type="Main" version="1.0" desc="Some header description...">
          <Title content="The quick brown fox." />
        </Header>
        <Content />
        <Footer type="Copyright" name="Footer01">Some random content...</Footer>
      </Message>
    </PostPayload>
  </soap:Body>
</soap:Envelope>
消息类

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Message")
public class Message {
   @XmlElement(name = "Header", required = true)
   private Header header;

   @XmlElement(name = "Content", required = true)
   private Content content;

   @XmlElement(name = "Footer", required = true)
   private Footer footer;

   // Getters and setters here...

   @Override
   public String toString() {
      // In here, I outputted the values of the header and footer.
   }
}
标题类

@XmlRootElement(name = "Header")
@XmlAccessorType(XmlAccessType.FIELD)
public class Header {
    @XmlAttribute(name = "type", required = true)
    private String type;

    @XmlAttribute(name = "version", required = true)
    private String version;

    @XmlAttribute(name = "desc", required = true)
    private String description;

    // Getters and setters here...
}
内容类

@XmlRootElement(name = "Content")
@XmlAccessorType(XmlAccessType.FIELD)
public class Content {
}
页脚类

@XmlRootElement(name = "Footer")
@XmlAccessorType(XmlAccessType.FIELD)
public class Footer {
    @XmlValue
    private String value;

    @XmlAttribute(name = "name")
    private String name;

    @XmlAttribute(name = "type")
    private String type;

    //Getter and setters here...
}

因此,如果我将soap消息发送到rest服务,它将返回null。rest控制器中的封送器只是检查输出是否与请求相同,这意味着我正确读取了XML。不幸的是,它返回null。有什么想法吗?

您不需要用Jaxb序列化请求,因为SpringREST控制器会自动执行此操作。作为函数中的参数的消息类必须是include PostPayload,并且在xml中具有名称空间()。 restcontroller正在检查标题中的内容类型并自动进行转换

此帖子包含更多信息:

工作示例:

package com.mkysoft.restxml.contoller;

import com.mkysoft.restxml.domain.*;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

@RestController
@RequestMapping("rest-service")
public class MessageController {

    @PostMapping(consumes = MediaType.APPLICATION_XML_VALUE)
    public String handler(@RequestBody Envelope envelope) {
        System.out.println(envelope);
        System.out.println("\n\n\n");

        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(Envelope.class);
            Marshaller marshaller = jaxbContext.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.marshal(envelope, System.out);
        } catch (JAXBException ex) {
            System.out.println(ex.toString());
        }

        return "Done!";
    }

    @GetMapping()
    public Envelope gethandler() {
        final Envelope envelope = new Envelope();
        final Message message = new Message();
        final Header header = new Header();
        header.setType("type");
        header.setDescription("description");
        header.setVersion("version");
        message.setHeader(header);
        message.setContent(new Content());
        message.setFooter(new Footer());
        final Body body = new Body();
        final PostPayload postPayload = new PostPayload();
        postPayload.setMessage(message);
        //body.setPostPayload(postPayload);
        envelope.setBody(body);
        return envelope;
    }

}
Envelope.java

package com.mkysoft.restxml.domain;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Envelope", namespace = "http://schemas.xmlsoap.org/soap/envelope/")
public class Envelope {

    @XmlElement(name = "Body", required = true, namespace = "http://schemas.xmlsoap.org/soap/envelope/")
    private Body body;

    public Body getBody() {
        return body;
    }

    public void setBody(Body body) {
        this.body = body;
    }

}
Body.java

package com.mkysoft.restxml.domain;

import com.sun.xml.internal.txw2.annotation.XmlNamespace;
import org.apache.cxf.jaxrs.ext.xml.XMLName;

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Body", namespace = "http://schemas.xmlsoap.org/soap/envelope/")
public class Body {

    @XmlElement(name = "PostPayload", required = true, namespace = "http://mynamespace/")
    private PostPayload postPayload;

    public PostPayload getPostPayload() {
        return postPayload;
    }

    public void setPostPayload(PostPayload postPayload) {
        this.postPayload = postPayload;
    }
}
PostPayload.java

package com.mkysoft.restxml.domain;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "PostPayload", namespace = "http://mynamespace/")
public class PostPayload {

    @XmlElement(name = "Message", required = true, namespace = "http://mynamespace/")
    private Message message;

    public Message getMessage() {
        return message;
    }

    public void setMessage(Message message) {
        this.message = message;
    }
}
Message.java

package com.mkysoft.restxml.domain;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Message", namespace = "http://mynamespace/")
public class Message {
    @XmlElement(name = "Header", required = true, namespace = "http://mynamespace/")
    private Header header;

    @XmlElement(name = "Content", required = true, namespace = "http://mynamespace/")
    private Content content;

    @XmlElement(name = "Footer", required = true, namespace = "http://mynamespace/")
    private Footer footer;

    public Header getHeader() {
        return header;
    }

    public void setHeader(Header header) {
        this.header = header;
    }

    public Content getContent() {
        return content;
    }

    public void setContent(Content content) {
        this.content = content;
    }

    public Footer getFooter() {
        return footer;
    }

    public void setFooter(Footer footer) {
        this.footer = footer;
    }

    @Override
    public String toString() {
        // In here, I outputted the values of the header and footer.
        return null;
    }
}
Header.java

package com.mkysoft.restxml.domain;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "Header", namespace = "http://mynamespace/")
@XmlAccessorType(XmlAccessType.FIELD)
public class Header {
    @XmlAttribute(name = "type", required = true)
    private String type;

    @XmlAttribute(name = "version", required = true)
    private String version;

    @XmlAttribute(name = "desc", required = true)
    private String description;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}
Footer.java

package com.mkysoft.restxml.domain;

import javax.xml.bind.annotation.*;

@XmlRootElement(name = "Footer", namespace = "http://mynamespace/")
@XmlAccessorType(XmlAccessType.FIELD)
public class Footer {
    @XmlValue
    private String value;

    @XmlAttribute(name = "name")
    private String name;

    @XmlAttribute(name = "type")
    private String type;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
}
Content.java

package com.mkysoft.restxml.domain;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "Content", namespace = "http://mynamespace/")
@XmlAccessorType(XmlAccessType.FIELD)
public class Content {
}

谢谢mkysoft。我知道Spring默认使用JAXB,RestController中的封送器只是为了检查它是否正确读取XML,但它只是返回null。我已经更新了帖子以反映消息类和子类。你的类没有名称空间属性,PostPayload必须是root。谢谢你mkysoft!谢谢你的帮助。现在,当放置正确的对象映射和名称空间时,它就可以工作了。最后一件事,我注意到它没有得到页脚文本的值,即“一些随机内容…”,即使我放置@XmlValue。您需要所有类的名称空间,我更新了我的答案。我为所有类添加了答案中定义的名称空间,但是,我仍然没有得到页脚文本。这是我从marshaller.marshall(信封,系统,输出)得到的输出;:
package com.mkysoft.restxml.domain;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "Content", namespace = "http://mynamespace/")
@XmlAccessorType(XmlAccessType.FIELD)
public class Content {
}