我们每次写一个接口,如果抛出一个异常给前端,会造成很不好的体验。如果每个接口都用try...catch包起来,工作量也非常大。
一、ErrorController 的应用
- 首先,我们先模拟异常场景,直接写了个接口,抛出空指针异常
package com.springboot.my.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
public class HelloController {
@RequestMapping("/")
public String index(){
log.info("index ...........");
return "Greetings from Spring Boot!";
}
@RequestMapping("/exception")
public String exception(){
throw new NullPointerException();
}
}
- postman验证,服务端抛出了一次,但是客户端返回了正常的结果。
这是因为 SpringBoot 默认提供了一个 /error 的映射,该映射被注册为 Servlet 容器中的一个全局错误页面用来合理处理所有的异常情况。
- 自定义ErrorController
默认的异常响应报文不符合我们定义的数据规范,我们可以自己定义一个新的 ErrorController,代码如下
Result.java
package com.springboot.my.model;
import lombok.Data;
@Data
public class Result {
private int code;
private String msg;
private Object data;
public Result(int code,String msg){
this.code = code;
this.msg = msg;
}
}
MExceptionController.java
package com.springboot.my.controller;
import com.springboot.my.model.Result;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class MExceptionController implements ErrorController{
@Override
public String getErrorPath() {
return "/error";
}
@RequestMapping
@ResponseBody
public Result doHandleError() {
return new Result(200,"服务器繁忙");
}
}
postman再次验证返回如下,验证成功:
二、ExceptionHandler 的使用
- 我们可以在一个controller中加入如下代码,实现异常的捕捉,经postman验证成功
@ExceptionHandler(Exception.class)
public Result doHandleError() {
return new Result(200,"服务器繁忙");
}
- 当然,如果每个controller都写一遍也很累,所以,我们可以定义一个BaseController,所有其他controller都要继承该父类即可。
package com.springboot.my.controller;
import com.springboot.my.model.Result;
import org.springframework.web.bind.annotation.ExceptionHandler;
public class BaseController {
@ExceptionHandler(Exception.class)
public Result doHandleError() {
return new Result(200,"服务器繁忙");
}
}
- 但是这样还有一个问题,万一哪次忘记继承BaseController了,异常信息又会再次暴露给用户,针对这种问题,我们可以使用注解***@ControllerAdvice ***来解决。代码示例如下,经postman验证通过。
package com.springboot.my.controller;
import com.springboot.my.model.Result;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
@ResponseBody
public class BaseController {
@ExceptionHandler(Exception.class)
public Result doHandleError(Exception e) {
e.printStackTrace();
return new Result(200,"服务器繁忙");
}
}
@ControllerAdvice
该注解是spring2.3以后新增的一个注解,主要是用来Controller的一些公共的需求的低侵入性增强提供辅助。
@ExceptionHandler
该注解是配合@ExceptionHandler一起使用的注解,自定义错误处理器,可自己组装json字符串,并返回到页面。
注:我们可以在@ControllerAdice定义的类中,通过定义多个@ExceptionHandler捕捉不同的异常来实现不同的异常处理