微服务架构统一异常处理规范

2018-04-26  本文已影响0人  花枫天o

1. 统一使用ResponseEntity类 : 用于统一响应格式

2.统一的Error类 : 用于统一异常格式

image.png

3.自定义异常 : 区分不同场景的异常

4.实现ExceptionHandler : 用于拦截处理异常

@ControllerAdvice
public class ExceptionTranslator implements ProblemHandling {

  /**
   * Post-process Problem payload to add the message key for front-end if needed
   */
  @Override
  public ResponseEntity<Problem> process(@Nullable ResponseEntity<Problem> entity, NativeWebRequest request) {
      if (entity == null || entity.getBody() == null) {
          return entity;
      }
      Problem problem = entity.getBody();
      if (!(problem instanceof ConstraintViolationProblem || problem instanceof DefaultProblem)) {
          return entity;
      }
      ProblemBuilder builder = Problem.builder()
        .withType(Problem.DEFAULT_TYPE.equals(problem.getType()) ? ErrorConstants.DEFAULT_TYPE : problem.getType())
        .withStatus(problem.getStatus())
        .withTitle(problem.getTitle())
        .with("path",   request.getNativeRequest(HttpServletRequest.class).getRequestURI());

      if (problem instanceof ConstraintViolationProblem) {
          builder
            .with("violations", ((ConstraintViolationProblem) problem).getViolations())
            .with("message", ErrorConstants.ERR_VALIDATION);
        return new ResponseEntity<>(builder.build(), entity.getHeaders(), entity.getStatusCode());
      } else {
          builder
            .withCause(((DefaultProblem) problem).getCause())
            .withDetail(problem.getDetail())
            .withInstance(problem.getInstance());
        problem.getParameters().forEach(builder::with);
        if (!problem.getParameters().containsKey("message") && problem.getStatus() != null) {
            builder.with("message", "error.http." + problem.getStatus().getStatusCode());
        }
        return new ResponseEntity<>(builder.build(), entity.getHeaders(), entity.getStatusCode());
    }
}

  @Override
  public ResponseEntity<Problem> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, @Nonnull NativeWebRequest request) {
      BindingResult result = ex.getBindingResult();
      List<FieldErrorVM> fieldErrors = result.getFieldErrors().stream()
        .map(f -> new FieldErrorVM(f.getObjectName(), f.getField(), f.getCode()))
        .collect(Collectors.toList());

      Problem problem = Problem.builder()
        .withType(ErrorConstants.CONSTRAINT_VIOLATION_TYPE)
        .withTitle("Method argument not valid")
        .withStatus(defaultConstraintViolationStatus())
        .with("message", ErrorConstants.ERR_VALIDATION)
        .with("fieldErrors", fieldErrors)
        .build();
      return create(ex, problem, request);
  }

  @ExceptionHandler(BadRequestAlertException.class)
  public ResponseEntity<Problem> handleBadRequestAlertException(BadRequestAlertException ex, NativeWebRequest request) {
      return create(ex, request, HeaderUtil.createFailureAlert(ex.getEntityName(), ex.getErrorKey(), ex.getMessage()));
  }

  @ExceptionHandler(ConcurrencyFailureException.class)
  public ResponseEntity<Problem> handleConcurrencyFailure(ConcurrencyFailureException ex, NativeWebRequest request) {
      Problem problem = Problem.builder()
        .withStatus(Status.CONFLICT)
        .with("message", ErrorConstants.ERR_CONCURRENCY_FAILURE)
        .build();
      return create(ex, problem, request);
  }
}

5.统一业务异常抛出

异常统一在service或者controller里面抛出,抛出异常类型为BadRequestAlertException

@PostMapping("/as")
@Timed
public ResponseEntity<A> createA(@Valid @RequestBody A a) throws URISyntaxException {
    log.debug("REST request to save A : {}", a);
    if (a.getId() != null) {
        throw new BadRequestAlertException("A new a cannot already have an ID", ENTITY_NAME, "idexists");
    }
    A result = aService.save(a);
    return ResponseEntity.created(new URI("/api/as/" + result.getId()))
        .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString()))
        .body(result);
}
上一篇 下一篇

猜你喜欢

热点阅读