使用JAX-WS修改Web服务的响应

时间:2013-01-03 14:13:56

标签: web-services soap jax-ws

如何修改响应的命名空间,如下所示:

老回复:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <ns2:GetAmountResponse xmlns:ns2="http://ws.dsi.otn.com/dab">
         <etat>0</etat>
         <montant>500.0</montant>
      </ns2:GetAmountResponse>
   </soap:Body>
</soap:Envelope>

需要新的回复:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <GetAmountResponse xmlns="http://ws.dsi.otn.com/dab">
         <etat>0</etat>
         <montant>500.0</montant>
      </GetAmountResponse>
   </soap:Body>
</soap:Envelope>

我想删除ns2 namespce前缀。

3 个答案:

答案 0 :(得分:3)

在第一种情况下,GetAmountResponse位于名称空间http://ws.dsi.otn.com/dab中,而etatmontant位于默认(空)名称空间中。

在您想要的新邮件中,GetAmountResponseetatmontant都在名称空间http://ws.dsi.otn.com/dab中。

可以从类的名称空间控制名称空间。在所有名称空间中使用相同的名称空间,您将在同一名称空间中使用它们,使用默认值保留类,并且它们默认为空名称空间。

例如,如果您在Web服务类中有类似的内容:

@WebMethod
    public 
    @WebResult(name = "getAmountResponse", targetNamespace = "http://ws.dsi.otn.com/dab")
    AmountResponse getAmount(
            @WebParam(name = "getAmountRequest", targetNamespace = "http://ws.dsi.otn.com/dab") AmountRequest request) {

        AmountResponse response = new AmountResponse();
        response.setEtat(0);
        response.setMontant(500.0);

        return response;
    }

有这样的响应类:

@XmlRootElement
public class AmountResponse {
    private int etat;
    private double montant;
    // getter and setters omitted
}

你将得到第一种肥皂信息。

但是如果你将响应类更改为这样:

@XmlRootElement(namespace = "http://ws.dsi.otn.com/dab")
@XmlAccessorType(XmlAccessType.NONE)
public class AmountResponse {

    @XmlElement(namespace = "http://ws.dsi.otn.com/dab")
    private int etat;

    @XmlElement(namespace = "http://ws.dsi.otn.com/dab")
    private double montant;

    // getters and setter omitted
}

您将把所有标记放在同一个命名空间中,并获得与您想要的新类型消息等效的内容。我之所以说相当,是因为我认为你不会得到这个:

<GetAmountResponse xmlns="http://ws.dsi.otn.com/dab">
     <etat>0</etat>
     <montant>500.0</montant>
</GetAmountResponse>

更有可能得到这样的东西:

<ns2:getAmountResponse xmlns:ns2="http://ws.dsi.otn.com/dab">
     <ns2:etat>0</ns2:etat>
     <ns2:montant>500.0</ns2:montant>
</ns2:getAmountResponse>

这两个消息的“XML含义”相同,尽管它们看起来不一样。

如果你绝对希望它看起来像这样,我认为你必须“低级别”并使用a SOAP handler to intercept the response and modify it之类的东西。但请注意,在消息传输之前更改消息并不是一项微不足道的任务。

答案 1 :(得分:0)

逻辑处理程序足以按预期转换为消息:

package com.ouertani.slim;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.LogicalMessage;
import javax.xml.ws.handler.LogicalHandler;
import javax.xml.ws.handler.LogicalMessageContext;
import javax.xml.ws.handler.MessageContext;

/**
 *
 * @author ouertani
 */
public class MyLogicalHandler implements LogicalHandler<LogicalMessageContext> {

    @Override
    public boolean handleMessage(LogicalMessageContext messageContext) {
        /// extract state and amount
        int state = 0;
        double amount = 200.0;
        transform(messageContext, state, amount);
        return false;
    }

    public boolean handleFault(LogicalMessageContext messageContext) {
        return true;
    }

    public void close(MessageContext context) {
    }
    private void transform( LogicalMessageContext messageContext, int etat, double montant){
            LogicalMessage msg = messageContext.getMessage();

        String htom = "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"+
   "<soap:Body>"+
      "<GetAmountResponse xmlns=\"http://ws.dsi.otn.com/dab\">"+
         "<etat>"+etat+"</etat>"+
         "<montant>"+montant+"</montant>"+
      "</GetAmountResponse>"+
   "</soap:Body>"+
"</soap:Envelope>";
        InputStream is = new ByteArrayInputStream(htom.getBytes());
        Source ht = new StreamSource(is);
        msg.setPayload(ht);
    }
}

答案 2 :(得分:0)

这是一个非常古老的问题,仍然有待有效回答。本周我遇到了一个非常相似的问题。我的应用程序正在调用由遗留系统提供的 Soap Web 服务,该系统的 XML 响应语法错误,在 XML 声明之前有一些空字符(换行符、制表符或空格)。在我的场景中,我无法更改遗留系统以修复其响应,因此在解析之前更改响应是我唯一的选择。

这是我的解决方案:

我已将以下 maven 依赖项添加到我的应用程序中:


<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.0</version>
</dependency>

<dependency>
    <groupId>javax.xml.ws</groupId>
    <artifactId>jaxws-api</artifactId>
    <version>2.3.0</version>
</dependency>

<dependency>
    <groupId>com.sun.xml.ws</groupId>
    <artifactId>jaxws-rt</artifactId>
    <version>2.3.0</version>
</dependency>

然后我注册了一个“com.oracle.webservices.impl.internalspi.encoding.StreamDecoder”的Java SPI自定义实现。此类在 XML 解析之前立即调用,并带有相应的响应 InputStream,因此此时您可以读取响应 InputStream 或包装/代理它并对 jax 进行任何更改-ws 解析前的响应。就我而言,我只是在第一个可见字符之前删除了一些不可见字符。

我的 StreamDecoder SPI 实现:

package sample.streamdecoder;


import com.oracle.webservices.impl.encoding.StreamDecoderImpl;
import com.oracle.webservices.impl.internalspi.encoding.StreamDecoder;
import com.sun.xml.ws.api.SOAPVersion;
import com.sun.xml.ws.api.message.AttachmentSet;
import com.sun.xml.ws.api.message.Message;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;

public class MyStreamDecoder implements StreamDecoder {

    //JAX-WS default implementation
    private static final StreamDecoderImpl streamDecoder = new StreamDecoderImpl();


    @Override
    public Message decode(InputStream inputStream, String charset, AttachmentSet attachmentSet, SOAPVersion soapVersion) throws IOException {
        //Wrapping inputStream
        InputStream wrapped = wrapInputStreamStrippingBlankCharactersBeforeXML(inputStream, charset);
        //Delegating further processing to default StreamDecoder
        return streamDecoder.decode(wrapped, charset, attachmentSet, soapVersion);
    }
    
    private InputStream wrapInputStreamStrippingBlankCharactersBeforeXML(InputStream inputStream, String charset) throws IOException {
        int WHITESPACE = (int) Charset.forName(charset).encode(" ").get();
        int LINE_BREAK = (int) Charset.forName(charset).encode("\n").get();
        int TAB        = (int) Charset.forName(charset).encode("\t").get();
        return new InputStream() {
            private boolean xmlBegin = true;

            @Override
            public int read() throws IOException {
                int read = inputStream.read();
                if (!xmlBegin) {
                    return read;
                } else {
                    while (WHITESPACE == read
                            || LINE_BREAK == read
                            || TAB == read) {
                        read = inputStream.read();
                    }
                    xmlBegin = false;
                }
                return read;
            }
        };
    }

}


为了注册它,只需创建一个名为“”的文件“META-INF/services/com.oracle.webservices.impl.internalspi.encoding.StreamDecoder”并在第一个写上你的SPI实现的全限定名像这样的行:

文件内容META-INF/services/com.oracle.webservices.impl.internalspi.encoding.StreamDecoder

sample.streamdecoder.MyStreamDecoder

现在每个响应都会在解析之前传递给您的实现。