2019独角兽企业重金招聘Python工程师标准>>>
谈到微服务,必不可免就谈到spring cloud.
笔者正是基于spring cloud架构下的异常处理.
异常,按照业务划分下来,分为三类: 参数校验异常,自定义异常,以及系统异常.
参数校验异常: 通常是缺少参数,参数类型错误,以及相关校验不通过(javax.validation).
通常我们项目一开始,便定义了统一的基础异常类,和统一的错误码.
例如:
- 成功: 2000
- 缺少参数: 5001
- 参数类型错误: 5002
- 参数校验异常: 5003
- 系统异常: 5000
基础异常类:
public abstract class BaseException extends RuntimeException {
private String code = ResultCodeConstant.SYSTEM_ERROR;
public Result getResult() {
return Result.fail(this.code, this.getMessage() != null?this.getMessage():"error");
}
public BaseException() {
}
public BaseException(String message) {
super(message);
}
public BaseException(String code, String message) {
super(message);
this.code = code;
}
public BaseException(String message, Throwable cause) {
super(message, cause);
}
public BaseException(Throwable cause) {
super(cause);
}
public BaseException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public String getCode() {
return this.code;
}
public void setCode(String code) {
this.code = code;
}
}
code常量类:
public class ResultCodeConstant {
public static final String SUCCESS = "2000";//成功
public static final String ARGUMENT_VANISH = "5001";//缺少参数
public static final String ARGUMENT_TYPE_MISMATCH = "5002";//类型错误
public static final String ARGUMENT_CONSTRAINT_VIOLATION = "5003";//参数校验错误
public static final String SYSTEM_ERROR = "5000";
}
对外服务
为了达到对外服务的友好和保密,处理异常时,往往是拦截异常后返回友好结果.
首先约定了对外的结果的封装
public class Result implements Serializable {
private String code;
private String desc;
private T data;
public T getData() {
return this.data;
}
public Result(String code, String desc, T data) {
this.code = code;
this.desc = desc;
this.data = data;
}
public void setData(T data) {
this.data = data;
}
public Result() {
}
public Result(String code, String desc) {
this.code = code;
this.desc = desc;
}
public String getCode() {
return this.code;
}
public void setCode(String code) {
this.code = code;
}
public String getDesc() {
return this.desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String toJsonString() {
return JSONObject.toJSONString(this, new SerializerFeature[]{SerializerFeature.WriteNullStringAsEmpty, SerializerFeature.WriteDateUseDateFormat});
}
public static Result okDesc() {
return new Result(ResultCodeConstant.SUCCESS, "成功");
}
public static Result okDesc(String desc) {
return new Result(ResultCodeConstant.SUCCESS, desc);
}
public static Result ok(Object data) {
return new Result(ResultCodeConstant.SUCCESS, "", data);
}
public static Result ok(String desc, Object data) {
return new Result(ResultCodeConstant.SUCCESS, desc, data);
}
public static Result fail() {
return new Result(ResultCodeConstant.SYSTEM_ERROR, "error");
}
public static Result fail(String dsec) {
return new Result(ResultCodeConstant.SYSTEM_ERROR, dsec);
}
public static Result fail(String code, String dsec) {
return new Result(code, dsec);
}
public static Result fail(String code, String dsec, Object data) {
return new Result(code, dsec, data);
}
}
在spring中,可以通过@ControllerAdvice来拦截controller中抛出的异常
/**
* Created by wenshiliang on 2017/1/16.
*/
@ControllerAdvice()
@ConfigurationProperties
@Slf4j
public class GlobalExceptionHandler {
@Autowired
private CounterService counterService;
public GlobalExceptionHandler() {
log.info("GlobalExceptionHandler构建");
}
@ExceptionHandler(BaseException.class)
@ResponseBody
public Result baseExceptionHandler(BaseException e, HttpServletResponse response) {
log.error("拦截自定义异常", e);
counterService.increment("exception.custom");
return e.getResult();
}
@ExceptionHandler(MissingServletRequestParameterException.class)
@ResponseBody
public Result missingServletRequestParameterExceptionHandler(MissingServletRequestParameterException e,
HttpServletResponse response) {
log.warn("缺少参数", e);
counterService.increment("exception.check");
return Result.fail(ResultCodeConstant.ARGUMENT_VANISH,"缺少参数");
}
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
@ResponseBody
public Result methodArgumentTypeMismatchExceptionExceptionHandler(MethodArgumentTypeMismatchException e,
HttpServletResponse response) {
log.warn("参数类型不正确", e);
counterService.increment("exception.check");
return Result.fail(ResultCodeConstant.ARGUMENT_TYPE_MISMATCH,"参数类型不正确");
}
/**
* 参数校验异常
*
* @param e
* @param response
* @return
*/
@ExceptionHandler(ConstraintViolationException.class)
@ResponseBody
public Result constraintViolationExceptionHandler(ConstraintViolationException e, HttpServletResponse response) {
log.warn("参数校验异常", e);
StringBuilder builder = new StringBuilder();
Set> set = e.getConstraintViolations();
if (set != null && set.size() > 0) {
set.forEach(active -> {
log.warn(active.getRootBeanClass() + active.getMessage());
builder.append(active.getMessage()).append(".");
});
} else {
builder.append("参数校验异常");
}
counterService.increment("exception.check");
return Result.fail(ResultCodeConstant.ARGUMENT_CONSTRAINT_VIOLATION,builder.toString());
}
@ExceptionHandler(BindException.class)
@ResponseBody
public Result BindException(BindException e, HttpServletResponse response) {
log.warn("参数校验异常", e);
counterService.increment("exception.check");
String desc = e.getBindingResult().getFieldError().getDefaultMessage();
return Result.fail(ResultCodeConstant.ARGUMENT_CONSTRAINT_VIOLATION, desc);
}
@ExceptionHandler//处理其他异常
@ResponseBody //
public Result exceptionHandler(Exception e, HttpServletResponse response) {
Result result = null;
log.error("拦截异常", e);
counterService.increment("exception.system");
result = Result.fail();
return result;
}
}
##对内服务