持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情
一、自动配置的分析
Spring Boot为Spring MVC提供了自动配置,可与大多数应用程序完美配合。
springboot给我们内置了自动配置类:WebMvcAutoConfiguration.java,自动配置在Spring的默认值之上添加了以下功能:
包含ContentNegotiatingViewResolver和BeanNameViewResolver。
- ViewResolver 都是SpringMVC内置的视图解析器
- ContentNegotiatingViewResolver:他并不会解析视图、而是委派给其他视图解析器进行解析
所有视图解析器,都会根据返回的视图名称进行解析视图 resolveViewName
- ContentNegotiatingViewResolver:他并不会解析视图、而是委派给其他视图解析器进行解析
1-1、ContentNegotiatingViewResolver是如何进行视图委派解析的
那最终ContentNegotiatingViewResolver通过resolveViewName是怎么委派给其他视图解析器进行解析的呢?我们接着往下看。
进入getCandidateViews
进入这个方法,他首先获得了所有的视图,然后进行迭代匹配
其中viewResolvers是如何获取的呢?我们往上面看,如下图,可以看到这个initServletContext方法,中进行了viewResolvers的初始化操作,这个方法在服务启动的时候就会进行调用。然后从spring容器中拿到匹配ViewResolver的所有Bean
通过以上的了解,那么我们就可以自己也配置一个ViewResolver的实现类,并注册为BEAN,这样spring在初始化的时候,我们自己写的继承与ViewResolver的类也就会被加载的viewResolver中了,这样就可以帮我们进行委派解析了。
需要注意的是使用viewResolver需要在Controller中返回一个视图才可以使用到这个委派的机制,之前用于做测试的项目,是无法加载到视图解析器的,我们可以打断点试一下。
访问之前通过ID获得用户的接口地址:http://localhost:8080/user/1 这样正常访问时不会进入断点的,因为我们Controller返回的是Result,非视图。然后我们再次访问地址:http://localhost:8080/user/3fdsafg 的时候,因为参数不是Integer,这个时候因为类型错误就会报错,导致跳转到错误页面,这样就经过视图解析器了,如下:
可以看到已经进入断点,并且viewName为error,即错误页面。
1-1-1、创建自己的视图解析器
为了方便,就直接在application中创建一个Bean,并且使用InternalResourceViewResolver视图解析器
然后访问http://localhost:8080/user/3fdsafg 看下断点
可以看到spring容器已经将我们刚刚配置的视图解析器放入到viewResolver中。
由以上代码可以得出结论,它是从Spring IOC容器获得ViewResolver类型Bean,那么我们可以自己定制一个ViewResolver,ContentNegotiatingViewResolver也会帮我们委派解析
1-1-2、ContentNegotiatingViewResolver视图解析器的选择
ContentNegotiatingViewResolver中的viewResolvers属性是一个List集合,其中可以指定多个视图解析器。除此之外ContentNegotiatingViewResolver还会扫描Spring 容器中所有的bean,如果发现了ViewResolver,那么该ViewResolver会供ContentNegotiatingViewResolver利用。
那么ContentNegotiatingViewResolver是如何“智能”地选择视图解析器呢? 有三种方式(优先级从高到底):
根据请求后缀,比如请求后缀是.xsl,那么它就会判断contentType是application/vnd.ms-excel…以此类推。
根据请求参数,比如请求参数xxxx/?format=json它就会判断contentType是application/json
根据Accept请求头,例如请求头包含text/html,他就会判断请求的contextType是text/html
1-2、BeanNameViewResolver
会根据handler方法返回的视图名称, 去ioc容器中到到名字叫这个视图的一个Bean,并且这个bean要实现了VIew接口,下面来创建一个。
1-2-1、创建Controller
首先创建一个控制器,然后跳转到jony视图
1-2-2、创建视图(jony)
上面控制器跳转到了jony视图,因此我们下面创建一个jony的视图,需要注意的是需要实现View接口。
1-2-3、测试访问如下
可以看到如上创建的视图继承了View,那么我们该如何判断继承那个视图呢、比如我们要下载Excel,该继承那个视图呢,可以看下官网
1-2-4、View的选择
首先选择spring framework
然后查看文档
进入Web Servlet
选择PDF and Excel,可以看到官网的说明,excel使用AbstractXlsView视图抽象类
如下图,我们继承了AbstractXlsView,然后可以重写buildExcelDocument方法,这个方法中有我们熟知的workbook,这样就可以操作excel了。
二、springboot静态资源的支持
以前要访问jpg\css、js 等 这些静态资源文件, 需要在web.xml配置 ,在springboot不需要配置,只需要放在约定文件夹static中就可以(约定大于配置)
首先在resource/static下创建img文件夹,然后将2.jpg图片复制进去
浏览器直接访问:http://localhost:8080/img/2.jpg
已经成功访问,不像springmvc的时候还需要对静态资源进行配置,springboot就方便了很多,开箱即用,那springboot是如何实现的呢?接下来,一起探究一下
2-1、静态配置类是如何支持静态资源的
在springboot的自动配置类WebMvcAutoConfiguration中,有一个针对resource处理的方法:addResourceHandlers
在上图中,可以看到有一个叫webjars的,它是做什么的呢?
2-1-1、WebJars的探究
WebJars: 就是将静态资源放在jar包中进行访问
- webjars官网:www.webjars.org/
往下拉就可以看到webjars给我们提供的相关jar
然后选择maven的方式,复制对应的maven依赖复制到pom.xml即可
比如我们想将jquery导入到项目中,在搜索框搜索jquery,然后复制对应的maven依赖即可。
pom.xml依赖配置,
<!--juqery 的webjars-->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.6.0</version>
</dependency>
下载之后,如下图
当访问/webjars/** 时 就会去classpath:/META-INF/resources/webjars/ 对应进行映射\
当访问http://localhost:8080/webjars/juqery/3.6.0/jquery.js 对应映射到 /META-INF/resources/webjars/juqery/3.6.0/jquery.js
访问如下:
2-1-2、静态资源路径的读取
可以看下如下代码,去查看getStaticLocations()
进入getStaticLocations方法
如上图就可以看到最终读取的是classpath下的地址文件:
{ "classpath:/META-INF/resources/",
"classpath:/resources/", "classpath:/static/", "classpath:/public/" }
通过以上信息,我们就可以得知,我们可以把文件放在如上的文件夹中,
在resource中创建public文件夹,然后复制一个2.jpg到public中,然后重新编译一下,就可以看到target中就有public了,然后浏览器访问如下:
2-2、配置欢迎页
在static下创建index.html
浏览器访问:http://localhost:8080
这在springboot中是怎么处理的呢?我们再重源码入手查看
如上图首先加载getWelcomePage,然后同样加载静态资源,逐个目录进行查找index.html
2-3、静态资源路径的设置
如下可以看到当前静态资源文件配置的为(根据springboot的版本,配置略有不同):@ConfigurationProperties("spring.web")
假如我们不想让resource/public生效,只使用static,就可以在资源文件中配置:spring.mvc.static-path-pattern=classpath:/static
这样springboot就只会去static中查找静态文件了,如果有多个可以用“,”分割开。
三、springboot的转换器
3-1、日志转换器
之前在springmvc的文章中有提到过类转换器,可以把日期格式进行转换,然后用springboot再看一下。
首先还是到自动配置类WebMvcAutoConfiguration.java中找到mvcConversionService方法,如下:
@Bean
@Override
public FormattingConversionService mvcConversionService() {
Format format = this.mvcProperties.getFormat();
WebConversionService conversionService = new WebConversionService(new DateTimeFormatters()
.dateFormat(format.getDate()).timeFormat(format.getTime()).dateTimeFormat(format.getDateTime()));
addFormatters(conversionService);
return conversionService;
}
可以看到这个转换器中对日期进行了处理,我们进入DateTimeFormatters这个类
然后看一下这个类中的DateTimeFormatters
通过上面代码可以看到如果
pattern没有传入值,则时间默认格式为yyyy-MM-dd,如果传入了则以传入的为准,
然后回到自动配置类中,继续看一下这个方法,是如何获得配置信息的,如下
如下代码,我们可以得知,配置时间格式,可以通过spring.mvc.format.date进行配置。
3-2、数据转换器HttpMessageConverters
我们在使用控制器的时候,从控制器向前端发送JavaBean,前端接收到的为Json数据,当前端向后端提交Json数据的时候,后端我们就可以使用JavaBean来进行接收,这都归功于HttpMessageConverters,大概工作顺序为:
3-3、自动注册MessageCodesResolver
- 修改4xx 错误下 格式换转换出错 类型转换出错的 错误代码:
- 以前的格式
- errorCode + "." + object name + "." + field
- typeMismatch.user.birthday
- 可以通过
spring.mvc.message-codes-resolver-format=postfix_error_code
将格式修改为:object name + "." + field + "." + errorCode
四、springboot中html的支持
在springboot中可以直接返回html的视图
4-1、在Controller中添加html的跳转
/**
* 跳转到html
* @return
*/
@RequestMapping("/html")
public String toHtml(){
return "hello";
}
4-2、在application.properties中添加视图配置信息
spring.mvc.view.prefix=/pages/
spring.mvc.view.suffix=.html
4-3、添加hello.html页面
4-4、在自动配置类WebMvcAutoConfigruation中查看
如上代码可以看到通过读取前缀和后缀的配置信息。