Abrufen von Raw-XML aus SOAPMessage in Java


79

Ich habe einen SOAP WebServiceProvider in JAX-WS eingerichtet, aber ich habe Probleme herauszufinden, wie das unformatierte XML von einem SOAPMessage-Objekt (oder einem beliebigen Knotenobjekt) abgerufen werden kann. Hier ist ein Beispiel des Codes, den ich gerade habe, und wo ich versuche, das XML abzurufen:

@WebServiceProvider(wsdlLocation="SoapService.wsdl")
@ServiceMode(value=Service.Mode.MESSAGE)
public class SoapProvider implements Provider<SOAPMessage>
{
    public SOAPMessage invoke(SOAPMessage msg)
    {
        // How do I get the raw XML here?
    }
}

Gibt es eine einfache Möglichkeit, das XML der ursprünglichen Anforderung abzurufen? Wenn es eine Möglichkeit gibt, das unformatierte XML durch Einrichten eines anderen Anbietertyps (z. B. Quelle) zu erhalten, wäre ich auch dazu bereit.

Antworten:


152

Sie könnten es auf diese Weise versuchen.

SOAPMessage msg = messageContext.getMessage();
ByteArrayOutputStream out = new ByteArrayOutputStream();
msg.writeTo(out);
String strMsg = new String(out.toByteArray());

4
Dies berücksichtigt nicht die Zeichenkodierung
Artbristol

Verbraucht es viel Speicher mit so etwas wie dem Erstellen von DOM-Objekten oder ähnlichem? Oder wird es wirklich die Rohzeichenfolge aus der HTTP-Antwort geben, ohne die XML intern zu analysieren?
Ruslan

21

Wenn Sie ein SOAPMessageoder haben SOAPMessageContext, können Sie ein verwenden Transformer, indem Sie es in ein SourceVia konvertieren DOMSource:

            final SOAPMessage message = messageContext.getMessage();
            final StringWriter sw = new StringWriter();

            try {
                TransformerFactory.newInstance().newTransformer().transform(
                    new DOMSource(message.getSOAPPart()),
                    new StreamResult(sw));
            } catch (TransformerException e) {
                throw new RuntimeException(e);
            }

            // Now you have the XML as a String:
            System.out.println(sw.toString());

Dadurch wird die Codierung berücksichtigt, sodass Ihre "Sonderzeichen" nicht entstellt werden.


Ist die Bereitstellung lösungsspeicherintensiv?
Lospejos

12

Es stellt sich heraus, dass man das unformatierte XML mithilfe von Provider <Quelle> auf folgende Weise erhalten kann:

import java.io.ByteArrayOutputStream;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.ws.Provider;
import javax.xml.ws.Service;
import javax.xml.ws.ServiceMode;
import javax.xml.ws.WebServiceProvider;

@ServiceMode(value=Service.Mode.PAYLOAD)
@WebServiceProvider()
public class SoapProvider implements Provider<Source>
{
    public Source invoke(Source msg)
    {
        StreamResult sr = new StreamResult();

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        sr.setOutputStream(out);

        try {
            Transformer trans = TransformerFactory.newInstance().newTransformer();
            trans.transform(msg, sr);

            // Use out to your heart's desire.
        }
        catch (TransformerException e) {
            e.printStackTrace();
        }    

        return msg;
    }
}

Ich brauchte diese Lösung letztendlich nicht, also habe ich diesen Code nicht selbst ausprobiert - es könnte einige Anpassungen erfordern, um richtig zu werden. Ich weiß jedoch, dass dies der richtige Weg ist, um das unformatierte XML von einem Webdienst abzurufen.

(Ich bin mir nicht sicher, wie ich das machen soll, wenn Sie unbedingt ein SOAPMessage-Objekt haben müssen, aber wenn Sie das rohe XML sowieso verarbeiten wollen, warum sollten Sie ein übergeordnetes Objekt verwenden?)


A StringWriterist eine gute Alternative zur ByteArrayOutputStream+ StreamResult-Kombination, wenn Sie das XML als Stringmit der richtigen Codierung
wünschen

12

Verwenden Sie zum Debuggen nur einen Zeilencode -

msg.writeTo(System.out);


Das OP debuggt nicht unbedingt in System.out (was für einen Webserver nicht unbedingt bequem zugänglich ist) - möglicherweise muss er / sie das ursprüngliche XML über einen Socket senden, irgendwo speichern oder seine Statistiken berechnen.
Nanofarad

Sie können leicht an einen ByteArrayOutputStreamKonvertiten schreiben, um String... scheint mir einfach
vikingsteve

7

Wenn Sie die XML-Zeichenfolge in XML formatieren müssen, versuchen Sie Folgendes:

String xmlStr = "your-xml-string";
Source xmlInput = new StreamSource(new StringReader(xmlStr));
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
transformer.transform(xmlInput,
        new StreamResult(new FileOutputStream("response.xml")));

Ist es möglich, zwischen Leerzeichen und Tabulatoren zu wählen, um diese Formatierung durchzuführen? Übrigens, ich weiß, dass Registerkarten nicht angezeigt werden.
Philippe Gioseffi

7

Verwenden von Transformer Factory: -

public static String printSoapMessage(final SOAPMessage soapMessage) throws TransformerFactoryConfigurationError,
            TransformerConfigurationException, SOAPException, TransformerException
    {
        final TransformerFactory transformerFactory = TransformerFactory.newInstance();
        final Transformer transformer = transformerFactory.newTransformer();

        // Format it
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");

        final Source soapContent = soapMessage.getSOAPPart().getContent();

        final ByteArrayOutputStream streamOut = new ByteArrayOutputStream();
        final StreamResult result = new StreamResult(streamOut);
        transformer.transform(soapContent, result);

        return streamOut.toString();
    }

3

das funktioniert

 final StringWriter sw = new StringWriter();

try {
    TransformerFactory.newInstance().newTransformer().transform(
        new DOMSource(soapResponse.getSOAPPart()),
        new StreamResult(sw));
} catch (TransformerException e) {
    throw new RuntimeException(e);
}
System.out.println(sw.toString());
return sw.toString();

Keine Erklärung erforderlich.
Martin Kersten

0

Wenn Sie den Client-Code haben, müssen Sie nur die folgenden zwei Zeilen hinzufügen, um die XML-Anforderung / Antwort zu erhalten. Hier _callistorg.apache.axis.client.Call

String request = _call.getMessageContext().getRequestMessage().getSOAPPartAsString();
String response = _call.getMessageContext().getResponseMessage().getSOAPPartAsString();

0

Es ist ein ziemlich alter Thread, aber kürzlich hatte ich ein ähnliches Problem. Ich habe einen Downstream-Seifendienst von einem Rest-Service aus aufgerufen und musste die XML-Antwort vom Downstream-Server unverändert zurückgeben.

Also habe ich einen SoapMessageContext-Handler hinzugefügt, um die XML-Antwort zu erhalten. Dann habe ich die Antwort-XML als Attribut in den Servlet-Kontext eingefügt.

public boolean handleMessage(SOAPMessageContext context) {

            // Get xml response
            try {

                ServletContext servletContext =
                        ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getServletContext();

                SOAPMessage msg = context.getMessage();

                ByteArrayOutputStream out = new ByteArrayOutputStream();
                msg.writeTo(out);
                String strMsg = new String(out.toByteArray());

                servletContext.setAttribute("responseXml", strMsg);

                return true;
            } catch (Exception e) {
                return false;
            }
        }

Dann habe ich die XML-Antwortzeichenfolge in der Service-Schicht abgerufen.

ServletContext servletContext =
                ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getServletContext();

        String msg = (String) servletContext.getAttribute("responseXml");

Ich hatte noch keine Gelegenheit, es zu testen, aber dieser Ansatz muss threadsicher sein, da er den Servlet-Kontext verwendet.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.