【问题标题】:How to create custom soap fault message using spring web service如何使用 Spring Web 服务创建自定义肥皂故障消息
【发布时间】:2010-11-08 04:36:57
【问题描述】:

我正在尝试使用 Spring Web 服务库编写 Web 服务。我能够成功配置我的端点并且工作正常,但我遇到了一些异常映射问题。

我可以使用 @SoapFault 和 SoapFaultAnnotationExceptionResolver 映射异常,但 wsdl 定义如下

<xsd:schema elementFormDefault="qualified" targetNamespace="http://abc.com/soap/">
    <xsd:complexType name="ServiceException">
        <xsd:sequence>
            <xsd:element name="message" nillable="true" type="xsd:string"/>
        </xsd:sequence>
    </xsd:complexType>

    <xsd:complexType name="ValidationException">
        <xsd:complexContent>
            <xsd:extension base="tns:ServiceException">
                <xsd:sequence/>
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>

    <xsd:complexType name="InternalException">
        <xsd:complexContent>
            <xsd:extension base="tns:ServiceException">
                <xsd:sequence/>
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>

    <xsd:complexType name="AuthenticationException">
        <xsd:complexContent>
            <xsd:extension base="tns:ServiceException">
                <xsd:sequence/>
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>

    <xsd:complexType name="LoginInput">
        <xsd:sequence>
            <xsd:element minOccurs="1" maxOccurs="1" name="UserName" nillable="false" type="xsd:string"/>
            <xsd:element minOccurs="1" maxOccurs="1" name="PassWord" nillable="false" type="xsd:string"/>
        </xsd:sequence>
    </xsd:complexType>

    <xsd:complexType name="LoginOutput">
        <xsd:sequence>
            <xsd:element minOccurs="1" maxOccurs="1" name="ValidTo" nillable="false" type="xsd:dateTime"/>
        </xsd:sequence>
    </xsd:complexType>

    <xsd:element name="login" type="tns:LoginInput"/>
    <xsd:element name="loginResponse" type="tns:LoginOutput"/>

    <xsd:element name="ValidationException" type="tns:ValidationException"/>
    <xsd:element name="InternalException" type="tns:InternalException"/>
    <xsd:element name="AuthenticationException" type="tns:AuthenticationException"/>
</xsd:schema>

<message name="LoginRequest">
    <part name="login" element="tns:login"/>
</message>

<message name="LoginResponse">
    <part name="loginResponse" element="tns:loginResponse"/>
</message>

<message name="ValidationException">
    <part name="ValidationException" element="tns:ValidationException"/>
</message>

<message name="InternalException">
    <part name="InternalException" element="tns:InternalException"/>
</message>

<message name="AuthenticationException">
    <part name="AuthenticationException" element="tns:AuthenticationException"/>
</message>

<portType name="ServicePortType">
    <operation name="Login">
        <input message="tns:LoginRequest"/>
        <output message="tns:LoginResponse"/>
        <fault name="ValidationException" message="tns:ValidationException"/>
        <fault name="InternalException" message="tns:InternalException"/>
        <fault name="AuthenticationException" message="tns:AuthenticationException"/>
    </operation>
</portType>

<binding name="ServiceBinding" type="tns:ServicePortType">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <operation name="Login">
        <soap:operation soapAction="urn://Service#Login"/>
        <input>
            <soap:body use="literal"/>
        </input>
        <output>
            <soap:body use="literal"/>
        </output>
        <fault name="ValidationException">
            <soap:fault name="ValidationException" use="literal"/>
        </fault>
        <fault name="InternalException">
            <soap:fault name="InternalException" use="literal"/>
        </fault>
        <fault name="AuthenticationException">
            <soap:fault name="AuthenticationException" use="literal"/>
        </fault>
    </operation>
</binding>

如何为此服务定义编写异常处理?

谢谢

【问题讨论】:

    标签: spring-ws


    【解决方案1】:

    经过一番搜索,我找到了this from spring source forum

    SoapMessage response = (SoapMessage) messageContext.getResponse();
    SoapBody soapBody = response.getSoapBody();
    
    SoapFault soapFault =
    soapBody.addClientOrSenderFault(ex.getMessage(), Locale.ENGLISH);
    
    SoapFaultDetail faultDetail = soapFault.addFaultDetail();
    Result result = faultDetail.getResult();
    
    // My detail XML object
    InvalidArgumentFault fault = new InvalidArgumentFault();
    fault.setErrorCode("Custom Error Code");
    fault.setOpsMessage("This is the ops message");
    fault.setSystemMessage("This is the system message");
    
    // Marshal the detail. We have to use the ObjectFactory which isn't
    // marshaller agnostic because the detail element doesn't have an
    // XmlRootElement tag as required by JAXB.
    ObjectFactory of = new ObjectFactory();
    mMarshaller.marshal(of.createInvalidArgumentFault( fault), result);
    

    更新

    这是我正在使用的完整示例实现,

    import java.lang.reflect.Method;
    import java.util.Collection;
    import java.util.HashMap;
    import java.util.Locale;
    import java.util.Map;
    
    import javax.xml.transform.Result;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.oxm.Marshaller;
    import org.springframework.ws.context.MessageContext;
    import org.springframework.ws.server.endpoint.AbstractEndpointExceptionResolver;
    import org.springframework.ws.soap.SoapBody;
    import org.springframework.ws.soap.SoapFault;
    import org.springframework.ws.soap.SoapFaultDetail;
    import org.springframework.ws.soap.SoapMessage;
    
    import org.apache.commons.lang.StringUtils;
    
    public class CustomSoapFaultDetailAnnotationExceptionResolver extends
            AbstractEndpointExceptionResolver implements ApplicationContextAware {
        private static Log log = LogFactory
                .getLog(CustomSoapFaultDetailAnnotationExceptionResolver.class);
    
        private Collection<Marshaller> marshallers;
    
        private Map<Class<? extends Object>, Marshaller> marshallerMap = new HashMap<Class<? extends Object>, Marshaller>();
    
        public CustomSoapFaultDetailAnnotationExceptionResolver() {
            setWarnLogCategory(getClass().getCanonicalName());
        }
    
        @Override
        protected boolean resolveExceptionInternal(MessageContext messageContext,
                Object endpoint, Exception ex) {
            boolean resolved = false;
    
            try {
                CustomSoapFaultDetails annotation = ex.getClass().getAnnotation(
                        CustomSoapFaultDetails.class);
                if (annotation != null) {
    
                    Method m = ex.getClass().getMethod("getFaultInfo",
                            new Class[] {});
                    Object fault = m.invoke(ex, new Object[] {});
    
                    SoapMessage response = (SoapMessage) messageContext
                            .getResponse();
                    SoapBody soapBody = response.getSoapBody();
    
                    SoapFault soapFault = soapBody
                            .addClientOrSenderFault(
                                    StringUtils.isBlank(ex.getMessage()) ? "server exception"
                                            : ex.getMessage(), Locale.ENGLISH);
    
                    SoapFaultDetail faultDetail = soapFault.addFaultDetail();
                    Result result = faultDetail.getResult();
    
                    if (marshallerMap.containsKey(fault.getClass())) {
                        marshallerMap.get(fault.getClass()).marshal(fault, result);
                        resolved = true;
                    } else {
                        for (Marshaller marshaller : marshallers) {
                            try {
                                marshaller.marshal(fault, result);
                                marshallerMap.put(fault.getClass(), marshaller);
                                resolved = true;
                                break;
                            } catch (Exception e) {
                                // Ignore error
                            }
                        }
                    }
                }
            } catch (Exception e) {
                log.error(e.toString(), e);
            }
            return resolved;
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext)
                throws BeansException {
            this.marshallers = applicationContext.getBeansOfType(Marshaller.class)
                    .values();
        }
    }
    

    【讨论】:

    • 你从哪里拉出mMarshaller
    • @Mark,我已经更新了答案。如果您有任何建议,请告诉我。
    • 我希望你设法将它从 MessageEndpoint 的某个地方捞出来,但最终我像你一样依赖注入它。
    • @Mark,我检查了这种可能性,但没有找到办法。如果您找到方法,请告诉我。
    • @ArunPJohny - 你能告诉我CustomSoapFaultDetails 吗?
    【解决方案2】:

    我已经成功地使用 SOAP Spring-WS 创建了一个 Web 服务。现在我正在这个 SOAP 服务中执行错误实现,并且我能够使用我创建的类来完成它,如下所示,

    public class ServiceSoapFaultMappingExceptionResolver extends SoapFaultMappingExceptionResolver
    

    在下面的重写函数中,

    @Override
    
    
    protected void customizeFault(Object endpoint, Exception ex, SoapFault fault) {
    
    //code for adding fault details
    
        SoapFaultDefinition soapFaultDefinition = new SoapFaultDefinition();
        String ENVELOPE_NAMESPACE_URI = "http://schemas.xmlsoap.org/soap/envelope/";
    
        //      soapFaultDefinition.setFaultStringOrReason("--" + ex);
    
        //      soapFaultDefinition.setLocale(Locale.ENGLISH);
    
        QName CLIENT_FAULT_NAME = new QName(ENVELOPE_NAMESPACE_URI,"5003", "e");
        soapFaultDefinition.setFaultCode(CLIENT_FAULT_NAME);
        setDefaultFault(soapFaultDefinition);
        Result result = fault.addFaultDetail().getResult();
    
            // marshal
            try {
                 JAXBContext.newInstance(ExceptionListType.class).createMarshaller().marshal(exceptionList, result);
    
    }
    

    this answer获取原始解决方案。

    【讨论】:

    • 虽然这在理论上可以回答这个问题,it would be preferable 在此处包含答案的基本部分,并提供链接以供参考。
    • 感谢更新。将来,为避免投反对票(不是我),请务必从一开始就包含相关细节。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多