Обратный инжиниринг: как создать XML-запрос SOAP в бэкэнде? - PullRequest
0 голосов
/ 28 августа 2018

У меня есть следующие классы:

Интерфейс 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, когда я добавляю WSDL в SoapUI, после добавления пользовательского ввода запрос метода add выглядит следующим образом:

<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>

Теперь я хочу, чтобы приведенный выше XML-запрос SOAP в моем методе com.mypackage.MathService.add(AddBean) с указанным пользовательским вводом.

  • Использование JAXB на com.mypackage.AddBean генерирует только частичный запрос
  • Обработчики WebService бесполезны для выполнения моего требования

Любой указатель был бы очень полезен.

Ответы [ 2 ]

0 голосов
/ 03 сентября 2018

Вы можете создать пользовательский объект 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()));
    }
}

Надеюсь, это поможет.

0 голосов
/ 31 августа 2018

Вы можете легко получить полный контроль над документом. Сначала давайте настроим компонент:

@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. 
...