前言
SpringMVC在请求过程中出现异常后都是交由异常处理器来处理的,自定义异常处理器可以实现一个系统的异常处理逻辑。
正文
异常处理的思路
系统中异常包括两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获得异常信息,后者主要通过规范代码开发、测试等手段减少运行时异常的发生。
系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理,如下图:
(一)配置方式实现全局异常处理
自定义异常类
为了区别不同的异常,在这里我们自定义一个系统异常,日过controller、service、dao抛出此类异常说明是系统预期的异常信息。
package com.xiaojian.springmvc.exception;
/**
* 自定义的异常
* @author wyz
*
*/
public class MyException extends Exception {
/**
*
*/
private static final long serialVersionUID = 1L;
public MyException(String message) {
super(message);
this.message = message;
}
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
异常定义好以后,我们要自定义异常的处理逻辑,在这里我们需要自定义一个异常处理器,在SpringMVC中,要自定义异常处理器,就要自定义一个类,实现HandlerExceptionResolver接口:
package com.xiaojian.springmvc.exception;
import java.io.PrintWriter;
import java.io.StringWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
/**
* 自定义全局异常处理器
* @author wyz
*
*/
public class GlobalExceptionResolver implements HandlerExceptionResolver {
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
String msg ;
if (ex instanceof MyException) {
//如果是自定义异常
MyException myException = (MyException) ex;
msg = myException.getMessage();
}else {
ex.printStackTrace();
StringWriter s = new StringWriter();
PrintWriter printWriter = new PrintWriter(s);
ex.printStackTrace(printWriter);
msg = s.toString();
}
//处理其他的业务逻辑
//返回错误页面
ModelAndView model = new ModelAndView();
model.addObject("msg", msg);
model.setViewName("/WEB-INF/jsp/error.jsp");
return model;
}
}
在这个例子中,我返回了一个error的jsp页面,页面简单的取出了错误信息:
<body>
<h1>错误页面</h1>
${msg}
</body>
</html>
除此之外,要想异常被正常拦截, 还要再springmvc.xml文件中配置异常处理器,或者直接在上面加上@Component注解,配置方式如下:
<bean id="handlerExceptionResolver" class="com.xiaojian.springmvc.exception.GlobalExceptionResolver" />
现在我们来测试一下,我们在controller的方法中修改一下,添加一个除零异常:
@RequestMapping("/login")
public ModelAndView login(User user, ModelAndView model, Date texttime) {
int i = 10 / 0 ;
System.out.println(user.getUsername());
System.out.println(user.getPassword());
System.out.println(texttime);
model.addObject("data", "登录成功");
model.addObject("texttime", new Date());
model.setViewName("/WEB-INF/jsp/login.jsp");
return model;
}
访问页面:http://localhost:8080/demo/login.action
结果如下:
以上就是通过配置的方式,自定义异常,下面还有一种更为方便的注解方式来实现相同的功能,推荐大家使用第二种。
(二)注解方式实现全局异常处理
除了以上的全局异常处理,Spring官方还推荐我们使用注解的方式优雅的实现全局异常处理。即使用@ControllerAdvice 、@ExceptionHandler这两个注解来实现异常处理。
首先自定义异常类:
public class MyException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = 1L;
public MyException(String message) {
super(message);
this.message = message;
}
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
然后自定义全局异常处理器:
@ControllerAdvice
public class GlobalExceptionResolver {
@ExceptionHandler(value = MyException.class)
@ResponseBody
public String myExceptionHandler(MyException e) {
return "{'msg':'222222'}";
}
@ExceptionHandler(value = Exception.class)
public ModelAndView exceptionHandler() {
return new ModelAndView("/WEB-INF/jsp/error.jsp");
};
}
在这个处理器中,我们在捕获到自定义异常的时候,向页面返回了一个json。
还要在springmvc中配置好这个处理器,使之被容器扫描:
<bean id="handlerExceptionResolver" class="com.xiaojian.springmvc.exception.GlobalExceptionResolver" />
在controller中定义异常:
@RequestMapping("/login")
public ModelAndView login(User user, ModelAndView model, Date texttime) {
//int i = 10 / 0 ;
if (true) {
throw new MyException("这个是注解实现的自定义异常");
}
model.addObject("data", "登录成功");
model.addObject("texttime", new Date());
model.setViewName("/WEB-INF/jsp/login.jsp");
return model;
}
启动项目,访问http://localhost:8080/demo/login.action
后显示如下:
总结
以上两种就是全局异常处理的两种方式,在实际工作做,还是比较推荐使用第二种,相比于第一种,它主要有一下几点优点:
- 使用注解的方式代码看上去更加的清晰。
- 对于自定义异常的捕获会很方便。
- 适用于对于返回json格式的情况(可以使用@ResponseBody注解方法对特定异常进行处理),使用HandlerExceptionResolver的话如果是ajax的请求,出现异常就会很尴尬,ajax并不认识ModelAndView。