返回http code

在使用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不友好,在swaggerui上看不出来你要返回的数据格式。

错误处理

但有时候,我们可能忘记了做错误处理,controller中出现了我们没有想到的异常。spring boot对异常处理提供了很多支持,但我比较常用的是两种方式,分别是controller级别错误处理的和全局的错误处理

controller级别的错误处理

public class FooController{
     
    //...
    @ExceptionHandler({ CustomException1.class, CustomException2.class })
    public void handleException() {
        //
    }
}

这种方式是在一个controller内部使用@ExceptionHandler标注一个方法,指定该方法来处理当前controller内所有未处理的异常。

使用@ControllerAdvice实现全局的错误处理

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

}

上面的代码使用了@ControllerAdvice注解,并使用了多个@ExceptionHandler注解。他们的处理流程就像try–catch一样,异常类型一样时,优先进入对应的catch块中,没有定义对应的catch块的话,则进入Exception的catch块中。上面的处理逻辑就是:
controller中未处理的IllegalArgumentException异常会由parameterErrorHandler方法处理,其他所有controller中未处理的异常都会交给othersErrorHandler方法处理。

总之,推荐使用@ControllerAdvice注解来处理异常,有以下好处:

  • controller中的方法的返回值不必设置为ResponseEntity,直接设置为正常情况下返回的数据类型即可,如果条件不满足,可以手动(且放心)抛异常。这样的话,既满足了逻辑完整性,也对swagger比较友好
  • 如果controller中出现了意料之外的异常,会有最终的地方来处理(记录下日志并返回你希望的内容)
  • 可以自定义一个或一些自己的异常,更加个性化地返回内容和HTTP Code。