逆向工程:如何在后端生成SOAP Request XML?

时间:2018-08-28 04:30:37

标签: java xml soap jax-ws java-ee-7

我有以下课程:

WS界面:

package com.mypackage;

import javax.ejb.Remote;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;

@Remote
@SOAPBinding(style = Style.DOCUMENT)
@WebService(name = "MathService", targetNamespace = "http://mypackage.com/")
public interface MathServiceWS {

    @WebResult(name = "result", targetNamespace = "http://mypackage.com/")
    @RequestWrapper(localName = "addRequest", className = "AddRequest", targetNamespace = "http://mypackage.com/")
    @WebMethod(action = "http://mypackage.com/add", operationName = "add")
    @ResponseWrapper(localName = "addResponse", className = "AddResponse", targetNamespace = "http://mypackage.com/")
    Long add(@WebParam(name = "add", targetNamespace = "http://mypackage.com/") AddBean add);
}

WS实施:

package com.mypackage;

import javax.ejb.Stateless;
import javax.jws.WebService;

@Stateless(mappedName = "MathService")
@WebService(serviceName = "MathService", endpointInterface = "com.mypackage.MathServiceWS", portName = "MathServicePort", targetNamespace = "http://mypackage.com/")
public class MathService implements MathServiceWS {

    @Override
    public Long add(AddBean add) {
        Long first = new Long(add.getFirst().intValue());
        Long second = new Long(add.getSecond().intValue());
        return Long.valueOf(Math.addExact(first.longValue(), second.longValue()));
    }
}

豆:

package com.mypackage;

import java.io.Serializable;

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

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(
    name = "Add",
    namespace = "http://mypackage.com/",
    propOrder = {
        "first",
        "second"
    }
)
public class AddBean implements Serializable {

    private static final long serialVersionUID = -7727938355039425419L;

    @XmlElement(required = true)
    private Integer first;

    @XmlElement(required = true)
    private Integer second;

    public AddBean() {

    }

    public Integer getFirst() {
        return first;
    }

    public void setFirst(Integer first) {
        this.first = first;
    }

    public Integer getSecond() {
        return second;
    }

    public void setSecond(Integer second) {
        this.second = second;
    }
}

部署此WS后,当我在SoapUI中添加WSDL时,在提供用户输入后,添加方法请求如下:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:myp="http://mypackage.com/">
   <soapenv:Header/>
   <soapenv:Body>
      <myp:addRequest>
         <myp:add>
            <first>1</first>
            <second>2</second>
         </myp:add>
      </myp:addRequest>
   </soapenv:Body>
</soapenv:Envelope>

现在,我想在com.mypackage.MathService.add(AddBean)方法中使用给定的用户输入来使用上述SOAP请求XML。

  • com.mypackage.AddBean上使用JAXB只会生成部分请求
  • WebService处理程序对于满足我的要求没有用

任何指针都将非常有帮助。

2 个答案:

答案 0 :(得分:2)

您可以创建一个自定义SOAPHandler对象,并可以读取请求有效负载并将其通过自定义属性设置为SOAPMessageContext。确保将范围设置为应用程序。

在服务类中,使用javax.xml.ws.WebServiceContext注入@javax.annotation.Resource并通过您的自定义属性访问有效载荷集。

例如:
1。创建处理程序并注册。

public class PopulateSOAPMessagePayloadHandler implements SOAPHandler<SOAPMessageContext> {
    public static final String SOAP_MESSAGE_PAYLOAD = "__soap_message_payload";

    @Override
    public boolean handleMessage(SOAPMessageContext smc) {
        Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (!outboundProperty.booleanValue()) {
            // for incoming:
            ByteArrayOutputStream bout = new ByteArrayOutputStream(1024);
            try {
                smc.getMessage().writeTo(bout);
                String payload = bout.toString(StandardCharsets.UTF_8.name());

                smc.put(SOAP_MESSAGE_PAYLOAD, payload);  //Set payload
                smc.setScope(SOAP_MESSAGE_PAYLOAD, MessageContext.Scope.APPLICATION);  //make it application scope

            } catch (SOAPException | IOException e) {
                e.printStackTrace();
                // handle exception if needed
                throw new WebServiceException(e);
            }

        }
        return true;
    }
 // Other method (no-op) omitted 
}


2。获取有效载荷

public class MathService implements MathServiceWS {
    @Resource
    private WebServiceContext context;

    @Override
    public Long add(AddBean add) {
        String payload = (String) context.getMessageContext().get(SOAP_MESSAGE_PAYLOAD);

        Long first = new Long(add.getFirst().intValue());
        Long second = new Long(add.getSecond().intValue());
        return Long.valueOf(Math.addExact(first.longValue(), second.longValue()));
    }
}

希望有帮助。

答案 1 :(得分:0)

您可以轻松地完全控制文档。首先让我们设置bean:

@XmlRootElement(name="addRequest")
@XmlAccessorType(XmlAccessType.FIELD) //Probably you don't need this line. it is by default field accessible. 
public class AddBean implements Serializable {

private static final long serialVersionUID = -7727938355039425419L;

@XmlElement(name="first",required = true) //you don't need name attribute as field is already exactly the same as soap element
private Integer first;

@XmlElement(name="second",required = true) //you don't need name attribute as field is already exactly the same as soap element
private Integer second;

public AddBean() { }
//Getters and Setters
}

现在,我认为这是您要寻找的部分。添加自定义名称空间声明并设置前缀等。如果使用org.springframework.ws.client.core.support.WebServiceGatewaySupport.getWebServiceTemplate发出SOAP请求,则可以执行以下操作:

public class WSCastorClient extends WebServiceGatewaySupport {

public CustomResponseObject callWebService(Addbean add) {
WebServiceTemplate wst = getWebServiceTemplate();
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.afterPropertiesSet();
wst.setMarshaller(marshaller);
wst.setUnmarshaller(marshaller);
wst.afterPropertiesSet();
CustomResponseObject response = (CustomResponseObject) 
wst.marshallSendAndReceive(add, new 
WebServiceMessageCallback() {

    public void doWithMessage(WebServiceMessage message) { 
        SaajSoapMessage saajSoapMessage = (SaajSoapMessage) message;
        SOAPMesage soapMEssage = saajSoapMessage.getSaajMessage();
        SOAPPart soapPart = soapMessage.getSOAPPart();
        SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
        SOAPHeader head = soapMessage.getSOAPHeader();
        SOAPBody soapBody = soapMessage.getSOAPBody();
        //Now you have full control of the soap header, body, envelope. You can add any namespace declaration, prefix, add header element, etc. You can add remove whatever you want. 
        soapEnvelope.removeNamespaceDeclaration(soapEnvelope.getPrefix()); //clear whatever namespace is there
        soapEnvelope.addNamespaceDeclaration("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");
        soapEnvelope.addNamespaceDeclaration("myp", "http://mypackage.com/");
        soapEnvelope.setPrefix("soapenv");
        soapHeader.setPrefix("soapenv");
        soapBody.setPrefix("soapenv");

        Document doc = saajSoapMessage.getDocument();
        StringWriter sw = new StringWriter();

        Transformer transformer  = TransformerFactory.newInstance().newTransformer();
        transformer.transform(new DOMSource(doc), new StreamResult(sw));
    }       
    });
return response;
}
//close off other brackets if I forgot any.