在使用 spring boot 开发 rest 接口的时候,如果在 controller 中出现了未处理的异常,默认会返回500 错误。如果我们希望在某些条件下返回一个特定的 HTTP CODE(如404),可以这么做。
@RequestMapping("/student/{name}")
public ResponseEntity<?> getStudent(@PathVariable(name = "name") String studentName) {
StudentEntity student = studentRepository.findByStudentName(studentName);
if (student != null) {
return new ResponseEntity<>(student, HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
返回一个 ResponseEntity<?> 类型的值,正常情况下直接返回一个对象,否则,可以返回一个特定的 http code。也可以同时返回 code 和 body。
这种情况可以动态返回 HTTP Code,但对 Swagger 不友好,在 Swagger-UI 上看不出来你要返回的数据格式。
有时候,我们可能忘记了做错误处理,controller 中出现了我们没有想到的异常。spring boot对异常处理提供了很多支持,但我比较常用的是两种方式,分别是 controller 级别错误处理的和全局的错误处理。
public class FooController{
//...
@ExceptionHandler({ CustomException1.class, CustomException2.class })
public void handleException() {
//
}
}
这种方式是在一个 controller 内部使用 @ExceptionHandler 标注一个方法,指定该方法来处理当前controller 内所有未处理的异常。
以下代码使用了 @ControllerAdvice 注解,并使用了多个 @ExceptionHandler 注解。他们的处理流程就像 try–catch一样,异常类型一样时,优先进入对应的catch块中,没有定义对应的catch块的话,则进入 Exception 的 catch 块中。
@ControllerAdvice
public class GlobalExceptionHandler {
Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(value = IllegalArgumentException.class)
@ResponseBody
public ResponseEntity<String> parameterErrorHandler(HttpServletRequest req, IllegalArgumentException e) {
return new ResponseEntity(e.getMessage(), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(value = Exception.class)
@ResponseBody
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public void othersErrorHandler(HttpServletRequest req, Exception e) throws Exception {
String url = req.getRequestURI();
logger.error("request error at " + url, e);
}
}
上面的处理逻辑如下:
controller 中未处理的 IllegalArgumentException 异常会由 parameterErrorHandler 方法处理,其他所有 controller 中未处理的异常都会交给othersErrorHandler方法处理。