通常在我们的项目中,在参数的校验,执行失败,校验返回值时业如果有业务异常,我们通常是原地进行异常的信息编写和抛出,如果业务异常使用频繁,代码看上去就很很杂乱。 我这里提供一种优雅抛出异常的方式
版本信息
springBoot 2.4.2 jdk11
具体步骤
- 定义一个异常接口
/**
* @author lyne
* @date 2022/9/11
*/
public interface ErrorCode {
/**
* 获取错误信息
* @return msg
*/
String getMsg();
/**
* 获取错误码
* @return code
*/
int getCode();
}
2.然后根据具体的业务领域创建一个或这多个的实现类,因为异常实体一旦定义,就不轻易修改,所以我推荐使用枚举类继承接口 下面随意定义基础异常实体
/**
* @author lyne
* @date 2022/9/11
*/
public enum BaseErrorCode implements ErrorCode {
/**
* 空值错误
*/
NULLError(5000, "参数不能为空!");
private final int code;
private final String msg;
@Override
public String getMsg() {
return this.msg;
}
@Override
public int getCode() {
return this.code;
}
BaseErrorCode(int code, String msg) {
this.code = code;
this.msg = msg;
}
}
- 在定义异常实体后,我们需要定义一个静态方法以便我们快速的使用 这里就写了个简单的方法集合,更多的功能还请结合实际需要增补
/**
* @author lyne
* @date 2022/9/11
*/
public class When {
public static <T> void emptyReturnError(T t, ErrorCode errorCode) {
if (t == null) nullReturnError(null, errorCode);
if (t instanceof String) {
if (((String) t).length() == 0) {
returnError(errorCode);
}
}
if (t instanceof Collection) {
if (((Collection<?>) t).isEmpty()) {
returnError(errorCode);
}
}
}
public static <T> void nullReturnError(T t, ErrorCode errorCode) {
if (t == null) {
returnError(errorCode);
}
}
public static void trueReturnError(boolean t, ErrorCode errorCode) {
if (t) {
returnError(errorCode);
}
}
public static void falseReturnError(boolean t, ErrorCode errorCode) {
trueReturnError(!t, errorCode);
}
public static void returnError(ErrorCode errorCode) {
throw new BaseException(errorCode.getCode(), errorCode.getMsg());
}
}
- 我们可以直接对异常拦截器进行改造以便入参兼容异常枚举类,也可以像本文中所写的那样兼容原有的异常入参处理。
@ExceptionHandler(value = BaseException.class)
public R<?> baseExceptionHandler(HttpServletRequest request, BaseException e) {
log.error("请求地址:{}; 业务异常:{}", request.getRequestURI(), e.getMessage());
return R.error(e.getMessage());
}
统一JSON实体
/**
* 前端返回体
* {"success": true, "code", 2000, "msg": "", "obj": null}
*
* @author lyne
* @date 2022/8/18
*/
@Data
public class R<T> implements Serializable {
private static final long serialVersionUID = 1L;
public static final String DEFAULT_SUCCESS_MESSAGE = "请求成功";
public static final String DEFAULT_ERROR_MESSAGE = "请求失败";
private static final int CODE_SUCCESS = 2000;
private static final int CODE_ERROR = 5000;
/**
* 是否成功
*/
private boolean success = true;
/**
* 状态码
*/
private int code;
/**
* 返回信息
*/
private String msg;
/**
* 返回实体
*/
private T obj;
public static <T> R<T> error(String msg) {
return error(CODE_ERROR, msg.trim().isEmpty() ? DEFAULT_ERROR_MESSAGE : msg);
}
public static <T> R<T> error(int code, String msg) {
return error(code, msg, null);
}
public static <T> R<T> error(int code, String msg, T obj) {
return create(code, msg.trim().isEmpty() ? DEFAULT_ERROR_MESSAGE : msg, obj);
}
public static <T> R<T> success(String msg) {
return success(CODE_SUCCESS, msg.trim().isEmpty() ? DEFAULT_SUCCESS_MESSAGE : msg);
}
public static <T> R<T> success(int code, String msg) {
return success(code, msg, null);
}
public static <T> R<T> success(String msg, T obj) {
return success(CODE_SUCCESS, msg, obj);
}
public static <T> R<T> success(int code, T obj) {
return success(code, "请求成功", obj);
}
public static <T> R<T> success(int code, String msg, T obj) {
return create(code, msg.trim().isEmpty() ? DEFAULT_SUCCESS_MESSAGE : msg, obj);
}
private static <T> R<T> create(int code, String msg, T obj){
R<T> ajaxR = new R<>();
ajaxR.code = code;
ajaxR.msg = msg;
ajaxR.obj = obj;
return ajaxR;
}
}
- 到这里就完成了业务异常的改造工作,下面就是具体的使用 这里截取了摸鱼君的部分代码
/**
* @author lyne
* @date 2022/10/7
*/
public enum UserErrorCode implements ErrorCode {
PASSWORD_MD5_LENGTH_ERROR(40001, "请使用MD5摘要算法对密码进行加密处理"),
USERNAME_OR_PASSWORD_ERROR(40002, "账号或密码不正确"),
USER_NOT_FOUND_ERROR(40003, "未找到该用户!"),
ADMIN_USER_FORBID_DISABLE(40004, "管理员账户无法禁用"),
USER_EMAIL_MAIL_CODE_ERROR(40004, "邮箱验证码不正确!"),
;
private final int code;
private final String msg;
UserErrorCode(int code, String msg) {
this.code = code;
this.msg = msg;
}
@Override
public String getMsg() {
return this.msg;
}
@Override
public int getCode() {
return this.code;
}
}
@Override
public R<String> resetPassword(LoginDto userDto) {
// 校验密码长度
When.trueReturnError(userDto.getPassword().length() != 32, UserErrorCode.PASSWORD_MD5_LENGTH_ERROR);
String mailCode = redisService.getCacheObject(Constants.User.KEY_MAIL_CODE + userDto.getEmail());
When.emptyReturnError(mailCode, UserErrorCode.USER_EMAIL_MAIL_CODE_ERROR);
When.trueReturnError(!mailCode.equals(userDto.getVerifyCode()), UserErrorCode.USER_EMAIL_MAIL_CODE_ERROR);
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
if (StrUtil.isNotBlank(userDto.getAccountId())) {
queryWrapper.eq(User.T_ID, userDto.getAccountId());
}
if (StrUtil.isNotBlank(userDto.getEmail())) {
queryWrapper.eq(User.T_EMAIL, userDto.getEmail());
}
User sysUser = getById(queryWrapper);
When.nullReturnError(sysUser, UserErrorCode.USER_NOT_FOUND_ERROR);
sysUser.setPassword(bCryptPasswordEncoder.encode(userDto.getPassword()));
updateById(sysUser);
logout();
return R.success("重置密码成功!");
}