异常是不可避免的,但是我们可以最大限制的去处理异常,让用户体验更好。下面先介绍异常对的几种处理方式。本次先介绍基于@ControllerAdvice注解的Controller层的全局异常统一处理,后面会出一篇用AOP来实现的全局异常处理。
开发环境:
win10+IntelliJ IDEA +JDK1.8
springboot版本:springboot 1.5.14 ——2.0后的springboot增加了挺多新特性,暂时先不做了解
xml version="1.0" encoding="UTF-8"?>xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.wen demo 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.14.RELEASE UTF-8 UTF-8 1.8 org.springframework.boot spring-boot-starter-web org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin
开发前先提醒,小编用了lombok插件,该插件让代码极其精简。如果你看到
@Slf4j
@Slf4j相当于:
Logger logger= LoggerFactory.getLogger(this.getClass());
而@Data注解
@Data //相当于帮你写完了get-set还有toString方法
Ok,废话说完,我们先准备个数据返回的实体(主要用于API数据返回格式)
package com.wen.springboot_test.ResultResponse; import lombok.Data; import java.io.Serializable; /** * 返回对象包装类(带泛型) */ @Data public class ResultBean<T> implements Serializable { private static final long serialVersionUID = 1L; public static final int NO_LOGIN = -1; public static final int SUCCESS = 0; public static final int CHECK_FAIL = 1; public static final int NO_PERMISSION = 2; public static final int UNKNOWN_EXCEPTION = -99; /** * 返回的信息(主要出错的时候使用) */ private String msg = "success"; /** * 接口返回码, 0表示成功, 其他看对应的定义 * 0 : 成功 * >0 : 表示已知的异常(例如提示错误等, 需要调用地方单独处理) * <0 : 表示未知的异常(不需要单独处理, 调用方统一处理) */ private int code = SUCCESS; /** * 返回的数据 */ private T data; public ResultBean() { super(); } public ResultBean(T data) { super(); this.data = data; } public ResultBean(Throwable e) { super(); this.msg = e.toString(); this.code = UNKNOWN_EXCEPTION; } }
既然是异常处理,我们总得需要一个自定义异常吧,自定义异常也很简单,就写了个CheckException来做测试
package com.wen.springboot_test.exception; import lombok.Data; /** * 自定义异常,主要用于校验错误异常 * */ public class CheckException extends RuntimeException { private static final long serialVersionUID = 1L; public CheckException() { } public CheckException(String message) { super(message); } public CheckException(Throwable cause) { super(cause); } public CheckException(String message, Throwable cause) { super(message, cause); } public CheckException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } }这两个写完,还少了控制器和异常处理器吧。。Go
package com.wen.springboot_test.controller; import com.wen.springboot_test.ResultResponse.ResultBean; import com.wen.springboot_test.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * 随便写一个Controller,为了简单点, * 方法就一个,传id来判断要抛什么异常 */ @RestController public class HelloController { @Autowired UserService userService; /** * 传id来判断抛什么异常 * @param id * @return */ @RequestMapping(value="test") public ResultBean hello(Integer id ){ return new ResultBean(userService.throwException(id)); } }异常处理器如下:
package com.wen.springboot_test.HandlerException; import com.wen.springboot_test.ResultResponse.ResultBean; import com.wen.springboot_test.exception.CheckException; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; /** * 异常处理器 */ @ControllerAdvice @Slf4j public class HandlerException { /** * 处理未知异常 * @param e * @return */ @ExceptionHandler(value=Exception.class) @ResponseBody public ResultBean unknowException(Exception e){ e.printStackTrace(); ResultBean resultBean =new ResultBean(); resultBean.setCode(ResultBean.UNKNOWN_EXCEPTION); resultBean.setMsg("系统出现未知异常,请于管理员联系"); /** * 未知异常的话,这里写逻辑,发邮件,发短信都可以、、 */ return resultBean; } /** * 处理已知异常 * @param e * @return */ @ExceptionHandler(value = CheckException.class) @ResponseBody public ResultBean handlerCheckException(CheckException e){ log.info("发生了已知错误:"+e.getMessage()); ResultBean resultBean =new ResultBean(); resultBean.setCode(ResultBean.CHECK_FAIL); resultBean.setMsg(e.getMessage()); return resultBean; } }下面就是service,逻辑处理层了。
package com.wen.springboot_test.service; public interface UserService { String throwException(Integer id); }实现类
package com.wen.springboot_test.service.Impl; import com.wen.springboot_test.exception.CheckException; import com.wen.springboot_test.service.UserService; import org.springframework.stereotype.Service; @Service public class UserServiceImpl implements UserService { @Override public String throwException(Integer id) { if (id==0) { throw new CheckException("已知异常啦"); }else if (id==1){ /** * 这里出个除以0异常 ,当做一个未知异常 */ Integer e=id/0; } return "这里不出异常"; } }
到这里,代码基本编写完成了。是不是很简单。写完要测试,这是个好习惯。运行main方法。访问来试着访问以下。
带个id参数主要是为了测试不同异常,懒得写多个Controller了。。
完整项目案例:
https://github.com/LuckToMeet-Dian-N/springboot_Learn_3
springboot的全局异常处理的方式还是挺多的。每种都有自己的优缺点。本次案例的主要演示的是自定义异常。也是我们比较常用的异常处理吧。后面将出一篇用AOP来实现异常处理的博文。最后祝大家学习进步,步步高升。
程序人生,与君共勉~