全局异常处理区分返回响应类型是页面还是JSON

一、准备工作

1.1 导入依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- thymeleaf模板依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

1.2 在 /templates 目录下新建 error 页面

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head lang="en">
    <meta charset="UTF-8"/>
    <title>统一页面异常处理</title>
</head>
<body>
<h1>统一页面异常处理</h1>
<div th:text="${message}"></div>
</body>
</html>

1.3 定义异常基类

@Data
public class BaseException extends RuntimeException {

    /**
     * 错误码
     */
    private Integer code;

    /**
     * 错误提示
     */
    private String message;

    public BaseException(Integer code, String message) {
        this.code = code;
        this.message = message;
    }

}  

二、根据 URL 后缀区分

2.1 创建 URL 异常类

@Data
public class UrlSuffixException extends BaseException {

    public UrlSuffixException(Integer code, String message) {
        super(code, message);
    }

}

2.2 申明接口

@Controller
@RequestMapping("/error")
public class ExceptionController {


    @RequestMapping("/url.html")
    public void throwsUrlSuffixExceptionByHtml() {
        throw new UrlSuffixException(0001, "throwUrlSuffixException");
    }

    @RequestMapping("/url.json")
    public void throwsUrlSuffixExceptionByJson() {
        throw new UrlSuffixException(0001, "throwUrlSuffixException");
    }
}

2.3 全局异常处理 UrlSuffixException

@ControllerAdvice
public class GlobalExceptionHandle {

    private static final String URL_SUFFIX_JSON = ".json";

    @ExceptionHandler(UrlSuffixException.class)
    public ModelAndView handleException(HttpServletRequest request, UrlSuffixException exception) {
        String url = request.getRequestURL().toString();
        if (url.endsWith(URL_SUFFIX_JSON)) {
            ModelAndView modelAndView = new ModelAndView(new MappingJackson2JsonView());
            modelAndView.addObject("code", exception.getCode());
            modelAndView.addObject("message", exception.getMessage());
            return modelAndView;
        } else {
            ModelAndView modelAndView = new ModelAndView("/error");
            modelAndView.addObject("message", exception.getMessage());
            return modelAndView;
        }
    }

}

2.4 测试

访问http://localhost:8080/error/url.json

{
    message: "throwUrlSuffixException",
    code: 1001
}

访问 `http://localhost:8080/error/url.html

全局异常处理区分返回响应类型是页面还是JSON

三、根据注解区分

3.1 创建注解异常类

@Data
public class AnnotationException extends BaseException {

    public AnnotationException(Integer code, String message) {
        super(code, message);
    }
}

3.2 申明接口

@Controller
@RequestMapping("/error")
public class ExceptionController {
    @RequestMapping("/annotation/html")
    public void throwsAnnotationExceptionByHtml() {
        throw new AnnotationException(2000, "throwAnnotationException");
    }

    @RequestMapping("/annotation/json")
    @ResponseBody
    public String throwsAnnotationExceptionByJson() {
        throw new AnnotationException(2001, "throwAnnotationException");
    }
}    

3.3 全局异常处理

@ControllerAdvice
public class GlobalExceptionHandle {

    @ExceptionHandler(AnnotationException.class)
    public ModelAndView handleException(AnnotationException exception, HandlerMethod handler) {
        if (isReturnJson(handler)) {
            ModelAndView modelAndView = new ModelAndView(new MappingJackson2JsonView());
            modelAndView.addObject("code", exception.getCode());
            modelAndView.addObject("message", exception.getMessage());
            return modelAndView;
        } else {
            ModelAndView modelAndView = new ModelAndView("/error");
            modelAndView.addObject("message", exception.getMessage());
            return modelAndView;
        }
    }
  
    private boolean isReturnJson(HandlerMethod handler) {
        if (handler.getBeanType().isAnnotationPresent(RestController.class)) {
            return true;
        }
        Method method = handler.getMethod();
        if (method.isAnnotationPresent(ResponseBody.class)) {
            return true;
        }
        return false;
    }    
}    

3.4 测试

访问 http://localhost:8080/error/annotation/json

{
    message: "throwAnnotationException",
    code: 2001
}

访问 `http://localhost:8080/error/annotation/html

全局异常处理区分返回响应类型是页面还是JSON

四、根据是否是 AJAX 请求区分

4.1 创建异常类

@Data
public class AjaxRequestException extends BaseException {
    public AjaxRequestException(Integer code, String message) {
        super(code, message);
    }
}

4.2 申明接口

@Controller
@RequestMapping("/error")
public class ExceptionController {
    @RequestMapping("/request")
    @ResponseBody
    public String throwsAjaxRequestException() {
        throw new AjaxRequestException(3000, "throwAjaxRequestException");
    }
}    

4.3 全局异常处理

@ControllerAdvice
public class GlobalExceptionHandle {

    @ExceptionHandler(AjaxRequestException.class)
    public ModelAndView handleException(HttpServletRequest request, AjaxRequestException exception) {
        if (isAjaxRequest(request)) {
            ModelAndView modelAndView = new ModelAndView(new MappingJackson2JsonView());
            modelAndView.addObject("code", exception.getCode());
            modelAndView.addObject("message", exception.getMessage());
            return modelAndView;
        } else {
            ModelAndView modelAndView = new ModelAndView("/error");//配置需要跳转的Controller方法
            modelAndView.addObject("message", exception.getMessage());
            return modelAndView;
        }
    }

    private boolean isAjaxRequest(HttpServletRequest request) {
        String accept = request.getHeader("accept");
        if (accept != null && accept.indexOf("application/json") != -1) {
            return true;
        }

        String xRequestedWith = request.getHeader("X-Requested-With");
        if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1) {
            return true;
        }

        String uri = request.getRequestURI();
        if (uri.endsWith(".json") || uri.endsWith(".xml")) {
            return true;
        }

        String ajax = request.getParameter("__ajax");
        if (ajax.endsWith("json") || ajax.endsWith("xml")) {
            return true;
        }
        return false;
    }
}    

4.4 测试

访问http://localhost:8080/error/request

全局异常处理区分返回响应类型是页面还是JSON

ajax 形式访问http://localhost:8080/error/request

全局异常处理区分返回响应类型是页面还是JSON

上一篇:SpringBoot自定义全局异常返回页面


下一篇:SpringMVC框架-传入Map集合