SpringBoot自定义错误码,并支持国际化

实现效果:不同的业务模块用不同的错误编码

一、错误码封装

获取错误信息接口类,所有的错误都要统一实现该接口类

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;
        }
    }

}

三、最终效果

英文:

中文:

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在开发过程中,我们常常需要自定义状态码,以更好地向客户端返回请求的结果。在SpringBoot中,我们可以轻松地自定义状态码,如下所述: 首先,我们需要创建一个自定义的异常类,继承RuntimeException类,并添加一个有参的构造方法,其中包含自定义的状态码和消息。例如: public class MyException extends RuntimeException { private Integer code; private String message; public MyException(Integer code, String message) { this.code = code; this.message = message; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } @Override public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } 然后,在Controller类中,我们可以使用@ExceptionHandler注解来捕获自定义异常,并将状态码和消息作为响应返回。例如: @RestController public class MyController { @RequestMapping(value = "/test", method = RequestMethod.GET) public String test() { throw new MyException(1001, "自定义异常错误信息"); } @ExceptionHandler(MyException.class) public ResponseEntity<Result<String>> handleMyException(MyException e) { return ResponseEntity.status(e.getCode()).body(Result.error(e.getMessage())); } } 在上面的例子中,我们在test()方法中抛出了自定义异常,然后在handleMyException()方法中捕获该异常,并将状态码和消息作为响应返回。 总之,在SpringBoot自定义状态码非常简单,我们只需创建一个继承RuntimeException的异常类,并在Controller中使用@ExceptionHandler注解来捕获自定义异常并返回响应即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值