写在前面
鉴于有人留言说想要学习SpringBoot相关的知识,我这里打算写一个SpringBoot系列的相关博文,目标呢是想让看了这一系列博文的同学呢,能够对SpringBoot略窥门径,这一系列的博文初步都定下来包括SpringBoot介绍、入门、配置、日志相关、web开发、数据访问、结合docker、缓存、消息队列、检索、任务安全、分布式等等一系列的博文,工作量很大,是个漫长的过程,每一步我都尽量详细,配上截图说明,也希望对看的同学真的有用。
单纯就是想分享技术博文,还想说一句就是,如果觉得有用,请点个关注、给个赞吧,也算对我来说是个宽慰,毕竟也得掉不少头发,嘿嘿嘿
系列文章传送条
详细SpringBoot教程之入门(一)
详细SpringBoot教程之入门(二)
详细SpringBoot教程之配置文件(一)
详细SpringBoot教程之配置文件(二)
详细SpringBoot教程之日志框架
详细SpringBoot教程之Web开发(一)
详细SpringBoot教程之Web开发(二)
详细SpringBoot教程之Web开发(三)
详细SpringBoot教程之数据访问
详细SpringBoot教程之启动配置原理
详细SpringBoot教程之缓存开发
错误处理机制
SpringBoot默认的错误处理机制
我们接上一篇博文的项目,我们现在把拦截器关掉,直接在主配置文件注释掉注入就可以直接关掉了,像这样
然后我们现在通过浏览器随便访问一个不存在的连接,会出现下面这样的错误提示,应该不陌生吧,之前肯定是遇到过的。
我们可以查看一下浏览器发送请求的请求头,如下:
当然SpringBoot还另外规定了客户端访问无效链接的错误机制,如果我们通过客户端访问会返回一个默认的json数据,像下面这样
1 | { |
默认错误处理机制原理
老样子,我们想要错误处理机制也有自己的自动配置类(之前说过,SpringBoot功能是通过配置文件来进行控制的,而配置文件一般是通过xxxAutoConfiguration这样的自动配置类来实现的),所以SpringBoot的默认的错误处理机制可以参照自动配置类,也就是ErrorMvcAutoConfiguration。
ErrorMvcAutoConfiguration通过给给容器中添加了以下组件,来控制错误处理机制
- DefaultErrorAttributes:帮我们在页面共享信息;
- BasicErrorController:处理默认/error请求
- ErrorPageCustomizer:系统出现错误以后来到error请求进行处理;
- DefaultErrorViewResolver:用来控制错误时,启用模板引擎视图,还是默认;
也就是默认的错误处理流程是,一但系统出现4xx或者5xx之类的错误,ErrorPageCustomizer就会生效(定制错误的响应规则),接着就会来到/error请求,然后就可以通过BasicErrorController来进行处理,进行相应时,响应页面去哪个页面是由DefaultErrorViewResolver解析得到的;
如何定制错误响应
如何定制错误页面
如果有模板引擎的情况下(我们项目中使用的是Thymeleaf模板引擎),可以通过error/状态码的形式来进行控制,也就是说,我们可以将错误页面命名为“错误状态码.html”,然后放在模板引擎文件夹(即templates目录下)里面的error文件夹下,没有error文件夹就创建一个,发生此状态码的错误就会来到 对应的页面,因为SpringBoot规则中已经默认规定好了。
更准确的将我们可以使用4xx和5xx作为错误页面的文件名,进而来匹配该种类型的所有错误,匹配的时候遵循精确优先(优先寻找精确的状态码.html),像下面这样
我们在默认的错误页面中可以获得如下信息:、
- timestamp:时间戳
- tstatus:状态码
- terror:错误提示
- texception:异常对象
- tmessage:异常消息
- terrors:JSR303数据校验的错误都在这里
这里要说明一下的是,如果我们项目中没有使用模板引擎(或者模板引擎找不到这个错误页面),就会去静态资源文件夹下找。如果静态资源文件夹中也没有错误页面,就是默认来到SpringBoot默认的错误提示页面。
如何定制错误的json
可以自定义异常处理和返回定制json数据,像下面这样,我们可以专门定义一个配置类用来解决错误定制的,我这里命名为MyExceptionHandler,然后通过@ExceptionHandler来定制响应的相关错误,进而返回定制数据
不过这样处理会有个问题,就是我们确实是定制了返回的json数据,但是本来SpringBoot会根据我们用什么访问请求,然后响应什么,比如我们用浏览器访问,响应html页面,客户端响应json数据,现在这样写,返回的都是接送数据了,所以我们需要换种方式,通过将相应转发到/error进行自适应响应效果处理,像下面这样
携带定制数据
前面我们讲过,出现错误以后,会来到/error请求,会被BasicErrorController处理,响应出去可以获取的数据是由getErrorAttributes得到的(是AbstractErrorController(ErrorController)规定的方法)
所以,我们可以通过编写一个ErrorController的实现类或者是编写AbstractErrorController的子类,然后放在容器中,我们要知道,页面上能用的数据,或者是json返回能用的数据都是通过errorAttributes.getErrorAttributes得到,也就是说容器中DefaultErrorAttributes.getErrorAttributes()来默认进行数据处理的,我们定制自定义ErrorAttributes,如下
这样,我们的错误响应是自适应的,可以通过定制ErrorAttributes改变需要返回的内容,就不在只有原先的默认属性了,形象的将,我们返回的信息就会是如下
- timestamp:时间戳
- tstatus:状态码
- terror:错误提示
- texception:异常对象
- tmessage:异常消息
- terrors:JSR303数据校验的错误都在这里
- author: dbc
配置嵌入式Servlet容器
SpringBoot默认使用Tomcat作为嵌入式的Servlet容器,这我们都是知道的
那么这个时候我们如果想要换成其他的Servlet容器,我们应该怎么做呢?那么接下来我们就来讲解怎么搞
如何定制和修改Servlet容器的相关配置
修改和server有关的配置(ServerProperties即也是使用WebServerFactoryCustomizer),在主配置文件中可以通过这样的形式来设置
除了在主配置文件中进行相关的设置之外,我们还可以通过注册WebServerFactoryCustomizer
注册Servlet三大组件
Servlet三大组件分别是Servlet、Filter、Listener,如果我们原先熟悉SpringMVC开发的应该知道,我们在Webapp下面的web.xml中,经常需要配置这三大组件用来过滤监听相关的请求,而在SpringBoot中,由于SpringBoot默认是以jar包的方式启动嵌入式的Servlet容器来启动SpringBoot的web应用,所以并没有没有web.xml文件。但是我们依旧可以通过SpringBoot特有的相关注册Bean进行注册,分别是
- ServletRegistrationBean
1 | //注册三大组件 |
- FilterRegistrationBean
1 |
|
- ServletListenerRegistrationBean
1 |
|
SpringBoot帮我们自动配置SpringMVC的时候,会自动的注册SpringMVC的前端控制器,即DIspatcherServlet,我们通过查阅DispatcherServletAutoConfiguration发现,会默认拦截,“/”的所有请求,包括静态资源,但是不拦截jsp请求,/*会拦截jsp,可以通过server.servletPath来修改SpringMVC前端控制器默认拦截的请求路径
更换其他嵌入式Servlet容器
我们知道,SpringBoot是默认支持Tomcat的,也就是在pom.xml中通过如下依赖引入的
所以,我们不能整个去除web依赖,因为里面还有其他除了Tomcat的依赖,所以我们在web下直接排除Tomcat的依赖就可以了,然后添加其他的嵌入式Servlet容器的依赖,不同的嵌入式Servlet依赖如下
Jetty
Undertow
使用外置的Servlet容器
在我们之前学习的SpringBoot应用,是通过嵌入式Servlet容器,应用打成可执行的jar,这样做的优点显而易见,就是简单、便携,但是缺点就是默认不支持JSP、优化定制比较复杂(使用定制器ServerProperties、自定义WebServerFactoryCustomizer,自己编写嵌入式Servlet容器的创建工厂ConfigurableWebServerFactory);
但是不着急,我们可以使用外置的Servlet容器,也就是外面安装Tomcat,然后应用war包的方式打包。
步骤
必须创建一个war项目,利用idea创建好目录结构
将嵌入式的Tomcat指定为provided;
1 | <dependency> |
- 必须编写一个SpringBootServletInitializer的子类,并调用configure方法
1
2
3
4
5
6
7
8
9public class ServletInitializer extends SpringBootServletInitializer {
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
//传入SpringBoot应用的主程序
return application.sources(SpringBoot04WebJspApplication.class);
}
} - 启动服务器就可以使用;
我这里说一下jar包和war包启动的区别
- jar包:执行SpringBoot主类的main方法,启动ioc容器,创建嵌入式的Servlet容器;
- war包:启动服务器,服务器启动SpringBoot应用通过SpringBootServletInitializer,启动ioc容器;