在项目开发过程中,不管是对底层数据库的操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到各种可预知的、不可预知的异常需要处理。如果对每个过程都单独作异常处理,那系统的代码耦合度会变得很高,此外,开发工作量也会加大而且不好统一,这也增加了代码的维护成本。
针对这种实际情况,我们需要将所有类型的异常处理从各处理过程解耦出来,这样既保证了相关处理过程的功能单一,也实现了异常信息的统一处理和维护。同时,我们也不希望直接把异常抛给用户,应该对异常进行处理,对错误信息进行封装,然后返回一个友好的信息给用户。
方法如下:
1. 定义返回的统一 json 结构
import lombok.Data; @Data public class EJson { /** * 异常码 */ protected String code; /** * 异常信息 */ protected String msg; public EJson() { this.code = "200"; this.msg = "操作成功"; } public EJson(String code, String msg) { this.code = code; this.msg = msg; } }
2. 处理系统异常
新建一个 GlobalExceptionHandler 全局异常处理类,
@ControllerAdvice 注解即可拦截项目中抛出的异常
@ResponseBody 注解是为了异常处理完之后给调用方输出一个 json 格式的封装 数据。
如下:
第一个拦截异常:参数缺失的时候,会抛出 HttpMessageNotReadableException
第二个拦截异常:空指针异常, NullPointerException
以此类推: 可以定义更多的异常.....................
最后把再定义一个 Exception异常, 前边没有被拦截的异常,统统都会在这里被拦截
Exception 异常是父类,所有异常都会继承该异常,所以我们可以直接拦截 Exception 异常,一劳永逸
@ControllerAdvice @ResponseBody public class GlobalExceptionHandler { // 打印log private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class); /** * 缺少请求参数异常 * @param ex HttpMessageNotReadableException * @return */ @ExceptionHandler(MissingServletRequestParameterException.class) @ResponseStatus(value = HttpStatus.BAD_REQUEST) public EJson handleHttpMessageNotReadableException( MissingServletRequestParameterException ex) { logger.error("缺少请求参数,{}", ex.getMessage()); return new EJson("400", "缺少必要的请求参数"); } /** * 空指针异常 * @param ex NullPointerException * @return */ @ExceptionHandler(NullPointerException.class) @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR) public EJson handleTypeMismatchException(NullPointerException ex) { logger.error("空指针异常,{}", ex.getMessage()); return new EJson("500", "空指针异常了"); } /** * 系统异常 预期以外异常 * @param ex * @return */ @ExceptionHandler(Exception.class) @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR) public EJson handleUnexpectedServer(Exception ex) { logger.error("系统异常:", ex); return new EJson("500", "系统发生异常,请联系管理员"); } }
定义控制器做个测试:
@RestController @RequestMapping("/exception") public class ExceptionController { private static final Logger logger = LoggerFactory.getLogger(ExceptionController.class); @PostMapping("/test") public EJson test(@RequestParam("name") String name, @RequestParam("sex") String sex) { logger.info("name:{}", name); logger.info("sex:{}", sex); return new EJson(); } @RequestMapping("/null") public EJson test1(String name,String sex){ if(sex.equals("男")){ logger.info("性别:{}",sex); } return new EJson(); } @RequestMapping("/byzero") public EJson test2(){ int result = 1 / 0; return new EJson(); } }
通过Postman访问做个测试