springboot初始教程之统一异常处理(代码片段)

夜宿山寺 夜宿山寺     2023-01-15     407

关键词:

SpringBoot初始教程之统一异常处理(三)

1.介绍

在日常开发中发生了异常,往往是需要通过一个统一的异常处理处理所有异常,来保证客户端能够收到友好的提示。SpringBoot在页面
发生异常的时候会自动把请求转到/error,SpringBoot内置了一个BasicErrorController对异常进行统一的处理,当然也可以自定义这个路径

application.yaml


server:
  port: 8080
  error:
    path: /custom/error

BasicErrorController提供两种返回错误一种是页面返回、当你是页面请求的时候就会返回页面,另外一种是json请求的时候就会返回json错误


    @RequestMapping(produces = "text/html")
    public ModelAndView errorHtml(HttpServletRequest request,
            HttpServletResponse response) 
        HttpStatus status = getStatus(request);
        Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
                request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
        response.setStatus(status.value());
        ModelAndView modelAndView = resolveErrorView(request, response, status, model);
        return (modelAndView == null ? new ModelAndView("error", model) : modelAndView);
    

    @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);
    

分别会有如下两种返回



  "timestamp": 1478571808052,
  "status": 404,
  "error": "Not Found",
  "message": "No message available",
  "path": "/rpc"


2.通用Exception处理

通过使用@ControllerAdvice来进行统一异常处理,@ExceptionHandler(value = Exception.class)来指定捕获的异常
下面针对两种异常进行了特殊处理分别返回页面和json数据,使用这种方式有个局限,无法根据不同的头部返回不同的数据格式,而且无法针对404、403等多种状态进行处理


    @ControllerAdvice
    public class GlobalExceptionHandler 
        public static final String DEFAULT_ERROR_VIEW = "error";
        @ExceptionHandler(value = CustomException.class)
        @ResponseBody
        public ResponseEntity defaultErrorHandler(HttpServletRequest req, CustomException e) throws Exception 
            return ResponseEntity.ok("ok");
        
        @ExceptionHandler(value = Exception.class)
        public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception 
            ModelAndView mav = new ModelAndView();
            mav.addObject("exception", e);
            mav.addObject("url", req.getRequestURL());
            mav.setViewName(DEFAULT_ERROR_VIEW);
            return mav;
        
    


3.自定义BasicErrorController 错误处理

在初始介绍哪里提到了BasicErrorController,这个是SpringBoot的默认错误处理,也是一种全局处理方式。咱们可以模仿这种处理方式自定义自己的全局错误处理
下面定义了一个自己的BasicErrorController,可以根据自己的需求自定义errorHtml()error()的返回值。


    @Controller
    @RequestMapping("$server.error.path:$error.path:/error")
    public class BasicErrorController extends AbstractErrorController 
        private final ErrorProperties errorProperties;
        private static final Logger LOGGER = LoggerFactory.getLogger(BasicErrorController.class);
        @Autowired
        private ApplicationContext applicationContext;

        /**
         * Create a new @link org.springframework.boot.autoconfigure.web.BasicErrorController instance.
         *
         * @param errorAttributes the error attributes
         * @param errorProperties configuration properties
         */
        public BasicErrorController(ErrorAttributes errorAttributes,
                                    ErrorProperties errorProperties) 
            this(errorAttributes, errorProperties,
                    Collections.<ErrorViewResolver>emptyList());
        

        /**
         * Create a new @link org.springframework.boot.autoconfigure.web.BasicErrorController instance.
         *
         * @param errorAttributes    the error attributes
         * @param errorProperties    configuration properties
         * @param errorViewResolvers error view resolvers
         */
        public BasicErrorController(ErrorAttributes errorAttributes,
                                    ErrorProperties errorProperties, List<ErrorViewResolver> errorViewResolvers) 
            super(errorAttributes, errorViewResolvers);
            Assert.notNull(errorProperties, "ErrorProperties must not be null");
            this.errorProperties = errorProperties;
        

        @Override
        public String getErrorPath() 
            return this.errorProperties.getPath();
        

        @RequestMapping(produces = "text/html")
        public ModelAndView errorHtml(HttpServletRequest request,
                                      HttpServletResponse response) 
            HttpStatus status = getStatus(request);
            Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
                    request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
            response.setStatus(status.value());
            ModelAndView modelAndView = resolveErrorView(request, response, status, model);
            insertError(request);
            return modelAndView == null ? new ModelAndView("error", model) : modelAndView;
        



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

        /**
         * Determine if the stacktrace attribute should be included.
         *
         * @param request  the source request
         * @param produces the media type produced (or @code MediaType.ALL)
         * @return if the stacktrace attribute should be included
         */
        protected boolean isIncludeStackTrace(HttpServletRequest request,
                                              MediaType produces) 
            ErrorProperties.IncludeStacktrace include = getErrorProperties().getIncludeStacktrace();
            if (include == ErrorProperties.IncludeStacktrace.ALWAYS) 
                return true;
            
            if (include == ErrorProperties.IncludeStacktrace.ON_TRACE_PARAM) 
                return getTraceParameter(request);
            
            return false;
        

        /**
         * Provide access to the error properties.
         *
         * @return the error properties
         */
        protected ErrorProperties getErrorProperties() 
            return this.errorProperties;
        
    

SpringBoot提供了一种特殊的Bean定义方式,可以让我们容易的覆盖已经定义好的Controller,原生的BasicErrorController是定义在ErrorMvcAutoConfiguration中的
具体代码如下:


    @Bean
    @ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
    public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) 
        return new BasicErrorController(errorAttributes, this.serverProperties.getError(),
                this.errorViewResolvers);
    

可以看到这个注解@ConditionalOnMissingBean 意思就是定义这个bean 当 ErrorController.class 这个没有定义的时候,
意思就是说只要我们在代码里面定义了自己的ErrorController.class时,这段代码就不生效了,具体自定义如下:


    @Configuration
    @ConditionalOnWebApplication
    @ConditionalOnClass(Servlet.class, DispatcherServlet.class)
    @AutoConfigureBefore(WebMvcAutoConfiguration.class)
    @EnableConfigurationProperties(ResourceProperties.class)
    public class ConfigSpringboot 
        @Autowired(required = false)
        private List<ErrorViewResolver> errorViewResolvers;
        private final ServerProperties serverProperties;

        public ConfigSpringboot(
                ServerProperties serverProperties) 
            this.serverProperties = serverProperties;
        

        @Bean
        public MyBasicErrorController basicErrorController(ErrorAttributes errorAttributes) 
            return new MyBasicErrorController(errorAttributes, this.serverProperties.getError(),
                    this.errorViewResolvers);
        


    

在使用的时候需要注意MyBasicErrorController不能被自定义扫描Controller扫描到,否则无法启动。

3.总结

一般来说自定义BasicErrorController这种方式比较实用,因为可以通过不同的头部返回不同的数据格式,在配置上稍微复杂一些,但是从实用的角度来说比较方便而且可以定义通用组件

本文代码

https://git.oschina.net/wangkang_daydayup/SpringBoot-Learn/tree/master

springboot-3

重学springboot系列之统一全局异常处理(代码片段)

重学SpringBoot系列之统一全局异常处理设计一个优秀的异常处理机制异常处理的乱象例举该如何设计异常处理开发规范自定义异常和相关数据结构该如何设计数据结构枚举异常的类型自定义异常请求接口统一响应数据结构使用示... 查看详情

springboot初始教程之日志处理(代码片段)

SpringBoot初始教程之日志处理(二)1.介绍SpringBoot默认是采用logback进行日志处理、Logback是由log4j创始人设计的又一个开源日志组件。Logback是由log4j创始人设计的又一个开源日志组件。logback当前分成三个模块:logback-core,logback-class... 查看详情

springboot初始教程之日志处理(代码片段)

SpringBoot初始教程之日志处理(二)1.介绍SpringBoot默认是采用logback进行日志处理、Logback是由log4j创始人设计的又一个开源日志组件。Logback是由log4j创始人设计的又一个开源日志组件。logback当前分成三个模块:logback-core,logback-class... 查看详情

springboot进阶之统一异常处理(含源码)

浅谈异常处理在J2EE项目的开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到各种可预知的、不可预知的异常需要处理。每个过程都单独处理异常,... 查看详情

springboot2系列教程(十四)|统一异常处理

如题,今天介绍SpringBoot是如何统一处理全局异常的。SpringBoot中的全局异常处理主要起作用的两个注解是@ControllerAdvice和@ExceptionHandler,其中@ControllerAdvice是组件注解,添加了这个注解的类能够拦截Controller的请求,而ExceptionHandler... 查看详情

springboot初始教程之日志处理

SpringBoot初始教程之日志处理(二)1.介绍SpringBoot默认是采用logback进行日志处理、Logback是由log4j创始人设计的又一个开源日志组件。Logback是由log4j创始人设计的又一个开源日志组件。logback当前分成三个模块:logback-core,logback-classic和... 查看详情

springboot全局异常统一处理(代码片段)

...ice&@ExceptionHandlerhttp异常ErrorControllerServlet异常Filter1.SpringBoot默认错误统一处理机制在基于SpringBoot的Web应用中,对于Http请求处理过程中发生的各种错误,如常见的400、404和500 查看详情

springboot统一异常处理(代码片段)

DemoException,自定义异常@GetterpublicclassDemoExceptionextendsRuntimeExceptionprivateIntegercode;publicDemoException(ResultEnumresultEnum)super(resultEnum.getMessage());this.code=resultEnum.getCode();pu 查看详情

springboot初始教程之redis集中式session管理(代码片段)

SpringBoot初始教程之Redis集中式Session管理(四)1.介绍有关Session的管理方式这里就不再进行讨论,目前无非就是三种单机Session(基于单机内存,无法部署多台机器)、基于Cookie(安全性差)、基于全局的统一Session管理(redis、mysql)... 查看详情

springboot初始教程之redis集中式session管理(代码片段)

SpringBoot初始教程之Redis集中式Session管理(四)1.介绍有关Session的管理方式这里就不再进行讨论,目前无非就是三种单机Session(基于单机内存,无法部署多台机器)、基于Cookie(安全性差)、基于全局的统一Session管理(redis、mysql)... 查看详情

springboot+shiro权限注解请求乱码解决统一异常处理

springboot+shiro权限注解、请求乱码解决、统一异常处理前篇后台权限管理系统相关:springboot+mybatis+layui+shiro后台权限管理系统springboot+shiro之登录人数限制、登录判断重定向、session时间设置springboot+shiro动态更新用户信息基于前篇... 查看详情

统一异常处理的实现(代码片段)

前面介绍了SpringBoot如何整合定时任务已经SpringBoot如何创建异步任务和定时任务。不清楚的朋友可以看看之前的文章:《SpringBoot入门系列文章》接下来主要讲解如何在SpringBoot应用中使用统一异常处理。如何实现对异常数据与正... 查看详情

springboot的统一异常处理(代码片段)

SpringBoot的统一异常处理在SpringBoot应用开发中,不管是对底层数据库的操作,对业务层的操作,还是对控制层的操作,都会不可避免的遇到各种未知的异常需要处理,如果每个过程都单独处理异常,那么系... 查看详情

springboot初始教程之项目结构(代码片段)

SpringBoot初始教程之项目结构1简介SpringBootmakesiteasytocreatestand-alone,production-gradeSpringbasedApplicationsthatyoucan“justrun”.WetakeanopinionatedviewoftheSpringplatformandthird-partylibrariessoyoucangetst 查看详情

springboot初始教程之项目结构(代码片段)

SpringBoot初始教程之项目结构1简介SpringBootmakesiteasytocreatestand-alone,production-gradeSpringbasedApplicationsthatyoucan“justrun”.WetakeanopinionatedviewoftheSpringplatformandthird-partylibrariessoyoucangetst 查看详情

springboot项目如何做到统一异常处理

...个项目中对于异常的处理就显得尤为重要.那么,小编就以SpringBoot框架,通过代码实例展示统一异常的处理方式.1.首先我们简单搭建一个SpringBoot框架的项目,项目名称是exceptionhandler(异常处理)2.导入 查看详情

不是所有的springboot异常都能被统一异常处理|javadebug笔记(代码片段)

通常我们在SpringBoot中设置的统一异常处理(@RestControllerAdvice配合@ExceptionHandler实现)只能处理Controller抛出的异常。有些请求还没到Controller就出异常了,而这些异常不能被统一异常捕获,例如Servlet容器的某... 查看详情

知识点-springboot统一异常处理汇总(代码片段)

...在实际开发中,我们会遇到很多异常,在发生异常的时候SpringBoot默认提供了错误页面展示给用户。看似比较友好,其实页面很丑。上面讲的是做页面开发的时候遇到的问题,还有一种情况就是用来开发Rest接口,当错误的时候我... 查看详情