Bootstrap

@RestControllerAdvice 和@ControllerAdvice 的注解使用

@RestControllerAdvice 和@ControllerAdvice 的注解使用

我们的异常得到期望的返回格式,就需要用到了@ControllerAdvice或者@RestControllerAdvice
而ControllerAdvice 和 RestControllerAdvice 区别也就是 和 Controller 和 RestCOntroller 一样了。
基于现在springboot 和 rest 风格的开发,这里就阐述@RestControllerAdvice ,来解决异常返回统一格式

@RestControllerAdvice

/**
 * 拦截异常并统一处理
 */
@Slf4j
@RestControllerAdvice
@Order(value = Ordered.HIGHEST_PRECEDENCE)
public class GlobalExceptionHandler {

    /**
     * 异常错误
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public RongheResponse HandleException(Exception e){
        log.error("系统内部异常,异常信息:", e);
        return new RongheResponse().message("内部异常");
    }

    /**
     * 系统内部业务错误
     */
    @ExceptionHandler(value = ServiceException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public RongheResponse handleParamsInvalidException(ServiceException e) {
        log.error("系统错误:{}", e.getMessage());
        return new RongheResponse().message(e.getMessage());
    }

    /**
     * 统一处理请求参数校验(普通传参)
     */
    @ExceptionHandler(value = ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public RongheResponse handleConstraintViolationException(ConstraintViolationException e){
        log.error("统一处理请求参数校验(普通传参)");
        StringBuilder message = new StringBuilder();
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        for (ConstraintViolation<?> violation : violations) {
            Path path = violation.getPropertyPath();
            String[] pathArr = StringUtils.splitByWholeSeparatorPreserveAllTokens(path.toString(), ".");
            message.append(pathArr[1]).append(violation.getMessage()).append(",");
        }
        message = new StringBuilder(message.substring(0, message.length() - 1));
        return new RongheResponse().message(message.toString());
    }

    /**
     * 统一处理请求参数校验(实体对象传参)
     *
     * @param e BindException
     * @return SixsectorResponse
     */
    @ExceptionHandler(BindException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public RongheResponse validExceptionHandler(BindException e) {
        log.info("统一处理请求参数校验(实体对象传参)");
        StringBuilder message = new StringBuilder();
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        for (FieldError error : fieldErrors) {
            message.append(error.getField()).append(error.getDefaultMessage()).append(",");
        }
        message = new StringBuilder(message.substring(0, message.length() - 1));
        return new RongheResponse().message(message.toString());
    }
	
	// 异常可以有很多自定义的Exception

	// 异常也可以有乐观锁这些问题。
    
}

把返回的json 类也写上

public class RongheResponse extends HashMap<String, Object> {

    private static final long serialVersionUID = -8713837118340960775L;

    public RongheResponse message(String message) {
        this.put("message", message);
        return this;
    }

    public RongheResponse data(Object data) {
        this.put("data", data);
        return this;
    }

    @Override
    public RongheResponse put(String key, Object value) {
        super.put(key, value);
        return this;
    }
}

自定义的异常类

/**
 * 业务处理异常类
 *
 */
public class ServiceException extends RuntimeException {
    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = -5376671034328576604L;

    public ServiceException() {
        super(BaseMessageCode.ERROR_SYSTEM_ERROR);
    }

    public ServiceException(String message) {
        super(message);
    }

    public ServiceException(String message, Throwable cause) {
        super(message, cause);
    }
}

在测试之前,再简单说一个 @Validated@Valid 注解在本案例中的用处
@Validated 注解是让 普通传参 上的注解搭配使用的
@Valid 注解 是让 实体对象传参 上的注解搭配使用的

@RestController
@Validated  
@RequestMapping("/v3")
public class TestController {

    @Autowired
    UserRedisService userRedisService;

    @GetMapping("/get2")  
    public void get2(){  // "message": "哈哈哈哈"
        throw new ServiceException("哈哈哈哈");
    }

    @GetMapping("/get3")
    public void get3(){  //"message": "内部异常"
        int i = 4/0;
    }

    @GetMapping("/get6")
    public void get6( @NotBlank(message = "{required}") String id){ //统一处理请求参数校验(普通传参)
        System.out.println(id);
    }

    @GetMapping("/get4")
    public void get4(@RequestParam(value = "message" , required = true) String message){  // "message": "内部异常"
        System.out.println(message);
    }

    @GetMapping("/get5")
    public void get5(@Valid StudentVO studentVO){  // 统一处理请求参数校验(实体对象传参)
        System.out.println(studentVO);
    }
}

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;