我们在开发过程中,可能希望能够统一地捕获和处理异常,免得异常处理分布在代码各处
我们可以使用spring mvc提供的全局异常捕获来实现这样的功能
首先我们新建一个专门复杂异常处理的工程
com.lzw.exception.exception包里是我们自定义的Exception
package com.lzw.exceptions.exception; public class BookingExpiredException extends Exception { /** * */ private static final long serialVersionUID = 573537091646842099L; }
com.lzw.exceptions.handler包里面是我们对异常的处理
package com.lzw.exceptions.handler; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import com.lzw.exceptions.exception.BookingExpiredException; import com.lzw.exceptions.exception.BookingNoSeatsException; public class BookingExceptionHandler { @ExceptionHandler(value = BookingNoSeatsException.class) @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR, reason = "no seats") @ResponseBody public void handleNoSeatsException(BookingNoSeatsException exception) { System.out.println("BookingNoSeatsException!"); } @ExceptionHandler(value = BookingExpiredException.class) @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR, reason = "booking expired") @ResponseBody public void handleExpiredException(BookingExpiredException exception) { System.out.println("BookingExpiredException!"); } }
package com.lzw.exceptions.resolver; import java.lang.reflect.Method; import org.springframework.core.Ordered; import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.annotation.ExceptionHandlerMethodResolver; import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver; import org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod; public class BookingExceptionHandlerResolver extends ExceptionHandlerExceptionResolver { private Object handler; private ExceptionHandlerMethodResolver methodResolver; public BookingExceptionHandlerResolver() { setOrder(Ordered.HIGHEST_PRECEDENCE); } public void setExceptionHandler(final Object handler) { this.handler = handler; this.methodResolver = new ExceptionHandlerMethodResolver( handler.getClass()); } protected ServletInvocableHandlerMethod getExceptionHandlerMethod( final HandlerMethod handlerMethod, final Exception exception) { ServletInvocableHandlerMethod result = super.getExceptionHandlerMethod( handlerMethod, exception); if (result != null) { return result; } Method method = this.methodResolver.resolveMethod(exception); return (method != null) ? new ServletInvocableHandlerMethod( this.handler, method) : null; }; }
例如上面,我们继承并实现了自己的BookingExceptionHandlerResolver,注入自己的异常处理器(BookingExceptionHandler),重写了getExceptionHandlerMethod,使得异常发生时能从BookingExceptionHandler里面取得处理该异常的处理方法
当业务代码抛出异常的时候,如果所在的Controller没有对异常进行处理,那么异常就会抛出到Spring Mvc,Spring Mvc会在各个ExceptionHandlerExceptionResolver类(或子类)里面查找能够处理该异常的handler,然后在handler里面找到处理那种异常的方法并执行
编写好以上类后,我们通过把ExceptionHandlerExceptionResolver给声明为bean
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"> <bean class="com.lzw.exceptions.resolver.BookingExceptionHandlerResolver"> <property name="exceptionHandler"> <bean class="com.lzw.exceptions.handler.BookingExceptionHandler" /> </property> <property name="messageConverters"> <list> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" /> </list> </property> </bean> <bean class="com.lzw.exceptions.resolver.PayExceptionHandlerResolver"> <property name="exceptionHandler"> <bean class="com.lzw.exceptions.handler.PayExceptionHandler" /> </property> <property name="messageConverters"> <list> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" /> </list> </property> </bean> </beans>
这样最后把整个工程打成jar包,给其他工程使用
下面新建一个代表业务的工程
把之前的Exception工程通过maven给依赖进来
然后在Spring Mvc配置文件中引入Exception工程的配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"> <context:component-scan base-package="com.lzw.business" /> <mvc:annotation-driven /> <import resource="classpath:com/lzw/exceptions/exceptions.xml"/> </beans>
package com.lzw.business; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import com.lzw.exceptions.exception.BookingExpiredException; import com.lzw.exceptions.exception.BookingNoSeatsException; import com.lzw.exceptions.exception.PayNoMoneyException; import com.lzw.exceptions.exception.PayTimeoutException; @Controller public class Test { @RequestMapping(value = "/testbooknoseats") public void TestBookingNoSeats() throws BookingNoSeatsException { throw new BookingNoSeatsException(); } @RequestMapping(value = "/testbookexpired") public void TestBookingExpired() throws BookingExpiredException { throw new BookingExpiredException(); } @RequestMapping(value = "/paynomoney") public void TestPayNoMoney() throws PayNoMoneyException { throw new PayNoMoneyException(); } @RequestMapping(value = "/paytimeout") public void TestPayTimeout() throws PayTimeoutException { throw new PayTimeoutException(); } }
测试一下