Java SpringWeb服务-异常跳过异常解析器
我有一个SOAP服务,如果我为一个XML元素指定了错误的输入,那么请求和响应在良好的输入下可以正常工作 在请求机构中:Java SpringWeb服务-异常跳过异常解析器,java,web-services,soap,spring-ws,Java,Web Services,Soap,Spring Ws,我有一个SOAP服务,如果我为一个XML元素指定了错误的输入,那么请求和响应在良好的输入下可以正常工作 在请求机构中: ... <ns:myIntegerElement>asdf</ns:myIntegerElement> ... 。。。 asdf ... 我的异常解析器被调用,这个解析器只是异常解析器的一个实现,所以它没有异常映射,只有几个System.out在抽象方法中 <bean id="exceptionResolver" class="com.myco
...
<ns:myIntegerElement>asdf</ns:myIntegerElement>
...
。。。
asdf
...
我的异常解析器被调用,这个解析器只是异常解析器的一个实现,所以它没有异常映射,只有几个System.out在抽象方法中
<bean id="exceptionResolver" class="com.mycompany.ws.MyExceptionResolver">
但是,如果我发送的请求看起来更像这样:
...
<ns:myIntegSOMETHINGGOTTOTALLYMESSUP!!!ent>asdf</ns:myIntegerElement>
...
。。。
asdf
...
我的解析器根本没有被执行
我将log4j设置为具有根调试级别,并查看以下输出:
2010-08-09 10:30:01900
[线程:http-8080-2]调试
[org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter]
-接受传入[org.springframework.ws.transport.http]。HttpServletConnection@c46dcf]
到
[
错误:“元素类型无效。”
“ns:MESSEDUPELEMENT”必须由终止
匹配的结束标记
"".' 2010-08-09
10:30:01920[线程: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.http11aprotocol$Http11ConnectionHandler.process(http11aprotocol.java:579)
位于org.apache.tomcat.util.net.aprenpoint$Worker.run(aprenpoint.java:1555)
运行(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.saxpasserimpl$jaxpsaxpasser.parse(saxpasserimpl.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在这里似乎缺少了一个可能的异常,并且没有包装它,但是这样一个基本的错误条件没有被捕获
<?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>
<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>
<bean class="org.springframework.ws.server.endpoint.adapter.MarshallingMethodEndpointAdapter">
<constructor-arg ref="marshaller"/>
<property name="exceptionHandler" ref="exceptionHandler" />
</bean>
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();
}
}
<servlet>
<servlet-name>web-services</servlet-name>
<servlet-class>CustomMessageDispatcherServlet</servlet-class>
</servlet>
<bean id="exceptionResolver" class="com.wdp.smm.ws.MyExceptionResolver">
<property name="order" value="1"/>
</bean>
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);
}
}
}
<!-- '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>
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>
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();
}
}
@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;
}