java架构统一处理异常

22 篇文章 0 订阅
2 篇文章 0 订阅

该统一异常处理基于springboot架构,利用切面技术,在service层或者controller层抛出异常后,被控制层切面捕获,转换后统一返回

1、切面:控制层异常类,HandlerExceptionAspect.java

/**
 * 控制层异常切面
 */
@Slf4j
@ControllerAdvice
public class HandlerExceptionAspect {
    /**
     * 统一处理JSON响应结果的错误结果 例如:{"code":201,message:"入参异常",data:null}
     *
     * @param cause   {@link Throwable} 异常
     * @param request {@link HttpServletRequest} 请求
     * @return {@link CommonResult} 响应结果
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public CommonResult process(Throwable cause, HttpServletRequest request, HttpServletResponse response) {
        CommonResult result;
        if (cause instanceof WyjmRPCException) {
            result = new CommonResult(((WyjmRPCException) cause).getCode(), cause.getMessage());
      
        } else if (cause instanceof MethodArgumentNotValidException) {
            String errorMessage = this.methodArgumentMessage((MethodArgumentNotValidException) cause);
            result = new CommonResult(CodeEnum.INCORRECT_REQ_PARAM.getCode(), errorMessage);
        } else if (cause instanceof SingleParamException) {
            String errorMessage = CodeEnum.getMessageByCode(Integer.valueOf(cause.getMessage()));
            result = new CommonResult(CodeEnum.INCORRECT_REQ_PARAM.getCode(), errorMessage);
     //等等异常分类
        } else {
            result = new CommonResult(CodeEnum.UNKOWN_ERROR.getCode(), CodeEnum.UNKOWN_ERROR.getMessage());
        }
        this.setHeader(request, response);
        log.error("error:{}", cause);
        return result;
    }

    /**
     * 参数异常消息获取
     *
     * @param cause 参数异常
     * @return 异常原因
     */
    private String methodArgumentMessage(MethodArgumentNotValidException cause) {
        MethodArgumentNotValidException validException = cause;
        BindingResult bindingResult = validException.getBindingResult();
        List<ObjectError> allErrors = bindingResult.getAllErrors();
        StringBuilder builder = new StringBuilder();
        for (ObjectError objectError : allErrors) {
            if (StringUtils.isNotBlank(objectError.getDefaultMessage())) {
                if (StringUtils.isNotBlank(builder)) {
                    builder.append(";");
                }
                builder.append(objectError.getDefaultMessage());
            }

        }
        if (StringUtils.isBlank(builder)) {
            builder.append(CodeEnum.INCORRECT_REQ_PARAM.getMessage());
        }
        return builder.toString();
    }

    /**
     * 响应头部跨域设置
     * @param request
     * @param response
     */
    private void setHeader(HttpServletRequest request, HttpServletResponse response) {
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
    }
}

2、异常基类:WyjmException.java,继承RuntimeException异常类

/**
 * 通用异常
 *
 */
@ToString
public class WyjmException extends RuntimeException {

    private static final long serialVersionUID = 111820440373615072L;

    /**
     * 异常代码
     */
    private int code;
    /**
     * 异常消息
     */
    private String message;

    public WyjmException(CodeEnum codeEnum) {
        this.code = codeEnum.getCode();
        this.message = codeEnum.getMessage();
    }

    public WyjmException(int code, String message) {
        super(message);
        this.code = code;
        this.message = message;
    }

    public WyjmException(int code, String message, Throwable cause) {
        super(message, cause);
        this.code = code;
        this.message = message;
    }

   //code、message的get\set方法

}

3、具体抛出异常类:WyjmRPCException、WyjmServiceException等代码类似,用来区别该异常是在哪个地方抛出,

public class WyjmRPCException extends WyjmException implements Serializable{
    public WyjmRPCException(CodeEnum codeEnum) {
        super(codeEnum);
    }

    public WyjmRPCException(int code, String message) {
        super(code, message);
    }

    public WyjmRPCException(int code, String message, Throwable cause) {
        super(code, message, cause);
    }
}
/**
 * 方法参数验证异常
 */
public class SingleParamException extends ServletRequestBindingException {
    /**
     * 异常结构
     * @param msg
     */
    public SingleParamException(String msg) {
        super(StringUtils.isEmpty(msg) ? "999" : msg);
    }
}

4、枚举类:CodeEnum

/**
 * 应答码枚举类
 * 
 * @create 2018-8-21
 */
public enum CodeEnum {
	/**
	 * 未登陆
	 */
	USER_NOT_LOGIN(100, "未登陆"),
	/**
	 * 未注册
	 */
	USER_NOT_REGISTER(101, "用户未注册")
    //等等

    /**
	 * 响应代码
	 */
	private final int code;

	/**
	 * 响应消息
	 */
	private final String message;

	CodeEnum(int _code, String _message) {

		this.code = _code;
		this.message = _message;

	}

	public int getCode() {
		return code;
	}

	public String getMessage() {
		return message;
	}

	/**
	 * 通过枚举code获取对应的message
	 * 
	 * @return 取不到时返回null
	 */
	public static String getMessageByCode(int code) {
		for (CodeEnum _enum : values()) {
			if (_enum.getCode() == code) {
				return _enum.getMessage();
			}
		}
		return null;
	}

	/**
	 * 通过枚举code获取枚举对象
	 * 
	 * @return 取不到时返回null
	 */
	public static CodeEnum getByCode(int code) {
		for (CodeEnum _enum : values()) {
			if (_enum.getCode() == code) {
				return _enum;
			}
		}
		return null;
	}

}

5、统一返回包装类:CommonResult

/**
 * 响应结果
 */
@Data
public class CommonResult<T> {
    /**
     * 应答码
     *
     * @see 默认值为操作成功
     */
    private int code = CodeEnum.SUCCESS.getCode();
    /**
     * 应答码描述
     *
     * @see 默认值为操作成功
     */
    private String message = CodeEnum.SUCCESS.getMessage();
    /**
     * 应答数据体
     *
     * @see 可以为空
     */
    private T data;

    public CommonResult() {
        this(CodeEnum.SUCCESS.getCode(), CodeEnum.SUCCESS.getMessage(), null);
    }

    public CommonResult(CodeEnum codeEnum) {
        this(codeEnum.getCode(), codeEnum.getMessage(), null);
    }

    /**
     * 默认返回的code=CodeEnum.SUCCESS.getCode()
     */
    public CommonResult(T data) {
        this(CodeEnum.SUCCESS.getCode(), CodeEnum.SUCCESS.getMessage(), data);
    }

    /**
     * 默认返回的data=null
     */
    public CommonResult(int code, String message) {
        this(code, message, null);
    }

    public CommonResult(int code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    /** 判断返回结果是否成功 */
    public boolean success() {
        return code == CodeEnum.SUCCESS.getCode();
    }
}

6、在service层使用:


@Slf4j
@Service
public class ProductCategoryServiceImpl implements ProductCategoryService {

    @Override
    public List<ProductCategoryResVO> getCategories(ProductCategoryReqVO req) {
        ProductJSFResult<List<CategoryResponseDTO>> result =
                categoryJSFService.searchCategories(req.getParentId(), ProductConstants.CATEGORY_LEVEL_ALL_NODE);
        if (!result.success()) {
            log.error("根据parentId获取分类数据失败 code={} msg={}", result.getCode(), result.getMessage());
            throw new WyjmException(CodeEnum.NOT_DATA);
        }
        log.info("根据parentId获取分类数据 parentId={} result={}", req.getParentId(), JSON.toJSONString(result.getData()));
        return transform(result.getData(), req.getParentId() == 0 ? Boolean.TRUE : Boolean.FALSE, req.getParentId());
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值