SpringBoot自定义/error路径失效的解决

 更新时间:2022年01月27日 14:20:56   作者:虎口脱险OvO  
这篇文章主要介绍了SpringBoot自定义/error路径失效的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

SpringBoot自定义/error路径失效

背景

最近使用SpringBoot做controller统一异常处理的时候,配置好映射路径(/error),使用SpringBoot自带的异常通知注解@ControllerAdvice配置好异常处理类,按理说在Controller发生异常的时候重定向到自定义错误页面(这里是重定向到SpringMVC的映射路径),可实际调试的时候却定向到了SpringBoot默认的错误页面。

配置信息

此处配置只是一个小示例,省略了对异常的处理。

@ControllerAdvice(annotations = Controller.class)
public class ExceptionAdvice {    
    @ExceptionHandler({Exception.class})
    // 此方法参数有多个,具体可参考相关文档
    public void handleException(Exception e, HttpServletRequest request, HttpServletResponse response) throws IOException {
       response.sendRedirect(request.getContextPath() + "/error");
    }
}
@Controller
public class HomeController {
    @GetMapping("/error")
    public String getErrorPage(){
        // 此处使用了Thymeleaf模板,返回的是页面
        return "/site/error/500";
    }
}

解决思路

由于我在controller中配置了/error的映射路径,我通过网页路径直接访问该路径也是上面那个错误页面,断点调试也没有进入我自定义的controller。

再看页面显示的状态码,不是404,说明该路径是没有问题的。

这个问题困惑了我很久,一开始没转过弯来。

说下我的解决思路,因为我在使用的SpringBoot配置文件是application.yml,这个文件在idea中会有提示,我在该配置文件中输入了error,如下图:

这里有一个server.error.path=/error,看到这个就大概知道原因了,路径冲突了,我在SpringMVC中配置的映射路径也是error。

尝试验证一下,将SpringMVC的路径修改了一下,果然可以正常访问了。

有没有可以不改变SpringMVC路径的方法呢?我一开始是在application.yml中加入下面这段配置:

server:
  error:
    # 此处可随便写一个路径,或者留空也行,只有不和自定义的error路径冲突
    path: 

这样确实可以解决路径冲突的问题,可是这只是去忽略它,而不是去修改它。

通过查阅资料发现,SpringBoot会为我们创建一个叫BasicErrorController的类,该类由Spring创建并默认用来处理Controller中的异常,如果能替换掉该类,就可以解决我们的问题。

如何替换?Spring提供的方法提供一个类型实现ErrorController接口,其实BasicErrorController也是实现了该类。

所有我们只需要将我们自定义ExceptionAdvice类实现该接口,实现相应方法即可,修改后代码如下:

@ControllerAdvice(annotations = Controller.class)
public class ExceptionAdvice implements ErrorController{    
    private static final String ERROR_PATH = "/error";    
    @ExceptionHandler({Exception.class})
    // 此方法参数有多个,具体可参考相关文档
    public void handleException(Exception e, HttpServletRequest request, HttpServletResponse response) throws IOException {
       response.sendRedirect(request.getContextPath() + "/error");
    }
    
    @Override
    public String getErrorPath() {
        return ERROR_PATH;
    }
}

小结:其实就是一个很简单的问题,而我在一开始的时候却在纠结是不是注解使用错误之类的事,debug方向是对的,就是一时间没转过弯来,导致这个问题困扰了我挺长的时间,好在及时理清思路后能解决该问题。

SpringBoot的/error的自定义处理

在springboot项目里,如果没有统一异常处理,或者如果没有处理全面,又或者在springCloud zuul中调用微服务接口出错时,spring会自动把错误转发到默认给/error处理。

正常情况下,可以配置错误页面来给用户提示错误,如404,500等。但是在前后分离项目中,可能更期望给前台返回一个特定格式的json来展示错误信息。所以可以用代码来自定义异常错误信息。

/error端点的实现来源于SpringBoot的org.springframework.boot.autoconfigure.web.BasicErrorController,

它的具体定义如下

@RequestMapping
@ResponseBody
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
    Map<String, Object> body = getErrorAttributes(request,isincludeStackTrace(request, MediaType.ALL)) ;
    HttpStatus status = getStatus(request);
    return new ResponseEntity<Map<String, Object>>(body, status);}

通过调用 getErrorAtt豆butes 方法来根据请求参数组织错误信息的返回结果,而这里的 getErrorAtt豆bu七es 方法会将具体组织逻辑委托给 org.springframework.boot.autoconfigure.web.ErrorAttributes接口提供的 ge七ErrorAttributes 来实现。

在 Spring Boot 的自动化配置机制中,默认会采用 org.springframework.boot.autoconfigure.web.DefaultErrorAttribut作为该接口的实现。

在spring注册这个bean的时候,使用了注解@ConditionalOnMissingBean(value = ErrorAttributes.class, search =SearchStrategy.CURRENT)

说明只有在不存在ErrorAttributes的bean的时候,才会使用DefaultErrorAttributes来处理,如果我们可以自定义一个,就可以使用我们的类来处理异常了。

编写一个类继承DefaultErrorAttributes

他有三个方法

public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,Exception ex)
public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace)
public Throwable getError(RequestAttributes requestAttributes)

他们的执行顺序就如上述顺序。

我们可以在getErrorAttributes方法中拿到所有的异常信息,展示如下:

{"timestamp":1528190975129,"status":200,"error":"OK","exception":"java.lang.RuntimeException","message":"error............","path":"/a/b"}

可以在resolveException中拿到异常信息,如果需要返回json,则可以利用response来输出到前台,比如:

    

/* 使用response返回 */
        response.setStatus(HttpStatus.OK.value()); // 设置状态码
        response.setContentType(MediaType.APPLICATION_JSON_VALUE); // 设置ContentType
        response.setCharacterEncoding("UTF-8"); // 避免乱码
        response.setHeader("Cache-Control", "no-cache, must-revalidate");
 
        try {
            response.getWriter().print("json..........");
            response.getWriter().flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                response.getWriter().close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

这样,当有异常发生时,就可以在前台收到异常的json信息,而这个也可以代替统一异常处理使用。同时在springCloud zuul中可以用来自定义异常。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Spring Boot项目利用Redis实现session管理实例

    Spring Boot项目利用Redis实现session管理实例

    本篇文章主要介绍了Spring Boot项目利用Redis实现session管理实例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-06-06
  • 理解 MyBatis 是如何在 Spring 容器中初始化的

    理解 MyBatis 是如何在 Spring 容器中初始化的

    这篇文章主要介绍了理解 MyBatis 是如何在 Spring 容器中初始化的,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • Security中的WebSecurityConfigurerAdapter详解

    Security中的WebSecurityConfigurerAdapter详解

    这篇文章主要介绍了Security中的WebSecurityConfigurerAdapter详解,今天我们要进一步的的学习如何自定义配置Spring Security,本文结合实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2023-07-07
  • Spring手动获取bean的四种方式

    Spring手动获取bean的四种方式

    本文主要介绍了Spring手动获取bean的四种方式,包括BeanFactoryPostProcessor接口,ApplicationContextAware接口,注解 @PostConstruct 初始化时获取,启动类ApplicationContext获取这四种方法,感兴趣的可以了解一下
    2024-01-01
  • java 出现问题javax.servlet.http.HttpServlet was not found解决方法

    java 出现问题javax.servlet.http.HttpServlet was not found解决方法

    这篇文章主要介绍了java 出现问题javax.servlet.http.HttpServlet was not found解决方法的相关资料,需要的朋友可以参考下
    2016-11-11
  • Spring与Redis集成的正确方式流程详解

    Spring与Redis集成的正确方式流程详解

    这篇文章主要为大家介绍了Spring与Redis集成的正确方式流程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-06-06
  • Spring Task定时任务的配置和使用详解

    Spring Task定时任务的配置和使用详解

    本篇文章主要介绍了Spring Task定时任务的配置和使用详解,实例分析了Spring Task定时任务的配置和使用的技巧,非常具有实用价值,需要的朋友可以参考下
    2017-04-04
  • idea手动刷新git分支的详细教程

    idea手动刷新git分支的详细教程

    这篇文章主要介绍了idea手动刷新git分支,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-08-08
  • Java IO流 File类的常用API实例

    Java IO流 File类的常用API实例

    这篇文章主要介绍了Java IO流 File类的常用API实例的相关资料,需要的朋友参考下吧
    2017-05-05
  • maven的pom.xml中profiles的作用详解

    maven的pom.xml中profiles的作用详解

    这篇文章主要介绍了maven的pom.xml中profiles的作用详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12

最新评论