为什么要使用异常处理器?
观察以下两种情况:
正常结果:
@GetMapping("/{id}")
public Result getById(@PathVariable int id){
// int i=1/0;
Book book = bookService.getById(id);
int code=(book!=null ? Code.GET_OK : Code.GET_ERR);
String msg=(book!=null ? "" : "id不存在请重新查询!");
return new Result(code,book,msg);
}
出现异常后的结果:
@GetMapping("/{id}")
public Result getById(@PathVariable int id){
//模拟一个异常
int i=1/0;
Book book = bookService.getById(id);
int code=(book!=null ? Code.GET_OK : Code.GET_ERR);
String msg=(book!=null ? "" : "id不存在请重新查询!");
return new Result(code,book,msg);
}
通过观察以上两种情况可知:
后台没有异常时会有正确的结果(result)返回给前台处理展示
但是后台出现异常时只有一长串错误(Exception)的提示前台根本无法处理
所以要使用异常处理器处理无论是否出现异常都要传给前台做统一处理
归纳一些异常出现的原因
-
框架内部抛出的异常:因使用不合规导致
-
数据层抛出的异常:因外部服务器故障导致(例如:服务器访问超时)
-
业务层抛出的异常:因业务逻辑书写错误导致(例如:遍历业务书写操作,导致索引异常等)
-
表现层抛出的异常:因数据收集、校验等规则导致(例如:不匹配的数据类型间导致异常)
-
工具类抛出的异常:因工具类书写不严谨不够健壮导致(例如:必要释放的连接长期未释放等)
异常处理器的使用:
package com.itheima.controller;
import com.itheima.exception.BusinessException;
import com.itheima.exception.SystemException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
//rest风格的异常处理器(包含@Controller和@ResponseBody)
//RestControllerAdvice指定当前类可以处理异常
@RestControllerAdvice
public class PojectExceptionAdvice {
//处理异常的类型(当前为处理一切异常)
@ExceptionHandler(Exception.class)
//Exception exc出现异常时直接拦截到这里被处理
public Result doException(Exception exc){
//记录日志
//发送消息给运维
//发送邮件给开发人员,ex对象发送给开发人员
System.out.println("嘿嘿,异常你往哪里跑!");
return new Result(666,null,"你真厉害,搞出了其他异常!");
}
}
这样的话后台无论是否出现异常,前台就可以统一通过接收到的Result在页面处理了
注意:注意异常处理器bean的位置,一定要被spring容器加载到,否则无法正常使用
当前编写的异常处理器是写在controller包下,springMvcConfig正好可以被扫描到
项目异常处理
自定义异常编码
package com.itheima.controller;
public class Code {
//业务请求状态码
public static final int SAVA_OK=20011;
public static final int DELETE_OK=20021;
public static final int UPDATE_OK=20031;
public static final int GET_OK=20041;
public static final int SAVA_ERR=20010;
public static final int DELETE_ERR=20020;
public static final int UPDATE_ERR=20030;
public static final int GET_ERR=20040;
//系统异常状态码
public static final int SYSTEM_ERR=50001;//系统异常
public static final int SYSTEM_TIMEOUT_ERR=50002;//系统超时
public static final int SYSTEM_UNKNOW_ERR=59999;//系统繁忙
//业务异常状态码
public static final int BUSINESS_ERR=50001;
}
1、创建自定义系统异常和业务异常
package com.itheima.exception;
public class BusinessException extends RuntimeException{
private int code;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public BusinessException(int code, String message) {
super(message);
this.code = code;
}
public BusinessException(int code,String message, Throwable cause) {
super(message, cause);
this.code = code;
}
}
系统异常和业务异常一样
2、service层中模拟自定义系统异常和业务异常并抛出
package com.itheima.service.Impl;
import com.itheima.controller.Code;
import com.itheima.dao.BookDao;
import com.itheima.domain.Book;
import com.itheima.exception.BusinessException;
import com.itheima.exception.SystemException;
import com.itheima.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class BookServiceImpl implements BookService {
//装配数据层bean
@Autowired
private BookDao bookDao;
public boolean save(Book book) {
bookDao.save(book);
return true;
}
public boolean update(Book book) {
bookDao.update(book);
return true;
}
public boolean delete(int id) {
bookDao.delete(id);
return true;
}
public Book getById(int id) {
if (id<0){
//模拟业务异常
throw new BusinessException(Code.BUSINESS_ERR,"查询id不能为负数!");
}else if (id==0){
//模拟系统异常
throw new SystemException(Code.SYSTEM_TIMEOUT_ERR,"系统繁忙请稍后再试!");
}
if (id==1){
//模拟其他异常
int i=1/0;
}
return bookDao.getById(id);
}
public List<Book> getAll() {
return bookDao.getAll();
}
}
3、处理系统异常和业务异常发给前端做页面处理
package com.itheima.controller;
import com.itheima.exception.BusinessException;
import com.itheima.exception.SystemException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
//rest风格的异常处理器(包含@Controller和@ResponseBody)
@RestControllerAdvice
public class PojectExceptionAdvice {
//处理异常的类型
@ExceptionHandler(Exception.class)
//处理其它异常
public Result doException(Exception exc){
//记录日志
//发送消息给运维
//发送邮件给开发人员,ex对象发送给开发人员
return new Result(666,null,"你真厉害,搞出了其他异常!");
}
//处理业务异常
//BusinessException.class,拦截自定义的BusinessException异常到这里处理
@ExceptionHandler(BusinessException.class)
public Result doBusinessException(BusinessException exception){
//向前台发送:异常编码(code)、异常的数据(data)出现异常则返回null,异常提示(message)
return new Result(exception.getCode(),null,exception.getMessage());
}
//处理系统异常
//SystemException,拦截自定义的SystemException异常到这里处理
@ExceptionHandler(SystemException.class)
public Result doSystemException(SystemException exception){
//记录日志
//发送消息给运维
//发送邮件给开发人员,ex对象发送给开发人员
//向前台发送:异常编码(code)、出现异常的数据(data)出现异常则返回null,异常提示(message)
return new Result(exception.getCode(),null,exception.getMessage());
}
}
4、前台接收的结果