【问题标题】:Spring Web Services - Exception Skipping ExceptionResolverSpring Web Services - 异常跳过 ExceptionResolver
【发布时间】:2010-08-09 14:45:36
【问题描述】:

我有一个 SOAP 服务,如果我为 XML 元素指定错误的输入,请求和响应会按预期工作,输入良好

在请求正文中:

...
<ns:myIntegerElement>asdf</ns:myIntegerElement>
...

我的异常解析器被调用了,这个解析器只是异常解析器的一个实现,所以它没有异常映射,只是抽象方法中的几个System.out

<bean id="exceptionResolver" class="com.mycompany.ws.MyExceptionResolver">

但是,如果我发送的请求看起来更像这样:

...
    <ns:myIntegSOMETHINGGOTTOTALLYMESSUP!!!ent>asdf</ns:myIntegerElement>
...

我的解析器根本没有执行

我将 log4j 设置为具有根调试级别并查看以下输出:

2010-08-09 10:30:01,900 [线程:http-8080-2] 调试 [org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter] - 接受传入 [org.springframework.ws.transport.http.HttpServletConnection@c46dcf] 到 [http://localhost:8080/myws/MyWebServices/] 错误:'元素类型 "ns:MESSEDUPELEMENT" 必须由 匹配的结束标签 “”。 2010-08-09 10:30:01,920 [线程:http-8080-2] 调试 [org.springframework.ws.transport.http.MessageDispatcherServlet] - 无法完成请求 org.springframework.ws.soap.saaj.SaajSoapMessageException: 无法访问信封:无法访问 从给定来源创建信封:; 嵌套异常是 com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: 无法从给定创建信封 来源: 在 org.springframework.ws.soap.saaj.support.SaajUtils.getSaajVersion(SaajUtils.java:162) 在 org.springframework.ws.soap.saaj.SaajSoapMessage.getImplementation(SaajSoapMessage.java:251) 在 org.springframework.ws.soap.saaj.SaajSoapMessage.(SaajSoapMessage.java:84) 在 org.springframework.ws.soap.saaj.SaajSoapMessage.(SaajSoapMessage.java:70) 在 org.springframework.ws.soap.saaj.SaajSoapMessageFactory.createWebServiceMessage(SaajSoapMessageFactory.java:168) 在 org.springframework.ws.transport.AbstractWebServiceConnection.receive(AbstractWebServiceConnection.java:90) 在 org.springframework.ws.transport.support.WebServiceMessageReceiverObjectSupport.handleConnection(WebServiceMessageReceiverObjectSupport.java:86) 在 org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter.handle(WebServiceMessageReceiverHandlerAdapter.java:57) 在 org.springframework.ws.transport.http.MessageDispatcherServlet.doService(MessageDispatcherServlet.java:230) 在 org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571) 在 org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:511) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:637) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:717) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 在 org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) 在 org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) 在 org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) 在 org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) 在 org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) 在 org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298) 在 org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:859) 在 org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:579) 在 org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1555) 在 java.lang.Thread.run(Thread.java:619) 造成的: com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: 无法从给定创建信封 来源: 在 com.sun.xml.internal.messaging.saaj.soap.EnvelopeFactory.createEnvelope(EnvelopeFactory.java:114) 在 com.sun.xml.internal.messaging.saaj.soap.ver1_1.SOAPPart1_1Impl.createEnvelopeFromSource(SOAPPart1_1Impl.java:70) 在 com.sun.xml.internal.messaging.saaj.soap.SOAPPartImpl.getEnvelope(SOAPPartImpl.java:122) 在 org.springframework.ws.soap.saaj.support.SaajUtils.getSaajVersion(SaajUtils.java:159) ... 24 更多原因:javax.xml.transform.TransformerException: org.xml.sax.SAXParseException: 元素类型“smm:smm-aid”必须是 由匹配的结束标签终止 “”。 在 com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:719) 在 com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:313) 在 com.sun.xml.internal.messaging.saaj.util.transform.EfficientStreamingTransformer.transform(EfficientStreamingTransformer.java:393) 在 com.sun.xml.internal.messaging.saaj.soap.EnvelopeFactory.createEnvelope(EnvelopeFactory.java:102) ... 27 更多原因:org.xml.sax.SAXParseException: 元素类型“smm:smm-aid”必须是 由匹配的结束标签终止 “”。 在 com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1231) 在 com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:522) 在 org.xml.sax.helpers.XMLFilterImpl.parse(XMLFilterImpl.java:333) 在 com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transformIdentity(TransformerImpl.java:636) 在 com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:707) ... 30 更多

看来 spring 在这里缺少一个可能的异常,并且没有包装它,但是在我看来,这种基本的错误条件没有被捕获似乎不太可能。谁能帮我找到这个问题的根源?

我也会包含 web.xml 和 servlet.xml:

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <servlet>
        <servlet-name>ws</servlet-name>
        <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
        <init-param>
            <param-name>transformWsdlLocations</param-name>
            <param-value>true</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>ws</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

servlet 上下文:

<context:component-scan base-package="com.mycomp.proj.ws" />
    <bean id="smmService" class="com.mycomp.proj.ws.SMMRequestHandlingServiceStubImpl"/>

    <bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping"/>
    <bean class="org.springframework.ws.server.endpoint.adapter.MarshallingMethodEndpointAdapter">
        <constructor-arg ref="marshaller"/>
    </bean>
    <bean id="marshaller" class="org.springframework.oxm.castor.CastorMarshaller">
        <property name="mappingLocations">
            <list>
                <value>classpath:mapping.xml</value>
                <value>classpath:hoursOfOperationMapping.xml</value>
            </list>
        </property>
    </bean>

    <bean id="smmws" class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition">
        <property name="schema" ref="schema" />
        <property name="portTypeName" value="SMM" />
        <property name="locationUri" value="/SMMWebServices/"/>
        <property name="targetNamespace" value="http://mycomp.proj.com" />
    </bean>

    <bean id="exceptionResolver" class="com.wdp.smm.ws.MyExceptionResolver"/>

    <bean id="schema" class="org.springframework.xml.xsd.SimpleXsdSchema">
        <property name="xsd" value="/WEB-INF/ws.xsd" />
    </bean>

【问题讨论】:

    标签: java web-services soap spring-ws


    【解决方案1】:

    MessageDispatcherServlet 默认创建自己的两个 EnpointExceptionResolver 实例,即 SoapFaultAnnotationExceptionResolver@1 和 SimpleSoapExceptionResolver@2

    当它解决异常时,SimpleSoapExceptionResolver@2 将停止任何其他已注册的 EnpointExceptionResolver 来处理异常。

    我花了很长时间才弄明白,但答案很简单, 在您的 servlet 上下文中,您必须这样做:

    <bean id="exceptionResolver" class="com.wdp.smm.ws.MyExceptionResolver">
        <property name="order" value="1"/>
    </bean>
    

    【讨论】:

      【解决方案2】:

      我仔细研究了您的问题,我想我知道发生了什么。您的异常处理程序没有被调用,因为它在肥皂处理中处于较高级别。您会看到,WebServiceMessageReceiverHandlerAdapter 尝试将传入的字符串解码为 XML,然后再将其发送到编组器进行处理。由于 XML 无效,因此调用失败。而且由于 WebServiceMessageReceiverHandlerAdapter 不支持异常处理程序,它只是重新抛出异常“SaajSoapMessageException”。

      现在您可以创建一个扩展 WebServiceMessageReceiverHandlerAdapter 的新类,但它还将 handleConnection() 包装在 try/catch 中,当抛出异常时使用您的异常处理程序。


      顺便说一下,在调试这类问题时,我的做法是在log4j中同时输出方法名和行号。以及下载 Spring 源代码。

      【讨论】:

      • 我可以子类化,但是我如何告诉 spring 使用那个实现呢?我没有看到任何可配置的地方
      • 我想补充一下你是完全正确的,但是我没有任何解决方案来实际解决这个问题,我不确定如何在我的 Web 服务项目中利用 WebServiceMessageReceiverHandlerAdapter 的实现,按照我的理解,只有某些 bean 会在 servlet-context.xml 中自动获取。在本周的某个时候,我将尝试在上下文文件中定义这个子类 bean,看看它是否自动使用,如果你认为你知道如何覆盖,请告诉我,赏金是你的
      • 我现在(三年后)在my answer 中添加了一个示例实现,证明这个答案是正确的。
      【解决方案3】:

      我认为@thierry-dimitri-roy 解释的内容是正确的,但是我在实际实现它时遇到了很多问题。例如,仅仅包装handleconnection 方法是不够的,因为没有抛出noendpointfoundexception。由于这是更好地处理异常的更普遍问题,因此我将代码放在这里以减轻后代的痛苦。这是用 spring-ws 2.1.3 和 JBoss AS7 测试的。

      我的消息处理程序将所有问题转换为响应代码为 200 的肥皂错误。

      package fi.eis.applications.spring.soap.server.transport.http;
      
      import java.io.IOException;
      import java.net.URISyntaxException;
      
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      
      import org.apache.commons.lang3.StringEscapeUtils;
      import org.springframework.beans.BeansException;
      import org.springframework.beans.factory.InitializingBean;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.ApplicationContextAware;
      import org.springframework.core.Ordered;
      import org.springframework.web.servlet.HandlerAdapter;
      import org.springframework.web.servlet.ModelAndView;
      import org.springframework.ws.FaultAwareWebServiceMessage;
      import org.springframework.ws.InvalidXmlException;
      import org.springframework.ws.NoEndpointFoundException;
      import org.springframework.ws.WebServiceMessage;
      import org.springframework.ws.WebServiceMessageFactory;
      import org.springframework.ws.context.DefaultMessageContext;
      import org.springframework.ws.context.MessageContext;
      import org.springframework.ws.support.DefaultStrategiesHelper;
      import org.springframework.ws.transport.EndpointAwareWebServiceConnection;
      import org.springframework.ws.transport.FaultAwareWebServiceConnection;
      import org.springframework.ws.transport.WebServiceConnection;
      import org.springframework.ws.transport.WebServiceMessageReceiver;
      import org.springframework.ws.transport.context.DefaultTransportContext;
      import org.springframework.ws.transport.context.TransportContext;
      import org.springframework.ws.transport.context.TransportContextHolder;
      import org.springframework.ws.transport.http.HttpServletConnection;
      import org.springframework.ws.transport.http.HttpTransportConstants;
      import org.springframework.ws.transport.http.MessageDispatcherServlet;
      import org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter;
      import org.springframework.ws.transport.support.TransportUtils;
      
      /**
       * Adapter to map XML parsing and other low-level errors to SOAP faults instead of
       * server standard error pages. Also, this class will always use return code HTTP_OK
       * (status 200) to requests, even if there are errors.
       *  
       */
      public class MyWebServiceMessageReceiverHandlerAdapter
          extends WebServiceMessageReceiverHandlerAdapter
          implements HandlerAdapter, Ordered, InitializingBean, ApplicationContextAware {
      
          private ApplicationContext context;
          @Override
          public void setApplicationContext(ApplicationContext applicationContext)
                  throws BeansException {
              this.context = applicationContext;
          }
      
          @Override
          public void afterPropertiesSet() {
              DefaultStrategiesHelper defaultStrategiesHelper = new DefaultStrategiesHelper(MessageDispatcherServlet.class);
              WebServiceMessageFactory factory = defaultStrategiesHelper
                      .getDefaultStrategy(WebServiceMessageFactory.class, context);
              setMessageFactory(factory);
          }
      
          public ModelAndView handle(HttpServletRequest httpServletRequest,
                                     HttpServletResponse httpServletResponse,
                                     Object handler) throws Exception {
              if (HttpTransportConstants.METHOD_POST.equals(httpServletRequest.getMethod())) {
                  WebServiceConnection connection = new MyWebServiceConnection(httpServletRequest, httpServletResponse);
                  try {
                      overriddenHandleConnection(connection, (WebServiceMessageReceiver) handler);
                  } catch (InvalidXmlException ex) {
                      handleInvalidXmlException(httpServletRequest, httpServletResponse, handler, ex);
                  } catch (Exception ex) {
                      handleGeneralException(httpServletRequest, httpServletResponse, handler, ex);
                  }
              }
              else {
                  handleNonPostMethod(httpServletRequest, httpServletResponse, handler);
              }
              return null;
          }
      
      
          /**
           * Overridden version of handleConnection from WebServiceMessageReceiverObjectSupport to be able to handle
           * missing endpoint ourselves. That method is final, so we need to use another method here.
           * 
           * This has been reported as https://jira.springsource.org/browse/SWS-850
           * 
           * @param connection
           * @param receiver
           * @throws Exception
           */
          protected void overriddenHandleConnection(WebServiceConnection connection, WebServiceMessageReceiver receiver)
                  throws Exception {
              logUri(connection);
              TransportContext previousTransportContext = TransportContextHolder.getTransportContext();
              TransportContextHolder.setTransportContext(new DefaultTransportContext(connection));
      
              try {
                  WebServiceMessage request = connection.receive(getMessageFactory());
                  MessageContext messageContext = new DefaultMessageContext(request, getMessageFactory());
                  receiver.receive(messageContext);
                  if (messageContext.hasResponse()) {
                      WebServiceMessage response = messageContext.getResponse();
                      if (response instanceof FaultAwareWebServiceMessage &&
                              connection instanceof FaultAwareWebServiceConnection) {
                          FaultAwareWebServiceMessage faultResponse = (FaultAwareWebServiceMessage) response;
                          FaultAwareWebServiceConnection faultConnection = (FaultAwareWebServiceConnection) connection;
                          faultConnection.setFault(faultResponse.hasFault());
                      }
                      connection.send(messageContext.getResponse());
                  }
              }
              catch (NoEndpointFoundException ex) {
                  if (connection instanceof EndpointAwareWebServiceConnection) {
                      ((EndpointAwareWebServiceConnection) connection).endpointNotFound();
                  }
                  throw ex;
              }
              finally {
                  TransportUtils.closeConnection(connection);
                  TransportContextHolder.setTransportContext(previousTransportContext);
              }
          }
      
          private void logUri(WebServiceConnection connection) {
              if (logger.isDebugEnabled()) {
                  try {
                      logger.debug("Accepting incoming [" + connection + "] at [" + connection.getUri() + "]");
                  }
                  catch (URISyntaxException e) {
                      // ignore
                  }
              }
          }
      
      
      
          private void handleGeneralException(
                  HttpServletRequest httpServletRequest,
                  HttpServletResponse response, Object handler,
                  Exception ex) throws IOException {
              writeErrorResponseWithMessage(response, ex.getClass().getName() + ": " + ex.getMessage());
          }
      
          /**
           * By default, sets SC_BAD_REQUEST as response in Spring, so overwritten to
           * provide HTTP_OK and reasonable SOAP fault response.
           */
          protected void handleInvalidXmlException(
                  HttpServletRequest httpServletRequest,
                  HttpServletResponse response, Object handler, InvalidXmlException ex)
                  throws IOException {
              writeErrorResponseWithMessage(response, ex.getClass().getName() + ": " + ex.getMessage());
          }
      
          /**
           * By default, sets SC_METHOD_NOT_ALLOWED as response in Spring, so overwritten to
           * provide HTTP_OK and reasonable SOAP fault response.
           */
          protected void handleNonPostMethod(HttpServletRequest httpServletRequest,
                                             HttpServletResponse response,
                                             Object handler) throws Exception {
              writeErrorResponseWithMessage(response, "HTTP Method not allowed");
          }
      
          private void writeErrorResponseWithMessage(HttpServletResponse response, String message)
                  throws IOException {
              String errorXml = String.format(
                       "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">"
                      +"    <SOAP-ENV:Header/>"
                      +"    <SOAP-ENV:Body>"
                      +"        <SOAP-ENV:Fault>"
                      +"            <faultcode>SOAP-ENV:Client</faultcode>"
                      +"            <faultstring xml:lang=\"en\">%s</faultstring>"
                      +"        </SOAP-ENV:Fault>"
                      +"    </SOAP-ENV:Body>"
                      +"</SOAP-ENV:Envelope>",
                      StringEscapeUtils.escapeXml(message)
                      );
      
              response.setStatus(HttpServletResponse.SC_OK);
              response.setContentType("text/xml");
              response.getWriter().write(errorXml);
              response.getWriter().flush();
          }
          @Override
          public int getOrder() {
              return 1;
          }
      
          /**
           * This class is needed as org.springframework.ws.transport.http.HttpServletConnection will throw an
           * exception if it is used outside Spring framework files. However, extending it and using the same
           * implementation seems to be fine.
           *
           */
          static class MyWebServiceConnection extends HttpServletConnection {
              protected MyWebServiceConnection(HttpServletRequest httpServletRequest,
                      HttpServletResponse httpServletResponse) {
                  super(httpServletRequest, httpServletResponse);
              }
          }    
      }
      

      这也需要正确配置。这是 spring 上下文中需要的东西:

      <!-- 'messageReceiverHandlerAdapter' is a magic name spring-ws
           org.springframework.ws.transport.http.MessageDispatcherServlet
           will bind to -->
      <bean id="messageReceiverHandlerAdapter"
          class="fi.eis.applications.spring.soap.server.transport.http.MyWebServiceMessageReceiverHandlerAdapter">
      </bean>
      

      【讨论】:

        【解决方案4】:

        我能想到的解决方案是重写 MessageDispatcherServlet 中的 doService 方法并捕获异常,然后呈现自定义响应。这对你来说可能不是最好的解决方案,但它对我有用,希望对你有帮助!

        public class CustomMessageDispatcherServlet extends MessageDispatcherServlet {
        
        protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
            try {
                super.doService(request, response);
            } catch (Exception e) {
                String error = e.getMessage();
                String errorXml = "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
                                        "<SOAP-ENV:Header/>" +
                                            "<SOAP-ENV:Body>" +
                                                "<SOAP-ENV:Fault>" +
                                                    "<faultcode>SOAP-ENV:Client</faultcode>" +
                                                    "<faultstring xml:lang=\"en\"></faultstring>" + error +
                                                "</SOAP-ENV:Fault>" +
                                            "</SOAP-ENV:Body>" +
                                        "</SOAP-ENV:Envelope>";
                response.setStatus(HttpServletResponse.SC_OK);
                response.setContentType("text/xml");
                response.getWriter().write(errorXml);
                response.getWriter().flush();
            }
        }
        

        }

        您可能只想捕获要处理的异常。

        将 org.springframework.ws.transport.http.MessageDispatcherServlet 替换为 web.xml 文件中的 CustomMessageDispatcherServlet。

        <servlet>
            <servlet-name>web-services</servlet-name>
            <servlet-class>CustomMessageDispatcherServlet</servlet-class>
        </servlet>
        

        【讨论】:

        • 默认情况下对我不起作用,org.springframework.ws.transport.http.MessageDispatcherServlet 将自行捕获异常并设置响应代码。因此,自定义调度程序 servlet 永远不会出现异常。
        【解决方案5】:

        我记得在使用 spring-security 时遇到了这种问题。我的异常解析器在某些情况下也没有被调用。

        然后的问题是有一个过滤器链来处理每个请求。调用异常解析器的代码是这个链中的一个过滤器,但它接近链的末端。因此,如果在异常解析器调用过滤器之前过滤器中的某处发生异常,我的解析器将永远不会被调用。

        我猜你在这里遇到了类似的情况,信封解析错误发生在异常解析器调用过滤器之前。如果是这种情况,您将不得不求助于一些其他方式来处理这些异常,例如 vanilla servlet 过滤器。

        【讨论】:

          【解决方案6】:

          在最新的 Spring WS 版本中,您可以使用自定义 webservice 消息监听器

          public class CustomWebServiceMessageListener extends WebServiceMessageListener {
          
          private static final Logger LOG = LoggerFactory.getLogger(CustomWebServiceMessageListener.class);
          
          @Override
          public void onMessage(Message message, Session session) throws JMSException {
              try {
                  this.handleMessage(message, session);
              } catch (JmsTransportException jmsTransportException) {
                  LOG.error(jmsTransportException.getMessage(), jmsTransportException);
              } catch (Exception e) {
                  JMSException jmsException = new JMSException(e.getMessage());
                  jmsException.setLinkedException(e);
                  LOG.error(e.getMessage(), e);
              }
            }
          }
          

          并像这样注入它:

            <bean id="messageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
              <property name="concurrentConsumers" value="#{properties.concurrentListeners}"/>
          
              <property name="connectionFactory" ref="connectionFactory"/>
              <property name="destination" ref="queue"/>
              <property name="messageListener" ref="messageListener"/>
              <property name="sessionTransacted" value="true"/>
          
          </bean>
          
          <bean id="messageListener" class="com.yourproject.transport.CustomWebServiceMessageListener">
              <property name="messageFactory" ref="saajMessageFactory"/>
              <property name="messageReceiver" ref="messageDispatcher"/>
          </bean>
          

          【讨论】:

            【解决方案7】:

            由于 doService 不再针对无效 XML 引发错误,而是简单地将状态设置为 400,因此我不得不进一步探索 Chen 的答案并实现以下内容。

            public class CustomWebServiceMessageReceiverHandlerAdapter extends WebServiceMessageReceiverHandlerAdapter {
            
              @Override
              protected void handleInvalidXmlException(HttpServletRequest httpServletRequest,
                                                       HttpServletResponse httpServletResponse,
                                                       Object handler,
                                                       InvalidXmlException ex) throws IOException {
                String error = ex.getMessage();
                String errorXml = "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
                    "<SOAP-ENV:Header/>" +
                    "<SOAP-ENV:Body>" +
                    "<SOAP-ENV:Fault>" +
                    "<faultcode>SOAP-ENV:Client</faultcode>" +
                    "<faultstring xml:lang=\"en\"></faultstring>" + error +
                    "</SOAP-ENV:Fault>" +
                    "</SOAP-ENV:Body>" +
                    "</SOAP-ENV:Envelope>";
                httpServletResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                httpServletResponse.setContentType("text/xml");
                httpServletResponse.getWriter().write(errorXml);
                httpServletResponse.getWriter().flush();
              }
            }
            

            通过将messageReceiverHandlerAdapterBeanName 设置为使用自定义WebServiceMessageReceiverHandlerAdapter 来更新messageDispatcherServlet 如下所示的bean 配置。

              @Bean
              public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
                MessageDispatcherServlet servlet = new MessageDispatcherServlet();
                servlet.setApplicationContext(applicationContext);
                servlet.setMessageReceiverHandlerAdapterBeanName("customMessageReceiverHandlerAdapter");
                return new ServletRegistrationBean(servlet, "/ws/*");
              }
            
              @Bean
              public CustomWebServiceMessageReceiverHandlerAdapter customMessageReceiverHandlerAdapter() {
                CustomWebServiceMessageReceiverHandlerAdapter customWebServiceMessageReceiverHandlerAdapter =
                    new CustomWebServiceMessageReceiverHandlerAdapter();
                customWebServiceMessageReceiverHandlerAdapter.setMessageFactory(new DomPoxMessageFactory());
                return customWebServiceMessageReceiverHandlerAdapter;
              }
            

            【讨论】:

              【解决方案8】:

              您必须在 spring bean 中“连接”(或“注入”)异常处理程序。我不确定您的哪个 Spring bean 实际上需要异常处理程序。

              就我个人而言,我使用default-autowire="byName",这会导致我的 exceptionHandler 自动连接到我的 Controller 类中。您的方法实际上使用手动接线。因此,您需要找出哪个 bean 应该实际使用异常处理程序。你有没有试过(就在我头上):

              <bean class="org.springframework.ws.server.endpoint.adapter.MarshallingMethodEndpointAdapter">
                  <constructor-arg ref="marshaller"/>
                  <property name="exceptionHandler" ref="exceptionHandler" />
              </bean>
              

              或者你可以添加 Spring 的自动装配机制,让它自动装配 bean。 :)

              【讨论】:

              • 我定义的异常解析器在 SOAP 调用的生命周期中自动使用,但是我给出的跟踪异常由于某种原因没有被它处理。要么是因为解析器在生命周期中还没有处理异常,要么是这个异常以某种方式溜过而未被捕获。
              • 我这样说是因为 MarshallingMethodEndpointAdapter 没有属性“exceptionHandler”,所以你不能以这种方式注入一个,除非我错过了什么
              猜你喜欢
              • 2012-10-23
              • 2013-03-07
              • 2014-04-26
              • 1970-01-01
              • 2020-04-04
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多