Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 11786|回复: 0

springboot全局异常处理

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-4-13 10:41:16 | 显示全部楼层 |阅读模式

    基于springboot的全局异常处理 

     

    1 编写ResultBuilder类

     
     
    package com.test.domi.common.utils;

    import org.apache.commons.lang.StringUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.boot.autoconfigure.web.ErrorProperties;
    import org.springframework.boot.autoconfigure.web.ServerProperties;
    import org.springframework.core.Ordered;
    import org.springframework.http.HttpStatus;
    import org.springframework.validation.BindingResult;
    import org.springframework.validation.FieldError;
    import org.springframework.web.bind.MethodArgumentNotValidException;
    import org.springframework.web.servlet.HandlerExceptionResolver;
    import org.springframework.web.servlet.ModelAndView;

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.List;

    public class ResultBuilder implements HandlerExceptionResolver,Ordered {

    private static final Logger LOGGER = LoggerFactory.getLogger(ResultBuilder.class);
    private static final String ERROR_NAME = "fp.error";
    private ErrorProperties errorProperties;

    public ErrorProperties getErrorProperties() {
    return errorProperties;
    }

    public ResultBuilder(ServerProperties serverProperties){
    LOGGER.info("serverProperties:{}",serverProperties.getError());
    this.errorProperties = serverProperties.getError();
    }

    public ResultInfo getErrorInfo(HttpServletRequest request){
    return this.getErrorInfo(request,this.getError(request));
    }

    /**
    * 全局异常返回处理
    * @param request
    * @param error
    * @return
    */
    public ResultInfo getErrorInfo(HttpServletRequest request,Throwable error){
    ResultInfo resultInfo = new ResultInfo();
    //根据不同的error获取错误信息
    String resultCode = "";
    StringBuffer msg = new StringBuffer();
    if (error instanceof MethodArgumentNotValidException) {
    //1 参数校验异常
    resultCode = getString2((MethodArgumentNotValidException) error, resultCode, msg);
    }else {
    //3 httpStatu枚举code对应的异常
    resultCode = getString3(request, msg);
    }
    resultInfo.setCode(resultCode);
    resultInfo.setMessage(msg.toString());
    resultInfo.setData((Object)null);
    return resultInfo;
    }

    private String getString3(HttpServletRequest request, StringBuffer msg) {
    msg.append(this.getHttpStatus(request).getReasonPhrase());
    return String.valueOf(this.getHttpStatus(request).value());
    }

    private String getString2(MethodArgumentNotValidException error, String resultCode, StringBuffer msg) {
    BindingResult bindingResult = error.getBindingResult();
    if (bindingResult.hasErrors()) {
    List<FieldError> list = bindingResult.getFieldErrors();
    resultCode =ResultCode.CONNECT_ERROR.getCode();
    for (FieldError fieldError : list) {
    msg.append(fieldError.getDefaultMessage() + ";");
    }
    }
    return resultCode;
    }

    private String getString(Throwable error, StringBuffer msg) {
    msg.append(error.getMessage());
    return ResultCode.INSERT_ERROR.getCode();
    }

    /**
    * 拿到最根部的error,携带手动抛出的异常信息
    * @param request
    * @return
    */
    public Throwable getError(HttpServletRequest request){
    Throwable error = (Throwable)request.getAttribute(ERROR_NAME);
    if (error == null) {
    error = (Throwable)request.getAttribute("javax.servlet.error.exception");
    }

    if (error != null) {
    //while (error instanceof ServletException && ((Throwable) error).getCause() != null) {
    while (error instanceof Exception && ((Throwable) error).getCause() != null) {
    error = ((Throwable) error).getCause();
    }
    } else {
    String message = (String)request.getAttribute("javax.servlet.error.message");
    if (StringUtils.isNotEmpty(message)) {
    HttpStatus status = this.getHttpStatus(request);
    message = "Unknown Exception With" + status.value() + " " + status.getReasonPhrase();
    }

    error = new Exception(message);
    }

    return (Throwable)error;
    }

    public HttpStatus getHttpStatus(HttpServletRequest request){
    Integer statusCode = (Integer)request.getAttribute("javax.servlet.error.status_code");
    try {
    return statusCode != null ? HttpStatus.valueOf(statusCode.intValue()) : HttpStatus.INTERNAL_SERVER_ERROR;
    } catch (Exception var4) {
    return HttpStatus.INTERNAL_SERVER_ERROR;
    }
    }

    @Override
    public int getOrder() {
    return 0;
    }

    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
    httpServletRequest.setAttribute(ERROR_NAME, e);
    return null;
    }
    }

     

    2 编写ExceptionConfig类(传入ServerProperties ,实例化ResultBuilder。springboot中ErrorProperties类定义了异常自动映射路径@Value("${error.path:/error}")private String path = "/error"

    package com.test.domi.config;
    
    import com.test.domi.common.system.ResultBuilder;
    import org.springframework.boot.autoconfigure.web.ServerProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.Ordered;
    import org.springframework.core.annotation.Order;
    import javax.annotation.Resource;
    
    @Configuration
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public class ExceptionConfig {
        @Resource
        private ServerProperties serverProperties;
        @Bean
        public ResultBuilder resultBuilder(){
            return  new ResultBuilder(serverProperties);
        }
    }

    ErrorProperties:

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package org.springframework.boot.autoconfigure.web;
    
    import org.springframework.beans.factory.annotation.Value;
    
    public class ErrorProperties {
        @Value("${error.path:/error}")
        private String path = "/error";
        private ErrorProperties.IncludeStacktrace includeStacktrace;
    
        public ErrorProperties() {
            this.includeStacktrace = ErrorProperties.IncludeStacktrace.NEVER;
        }
    
        public String getPath() {
            return this.path;
        }
    
        public void setPath(String path) {
            this.path = path;
        }
    
        public ErrorProperties.IncludeStacktrace getIncludeStacktrace() {
            return this.includeStacktrace;
        }
    
        public void setIncludeStacktrace(ErrorProperties.IncludeStacktrace includeStacktrace) {
            this.includeStacktrace = includeStacktrace;
        }
    
        public static enum IncludeStacktrace {
            NEVER,
            ALWAYS,
            ON_TRACE_PARAM;
    
            private IncludeStacktrace() {
            }
        }
    }

     

    3 定义全局 异常Controller接管所有抛出的异常

    package spring.cloud.common.controller;

    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
    import org.springframework.boot.web.servlet.error.ErrorController;
    import org.springframework.http.MediaType;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.servlet.ModelAndView;
    import spring.cloud.common.util.ResultBuilder;
    import spring.cloud.common.util.ResultInfo;
    import javax.annotation.Resource;
    import javax.servlet.http.HttpServletRequest;


    @RestController
    @RequestMapping("/error")
    public class GlobalErrorController implements ErrorController{

    /**
    * 1 ErrorController 接口的默认实现类是abstract:AbstractErrorController
    * 2 AbstractErrorController 的子类 BasicErrorController 才是真正干活儿的实现类(分html、json 两个方法处理,我们只需要在GlobalErrorController重写这2个方法即可)
    * 3 BasicErrorController 有 private final ErrorProperties errorProperties;属性
    * ErrorProperties里面记录了error的路径:
    * @Value("${error.path:/error}")
    * private String path = "/error";
    * -----
    * 4 BasicErrorController 的封装只能将状态码的提示信息返回前台,不能拿到手动抛异常的信息,因此需要实现HandlerExceptionResolver
    * ------------------------------------------------------------
    * BasicErrorController只有有参构造,无法直接继承
    * 如果不实现ErrorController,则会造成相同路径/error有2个类,冲突了。启动时报如下异常:
    * org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'basicErrorController' method
    * public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
    * to {[/error],produces=[text/html]}: There is already 'globalErrorController' bean method
    */
    private final static String DEFAULT_ERROR_VIEW = "/error";
    private final static org.slf4j.Logger LOGGER = LoggerFactory.getLogger(GlobalErrorController.class);
    /**
    * ResultBuilder 实现 HandlerExceptionResolver 接口重写public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e)
    * 通过httpServletRequest.setAttribute("fp.error", e);将Exception放到request中
    * 这种方法的好处是能拿到手动抛异常的信息
    */
    @Resource
    private ResultBuilder resultBuilder;

    /** 1- BasicErrorController只有有参构造,无法直接继承,
    * 2- 如果不实现ErrorController,则会造成相同路径/error有2个类,冲突了。启动时报如下异常:
    * org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'basicErrorController' method
    * public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
    * to {[/error],produces=[text/html]}: There is already 'globalErrorController' bean method
    * ----------------------
    * ErrorProperties里面记录了error的路径:
    * * @Value("${error.path:/error}")
    * * private String path = "/error";
    * 如果不需要从GlobalErrorController中的getErrorPath方法获取该路径,则该方法可以空实现
    */
    @Override
    public String getErrorPath(){
    // return null;
    return resultBuilder.getErrorProperties().getPath();
    }

    /**
    * 如果请求头返回的类型是text/html,则返回到错误信息页面
    * @param request
    * @return
    */
    @RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
    public ModelAndView errorHtml(HttpServletRequest request) {
    return new ModelAndView(DEFAULT_ERROR_VIEW,"errorInfo",resultBuilder.getErrorInfo(request));
    }

    /**
    * 除了text/html的请求头信息,其它都返回json格式
    * @param request 请求对象
    * @return 错误信息字符串
    */
    @RequestMapping(produces = {MediaType.APPLICATION_JSON_VALUE})
    public ResultInfo error(HttpServletRequest request){
    return resultBuilder.getErrorInfo(request);
    }



    }
     
     
     

     

    配置完毕,后台的未被捕获的异常将从dao层到dervice层到controller层,然后被全局异常controller统一接管,封装之后返回给前台!

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-12-23 05:13 , Processed in 0.111816 second(s), 28 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表