JAX-WS spring 服务器端为 RuntimeExceptions 设置自定义故障消息

JAX-WS spring server-side set custom fault message for RuntimeExceptions

问题

默认情况下,当我的服务器上发生扩展 RuntimeException 的未捕获异常时,JAX-WS 构建以下 SOAP 错误消息:

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
   <S:Body>
      <S:Fault xmlns:ns3="http://www.w3.org/2003/05/soap-envelope">
         <faultcode>S:Server</faultcode>
         <faultstring>[runtime exception message here]</faultstring>
         <detail>
            <ns2:exception class="java.lang.RuntimeException" note="To disable this feature, set com.sun.xml.ws.fault.SOAPFaultBuilder.disableCaptureStackTrace system property to false" xmlns:ns2="http://jax-ws.dev.java.net/">
               <message>[runtime exception message here too]</message>
               <ns2:stackTrace>
                  [stack trace details]
               </ns2:stackTrace>
            </ns2:exception>
         </detail>
      </S:Fault>
   </S:Body>
</S:Envelope>

哪种方式有意义,只是我想更改该行为以便改为发送:

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
   <S:Body>
      <S:Fault xmlns:ns3="http://www.w3.org/2003/05/soap-envelope">
         <faultcode>S:Server</faultcode>
         <faultstring>Something wrong happened and it's totally our fault</faultstring>
      </S:Fault>
   </S:Body>
</S:Envelope>

请注意,该消息应该不是 RuntimeException 的消息内容,而是 any[的自定义静态消息 扩展 RuntimeException 的异常可能发生在服务器端。

我无法更改 WSDL,也不想设置自定义异常。

我正在使用 spring 插件:com.sun.xml.ws.transport.http.servlet.WSSpringServlet

我该怎么做?

我认为您可以使用 SoapFaultMappingExceptionResolver 解决问题 http://docs.spring.io/spring-ws/site/reference/html/server.html

The SoapFaultMappingExceptionResolver is a more sophisticated implementation. This resolver enables you to take the class name of any exception that might be thrown and map it to a SOAP Fault, like so:

<beans>
    <bean id="exceptionResolver"
        class="org.springframework.ws.soap.server.endpoint.SoapFaultMappingExceptionResolver">
        <property name="defaultFault" value="SERVER"/>
        <property name="exceptionMappings">
            <value>
                org.springframework.oxm.ValidationFailureException=CLIENT,Invalid request
            </value>
        </property>
    </bean> </beans>

The key values and default endpoint use the format faultCode,faultString,locale, where only the fault code is required. If the fault string is not set, it will default to the exception message. If the language is not set, it will default to English. The above configuration will map exceptions of type ValidationFailureException to a client-side SOAP Fault with a fault string "Invalid request", as can be seen in the following response:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Body>
       <SOAP-ENV:Fault>
           <faultcode>SOAP-ENV:Client</faultcode>
           <faultstring>Invalid request</faultstring>
       </SOAP-ENV:Fault>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

If any other exception occurs, it will return the default fault: a server-side fault with the exception message as fault string.

您应该将 org.springframework.oxm.ValidationFailureException 异常更改为您感兴趣的异常,即 java.lang.Exception 或 java.lang.RuntimeException

您还可以创建自定义例外 class

public class CustomGenericAllException extends RuntimeException {


    private String errorCode;
    private String errorMsg;

   //getter and setter for errorCode and errorMsg       

    public CustomGenericAllException(String errorCode, String errorMsg) {
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
    }

}

在每个方法中你都可以抛出这个异常

 throw new CustomGenericAllException("S:Server", "Something wrong happened and it's totally our fault");

并且在 xml 配置中你可以映射这个通用异常 <value>com.testpackage.CustomGenericAllException ....

希望这对您有所帮助

我假设您有一个类似于以下端点的端点:

import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.soap.SoapFaultException;
import org.w3c.dom.Element;

@Endpoint
public class HolidayEndpoint {

    private static final String NAMESPACE_URI = "http://mycompany.com/hr/schemas";

    public HolidayEndpoint() {
    }

    @PayloadRoot(namespace = NAMESPACE_URI, localPart = "HolidayRequest")                  
    public void handleHolidayRequest(@RequestPayload Element holidayRequest)               
        throws Exception {
      //your code to handle the request on the server
    }
}

现在,假设 handleHolidayRequest() 是您预期 RuntimeException 发生的地方,则必须像这样更改代码:

import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.soap.SoapFaultException;
import org.w3c.dom.Element;

@Endpoint
public class HolidayEndpoint {

    private static final String NAMESPACE_URI = "http://mycompany.com/hr/schemas";

    public HolidayEndpoint() {
    }

    @PayloadRoot(namespace = NAMESPACE_URI, localPart = "HolidayRequest")                  
    public void handleHolidayRequest(@RequestPayload Element holidayRequest)               
        throws Exception {
        try
        {
            //your code to handle the request on the server
        }
        catch(RuntimeException e)
        {
            String faultMessage = "Something's wrong on our end. Try again later.";
            throw new SoapFaultException(faultMessage);
        }
    }
}

请注意我是如何捕获运行时异常并抛出新的 SoapFaultException 的?这样就可以了,响应如下:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header/>
   <SOAP-ENV:Body>
      <SOAP-ENV:Fault>
         <faultcode>SOAP-ENV:Server</faultcode>
         <faultstring xml:lang="en">Something's wrong on our end. Try again later.</faultstring>
      </SOAP-ENV:Fault>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

现在,如果您正在使用类似 spring 的东西 - 与服务激活器集成,它只是相同的概念,除了不是抛出 SoapFaultException,您只需构建一条消息,将 SoapFaultException 作为负载:

@ServiceActivator(inputChannel = "input", outputChannel = "output")
public Message<?> handleHolidayRequest(HolidayRequest holidayRequest) {
   try {
      // your code to handle the request on the server
   } catch (RuntimeException e) {
      String faultMessage = "Something's wrong on our end. Try again later.";
      SoapFaultException soapFaultException = new SoapFaultException(faultMessage);
      return MessageBuilder.withPayload(soapFaultException).build();
   }
}

PS:为了您的理解,我使用了此处的 Web 服务教程示例进行说明(如果您仍在苦苦挣扎,我确实有一个工作示例): http://docs.spring.io/spring-ws/site/reference/html/tutorial.html

祝你好运!