spring全局异常定义@ControllerAdvice和@ExceptionHandler

什么是@ControllerAdvice

查看源码的相关注释:
@ControllerAdvice是一个特殊的@Component,用于标识一个类,这个类中被以下三种注解标识的方法:@ExceptionHandler,@InitBinder,@ModelAttribute,将作用于所有的@Controller类的接口上。

个人看起来,觉得像是@controller的增强类,可以对所有的相关接口进行辅助操作。关于Advice,在Spring的AOP中,是用来封装一个切面所有属性的,包括切入点和需要织入的切面逻辑。这里ControllerAdvice也可以这么理解,其抽象级别应该是用于对Controller进行切面环绕的,而具体的业务织入方式则是通过结合其他的注解来实现的.

如何在代码中定义全局的异常处理

@ControllerAdvice结合@ExceptionHandler,可以统一处理来自前后端交互产生的异常,并设置到Result对象中,返回给前端,保持系统风格一致。

/**
  *全局异常处理类
  *用于接收@Controller类抛出的异常并处理
 */
@ControllerAdvice(basePackages={""})
@Slf4j
public class GlobalExceptionHandler {

 
    @ResponseBody
    @ExceptionHandler(value = Exception.class) //指定拦截异常类型,可自定义异常类
    @ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR) //自定义浏览器返回状态码
    public Result<String> handle(Exception e) {
     return GlobalExceptionHandler.mapExceptionToResult(e);
    }
	
	//此方法可以针对不同的异常进行相应处理
	public static  Result<String> mapExceptionToResult(Exception e){
	//SystemException、WarnException可以由自己定义异常
		if(e instanceof SystemException){
		SystemException s=(SystemException)e;
		return s.toResult();
		}else if(e instanceof WarnException){
		WarnException w=(WarnException)e;
		return w.toResult();
		}
		
		return null;
	}
}

//自定义异常类

@Slf4j
@Data
public  class WarnException extends RuntimeException{

    /**
     * 异常流水号
     */
    protected final String seqNo;

    /**
     * 抛出异常的源服务信息, appid + : + ip
     */
    protected final String sourceService;

    /**
     * 错误码
     */
    protected final String errorCode;

    /**
     * 抛出异常的源服务信息
     */
    public volatile static String sourceServiceCache;


    private static final RespLevel RESP_LEVEL = "警告信息-用户输入不合适、不合法";


    public WarnException(String message){
        this((String)null, message);
    }

    public WarnException(String message, Throwable t){
        this(message, null, t);
    }

    public WarnException(String errorCode, String message){
        this(errorCode, message, null, null, null);
    }

    public WarnException(String message, String seqNo, Throwable t){
        this(message, seqNo, null, t);
    }

    public WarnException(String message, String seqNo, String sourceService){
        this(null, message, seqNo, sourceService, null);
    }

    public WarnException(String message, String seqNo, String sourceService, Throwable t){
        this(null, message, seqNo, sourceService, t);
    }

    public WarnException(String errorCode, String message, String seqNo, String sourceService){
        this(errorCode, message, seqNo, sourceService, null);
    }

    public WarnException(String errorCode, String message, String seqNo, String sourceService, Throwable t){
        super(message, t);
        this.errorCode = StringUtils.defaultString(errorCode, Result.FALSE_CODE);
        this.seqNo = StringUtils.defaultString(seqNo, generateSeqNo());
        this.sourceService = StringUtils.defaultIfBlank(sourceService, sourceServiceCache);
    }

  /**
     * 生成日志流水号
     * 格式为 年月日时分秒毫秒(17位)+7位随机字符串,共24位
     * */
    private String generateSeqNo(){
        int length=7;
            SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmssSSS");
            Calendar c= Calendar.getInstance();
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < length; i++) {
                sb.append(new Random().nextInt(10));
            }
            return format.format(c.getTime())+sb.toString();
    }


    /**
     * 将异常转换成接口响应数据
     * @param <T>
     * @return
     */
    public <T> Result<T> toResult(){
        Result<T> result = new Result<>();
        String message = getMessage();
        String seqNo = getSeqNo();
        result.setErrorMessage(message, getErrorCode());
        result.setErrorSeqNo(seqNo);
        result.setLevel(RESP_LEVEL );
        result.setSourceService(getSourceService());
        return result;
    }
}

//自定义返回给前端的数据类型

@ApiModel(value = "restful接口响应结果")
@Data
public class Result<T> {

    public static final String SUCCESS = "S";
    public static final String FALSE = "F";
    public static final String SUCCESS_CODE = "000000";
    public static final String FALSE_CODE = "999999";
    public static final String SUCCESS_MSG = "操作成功";
    public static final String FALSE_MSG = "操作失败";
    public static final String FAILED_MSG = "系统暂时无法处理您的操作,请联系管理员";// 默认的异常提示

    @ApiModelProperty(name = "returnStatus", value = "接口执行状态:S-成功,F-失败", notes = "新建默认为失败")
    private String returnStatus = FALSE;

    @ApiModelProperty(name = "returnCode", value = "接口返回码:000000-成功,非000000-失败", notes = "错误码定义见XXX,默认失败码为999999")
    private String returnCode = FALSE_CODE;

    @ApiModelProperty(name = "errorSeqNo", value = "异常信息流水号")
    private String errorSeqNo;

    @ApiModelProperty(name = "returnMessage", value = "接口返消息", notes = "")
    private String returnMessage = FALSE_MSG;

    @ApiModelProperty(value = "异常源服务信息, 比如90195:192.168.1.1")
    private String sourceService;

    @ApiModelProperty(value = "响应信息等级, WARN-用户输入不合适、不合法, ERROR-系统错误, NOTICE-常规提示信息")
    private RespLevel level;

    @ApiModelProperty(name = "data", value = "返回数据", notes = "")
    private T data;

    public Result() {
        super();
    }

    public static <T> Result<T> getSuccessResultInstance() {
        Result<T> result = new Result<>();
        result.setSuccess();
        return result;
    }

    public static <T> Result<T> getSuccessResultDataInstance(T data) {
        Result<T> result = new Result<>();
        result.setSuccess();
        result.setData(data);
        return result;
    }

    public static <T> Result<T> getSuccessResultInstance(String returnMessage) {
        Result<T> result = new Result<>();
        result.setSuccessWithMessage(returnMessage);
        return result;
    }

    public static <T> Result<T> getFalseResultInstance() {
        return new Result<>();
    }

    public static <T> Result<T> getFalseResultInstance(String errorMessage) {
        Result<T> result = new Result<>();
        result.setErrorMessageWithDefaultErrorCode(errorMessage);
        return result;
    }

    public static <T> Result<T> getFalseResultInstance(String errorMessage, T data) {
        Result<T> result = new Result<>();
        result.setErrorMessageWithDefaultErrorCode(errorMessage);
        result.setData(data);
        return result;
    }

    public static <T> Result<T> getSuccessResulInstance(String successMessage, String successCode) {
        Result<T> result = new Result<>();
        result.setSuccessMessage(successMessage, successCode);
        return result;
    }

    public static <T> Result<T> getExceptionResultInstance(String errorMessage, String errorCode, String errorSeqNo) {
        Result<T> result = new Result<>();
        result.setErrorMessage(errorMessage, errorCode);
        result.setErrorSeqNo(errorSeqNo);
        return result;
    }

    public static <T> Result<T> getFalseResultInstance(String errorMessage, String errorCode) {
        Result<T> result = new Result<>();
        result.setErrorMessage(errorMessage, errorCode);
        return result;
    }

 

    /**
     * 设置消息为成功
     */
    public void setSuccess() {
        this.returnStatus = SUCCESS;
        this.returnCode = SUCCESS_CODE;
        this.returnMessage = SUCCESS_MSG;
    }

    public void setSuccessWithMessage(String returnMessage) {
        this.returnStatus = SUCCESS;
        this.returnCode = SUCCESS_CODE;
        this.returnMessage = returnMessage;
    }

    /**
     * 返回默认错误码999999
     */
    public void setErrorMessageWithDefaultErrorCode(String errorMessage) {
        this.returnMessage = errorMessage;
    }

    public void setErrorMessage(String errorMessage, String errorCode) {
        this.returnMessage = errorMessage;
        this.returnCode = errorCode;
    }

    private void setSuccessMessage(String successMessage, String successCode) {
        this.returnStatus = SUCCESS;
        this.returnMessage = successMessage;
        this.returnCode = successCode;
    }

    @JsonIgnore
    public boolean isAllSuccess() {
        return SUCCESS.equals(returnStatus) && SUCCESS_CODE.equals(returnCode);
    }

    /**
     * 将接口响应转换成系统的功能异常,如果接口是成功的,则返回null
     * @return
     */
    public WarnException toException(){
        RespLevel level = getLevel();
        if (FALSE.equals(getReturnStatus())){
            if (level == RespLevel.WARN){
                return new WarnException(getReturnCode(), getReturnMessage(), getErrorSeqNo(), getSourceService());
            }
            return new SystemException(getReturnCode(), getReturnMessage(), getErrorSeqNo(), getSourceService());
        }
        return null;
    }

    /**
     * 返回成功
     * @param data
     * @param <T>
     * @return
     */
    public static <T> Result<T> succeed(T data){
        return succeed(SUCCESS_MSG, data);
    }

    /**
     * 返回成功, 指定信息
     * @param message 成功提示信息
     * @param data
     * @param <T>
     * @return
     */
    public static <T> Result<T> succeed(String message, T data){
        return succeed(SUCCESS_CODE, message, data);
    }

    /**
     * 返回成功
     * @param data
     * @param <T>
     * @return
     */
    public static <T> Result<T> succeed(String code, String message, T data){
        return new Result<>(SUCCESS, SUCCESS_CODE, message, RespLevel.SUCCESS, null, null, data);
    }

    /**
     * 返回失败, 默认的提示信息
     * @param <T>
     * @return
     */
    public static <T> Result<T> error(){
        return error(FAILED_MSG);
    }

    /**
     *  返回失败, 指定信息
     * @param message
     * @param <T>S
     * @return
     */
    public static <T> Result<T> error(String message){
        return new Result<T>(FALSE, FALSE_CODE, message, RespLevel.ERROR, BizException.generateSeqNo(), SystemException.sourceServiceCache);
    }

    /**
     * 返回警告, 用户输入错误,如参数不合法、入口错误等
     * @param message 警告提示信息, 提示用户修改
     * @param <T>
     * @return
     */
    public static <T> Result<T> warn(String message){
        return new Result<>(FALSE, FALSE_CODE, message, RespLevel.WARN, null, WarnException.sourceServiceCache);
    }

    /**
     * 返回notice类型的消息
     * @param message
     * @param <T>
     * @return
     */
    public static <T> Result<T> info(String message){
        return new Result<>(SUCCESS, SUCCESS_CODE, message, RespLevel.INFO, null, null);
    }

    private Result(String returnStatus, String code, String message){
        this(returnStatus, code, message, RespLevel.INFO, null, null);
    }

    private Result(String returnStatus, String code, String message, RespLevel level, String seqNo, String sourceService){
        this(returnStatus, code, message, level, seqNo, sourceService, null);
    }

    private Result(String returnStatus, String code, String message, RespLevel level, String seqNo, String sourceService, T data){
        this.returnStatus = returnStatus;
        this.returnCode = code;
        this.returnMessage = message;
        this.level = level;
        this.errorSeqNo = seqNo;
        this.sourceService = sourceService;
        this.data = data;
    }

}

//controller层

@RestController
@Slf4j
public class QuotaController{
    @Autowired
    IQuotaService iQuotaService;

	//此方法抛出的异常都可以被全局异常类处理,包括其iQuotaInfoService类的具体实现中也可以,使用throw
	// if ("".equals(a)) {
    //        throw new WarnException("eee");
   //     }
    public Result<QuotaRsp> getQuotatail(QuotaReq quotaReq) {
        QuotaRsp quotaRsp = iQuotaInfoService.quota(quotaReq);
        return Result.getSuccessResultDataInstance(quotaRsp);
    }
  }

其他:
@RestControllerAdvice = @ControllerAdvice+ @ResponseBody

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值