我们在开发过程中,可能希望能够统一地捕获和处理异常,免得异常处理分布在代码各处
我们可以使用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!");
}
}
com.lzw.exceptions.resolver包里面的类负责对异常进行捕获
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;
};
}
ExceptionHandlerExceptionResolver是spring mvc默认的异常处理器,我们可以通过继承它来实现自己的处理逻辑
例如上面,我们继承并实现了自己的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>
最后看看Mvc的Controller
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();
}
}
测试一下