为什么需要统一处理异常
框架的强大之处就在于把很多需要码农多次重复编写的代码剥离出来,形成核心的处理方式。当然这都是基于IOC和AOP,相信很多程序员在编写dao层的时候都没有进行事务的开启和关闭,只需要注意业务逻辑就行了,你只需要加个@Transactional注解,框架自然而然就开启和关闭事务以及事务的回滚,事务的隔离级别等核心配置都不需要再关心了。那么在异常的处理这块同样可以以类似的方式来进行编码的风格改变,你不需要再有过多的trycatch语句,只需要把异常抛给框架就行了,框架帮你处理!
废话不多说了,开始如何让你在异常处理这块统一化吧(因为springmvc中的统一异常处理有3种,百度一大片。笔者比较了几种之后,拿出了最实用,简单的一种来演示)
需求:
dao,service,controller层如果遇到异常只需要throw,不需要try catch,异常处理交由异常处理类来完成,以json数据格式返回给前端,由前端根据返回的json数据来处理之后显示友好的界面提示错误。(当然,前端这里不写,我们只需返回json数据就行了。这就是前后端分离的开发模式,后端只提供数据给前端,不参与页面的使用)
先是项目的结构(普通的ssm工程):
因为这里只需要模拟程序抛出了异常,所以其实只需要用controller层来模拟就行了,其他层用不到(当然也可以在Service或者是dao层抛出异常,是一样的)
controller层
(根据前端传入的参数来抛出不同类型的自定义异常):
@Controller
@RequestMapping("/item")
//public class ItemController extends BaseExceptionHandler {
public class ItemController{
@RequestMapping("/items/{id}")
public String getItems(@PathVariable("id") int id) {
switch (id) {
case 1:
if (1 == 1)
throw new BusinessException("1001", "业务错误1001");
break;
case 2:
if (1 == 1)
throw new BusinessException("1002", "业务错误1002");
break;
default:
throw new ParameterException("参数错误");
}
return "ok";
}
}
自定义异常类
(为了更好的封装异常,自定义异常是肯定要的,这里我只帖一个就行了,其他的大同小异,不同的在于你的业务逻辑):
public class BusinessException extends RuntimeException{
private static final long serialVersionUID = 1394818049620775426L;
private String exceptionCode;
private String exceptionMsg;
public BusinessException(){}
public BusinessException(String exceptionCode, String exceptionMsg) {
super();
this.exceptionCode = exceptionCode;
this.exceptionMsg = exceptionMsg;
}
public String getExceptionCode() {
return exceptionCode;
}
public void setExceptionCode(String exceptionCode) {
this.exceptionCode = exceptionCode;
}
public String getExceptionMsg() {
return exceptionMsg;
}
public void setExceptionMsg(String exceptionMsg) {
this.exceptionMsg = exceptionMsg;
}
@Override
public String toString() {
return "BusinessException [exceptionCode=" + exceptionCode + ", exceptionMsg=" + exceptionMsg + "]";
}
}
统一异常处理类
(这里是重点,把BaseExceptionHandler注入到容器就行,再通俗点说就是把BaseExceptionHandler的包路径配置到spring的注解扫描base-package中)
@ControllerAdvice
public class BaseExceptionHandler {
@ExceptionHandler
@ResponseBody
public Map<String,Object> handleAndReturnData(HttpServletRequest requset,HttpServletResponse response,Exception ex){
Map<String,Object> resultMap = new HashMap<String,Object>();
if(ex instanceof BusinessException) {
resultMap.put("msg", ((BusinessException)ex).getExceptionMsg());
resultMap.put("error-code", ((BusinessException)ex).getExceptionCode());
}else if(ex instanceof ParameterException) {
resultMap.put("msg", ((ParameterException)ex).getExceptionMsg());
resultMap.put("error-code", "999");
}
return resultMap;
}
}
运行项目,访问url:(json格式的数据)
为了比较,下面贴出一张没有使用统一异常处理的访问
总结:
注意BaseExceptionHandler统一异常处理类中的三个注解@ControllerAdvice还有@ExceptionHandler和@ResponseBody,@ControllerAdvice是对@Controller的一种增强,目前比较常用的就是用来注解统一异常处理类,这样@ExceptionHandler就能使用了,由@ExceptionHandler注解的方法就是处理异常的方法,具体的可以百度。这里明白怎么使用就行了。