首页 > 其他分享 >SpringMVC之异常处理机制

SpringMVC之异常处理机制

时间:2022-10-06 18:55:28浏览次数:54  
标签:响应 SpringMVC 处理 html error 机制 异常 页面

SpringBoot异常处理机制

默认异常处理机制

springboot默认提供了一个处理/error的handler,全局异常处理。

对于机器客户端来说,产生JSON(具体的错误)、状态码和异常信息;

对于浏览器来说,产生一个白页同时附带上html错误信息;

为了自定义,还可以利用视图来解析和错误。

浏览器端响应页面

机器端响应JSON

对比一下,二者错误信息十分类似。

SpringBoot提供利用自定义页面处理异常

可以自定义页面在错误发生的时候响应到该页面上来

放在public/templates目录下的error目录下的页面来进行渲染响应,而且也说明了如果是以5开头的错误,都可以进入到5xx这个页面进行渲染响应,同理4xx也是可以的。

默认异常处理机制源码

看一下springboot中提供的ErrorMvcAutoConfiguration异常自动配置原理

首先放入了两个组件:DefaultErrorAttributes和BasicErrorController

BasicErrorController

看一下对应的类的信息,默认在server.error.path没有配置的时候,BasicErrorController默认处理的是/error请求。

然后接着看下面的handlermethod

存在着两种处理方式:一个是html,另外一个是json格式的数据。

对于html页面来说,默认响应的页面是error页面。

除此之外,还会放置一个默认的error视图bean和一个处理error的视图解析器,这个视图解析器是按照bean的名称来进行解析的。

也就是说,如果发送了/error请求,会从容器中根据/error作为组件ID来找(利用BeanNameViewResolver来找到的),然后进行渲染。

所以视图长什么样子,就渲染成什么样子。默认放置的view是StaticView,看看类中的渲染方式:

这里是默认的渲染页面风格

上面的只是响应页面,但是也可以响应json。

这里是根据内容协商原理来进行判断的。

也就是说如果希望的是响应JSON,那么将会调用BasicErrorController的error方法来处理当前请求,然后根据响应json还是页面来进行确定是否使用默认的视图解析器来进行响应。

DefaultErrorViewResolver

默认错误视图解析器

从这里可以知道官网中说明的支持4xx和5xx的大概逻辑了。

那么看一下具体的实现逻辑:

根据状态码来决定view。可以精确匹配,也可以模糊匹配。

如状态码是405,那么对应的页面是/error/405.html,也可以是/errot/4xx.html

从这里可以看到/error下面,然后加上错误错误码对应的详细信息来匹配到对应的viewname作为ModelAndView中的view对象。

DefaultErrorAttributes

从这里可以看到默认的错误属性,然后联想到响应出去的json和html中的信息都应该保存在哪个地方呢?就是这个地方了。

响应的错误信息会保存到reqeust作用域对象中来,然后在响应的时候会根据具体信息来进行删除。

这里只是简单的分析,但是具体是如何联动起来的,再来进行分析。

异常处理步骤

从例子开始,先来写一个案例来进行说明:

@RestController
public class ExceptionController {
    
    @RequestMapping("/teste")
    public String testException(){
        int i = 1 / 0;
        return "success";
    }
    
}

访问的时候,下面这行代码肯定会出现问题:

// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

然后看看里面是如何来进行处理的:

		try {
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);		
				.............
				// Actually invoke the handler.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
				...........
				applyDefaultViewName(processedRequest, mv);
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			catch (Throwable err) {
				dispatchException = new NestedServletException("Handler dispatch failed", err);
			}
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

目标方法执行期间,出现了任何异常都会被之后,然后肯定会来到processDispatchResult方法中来进行处理异常。

这里也说明了什么?说明了controller中出现了异常信息,那么会有异常处理器来进行处理请求。

开始来处理Handler中出现的异常。

上来就是先把request作用域中设置的响应数据格式给清空掉,从新匹配新的数据格式。

开始来找异常处理器来处理请求,如果找到异常处理器能够处理请求,那么返回ModelAndView;如果没有找到,那么将再次抛出异常。

看看遍历异常处理器如何处理的

遍历异常处理器处理

DefaultErrorAttributes

实现了HandlerExceptionResolver接口

这个类的出来方式就是只做存储,返回null

public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,Exception ex) {
    storeErrorAttributes(request, ex);
    return null;
}

将异常信息存储起来。

ExceptionHandlerExceptionResolver

用来处理方法上加了@ExceptionHandlerException注解信息的。

类似如下:

@ControllerAdvice
public class ExceptionControllerAdvice {

    private static final Logger logger = LoggerFactory.getLogger(ExceptionControllerAdvice.class);

    public ExceptionControllerAdvice() {
    }

    @ExceptionHandler({Throwable.class})
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public CommonHttpEntity<Object> buildErrorMessage(Throwable t) {
        if (t instanceof ServiceException) {
            ServiceException serviceException = (ServiceException) t;
            return CommonHttpEntity.buildFailResponse(serviceException);
        } else {
            logger.error("未捕获异常", t);
            return CommonHttpEntity.buildFailResponse(ServiceExeceptionEnum.F999.buildServiceException());
        }
    }
}

那么就会进入到下面的响应中来

这么做的目的在于不管是否发生了错误,那么都将会来响应JSON数据。

这个是我们最终需要采用的数据格式。

ResponseStatusExceptionResolver

如果在方法上标注了@ResponseStatus那么这里将会来获取得到信息。

这里处理方式和ExceptionHandlerExceptionResolver是相同的处理逻辑。

DefaultHandlerExceptionResolver

和上面是相同的处理逻辑

没有任何异常处理器处理

将会抛出异常,进入到拦截器的最终拦截方法中来,做没有意义的事情。

但是此时此刻,springmvc将会再发一个/error的请求,那么将会由BasicErrorController中来进行请求。

又因为对于客户端来说(浏览器)发送的Accep字段中接收text的权重比较高,所以是响应页面的。

默认的 DefaultErrorViewResolver ,作用是把响应状态码作为错误页的地址,error/500.html

模板引擎最终响应这个页面 error/500.html

SpringBoot处理处理最佳方案

总结一下springboot中可以使用的几种方式:

  • 1、自定义错误页

    • error/404.html error/5xx.html;有精确的错误状态码页面就匹配精确,没有就找 4xx.html;如果都没有就触发白页
  • 2、 @ControllerAdvice+@ExceptionHandler处理全局异常

    • 底层是 ExceptionHandlerExceptionResolver 支持的
  • 3、@ResponseStatus+自定义异常

    • 底层是 ResponseStatusExceptionResolver ,把responsestatus注解的信息底层调用 response.sendError(statusCode, resolvedReason);tomcat发送的/error
  • 4、Spring底层的异常

    • 如 参数类型转换异常;DefaultHandlerExceptionResolver 处理框架底层的异常response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage());

推荐使用第二种方式

@ControllerAdvice
public class ExceptionControllerAdvice {

    private static final Logger logger = LoggerFactory.getLogger(ExceptionControllerAdvice.class);

    public ExceptionControllerAdvice() {
    }

    @ExceptionHandler({Throwable.class})
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public CommonHttpEntity<Object> buildErrorMessage(Throwable t) {
        if (t instanceof ServiceException) {
            ServiceException serviceException = (ServiceException) t;
            return CommonHttpEntity.buildFailResponse(serviceException);
        } else {
            logger.error("未捕获异常", t);
            return CommonHttpEntity.buildFailResponse(ServiceExeceptionEnum.F999.buildServiceException());
        }
    }
}

标签:响应,SpringMVC,处理,html,error,机制,异常,页面
From: https://www.cnblogs.com/likeguang/p/16758194.html

相关文章

  • 电网异常处理
    一、频率异常1、判定:正负0.2HZ,正负0.5HZ。2、异常处理:调整负荷,调整发电机出力,具体处理方法。二、电压异常处理1、判定:正负5%,正负10%。2、原因。3、电压低的处理。4......
  • SpringMVC之内容协商策略
    内容协商原理目录内容协商原理一、引言二、正常请求请求数据格式确定和返回值数据格式确定三、内容协商确定客户端接收数据格式默认基于请求头确定请求数据格式确定服务端......
  • Java当中jvm运行时区域新生代、老年代、永久代和Garbage Collection垃圾回收机制【杭
       1、本地方法栈和程序计数器==》偏底层一般不会接触到2、方法区==》对应为永久代3、虚拟机栈(stack)==》对应为栈4、堆(heap)==》对应里面有新生代+老年代sta......
  • 事件分发的处理机制
    事件分发的处理机制ActionDown手指初次触碰到屏幕ActionMove手指向上滑动会多次触发ActionUp手指离开屏幕时触发ActionCancel事件被上层拦截View继承关系父容......
  • 深入理解linux内核第三版(三)中断和异常
    中断:也叫异步中断,是由外设产生的。异常:也叫同步中断,是由CPU产生的,是指令执行过程中产生的。中断信号的作用:中断信号提供了一种特殊的方式,使处理器转而去运行正常控制流之......
  • 基于 angular material theming 机制修改 mat-toolbar 的背景色
    最近在学习angular,记录一下昨天的进展,解决的问题是通过theme的配置修改mat-toolbar的背景色,避免对色彩的硬编码。首先通过mat-toolbar(以下统一称为toolbar)的实现......
  • 从setTimeout理解JS运行机制
    序setTimeout()函数:用来指定某个函数或某段代码在多少毫秒之后执行。它返回一个整数,表示定时器timer的编号,可以用来取消该定时器。例子console.log(1);setTimeout(func......
  • (函数)编程:定义一个函数fun(a,b,c),返回一元二次方程ax^2+bx+c=0的两个解。程序运行后输
    样例输入231 样例输出(-0.5,-1.0) 样例输入246 样例输出输入错误,无解 解题代码importmathdeffun(a,b,c):dt=b*b-4*a*cx1=(-b......
  • SpringMVC笔记
    一、SpringMVC简介1、什么是MVCMVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分M:Model,模型层,指工程中的JavaBean,作用是处理数据JavaBean分为两类:一类称......
  • 2022最新SpringMVC面试题附完整答案
    SpringMVC面试题一、单选题1.下列关于SpringMVC说法正确的是BA.SpringMVC和Spring没有关系B.SpringMVC是一个控制层框架,复制接收和处理请求C.SpringMVC可以脱离Spring单独......