目录:
1 前言
在实际开发中,SpringBoot 通过自动装配帮我们解决许多问题,那么我们能不能自定义修改其中的一些内容呢?
SpringBoot 自动装配的代码位置:
- ***Autoconfiguration:向容器中自动配置组件;
- ***Properties:自动配置类,装配配置文件中自定义的内容。
SpringBoot 自动装配的过程:
- SpringBoot 启动会加载大量的自动配置类;
- 我们看我们需要的功能有没有在 SpringBoot 默认写好的自动配置类当中;
- 我们再来看这个自动配置类中到底配置了哪些组件;
- 给容器中自动配置类添加组件的时候,会从 ***Properties 类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可;
- 对于 SpringBoot 本身,如果其发现存在用户手动配置的数据,那么就会使用用户配置的数据,如果没有,则使用 SpringBoot 默认的。
2 静态资源导入
2.1 静态资源映射规则
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
// 已禁用默认资源处理
logger.debug("Default resource handling disabled");
return;
}
// 缓存控制
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
// webjars 配置
if (!registry.hasMappingForPattern("/webjars/**")) {
customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/")
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
// 静态资源配置
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
.addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
}
2.2 使用 webjars 方法
webjars 本质就是以 jar 包的方式引入我们的静态资源。
比如当我们想要使用 jQuery 时,我们只需在 https://www.webjars.org 查找引入 jQuery 对应版本的pom依赖即可。
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.4.1</version>
</dependency>
这样,我们便可以在对应的路径访问静态资源:http://localhost:8080/webjars/jquery/3.4.1/jquery.js
2.3 使用默认静态资源目录
"classpath:/META-INF/resources/"
"classpath:/resources/"
"classpath:/static/"
"classpath:/public/"
我们可以在resources根目录下新建对应的文件夹,都可以存放我们的静态文件;
2.4 自定义静态资源文件夹
我们也可以自己通过配置文件来指定一下,哪些文件夹是需要我们放静态资源文件的,在 application.properties 中配置;
spring.resources.static-locations=classpath:/coding/
一旦自己定义了静态文件夹的路径,原来的自动配置就都会失效了。
3 Thymeleaf 模板引擎
3.1 模板引擎
如下图所示,模板引擎通过将我们给定的数据以及指定的模板进行填充,最终生成一个我们想要的内容。JSP 便是一种模板引擎。
由于 SpringBoot 默认不支持 JSP,且静态页面的开发过于繁琐,因此这里我们可以使用 Thymeleaf 模板引擎。
3.2 导入 Thymeleaf 依赖
要想使用 Thymeleaf,只需导入对应的依赖即可。对应的 pom 文件以及说明文档可以从以下三个网站中找到:
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
3.3 Thymeleaf 使用
3.3.1 Thymeleaf 的规则
根据 SpringBoot 的自动配置原理可知,我们可以通过查找 Thymeleaf 的自动配置类 ThymeleafProperties 来了解其使用规则。
在 IDEA 中可以使用 ctrl + shift + alt + N 通过类名查找类。
@ConfigurationProperties(
prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
private boolean checkTemplate = true;
private boolean checkTemplateLocation = true;
private String prefix = "classpath:/templates/";
private String suffix = ".html";
private String mode = "HTML";
private Charset encoding;
}
可以看到,我们只要把我们的 html 页面放在类路径下的 templates 下,thymeleaf 就可以帮我们自动渲染了。使用 thymeleaf 什么都不需要配置,只需要将他放在指定的文件夹下即可。
3.3.2 测试
1 编写一个测试页面 test.html 放在 templates 目录下;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>这是一个测试页面</h1>
</body>
</html>
2 编写一个 TestController;
@Controller
public class TestController {
@RequestMapping("/t1")
public String test1(){
// 便会自动转到 classpath:/templates/test.html 这个目录下
return "test";
}
}
3 浏览器输入对应网站,输入如下内容;
3.4 Thymeleaf 语法
语法参考 Thymeleaf 的官方文档,传送门。弄几个测试。
3.4.1 后端传送内容到前端显示
1 编写一个 TestController;
@Controller
public class TestController {
@RequestMapping("/t1")
public String test1(Map<String,Object> map){
//存入数据
map.put("msg","<h1>Hello, Thymeleaf</h1>");
// 便会自动转到 classpath:/templates/test.html 这个目录下
return "test";
}
}
2 编写一个测试页面 test.html 放在 templates 目录下;
<!DOCTYPE html>
<!-- 若要使用 Thymeleaf,需要在 html 文件中导入命名空间的约束,方便提示 -->
<!-- 只有被接管了,才可以使用他的表达式 -->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- th:text就是将div中的内容设置为它指定的值 -->
<div th:text="${msg}"></div>
<!--不转义-->
<div th:utext="${msg}"></div>
</body>
</html>
3.4.2 前端遍历数据
1 编写一个 TestController;
@Controller
public class TestController {
@RequestMapping("/t1")
public String test1(Map<String,Object> map){
//存入数据
map.put("users", Arrays.asList("sharm","jack"));
// 便会自动转到 classpath:/templates/test.html 这个目录下
return "test";
}
}
2 编写一个测试页面 test.html 放在 templates 目录下;
<!DOCTYPE html>
<!-- 若要使用 Thymeleaf,需要在 html 文件中导入命名空间的约束,方便提示 -->
<!-- 只有被接管了,才可以使用他的表达式 -->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--th:each每次遍历都会生成当前这个标签:建议用行内写法 -->
<h4 th:each="user :${users}" th:text="${user}"></h4>
</body>
</html>
4 装配扩展 SpringMVC
Spring 的官方文档如是说:If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.
Spring 的说明文档怎么找,我以找到 Spring MVC 的自动配置这部分为例:Spring 官网 - Projects - Spring Boot - LEARN - Reference Doc. - Web - Servlet Web Applications - Spring MVC Auto-configuration。
4.1 扩展视图解析器
从源码中可以看到,我们只需要自己写一个视图解析器,并且把它注册到 bean 里面,SpringBoot 就会自动帮我们装配上。
写上视图解析器为:
// If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors
// ,formatters, view controllers, and other features), you can add your own @Configuration class of type
// WebMvcConfigurer.
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Bean
// MyViewResolver 是实现了视图解析器接口的类,因此我们可以将它看成视图解析器
public ViewResolver myViewResolver(){
return new MyViewResolver();
}
}
// 自定义了一个视图解析器
class MyViewResolver implements ViewResolver{
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
return null;
}
}
测试视图解析器是否起作用:
1 给 DispatcherServlet 中的 doDispatch方法 加个断点进行调试一下,因为所有的请求都会走到这个方法中;
2 启动我们的项目,随便访问一个页面,看一下 Debug 信息;
3 找到视图解析器,可以看到我们自定义的视图解析器就在这里,且发挥了作用。
4.2 扩展格式化配置
在 WebMvcAutoConfiguration 中找到格式化转换器:
@Bean
@Override
public FormattingConversionService mvcConversionService() {
// 拿到配置文件中的格式化规则
WebConversionService conversionService =
new WebConversionService(this.mvcProperties.getDateFormat());
addFormatters(conversionService);
return conversionService;
}
进入到.getDateFormat
方法中,可以看到:
public String getDateFormat() {
return this.dateFormat;
}
/**
* Date format to use. For instance, `dd/MM/yyyy`. 默认的
*/
private String dateFormat;
所以我们可以在我们的 Properties 文件中设置新的配置日期格式化的规则为:
spring.mvc.data-format=……
4.3 扩展视图跳转
这样的话,当我们书写一个新的链接,新的链接会跳转到指定的链接里。
// If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors
// ,formatters, view controllers, and other features), you can add your own @Configuration class of type
// WebMvcConfigurer.
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/sharm").setViewName("test");
}
}
其中 test.html 的内容为:
<body>
<!--th:each每次遍历都会生成当前这个标签:官网-->
<!--<h4 th:each="user :${users}" th:text="${user}"></h4>-->
<h1>This is new page!</h1>
</body>
浏览器输出为:
4.4 全面接管 SpringMVC
官方文档:
If you want to take complete control of Spring MVC you can add your own @Configuration annotated with @EnableWebMvc.
@Configuration
// 当在配置类中加上 @EnableWebMvc 这个注解,可以看到之前 SpringBoot 给我们配置的静态资映射全都无效了。在开发中,不推荐使用全面接管 SpringMVC
@EnableWebMvc
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/sharm").setViewName("test");
}
}
访问首页出现的结果。
原因:
1 该注解导入了一个类
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}
2 它继承了一个父类 WebMvcConfigurationSupport
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
// ......
}
3 Webmvc 自动配置类为:
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
// 这个注解的意思就是:容器中没有这个组件的时候,这个自动配置类才生效
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
}