目录
为什么使用统一异常处理?
1.软件开发过程中,不可避免的是需要处理各种异常,就我自己来说,至少有一半以上的时间都是在处理各种异常情况,所以代码中就会出现大量的try {…} catch {…} finally {…} 代码块,不仅有大量的冗余代码,而且还影响代码的可读性。
2.使用统一结果处理时,有些异常我们可以提前预知并处理,但是一个运行时异常,我们不一定能预知并处理,这时可以使用统一异常处理,当异常发生时,触发该处理操作,从而保证程序的健壮性
下面开始实战
定义通用结果返回类
为了规范后台开发接口的标准,以及便于前台统一处理接口返回数据,定义一个通用的返回类是必要的。
/**
* @Author: Ambation
* @Description: 通用返回类
* @Date Created in 2023-02-04-20:57
* @Modified By:
*/
@Data
public class BaseResponse<T> implements Serializable {
private static final long serialVersionUID = -2243004256529006189L;
private int code;
private T data;
private String message;
private String description;
public BaseResponse(int code, T data, String message,String description) {
this.code = code;
this.data = data;
this.message = message;
this.description = description;
}
public BaseResponse(int code, T data,String message) {
this(code,data,message,"");
}
public BaseResponse(int code, T data) {
this(code,data,"","");
}
public BaseResponse(ErrorCode code) {
this(code.getCode(),null,code.getMessage(),code.getDescription());
}
}
定义错误码
可分类自定义错误编码,这样可以统一管理(尽量不要跟请求返回的状态码保持一直,比如500,400,404等)
/**
* @Author: Ambation
* @Description: 错误码
* @Date Created in 2023-02-04-21:18
* @Modified By:
*/
public enum ErrorCode{
SUCCESS(0,"ok",""),
PARAM_ERROR(40000,"请求参数错误",""),
NULL_ERROR(40001,"数据为空",""),
NULL_AUTH(40101,"无权限",""),
NOT_LOGIN(40100,"未登录",""),
SYSTEM_ERROR(50000,"系统内部异常","");
private final int code;
/**
* 状态码信息
*/
private final String message;
/**
* 状态码详情
*/
private final String description;
ErrorCode(int code, String message, String description) {
this.code = code;
this.message = message;
this.description = description;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
public String getDescription() {
return description;
}
}
定义返回工具类
减少重复new BaseResponse 返回类,使代码更加简洁
/**
* @Author: Ambation
* @Description: 返回工具类
* @Date Created in 2023-02-04-21:04
* @Modified By:
*/
public class ResultUtils {
/**
* 成功
* @param data
* @param <T>
* @return
*/
public static<T> BaseResponse<T> success(T data){
return new BaseResponse<T>(0,data,"ok");
}
/**
* 失败
* @param errorCode
* @return
*/
public static BaseResponse error(ErrorCode errorCode){
return new BaseResponse<>(errorCode);
}
/**
* 失败
* @param errorCode
* @return
*/
public static BaseResponse error(ErrorCode errorCode,String message,String descrition){
return new BaseResponse<>(errorCode.getCode(),null,message,descrition);
}
/**
* 失败
* @param errorCode
* @return
*/
public static BaseResponse error(ErrorCode errorCode,String message){
return new BaseResponse<>(errorCode.getCode(),message);
}
/**
* 失败
* @param errorCode
* @return
*/
public static BaseResponse error(int errorCode,String message,String descrition){
return new BaseResponse<>(errorCode,null,message,descrition);
}
}
作用展示:
使用返回结果公共类的方法:
@PostMapping("/register")
@ApiOperation("用户注册")
public BaseResponse<Long> userRegister(@RequestBody UserRegisterRequest userRegisterRequest) {
if (Objects.isNull(userRegisterRequest)) {
throw new BusinessException(ErrorCode.PARAM_ERROR);
}
String userAccount = userRegisterRequest.getUserAccount();
String userPassword = userRegisterRequest.getUserPassword();
String checkPassword = userRegisterRequest.getCheckPassword();
String planetCode = userRegisterRequest.getPlanetCode();
if (StringUtils.isAnyBlank(userAccount, userPassword, checkPassword,planetCode)) {
throw new BusinessException(ErrorCode.PARAM_ERROR);
}
long id = userService.userRegister(userAccount, userPassword, checkPassword, planetCode);
return ResultUtils.success(id);
}
未使用返回结果公共类的方法:
@PostMapping("/register")
@ApiOperation("用户注册")
public BaseResponse<Long> userRegister(@RequestBody UserRegisterRequest userRegisterRequest) {
if (Objects.isNull(userRegisterRequest)) {
throw new BusinessException(ErrorCode.PARAM_ERROR);
}
String userAccount = userRegisterRequest.getUserAccount();
String userPassword = userRegisterRequest.getUserPassword();
String checkPassword = userRegisterRequest.getCheckPassword();
String planetCode = userRegisterRequest.getPlanetCode();
if (StringUtils.isAnyBlank(userAccount, userPassword, checkPassword,planetCode)) {
throw new BusinessException(ErrorCode.PARAM_ERROR);
}
long id = userService.userRegister(userAccount, userPassword, checkPassword, planetCode);
return new BaseResponse<>(0, id, null);
}
对比上面两个方法,可以看出第二个方法,每次都要new 一个 BaseResponse 是不是很麻烦,代码看起来也不够整洁。使用返回结果公共类,可以方便管理各种请求返回结果,代码也更加美观。
自定义异常类(可根据业务需求进行扩展)
java有那么多异常类,为啥还要自定义异常?
Java虽然提供了丰富的异常处理类,但是在项目中还会经常使用自定义异常,其主要原因是Java提供的异常类在某些情况下还是不能满足实际需求。例如以下情况:
1、系统中有些错误是符合Java语法,但不符合业务逻辑。
2、在分层的软件结构中,通常是在表现层统一对系统其他层次的异常进行捕获处理。
例如导数据的项目,向Map中存数据,如果最后Map为空,则认为是业务逻辑错误,直接抛出自定义异常,程序结束,并且可显示具体的错误信息。
我之前写过一篇关于异常详解的文章,有需要的小伙伴,可以去看一下
Java异常详解之异常基础_Big_Ambation的博客-CSDN博客
/**
* @Author: Ambation
* @Description: 自定义异常类
* @Date Created in 2023-02-04-21:27
* @Modified By:
*/
public class BusinessException extends RuntimeException{
private final int code;
private final String description;
public BusinessException(String message, int code, String description) {
super(message);
this.code = code;
this.description = description;
}
public BusinessException(ErrorCode errorCode) {
super(errorCode.getMessage());
this.code = errorCode.getCode();
this.description = errorCode.getDescription();
}
public BusinessException(ErrorCode errorCode, String description) {
super(errorCode.getMessage());
this.code = errorCode.getCode();
this.description = description;
}
public int getCode() {
return code;
}
public String getDescription() {
return description;
}
}
全局异常处理类
/**
* @Author: Ambation
* @Description:
* @Date Created in 2023-02-04-21:53
* @Modified By:
*/
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
//捕获自定义异常
@ExceptionHandler(BusinessException.class)
public BaseResponse businessException(BusinessException e) {
log.error("BusinessException:"+ e.getMessage(), e);
return ResultUtils.error(e.getCode(), e.getMessage(),e.getDescription());
}
//捕获所有运行时异常
@ExceptionHandler(RuntimeException.class)
public BaseResponse runtimeExceptionException(RuntimeException e) {
log.error("RuntimeException", e);
return ResultUtils.error(ErrorCode.SYSTEM_ERROR, e.getMessage());
}
}
验证全局异常处理器
postman调用后端接口
当前用户为空,手动抛出异常
进入全局异常处理器,并返回指定的错误信息
今天的分享就先到这里,文章有哪些不足之处,欢迎指出!!!