@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);
}
}