目录
Spring MVC统一异常处理
异常处理流程
Spring MVC处理异常方式(3种)
1.SimpleMappingExceptionResolver
使用 org.springframework.web.servlet.handler.SimpleMappingExceptionResolver 类统一处理异常时需要在配置文件中提前配置异常类和 View 的对应关系。配置文件 springmvc-servlet.xml
<!--SimpleMappingExceptionResolver(异常类与 View 的对应关系) -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 定义默认的异常处理页面,当该异常类型注册时使用 -->
<property name="defaultErrorView" value="error"></property>
<!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception -->
<property name="exceptionAttribute" value="ex"></property>
<!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常页名作为值 -->
<property name="exceptionMappings">
<props>
<prop key="exception.MyException">my-error</prop>
<prop key="java.sql.SQLException">sql-error</prop>
<!-- 在这里还可以继续扩展对不同异常类型的处理 -->
</props>
</property>
</bean>
2.使用@ExceptionHandler注解
使用@ExceptionHandler注解作用在方法上面,参数是具体的异常类型。一旦系统抛出这种类型的异常时,会引导到该方法来处理
缺陷很明显:处理异常的方法和出错的方法(或者异常最终抛出来的地方)必须在同一个Controller,不能全局控制
该注解缺点:进行异常处理的方法必须与出错的方法在同一个Controller里面
@Controller
public class GlobalController {
/**
* 用于处理异常的,MyException自定义异常类
*/
@ExceptionHandler({MyException.class})
public String exception(MyException e) {
System.out.println(e.getMessage());
e.printStackTrace();
return "exception";
}
@RequestMapping("/test")
public void test() {
throw new MyException("出错了!");
}
}
访问…/test路径,抛出了MyException异常。运行下@ExceptionHandler的方法,调转到…/exception.jsp页面
3.实现HandlerExceptionResolver接口
可以进行全局的异常控制
@Component
public class ExceptionTest implements HandlerExceptionResolver {
// 简单描述该方法的实现功能(可选)
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,Exception ex) {
System.out.println("This is exception handler method!");
return "error";
}
}
4.使用@ControllerAdvice + @ExceptionHandler注解
@ExceptionHandler需要进行异常处理的方法必须与出错的方法在同一个Controller里面。那么当代码加入了@ControllerAdvice,则不需要必须在同一个Controller 中了。这也是 Spring 3.2 带来的新特性。从名字上可以看出大体意思是控制器增强。
也就是说,@ControllerAdvice + @ExceptionHandler可以实现全局的异常捕捉;可以全局控制异常,使业务逻辑和异常处理分隔开
注意:确保此WebExceptionHandler类能被扫描到并装载进Spring容器中
(1)自定义枚举类
public enum ErrorEnum {
SystemError("999","系统异常,请联系管理员"),
MyError1("001","自定义异常1"),
MyError2("002","自定义异常2"),
MyError3("003","自定义异常3");
private String code;
private String msg;
ErrorEnum(String code,String msg){
this.code = code;
this.msg = msg;
}
// 省略getter/settter方法
}
(2)自定义异常
public class MyException extends RuntimeException {
private ErrorEnum errorEnum;
public MyException(ErrorEnum errorEnum) {
this.errorEnum = errorEnum;
}
public ErrorEnum getErrorEnum() {
return errorEnum;
}
}
@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
public class ResultBean <T>{
private final String SUCCESSCODE = "000";
private final String SUCCESSMSG = "请求成功";
/**
*999 : 请求失败 (系统异常:这时候具体问题原因要去看日志)
*000 : 请求成功
*001 : 自定义异常1,用户一眼就能看出问题在哪
*002 : 自定义异常2,用户一眼就能看出问题在哪
*003 : 自定义异常3,用户一眼就能看出问题在哪
*/
public String code;
public String message;
public T data;
public ResultBean(){
this.code = SUCCESSCODE;
this.message = SUCCESSMSG;
}
public ResultBean(String code, String message) {
this.code = code;
this.message = message;
}
public ResultBean(T data) {
this();
this.data = data;
}
}
(3)Handler(Controller)
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MyException.class)
@ResponseBody
public ResultBean handleMyException(MyException e){
System.out.println("handleMyException....");
return new ResultBean(e.getErrorEnum().getCode(),e.getErrorEnum().getMsg());
}
}
优先级
既然在Spring MVC中有两种处理异常的方式,那么就存在一个优先级的问题:
当发生异常的时候,Spring MVC会如下处理:
(1)Spring MVC会先从配置文件找异常解析器HandlerExceptionResolver
(2)如果找到了异常异常解析器,那么接下来就会判断该异常解析器能否处理当前发生的异常
(3)如果可以处理的话,那么就进行处理,然后给前台返回对应的异常视图
(4)如果没有找到对应的异常解析器或者是找到的异常解析器不能处理当前的异常的时候,就看当前的Controller中有没有提供对应的异常处理器,如果提供了就由Controller自己进行处理并返回对应的视图
(5)如果配置文件里面没有定义对应的异常解析器,而当前Controller中也没有定义的话,就看有没有全局ControllerAdvice提供的全局异常处理器,如果没有那么该异常就会被抛出来
未捕获异常处理
对于Unchecked Exception而言,由于代码不强制捕获,往往被忽略,如果运行期产生了Unchecked Exception,而代码中又没有进行相应的捕获和处理,则我们可能不得不面对尴尬的404、500等服务器内部错误提示页面。
需要一个全面而有效的异常处理机制。目前大多数服务器也都支持在Web.xml中通过<error-page>(Websphere/Weblogic)或者<error-code>(Tomcat)节点配置特定异常情况的显示页面。修改 web.xml文件
<!-- 出错页面定义 -->
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/500.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/500.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/404.jsp</location>
</error-page>
<!-- 这里可继续增加服务器错误号的处理及对应显示的页面 -->