如何使用Spring Web服务创建自定义soap故障消息

时间:2010-11-08 04:36:57

标签: spring-ws

我正在尝试使用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>

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

谢谢

2 个答案:

答案 0 :(得分:7)

经过多次搜索后,我找到了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();
    }
}

答案 1 :(得分: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了解原始解决方案。