Java 如何在客户端记录SOAP消息?

Java 如何在客户端记录SOAP消息?,java,jax-ws,soap-client,spring-ws,java-ws,Java,Jax Ws,Soap Client,Spring Ws,Java Ws,你好。我正在学习如何将连接器写入外部SOAPRCP样式的服务。我正在使用jaxws-maven插件从WSDL文件生成Java类。我正在使用Spring创建web服务客户端bean: @Configuration public class StoreServiceConfig { @Bean public StoreWS storeWS() throws IOException { JaxWsPortProxyFactoryBean factoryBean = n

你好。我正在学习如何将连接器写入外部SOAPRCP样式的服务。我正在使用jaxws-maven插件从WSDL文件生成Java类。我正在使用Spring创建web服务客户端bean:

@Configuration
public class StoreServiceConfig {

    @Bean
    public StoreWS storeWS() throws IOException {
        JaxWsPortProxyFactoryBean factoryBean = new JaxWsPortProxyFactoryBean();
        factoryBean.setServiceInterface(StoreWS.class);
        factoryBean.setWsdlDocumentUrl(new ClassPathResource("/wsdl/StoreWS.wsdl").getURL());
        factoryBean.setNamespaceUri("urn_store");
        factoryBean.setServiceName("StoreWSService");
        factoryBean.setEndpointAddress("https://10.34.45.82/storeservice/services/StoreWS");
        factoryBean.setUsername("testuser");
        factoryBean.setPassword("testpassword");
        factoryBean.afterPropertiesSet();
        return (StoreWS) factoryBean.getObject();
    }
}
@Configuration
public class StoreServiceConfig {

    @Autowired
    private LoggingHandler loggingHandler;

    @Bean
    public StoreWS storeWS() throws IOException {
        JaxWsPortProxyFactoryBean factoryBean = new JaxWsPortProxyFactoryBean();
        factoryBean.setServiceInterface(StoreWS.class);
        factoryBean.setWsdlDocumentUrl(new ClassPathResource("/wsdl/StoreWS.wsdl").getURL());
        factoryBean.setNamespaceUri("urn_store");
        factoryBean.setServiceName("StoreWSService");
        factoryBean.setEndpointAddress("https://10.34.45.82/storeservice/services/StoreWS");
        factoryBean.setUsername("testuser");
        factoryBean.setPassword("testpassword");

        factoryBean.setHandlerResolver(handlerResolver());

        factoryBean.afterPropertiesSet();
        return (StoreWS) factoryBean.getObject();
    }

    @Bean
    public HandlerResolver handlerResolver() {
        return new HandlerResolver() {
            @Override
            public List<Handler> getHandlerChain(PortInfo portInfo) {
                List<Handler> handlerChain = new ArrayList<>();
                handlerChain.add(loggingHandler);
                return handlerChain;
            }
        };
    }
}
为了测试客户端,我使用JUnit编写了一个测试类。我这样称呼客户:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = StoreServiceTestConfig.class)
public class StoreServiceImplTest {
    @Autowired
    private StoreWS storeWS;
    ...
    @Test
    public void testExecuteQuery() throws Exception {
        ...
        StoreResponseType response = storeWS.executeQuery(storeRequest);
        ...
    }
}
现在,我需要将完整的传出和传入SOAP消息记录到控制台中。请问怎么做?越简单越好

我找到了使用以下系统参数的建议,但没有一个适合我:

com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump=true
com.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true
com.sun.xml.ws.transport.local.LocalTransportPipe.dump=true
com.sun.xml.ws.transport.http.HttpAdapter.dump=true
我使用的是Spring配置类(无XML)和所有依赖项的最新版本

我已经找到了,但我不知道如何在我的场景中使用它

非常感谢!沃伊特

编辑: 我的logback.xml看起来像这样,但在控制台中仍然看不到任何soap消息:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg %n
            </Pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
    </appender>
    <logger name="org.springframework.ws.client.MessageTracing">
        <level value="DEBUG" />
        <appender-ref ref="consoleAppender" />
    </logger>
    <logger name="org.springframework.ws.server.MessageTracing">
        <level value="DEBUG" />
        <appender-ref ref="consoleAppender" />
    </logger>
    <root>
        <level value="DEBUG" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>
如果我注释掉下面的行,那么它将再次开始工作,并为响应分配一个对象,但不会记录SOAP消息:

// factoryBean.setHandlerResolver(handlerResolver());
我发现LoggingHandler类中的以下行导致调用服务的响应为null:

SOAPMessage message = context.getMessage();

您谈论的答案似乎是指基于CXF的SOAP客户端实现。在这种实现中,您必须向端点添加日志拦截器。如果您愿意,您可以使用Spring的某种实现,并且您可以在不使用任何XML的情况下配置所有内容,如果您感兴趣,请告诉我

在您的情况下,如果希望查看消息,可以修改org.springframework.ws.server.MessageTracing的日志级别以进行调试

我希望这对你有帮助,祝你度过愉快的一天


编辑

经过一些研究,日志配置似乎不能与JaxWsPortProxyFactoryBean一起工作。在春季论坛上,你会谈论和你一样的问题。因此,正如上面所建议的,您可以创建自己的消息处理程序和自己的HandlerResolver实现来记录消息。 为了测试该解决方案,我使用了中的日志处理程序logMessage代码,并创建了一个新的HandlerChain实现,该实现将LoggingHandler添加到HandlerChain中。最后,我将HandlerChain设置到JaxWsPortProxyFactoryBean中

更具体地说,以下是您修改的配置:

@Configuration
public class StoreServiceConfig {

    @Bean
    public StoreWS storeWS() throws IOException {
      JaxWsPortProxyFactoryBean factoryBean = new JaxWsPortProxyFactoryBean();
      factoryBean.setServiceInterface(StoreWS.class);
      factoryBean.setWsdlDocumentUrl(new ClassPathResource("/wsdl/StoreWS.wsdl").getURL());
      factoryBean.setNamespaceUri("urn_store");
      factoryBean.setServiceName("StoreWSService");
      factoryBean.setEndpointAddress("https://10.34.45.82/storeservice/services/StoreWS");
      factoryBean.setUsername("testuser");
      factoryBean.setPassword("testpassword");

      factoryBean.setHandlerResolver(handlerResolver());

      factoryBean.afterPropertiesSet();
      return (StoreWS) factoryBean.getObject();
  }

  public HandlerResolver handlerResolver() {
    return new HandlerResolver() {

        public List<Handler> getHandlerChain(PortInfo portInfo) {
            List<Handler> handlerChain = new ArrayList<Handler>();
            handlerChain.add(new LoggingHandler());
            return handlerChain;
        }

    };
 }
@配置
公共类StoreServiceConfig{
@豆子
public StoreWS StoreWS()引发IOException{
JaxWsPortProxyFactoryBean factoryBean=新的JaxWsPortProxyFactoryBean();
setServiceInterface(StoreWS.class);
setWsdlDocumentUrl(新类路径资源(“/wsdl/StoreWS.wsdl”).getURL();
setNamespaceUri(“urn_商店”);
setServiceName(“StoreWSService”);
factoryBean.setEndpointAddress(“https://10.34.45.82/storeservice/services/StoreWS");
setUsername(“testuser”);
setPassword(“testpassword”);
setHandlerResolver(handlerResolver());
factoryBean.AfterPropertieSet();
return(StoreWS)factoryBean.getObject();
}
公共HandlerResolver HandlerResolver(){
返回新的HandlerResolver(){
公共列表getHandlerChain(PortInfo PortInfo){
List handlerChain=new ArrayList();
add(新的LoggingHandler());
返回手柄链;
}
};
}
}

以及LoggingHandler类:

public class LoggingHandler implements SOAPHandler<SOAPMessageContext> {

  private final org.slf4j.Logger LOG = LoggerFactory
        .getLogger("SOAPMessageLoggingHandler");

  public void close(MessageContext context) {
     }

  public boolean handleFault(SOAPMessageContext context) {
    logMessage(context, "SOAP Error is : ");
    return true;
  }

  public boolean handleMessage(SOAPMessageContext context) {
    logMessage(context, "SOAP Message is : ");
    return true;
  }

  public Set<QName> getHeaders() {
    return Collections.EMPTY_SET;
  }

  private boolean logMessage(MessageContext mc, String type) {
    try {
        if (LOG.isDebugEnabled()) {
            LOG.debug(type);
            SOAPMessage msg = ((SOAPMessageContext) mc)
                    .getMessage();

            // Print out the Mime Headers
            MimeHeaders mimeHeaders = msg.getMimeHeaders();
            Iterator mhIterator = mimeHeaders.getAllHeaders();
            MimeHeader mh;
            String header;
            LOG.debug("  Mime Headers:");
            while (mhIterator.hasNext()) {
                mh = (MimeHeader) mhIterator.next();
                header = new StringBuffer(" Name: ")
                        .append(mh.getName()).append(" Value: ")
                        .append(mh.getValue()).toString();
                LOG.debug(header);
            }

            LOG.debug(" SOAP Message: ");
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            msg.writeTo(baos);
            LOG.debug("   " + baos.toString());
            baos.close();
        }

        return true;
    } catch (Exception e) {
        if (LOG.isErrorEnabled()) {
            LOG.error("Error logging SOAP message",
                    e);
        }

        return false;
    }
  }
}
公共类LoggingHandler实现SOAPHandler{
private final org.slf4j.Logger LOG=LoggerFactory
.getLogger(“SOAPMessageLoggingHandler”);
公共无效关闭(MessageContext上下文){
}
公共布尔handleFault(SOAPMessageContext上下文){
日志消息(上下文,“SOAP错误为:”);
返回true;
}
公共布尔handleMessage(SOAPMessageContext上下文){
logMessage(上下文,“SOAP消息是:”);
返回true;
}
公共集getHeaders(){
返回集合。空集合;
}
私有布尔日志消息(MessageContext mc,字符串类型){
试一试{
if(LOG.isDebugEnabled()){
LOG.debug(类型);
SOAPMessage消息=((SOAPMessageContext)mc)
.getMessage();
//打印出Mime标题
MimeHeaders MimeHeaders=msg.getMimeHeaders();
迭代器mIterator=mimeHeaders.getAllHeaders();
MIMH;
字符串头;
调试(“Mime头:”);
while(mHierator.hasNext()){
mh=(MimeHeader)mhierator.next();
header=新的StringBuffer(“名称:”)
.append(mh.getName()).append(“值:”)
.append(mh.getValue()).toString();
LOG.debug(头文件);
}
调试(“SOAP消息:”);
ByteArrayOutputStream bas=新的ByteArrayOutputStream();
消息写入(BAS);
LOG.debug(“+baos.toString());
baos.close();
}
返回true;
}捕获(例外e){
if(LOG.isErrorEnabled()){
LOG.error(“错误记录SOAP消息”,
e) );
}
返回false;
}
}
}
最后,在控制台中打印的内容,以及请求消息的Logback…:

    17:29:22 [main] DEBUG SOAPMessageLoggingHandler - SOAP Message is :  
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -   Mime Headers: 
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -  Name: Accept Value: text/xml, text/html
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -  Name: Content-Type Value: text/xml; charset=utf-8 
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -  Name: Content-Length Value: 246 
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -  SOAP Message:  
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -    <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><S:Body><ns2:executeQuery xmlns:ns2="org.test"><arg0>test</arg0></ns2:executeQuery></S:Body></S:Envelope> 
17:29:22[main]调试SOAPMessageLoggingHandler-SOAP消息是:
17:29:22[main]调试SOAPMessageLoggingHandler-Mime头:
17:29:22[main]调试SOAPMessageLoggingHandler-名称:接受值:text/xml,text/html
17:29:22[main]调试SOAPMessageLoggingHandler-名称:内容类型值:text/xml;字符集=utf-8
17:29:22[main]调试SOAPMessageLoggingHandler-名称:内容长度值:246
17:29:22[main]调试SOAPMessageLoggingHandler-SOAP消息:
17:29:22[main]调试SOAPMessageLoggingHandler-测试
。。。对于响应消息:

    17:29:22 [main] DEBUG SOAPMessageLoggingHandler - SOAP Message is :  
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -   Mime Headers: 
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -  Name: Accept Value: text/xml, text/html
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -  Name: Content-Type Value: text/xml; charset=utf-8 
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -  Name: Content-Length Value: 266 
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -  SOAP Message:  
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -    <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><S:Body><ns2:executeQueryResponse xmlns:ns2="org.test"><return>test</return></ns2:executeQueryResponse></S:Body></S:Envelope> 
17:29:22[main]调试
@Configuration
public class StoreServiceConfig {

    @Bean
    public StoreWS storeWS() throws IOException {
      JaxWsPortProxyFactoryBean factoryBean = new JaxWsPortProxyFactoryBean();
      factoryBean.setServiceInterface(StoreWS.class);
      factoryBean.setWsdlDocumentUrl(new ClassPathResource("/wsdl/StoreWS.wsdl").getURL());
      factoryBean.setNamespaceUri("urn_store");
      factoryBean.setServiceName("StoreWSService");
      factoryBean.setEndpointAddress("https://10.34.45.82/storeservice/services/StoreWS");
      factoryBean.setUsername("testuser");
      factoryBean.setPassword("testpassword");

      factoryBean.setHandlerResolver(handlerResolver());

      factoryBean.afterPropertiesSet();
      return (StoreWS) factoryBean.getObject();
  }

  public HandlerResolver handlerResolver() {
    return new HandlerResolver() {

        public List<Handler> getHandlerChain(PortInfo portInfo) {
            List<Handler> handlerChain = new ArrayList<Handler>();
            handlerChain.add(new LoggingHandler());
            return handlerChain;
        }

    };
 }
public class LoggingHandler implements SOAPHandler<SOAPMessageContext> {

  private final org.slf4j.Logger LOG = LoggerFactory
        .getLogger("SOAPMessageLoggingHandler");

  public void close(MessageContext context) {
     }

  public boolean handleFault(SOAPMessageContext context) {
    logMessage(context, "SOAP Error is : ");
    return true;
  }

  public boolean handleMessage(SOAPMessageContext context) {
    logMessage(context, "SOAP Message is : ");
    return true;
  }

  public Set<QName> getHeaders() {
    return Collections.EMPTY_SET;
  }

  private boolean logMessage(MessageContext mc, String type) {
    try {
        if (LOG.isDebugEnabled()) {
            LOG.debug(type);
            SOAPMessage msg = ((SOAPMessageContext) mc)
                    .getMessage();

            // Print out the Mime Headers
            MimeHeaders mimeHeaders = msg.getMimeHeaders();
            Iterator mhIterator = mimeHeaders.getAllHeaders();
            MimeHeader mh;
            String header;
            LOG.debug("  Mime Headers:");
            while (mhIterator.hasNext()) {
                mh = (MimeHeader) mhIterator.next();
                header = new StringBuffer(" Name: ")
                        .append(mh.getName()).append(" Value: ")
                        .append(mh.getValue()).toString();
                LOG.debug(header);
            }

            LOG.debug(" SOAP Message: ");
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            msg.writeTo(baos);
            LOG.debug("   " + baos.toString());
            baos.close();
        }

        return true;
    } catch (Exception e) {
        if (LOG.isErrorEnabled()) {
            LOG.error("Error logging SOAP message",
                    e);
        }

        return false;
    }
  }
}
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler - SOAP Message is :  
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -   Mime Headers: 
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -  Name: Accept Value: text/xml, text/html
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -  Name: Content-Type Value: text/xml; charset=utf-8 
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -  Name: Content-Length Value: 246 
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -  SOAP Message:  
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -    <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><S:Body><ns2:executeQuery xmlns:ns2="org.test"><arg0>test</arg0></ns2:executeQuery></S:Body></S:Envelope> 
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler - SOAP Message is :  
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -   Mime Headers: 
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -  Name: Accept Value: text/xml, text/html
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -  Name: Content-Type Value: text/xml; charset=utf-8 
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -  Name: Content-Length Value: 266 
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -  SOAP Message:  
    17:29:22 [main] DEBUG SOAPMessageLoggingHandler -    <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><S:Body><ns2:executeQueryResponse xmlns:ns2="org.test"><return>test</return></ns2:executeQueryResponse></S:Body></S:Envelope> 
public boolean handleMessage(SOAPMessageContext context) {
        SOAPMessage message= context.getMessage();
        boolean isOutboundMessage=  (Boolean)context.get (MessageContext.MESSAGE_OUTBOUND_PROPERTY);

        if(isOutboundMessage){
            handlerLog.debug("OUTBOUND MESSAGE\n");

        }else{
            handlerLog.debug("INBOUND MESSAGE\n");
        }

        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            message.writeTo(baos);
            handlerLog.debug("   " + baos.toString());
            baos.close();
            return true;
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return false;
    }