2014-12-14 3 views
4

안녕하세요. 외부 SOAP RCP 스타일 서비스에 커넥터를 쓰는 방법을 배우고 있습니다. jaxws-maven-plugin 플러그인을 사용하여 WSDL 파일에서 Java 클래스를 생성합니다. 그리고 웹 서비스 클라이언트 빈을 생성하기 위해 Spring을 사용하고 있습니다 :SOAP 메시지를 클라이언트 측에 기록하는 방법은 무엇입니까?

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

클라이언트를 테스트하기 위해 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 메시지를 기록 할 수있는 테스트가 필요합니다 나는 클라이언트에게 이런 식으로 호출합니다. 제발 어떻게 그럴 수있어? 더 쉬운 방법.

나는 다음과 같은 시스템 매개 변수를 사용하여 조언을 발견하지만, 그들 중 누구도 나를 위해 작동하지 : 나는 봄 구성 클래스 (NO XMLS) 및 모든 종속성의 최신 버전을 사용하고

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 

.

내가 발견 한 this answer하지만 내 시나리오에서 사용하는 방법을 모르겠다.

미리 감사드립니다. Vojtech

편집 : 내 logback.xml은 다음과 같습니다하지만, 난 여전히 콘솔의 모든 비누 메시지를 볼 수 없습니다 :

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

편집 2 : 상위 프로젝트 지정의 의 pom.xml 이러한 종속성 :

: 테스트 클래스가 위치한 모듈의

<properties> 
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
    <spring.version>4.1.2.RELEASE</spring.version> 
    <spring-ws-core.version>2.2.0.RELEASE</spring-ws-core.version> 
    <slf4j.version>1.7.7</slf4j.version> 
    <logback.version>1.1.2</logback.version> 
    <junit.version>4.12</junit.version> 
    <commons-logging.version>1.1.1</commons-logging.version> 
</properties> 

<dependencyManagement> 
    <dependencies> 
     <dependency> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-context</artifactId> 
      <version>${spring.version}</version> 
      <exclusions> 
       <exclusion> 
        <groupId>commons-logging</groupId> 
        <artifactId>commons-logging</artifactId> 
       </exclusion> 
      </exclusions> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-web</artifactId> 
      <version>${spring.version}</version> 
      <exclusions> 
       <exclusion> 
        <groupId>commons-logging</groupId> 
        <artifactId>commons-logging</artifactId> 
       </exclusion> 
      </exclusions> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework.ws</groupId> 
      <artifactId>spring-ws-core</artifactId> 
      <version>${spring-ws-core.version}</version> 
      <exclusions> 
       <exclusion> 
        <groupId>commons-logging</groupId> 
        <artifactId>commons-logging</artifactId> 
       </exclusion> 
      </exclusions> 
     </dependency> 
     <!-- LOGGING --> 
     <dependency> 
      <groupId>org.slf4j</groupId> 
      <artifactId>slf4j-api</artifactId> 
      <version>${slf4j.version}</version> 
     </dependency> 
     <dependency> 
      <groupId>org.slf4j</groupId> 
      <artifactId>jcl-over-slf4j</artifactId> 
      <version>${slf4j.version}</version> 
     </dependency> 
     <dependency> 
      <groupId>org.slf4j</groupId> 
      <artifactId>log4j-over-slf4j</artifactId> 
      <version>${slf4j.version}</version> 
     </dependency> 
     <dependency> 
      <groupId>commons-logging</groupId> 
      <artifactId>commons-logging</artifactId> 
      <version>${commons-logging.version}</version> 
     </dependency> 
     <dependency> 
      <groupId>ch.qos.logback</groupId> 
      <artifactId>logback-classic</artifactId> 
      <version>${logback.version}</version> 
     </dependency> 
     <!-- TESTING --> 
     <dependency> 
      <groupId>junit</groupId> 
      <artifactId>junit</artifactId> 
      <version>${junit.version}</version> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-test</artifactId> 
      <version>${spring.version}</version> 
     </dependency> 
    </dependencies> 
</dependencyManagement> 

의 pom.xml은에 따라 달라집니다3210

<dependencies> 
    <dependency> 
     <groupId>${project.groupId}</groupId> 
     <artifactId>vinweb-connector-ws</artifactId> 
    </dependency> 
    <dependency> 
     <groupId>${project.groupId}</groupId> 
     <artifactId>vinweb-connector-api</artifactId> 
    </dependency> 
    <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-context</artifactId> 
    </dependency> 
    <!-- LOGGING --> 
    <dependency> 
     <groupId>org.slf4j</groupId> 
     <artifactId>slf4j-api</artifactId> 
    </dependency> 
    <dependency> 
     <groupId>commons-logging</groupId> 
     <artifactId>commons-logging</artifactId> 
    </dependency> 
    <!-- TESTING --> 
    <dependency> 
     <groupId>junit</groupId> 
     <artifactId>junit</artifactId> 
    </dependency> 
    <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-test</artifactId> 
    </dependency> 
</dependencies> 

편집 3 : I'v 내 프로젝트에 LoggingHandler 클래스를 추가 :

package storeservice.log; 

import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.stereotype.Component; 
import javax.xml.namespace.QName; 
import javax.xml.soap.MimeHeader; 
import javax.xml.soap.MimeHeaders; 
import javax.xml.soap.SOAPMessage; 
import javax.xml.ws.handler.MessageContext; 
import javax.xml.ws.handler.soap.SOAPHandler; 
import javax.xml.ws.handler.soap.SOAPMessageContext; 
import java.io.ByteArrayOutputStream; 
import java.io.OutputStream; 
import java.util.Collections; 
import java.util.Iterator; 
import java.util.Set; 

@Component 
public class LoggingHandler implements SOAPHandler<SOAPMessageContext> { 

    private final Logger LOG = LoggerFactory.getLogger(LoggingHandler.class); 

    @Override 
    public Set<QName> getHeaders() { 
     return Collections.emptySet(); 
    } 

    @Override 
    public boolean handleMessage(SOAPMessageContext context) { 
     logMessage(context, "SOAP message : "); 
     return true; 
    } 

    @Override 
    public boolean handleFault(SOAPMessageContext context) { 
     logMessage(context, "SOAP error : "); 
     return true; 
    } 

    @Override 
    public void close(MessageContext context) { 
    } 

    private void logMessage(SOAPMessageContext context, String type) { 
     try { 
      if(LOG.isDebugEnabled()) { 
       Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); 
       if(outboundProperty) { 
        LOG.debug("Outbound " + type); 
       } else { 
        LOG.debug("Inbound " + type); 
       } 

       SOAPMessage message = context.getMessage(); 

       // Print out the MIME headers 
       MimeHeaders headers = message.getMimeHeaders(); 
       Iterator<MimeHeader> headersIterator = headers.getAllHeaders(); 
       MimeHeader mimeHeader; 
       LOG.debug(" Mime headers :"); 
       while(headersIterator.hasNext()) { 
        mimeHeader = headersIterator.next(); 
        LOG.debug(" " + mimeHeader.getName() + " : " + mimeHeader.getValue()); 
       } 

       // Print out the message body 
       LOG.debug(" Message body :"); 
       try(OutputStream outStream = new ByteArrayOutputStream()) { 
        message.writeTo(outStream); 
        LOG.debug(" " + outStream.toString()); 
       } 
      } 
     } catch (Exception e){ 
      if(LOG.isErrorEnabled()) { 
       LOG.error("Error logging SOAP message", e); 
      } 
     } 
    } 
} 

그리고 웹 서비스 클라이언트 빈 생성하는 데 사용

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

그 결과입니다 SOAP 메시지는 기록되지만 storeWS.executeQuery 호출 응답은 NULL입니다.

StoreResponseType response = storeWS.executeQuery(storeRequest); 
내가 행 다음에 주석 경우 691,363,210

그런 다음 다시 일을 시작하고 응답 객체를 할당하지만 SOAP 메시지가 기록되지 않습니다 :

// factoryBean.setHandlerResolver(handlerResolver()); 

내가 수업 시간에 라인을 다음 중 응답 것을 원인 LoggingHandler 것을 발견했다 서비스 호출은 null입니다.

SOAPMessage message = context.getMessage(); 

답변

7

SOAP 클라이언트의 CXF 기반 구현을 언급 한 것 같습니다. 그런 종류의 구현에서는 엔드 포인트에 로깅 인터셉터를 추가해야합니다. 원하는 경우 Spring과 함께 구현할 수 있으며 XML없이 모든 것을 구성 할 수 있습니다. 관심이 있다면 알려주십시오.

메시지를보고 싶다면 org.springframework.ws.server.MessageTracing의 로그 레벨을 DEBUG로 수정할 수 있습니다.

나는 이것이 당신을 돕고, 좋은 하루 보내길 바랍니다.


몇 가지 조사 후 편집

, 구성 로깅하는 것은 JaxWsPortProxyFactoryBean 작동하지 않는 것 같다. Spring 포럼의 This topic은 당신과 같은 문제에 대해 이야기합니다. 그래서 거기에 제안 된대로, 당신은 자신의 메시지 처리기를 만들 수 있으며 자신의 HandlerResolver 구현을 통해 메시지를 기록 할 수 있습니다. 해당 솔루션을 테스트하려면 docs.oracle.com의 로깅 처리기 logMessage 코드를 사용하고 해당 LoggingHandler를 handlerChain에 추가하는 새로운 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; 
     } 

    }; 
} 

}

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

그리고, 그가 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] 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> 

그것은 CXF 하나와 봄 구현을 대체 미만의 충격을, 나는 생각한다. 그 대답이 내 첫사람보다 효과적 일 것이라고 기대합니다 ^^.

+0

예, 나는 봄 옵션에 관심하시기 바랍니다. org.springframework.ws.server.MessageTracing과 org.springframework.ws.client.MessageTracing의 로그 레벨을 DEBUG로 설정했지만 (내 질문에 편집 참조) 콘솔에서 비누 메시지를 볼 수 없습니다. 고맙습니다. – Vojtech

+0

커먼즈 로깅 의존성 (문서에 따르면 1.1 이상)을 클래스 패스에 추가 했습니까? 그렇지 않으면 root-logger를 DEBUG 레벨로 설정하면 Spring 로그를 볼 수 있습니까? 웹 서비스 구성보다 로거 구성/종속성 문제가 더 많을 수 있습니다. – KevinHol

+0

첫 번째 답변을 수정합니다. 로깅 구성을 조사하기 전에 해당 솔루션을 사용해보십시오. – KevinHol

0

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

처리기

public class MyServiceLogHandler implements SOAPHandler<SOAPMessageContext> { 

    Logger handlerLog = LogManager.getLogger(MyServiceLogHandler.class); 

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

    public boolean handleFault(SOAPMessageContext context) { 
     SOAPMessage message= context.getMessage(); 
     try { 
      message.writeTo(System.out); 
     } catch (SOAPException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     return false; 
    } 

    public void close(MessageContext context) { 
     // TODO Auto-generated method stub 

    } 

    public Set<QName> getHeaders() { 
     // TODO Auto-generated method stub 
     return null; 
    } 

} 

사용

import javax.xml.ws.handler.Handler; 
import java.util.List; 
import javax.xml.ws.Binding; 
import javax.xml.ws.BindingProvider; 

Binding binding = ((BindingProvider) bookService).getBinding(); 
     List<Handler> handlerList = binding.getHandlerChain(); 
     handlerList.add(new MyServiceLogHandler()); 
     binding.setHandlerChain(handlerList); 
관련 문제