Java의 SOAPMessage에서 원시 XML 가져 오기


79

JAX-WS에서 SOAP WebServiceProvider를 설정했지만 SOAPMessage (또는 모든 노드) 개체에서 원시 XML을 가져 오는 방법을 파악하는 데 문제가 있습니다. 다음은 내가 지금 가지고있는 코드 샘플과 XML을 가져 오려는 위치입니다.

@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?
    }
}

원래 요청의 XML을 얻는 간단한 방법이 있습니까? 다른 유형의 공급자 (예 : 소스)를 설정하여 원시 XML을 얻는 방법이 있다면 저도 그렇게 할 것입니다.

답변:


152

이런 식으로 시도 할 수 있습니다.

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

4
이것은 문자 인코딩을 고려하지 않습니다
artbristol 2013

DOM 객체를 생성하는 것과 같은 일로 많은 메모리를 소비합니까? 아니면 내부적으로 xml을 구문 분석하지 않고 HTTP 응답에서 원시 문자열을 실제로 제공합니까?
Ruslan

22

당신이있는 경우 SOAPMessage또는 SOAPMessageContext, 당신은을 사용할 수 있습니다 TransformerA를 변환하여, Source경유 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());

이것은 인코딩을 고려하므로 "특수 문자"가 엉망이되지 않습니다.


제공된 솔루션은 메모리를 많이 사용합니까?
lospejos

12

다음과 같이 Provider <Source>를 사용하여 원시 XML을 가져올 수 있습니다.

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

이 솔루션이 필요하지 않게되었으므로 실제로이 코드를 직접 시도하지 않았습니다. 제대로 작동하려면 약간의 조정이 필요할 수 있습니다. 그러나 이것이 웹 서비스에서 원시 XML을 가져 오는 올바른 경로라는 것을 알고 있습니다.

(SOAPMessage 객체가 반드시 있어야하는 경우 어떻게 작동하는지 모르겠지만, 어쨌든 원시 XML을 처리하려는 경우 왜 더 높은 수준의 객체를 사용합니까?)


A StringWriterByteArrayOutputStream+ StreamResult조합에 대한 좋은 대안입니다 . XML을 String올바른 인코딩 으로 사용하려는 경우
artbristol

12

디버깅 목적으로 한 줄 코드를 사용하십시오.

msg.writeTo(System.out);


OP는 반드시 System.out으로 디버깅하는 것은 아닙니다 (웹 서버에서 편리하게 액세스 할 수있는 것은 아닙니다). 소켓을 통해 원본 XML을 보내거나 어딘가에 저장하거나 통계를 계산해야 할 수도 있습니다.
nanofarad 2014 년

당신은 쉽게 쓸 수 ByteArrayOutputStream로 변환 String... 나에게 쉬운 것
vikingsteve

7

xml 문자열을 xml로 형식화해야하는 경우 다음을 시도하십시오.

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")));

이 서식을 지정하기 위해 공백과 탭 중에서 선택할 수 있습니까? BTW, 탭이 표시되지 않는다는 것을 알고 있습니다.
Philippe Gioseffi

7

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

이것은 작동한다

 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();

설명이 필요하지 않습니다.
Martin Kersten

0

클라이언트 코드가있는 경우 다음 두 줄을 추가하여 XML 요청 / 응답을 가져 오면됩니다. 여기 _call있습니다org.apache.axis.client.Call

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

0

꽤 오래된 스레드이지만 최근에 비슷한 문제가 발생했습니다. 나머지 서비스에서 다운 스트림 SOAP 서비스를 호출하고 있었고 다운 스트림 서버에서 오는 xml 응답을 그대로 반환해야했습니다.

그래서 XML 응답을 얻기 위해 SoapMessageContext 핸들러를 추가했습니다. 그런 다음 응답 xml을 서블릿 컨텍스트에 속성으로 삽입했습니다.

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

그런 다음 서비스 계층에서 xml 응답 문자열을 검색했습니다.

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

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

아직 테스트 할 기회가 없었지만이 접근 방식은 서블릿 컨텍스트를 사용하기 때문에 스레드로부터 안전해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.