【问题标题】:Modify response of web service with JAX-WS使用 JAX-WS 修改 Web 服务的响应
【发布时间】:2013-01-03 14:13:56
【问题描述】:

我怎样才能像这样修改响应的命名空间:

旧响应:

<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 命名空间前缀。

【问题讨论】:

  • 请对我的任务有任何回应?

标签: web-services soap jax-ws


【解决方案1】:

在第一种情况下,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 的东西。但请注意,在消息上线之前更改消息并非易事。

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      这是一个非常古老的问题,仍然没有得到有效的回答。本周我遇到了一个非常相似的问题。我的应用程序正在调用由遗留系统提供的 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
      

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

      【讨论】:

        猜你喜欢
        • 2023-04-10
        • 2010-10-16
        • 1970-01-01
        • 2023-03-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-09
        • 1970-01-01
        相关资源
        最近更新 更多