SpringBoot项目自定义异常,配置全局异常统一处理,避免出
2021-03-22 本文已影响0人
天不生我小金
前言:该博客主要是记录自己学习的过程,方便以后查看,当然也希望能够帮到大家。
完整代码地址在结尾!!
第一步,创建一个SpringBoot项目,此处不赘述
第二步,编写application.yml配置文件,如下
server:
port: 8085
spring:
application:
name: exception-demo-server
第三步,创建响应码枚举ResponseEnums,统一响应类Response,如下
ResponseEnums
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @version 1.0
* @author jinhaoxun
* @date 2018-05-09
* @description 响应码枚举
*/
@Getter
@AllArgsConstructor
public enum ResponseEnums {
/**
* 请求成功
*/
SUCCESS(200,"请求成功"),
/**
* 系统异常,请稍后重试
*/
EXCEPTION(10000,"系统异常,请稍后重试"),
/**
* 请求的资源(网页等)不存在
*/
NOT_FOUND(404,"请求的资源(网页等)不存在"),
/**
* 共6位,1:系统异常码和值定义在该类中,大家公用
* 前2位表示大板块(10:系统,11:管理后台模块,12:文章模块,13:公共模块,14:上传下载文件模块)
* 第3,4位表示项目的小模块,5,6位代表具体错误
*/
/************************** 系统模块 *******************************/
/**
* 登陆超时
*/
LOGIN_TIMEOUT(100001 ,"登陆超时"),
/**
* 参数有误
*/
WRONG_PARAM(100002 ,"参数有误"),
/**
* 缺少必要的参数
*/
MISS_PARAM(100003 ,"缺少必要的参数"),
/**
* Hystrix 降级开启抛出异常
*/
HYSTRIX_THROW_EXCEPTION(100004 ,"请求超时,请稍后重试"),
/************************** 账号模块 *******************************/
/**
* 您没有该权限
*/
MNG_PERMISSION_DENY(110101,"您没有该权限"),
/**
* 密码错误
*/
PASSWORD_WRONG(110102,"密码错误"),
/**
* 用户不存在
*/
USER_NOT_EXIST(110103,"用户不存在"),
/**
* 账号被封禁
*/
ACCOUNT_IS_BLOCKED(110104,"账号被封禁"),
/**
* 账号已注销
*/
ACCOUNT_IS_CANCELLED(110105,"账号已注销"),
/**
* 验证码已过期
*/
VERIFICATION_CODE_EXPIRED(110106,"验证码已过期"),
/**
* 从Redis中获取验证码错误
*/
GET_CODE_WRONG_FROM_REDIS(110107,"从Redis中获取验证码错误"),
/**
* 身份信息已过期
*/
IDENTITY_INFORMATION_IS_EXPIRED(110108,"身份信息已过期"),
/**
* 用户未登录
*/
USER_NOT_LOG_IN(110109,"用户未登录"),
/**
* 用户退出登录失败
*/
USER_LOG_OUT_FAIL(110110,"用户退出登录失败"),
/**
* 密码修改失败
*/
PASSWORD_CHANGE_FAIL(110112,"密码修改失败"),
/**
* 账号封禁失败
*/
ACCOUNT_BLOCK_FAIL(110113,"账号封禁失败"),
/**
* 账号解封失败
*/
ACCOUNT_UNSEALING_FAIL(110114,"账号解封失败"),
/**
* 账号注册失败
*/
ACCOUNT_REGISTRATION_FAIL(110115,"账号注册失败"),
/**
* 获取手机验证码失败
*/
GET_PHONE_CODE_FAIL(110116,"获取手机验证码失败"),
/**
* 获取邮箱验证码失败
*/
GET_EMAIL_CODE_FAIL(110117,"获取邮箱验证码失败"),
/**
* 获取用户信息失败
*/
GET_USERINFO_FAIL(110118,"获取用户信息失败"),
/**
* 更新用户信息失败
*/
UPDATE_USERINFO_FAIL(110119,"更新用户信息失败"),
/**
* 账号注销失败
*/
ACCOUNT_CANAEL_FAIL(110120,"账号注销失败"),
/**
* 重复获取验证码
*/
REPEAT_GET_USER_LOG_IN_CODE(110121,"重复获取验证码"),
/**
* 验证码已过期
*/
USER_LOG_IN_CODE_EXPIRATIONED(110122,"验证码已过期"),
/**
* 验证码错误
*/
USER_LOG_IN_CODE_WRONG(110123,"验证码错误"),
;
public Integer code;
public String msg;
}
Response
import com.luoyu.exception.constant.ResponseEnums;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* Response
*
* @author luoyu
* @date 2018/10/07 13:28
* @description 通用返回类
*/
@Data
public class Response implements Serializable {
private String msg;
private int code;
private Object data;
private String time;
private Response() {
}
private Response(int code, String msg) {
this.code = code;
this.msg = msg;
this.time = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now());
}
private Response(int code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
this.time = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now());
}
public static Response success() {
return new Response(ResponseEnums.SUCCESS.getCode(), ResponseEnums.SUCCESS.getMsg());
}
public static Response success(Object data) {
return new Response(ResponseEnums.SUCCESS.getCode(), ResponseEnums.SUCCESS.getMsg(), data);
}
public static Response success(Object data, String msg) {
return new Response(ResponseEnums.SUCCESS.getCode(), msg, data);
}
public static Response fail() {
return new Response(ResponseEnums.EXCEPTION.getCode(), ResponseEnums.EXCEPTION.getMsg());
}
public static Response fail(ResponseEnums responseEnums) {
return new Response(responseEnums.getCode(), responseEnums.getMsg());
}
public static Response fail(ResponseEnums responseEnums, Object data) {
return new Response(responseEnums.getCode(), responseEnums.getMsg(), data);
}
public static Response fail(int code, String msg) {
return new Response(code, msg);
}
public static Response fail(int code, String msg, Object data) {
return new Response(code, msg, data);
}
}
第四步,创建自定义异常类CustomException,如下
import lombok.Data;
import java.io.Serializable;
/**
* @version 1.0
* @author jinhaoxun
* @date 2018-05-09
* @description 自定义统一异常(相当于业务异常)
*/
@Data
public class CustomException extends Exception implements Serializable {
private static final long serialVersionUID = 1L;
private Integer code;
private String log;
/**
* @author jinhaoxun
* @description 构造器
* @param code 异常状态码
* @param log 异常打印日志
* @param msg 异常返回信息
*/
public CustomException(Integer code, String log, String msg) {
super(msg);
this.code = code;
this.log = log;
}
}
第五步,创建全局异常统一处理类ExceptionHandle,如下
import com.luoyu.exception.constant.ResponseEnums;
import com.luoyu.exception.entity.vo.Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* @version 1.0
* @author jinhaoxun
* @date 2018-05-09
* @description 统一的异常处理
*/
@Slf4j
@RestControllerAdvice
public class ExceptionHandle {
/**
* @author jinhaoxun
* @description 统一的异常处理方法
* @param e 抛出的异常
* @return 返回给前端的错误信息提示
*/
@ExceptionHandler(value = Exception.class)
public Response handleException(Exception e){
if(e instanceof CustomException) {
CustomException ex = (CustomException)e;
log.info("自定义业务异常:msg:" + ex.getMessage() + ",log:" + ex.getLog(), e);
return Response.fail(ex.getCode(), ex.getMessage(),null);
}else if(e instanceof MethodArgumentNotValidException) {
MethodArgumentNotValidException ex = (MethodArgumentNotValidException)e;
log.error("参数校验异常:msg:" + ex.getBindingResult().getFieldError().getDefaultMessage());
return Response.fail(ResponseEnums.WRONG_PARAM.getCode(),
ResponseEnums.WRONG_PARAM.getMsg() + ":"
+ ex.getBindingResult().getFieldError().getDefaultMessage(), null);
}else{
log.error("统一系统异常:msg:" + e.getMessage(), e);
return Response.fail(ResponseEnums.EXCEPTION.getCode(), ResponseEnums.EXCEPTION.getMsg(), null);
}
}
}
说明
- @ExceptionHandler用于统一处理某一类异常,从而能够减少代码重复率和复杂度,所有抛出来的异常都会在这里被捕获
第六步,创建TestService,TestServiceImpl,TestController,如下
TestService
/**
* @Description:
* @Author: jinhaoxun
* @Date: 2020/7/10 10:31 上午
* @Version: 1.0.0
*/
public interface TestService {
void get1() throws Exception;
void get2() throws Exception;
}
TestServiceImpl
import com.luoyu.exception.exception.CustomException;
import com.luoyu.exception.service.TestService;
import org.springframework.stereotype.Service;
/**
* @Description:
* @Author: jinhaoxun
* @Date: 2020/7/10 10:32 上午
* @Version: 1.0.0
*/
@Service
public class TestServiceImpl implements TestService {
@Override
public void get1() throws Exception {
int i = 1/0;
}
@Override
public void get2() throws Exception {
try {
int i = 1/0;
}catch (Exception e){
throw new CustomException(10086, "自定义打印异常", "自定义返回异常");
}
}
}
TestController
import com.luoyu.exception.entity.vo.Response;
import com.luoyu.exception.service.TestService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @Description:
* @Author: jinhaoxun
* @Date: 2020/7/10 10:31 上午
* @Version: 1.0.0
*/
@RestController
@RequestMapping("/test")
public class TestController {
@Resource
private TestService testService;
/**
* @author jinhaoxun
* @description 测试接口1
*/
@GetMapping("/get1")
public Response get1() throws Exception {
testService.get1();
return Response.success();
}
/**
* @author jinhaoxun
* @description 测试接口2
*/
@GetMapping("/get2")
public Response get2() throws Exception {
testService.get2();
return Response.success();
}
}
解释
- 从可能出现异常的地方往外面抛异常,本文是从service开始,直到controller往外面抛出异常后,会被ExceptionHandle捕获,然后自行进行处理,打印日志,统一状态码,错误信息返回给前端。
第七步,启动项目,使用postman调接口,如下图
测试1,使用GET请求http://localhost:8085/test/get1
image.pngimage.png
测试2,使用GET请求http://localhost:8085/test/get2
image.pngimage.png
完整代码地址:https://github.com/Jinhx128/springboot-demo
注:此工程包含多个module,本文所用代码均在exception-demo模块下
后记:本次分享到此结束,本人水平有限,难免有错误或遗漏之处,望大家指正和谅解,欢迎评论留言。