我正在尝试使用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>
如何为此服务定义编写异常处理?
谢谢
答案 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了解原始解决方案。