实现效果:不同的业务模块用不同的错误编码
一、错误码封装
获取错误信息接口类,所有的错误都要统一实现该接口类
public interface BaseErrorCode {
/**
* 获取错误码
* @return int
*/
int getCode();
/**
* 获取错误提示
* @return String
*/
String getMsg();
/**
* 获取错误状态
* @return HttpStatus
*/
HttpStatus getStatus();
}
错误异常始祖抽象类定义,所有的错误信息都是通过该类去实现
@Getter
public abstract class BaseException extends RuntimeException {
private BaseErrorCode error;
private Object data ;
public BaseException(BaseErrorCode error, Object data) {
super(error.getMsg());
this.error = error;
this.data=data;
}
protected BaseException(BaseErrorCode error, Object data, Throwable cause) {
super(error.getMsg(), cause);
this.error = error;
this.data=data;
}
}
统一异常响应类,反馈给前端信息
@Data
public class ErrorResponse {
private int code;
@JsonIgnore
private int status;
private String msg;
private String path;
private Date dateTime;
private Object data = new Object();
private Boolean success=false;
public ErrorResponse() {
}
/**
* 服务器未知错误(非业务类错误)
* @param msg 错误信息
* @param path 访问接口
*/
public ErrorResponse(String msg,String path) {
this(100000, 500, msg, path, null);
}
public ErrorResponse(BaseException ex, String path) {
this(ex.getError().getCode(), ex.getError().getStatus().value(),LocalUtil.getErrorMsg(ex)==null?ex.getError().getMsg():LocalUtil.getErrorMsg(ex), path, ex.getData());
}
public ErrorResponse(int code, int status, String message, String path, Object data) {
this.code = code;
this.status = status;
this.msg = message;
this.path = path;
this.dateTime = new Date();
this.data=data;
}
}
错误枚举定义举例
@Getter
public enum CommonErrorCode implements BaseErrorCode {
/**
* 成功
*/
OK(100000, HttpStatus.BAD_REQUEST, "成功"),
/**
* 错误请求
*/
BAD_REQUEST(100001, HttpStatus.BAD_REQUEST, "错误请求"),
/**
* 服务器异常
*/
INTERNAL_SERVER_ERROR(100002, HttpStatus.INTERNAL_SERVER_ERROR, "服务器异常"),
/**
* 超过API限制的访问次数
*/
TOO_MANY_REQUESTS(100003, HttpStatus.TOO_MANY_REQUESTS, "超过API限制的访问次数"),
/**
* 超过API一天访问次数
*/
DAILY_TOO_MANY_REQUESTS(100004, HttpStatus.TOO_MANY_REQUESTS, "超过API一天访问次数");
private final int code;
private final HttpStatus status;
private final String msg;
CommonErrorCode(int code, HttpStatus status, String msg) {
this.code = code;
this.status = status;
this.msg = msg;
}
}
@Getter
public enum UserErrorCode implements BaseErrorCode {
/**
* 用户未被授权
*/
USER_UNAUTHORIZED(101001, HttpStatus.UNAUTHORIZED, "未被授权"),
/**
* 用户权限不足
*/
USER_FORBIDDEN(101002, HttpStatus.FORBIDDEN, "权限不足"),
/**
* 超过接口使用次数
*/
EXCEEDED_API_USAGE_TIMES(101003, HttpStatus.FORBIDDEN, "超过接口使用次数"),
/**
* token已过期
*/
TOKEN_HAS_EXPIRED(101004, HttpStatus.FORBIDDEN, "token已过期"),
/**
* token不支持
*/
TOKEN_DOES_NOT_SUPPORT(101005, HttpStatus.FORBIDDEN, "token不支持"),
/**
* token格式不对
*/
BAD_Token_Format(101006, HttpStatus.FORBIDDEN, "token格式不对"),
/**
* token签名不对
*/
BAD_TOKEN_SIGNATURE(101007, HttpStatus.FORBIDDEN, "token签名不对"),
/**
* token格式转换错误
*/
TOKEN_FORMAT_CONVERSION_ERROR(101008, HttpStatus.FORBIDDEN, "token格式转换错误"),
/**
* 无效token
*/
INVALID_TOKEN(101009, HttpStatus.FORBIDDEN, "无效token"),
;
private final int code;
private final HttpStatus status;
private final String msg;
UserErrorCode(int code, HttpStatus status, String msg) {
this.code = code;
this.status = status;
this.msg = msg;
}
}
错误异常定义举例
public class CommonException extends BaseException {
public CommonException(CommonErrorCode errorCode, Object data) {
super(errorCode, data);
}
public CommonException(CommonErrorCode errorCode) {
super(errorCode, null);
}
}
public class UserException extends BaseException {
public UserException(UserErrorCode errorCode,Object data) {
super(errorCode, data);
}
public UserException(UserErrorCode errorCode) {
super(errorCode, null);
}
}
全局异常处理
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 参数校验异常
* @param ex 校验异常
* @return ErrorResponse
*/
@ExceptionHandler({BindException.class, MethodArgumentNotValidException.class})
@ResponseStatus(HttpStatus.FORBIDDEN)
public ErrorResponse validExceptionHandler(Exception ex ,HttpServletRequest request) {
String errMsg = null;
if (ex instanceof BindException) {
errMsg = ((BindException) ex).getBindingResult().getFieldErrors()
.stream().map(error -> error.getField() + ":" +error.getDefaultMessage())
.collect(Collectors.joining(";"));
} else if (ex instanceof MethodArgumentNotValidException) {
errMsg = ((MethodArgumentNotValidException) ex).getBindingResult().getFieldErrors()
.stream().map(error -> error.getField() + ":" + error.getDefaultMessage())
.collect(Collectors.joining(";"));
}
log.error(errMsg);
return this.handleBusinessException(new CommonException(CommonErrorCode.BAD_REQUEST,errMsg),request);
}
/**
* 业务异常
* @param ex 业务异常
* @param request 请求
* @return ErrorResponse
*/
@ExceptionHandler(BaseException.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResponse handleBusinessException(BaseException ex, HttpServletRequest request) {
log.error("业务异常:url:{},参数:{}", request.getRequestURI(), request.getQueryString(), ex);
return new ErrorResponse(ex, request.getRequestURI());
}
/**
* 最后兜底的异常
* @param ex 异常
*/
@ExceptionHandler({Exception.class})
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResponse exceptionHandler(Exception ex,HttpServletRequest request) {
log.error("最后兜底的异常:url:{},参数:{}", request.getRequestURI(), request.getQueryString(), ex);
return this.handleBusinessException(new CommonException(CommonErrorCode.INTERNAL_SERVER_ERROR,ex.getMessage()),request);
}
}
二、国际化封装
编写多语言文件:
@Configuration
public class LocalLanguageConfig {
/**
* 默认解析器 其中locale表示默认语言
*/
@Bean
public LocaleResolver localeResolver() {
AcceptHeaderLocaleResolver acceptHeaderLocaleResolver = new AcceptHeaderLocaleResolver();
return acceptHeaderLocaleResolver;
}
}
/**
* 改变语言解析逻辑
*/
class LanguageLocalResolvers extends AcceptHeaderLocaleResolver {
/**
* 语言类型
*/
List<Locale> locales = Arrays.asList(new Locale("en"), new Locale("zh"));
@Override
public Locale resolveLocale(HttpServletRequest request) {
String headerLang = request.getHeader("Accept-Language");
return headerLang == null || headerLang.isEmpty()
? Locale.CHINESE
: Locale.lookup(Locale.LanguageRange.parse(headerLang), locales);
}
}
@Slf4j
@Component
public class LocalUtil {
private static MessageSource messageSource;
public LocalUtil(MessageSource messageSource) {
LocalUtil.messageSource = messageSource;
}
/**
* 翻译错误提示
*/
public static String getErrorMsg(BaseException ex) {
try {
return messageSource.getMessage(String.valueOf(ex.getError().getCode()), null, LocaleContextHolder.getLocale());
} catch (NoSuchMessageException e) {
log.error(" 翻译错误:{}",e.getMessage());
return null;
}
}
/**
* 翻译错误提示
*/
public static String getErrorMsg(String errorCode){
try {
return messageSource.getMessage(errorCode, null, LocaleContextHolder.getLocale());
} catch (NoSuchMessageException e) {
log.error(" 翻译错误:{}",e.getMessage());
return null;
}
}
}
三、最终效果
英文:
中文: