通用错误处理

在Spring Boot中,Controller中抛出的异常默认交给了/error来处理,应用程序可以将/error映射到一个特定的Controller中处理来代替Spring Boot的默认实现,应用可以继承AbstractErrorController来统一处理系统的各种异常。

pom

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.gcz</groupId>
    <artifactId>errorhandle</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- springboot应用 -->
    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.3.0.RELEASE</version>
    </parent>

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

        <!-- 使用热部署 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- hibernate验证框架 -->
        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>6.0.17.Final</version>
            <scope>compile</scope>
        </dependency>

        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!-- hutool -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.5.9</version>
        </dependency>

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

    <!-- 指定springboot仓库位置 -->
    <repositories>
        <repository>
            <id>milestones</id>
            <name>Spring Milestones</name>
            <url>http://code.yhsperp.com:8081/nexus/repository/maven-public/</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

</project>
复制代码

error.html

复制代码
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>error</title>
</head>
<body>
status:<text th:text="${status}" id="userId"></text>
<br>
errorMessage:<text th:text="${errorMessage}" id="userId"></text>
</body>
</html>
复制代码

controller

复制代码
package com.gcz.controller;

import cn.hutool.json.JSONUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

/**
 * @author guocz
 * @date 20210707
 * 通用错误处理
 */
@Controller
public class ErrorController extends AbstractErrorController {

    Log log = LogFactory.get(ErrorController.class);

    @Autowired
    ObjectMapper objectMapper;

    public ErrorController() {
        super(new DefaultErrorAttributes());
    }

    @RequestMapping("/error")
    public ModelAndView getErrorPath(HttpServletRequest request, HttpServletResponse response) throws IOException {

        Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(request, false));
        // 获取异常,有可能为空
        Throwable cause = getCause(request);
        // 对应于HTTP Status,如404
        int status = (int) model.get("status");
        // 错误信息
        String message = (String) model.get("message");
        // 友好提示
        String errorMessage = getErrorMessage(cause);
        // 后台打印日志信息方便查错
        log.info(status + "," + message, cause);
        response.setStatus(status);
        if (!isJsonRequest(request)) {
            // error.btl模板显示错误的详细信息
            ModelAndView view = new ModelAndView("/error.html");
            view.addAllObjects(model);
            view.addObject("errorMessage", errorMessage);
            view.addObject("status", status);
            view.addObject("cause", cause);
            return view;
        }else {
            Map<String, Object> error = new HashMap<>(16);
            error.put("success", false);
            error.put("errorMessage", errorMessage);
            error.put("message", message);
            response.getWriter().write(JSONUtil.toJsonStr(error));
            response.setCharacterEncoding("utf-8");
            return null;
        }
    }

    protected Throwable getCause(HttpServletRequest request) {
        Throwable error = (Throwable) request.getAttribute("javax.servlet.error.exception");
        if (error != null) {
            // MVC有可能会封装异常成ServletException,需要调用getCause获取真正的异常
            while (error instanceof ServletException && error.getCause() != null) {
                error = error.getCause();
            }
        }
        return error;
    }

    protected String getErrorMessage(Throwable ex) {
        // 自定义异常
//        if (ex instanceof YourApplicationException) {
//            return ex.getMessage();
//        }
        return "服务器错误,请联系管理员";
    }

    protected boolean isJsonRequest(HttpServletRequest request) {
        String requestUri = (String) request.getAttribute("javax.servlet.error.request_uri");
        // 也可通过获取HTTP头,根据Accept字段是否包含JSON来进一步判断,比如
//        return request.getHeader("Accept").contains("application/json");
        return requestUri != null && requestUri.endsWith(".json");
    }

    @Override
    public String getErrorPath() {
        return  null;
    }
}
复制代码

 

posted @   幻影黑子  阅读(80)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示