SpringBoot配置了什么?能不能对其进行修改?能修改什么?能不能扩展?通过自动装配原理的学习,接下来主要根据自动装配源码分析并得到以下结论。
1.导入静态资源
-
这里的静态资源由果索因,即在网页中
localhost:8080/
后输入webjars
路径相当于访问源文件路径,以此找到源文件中存放静态资源位置,注:静态资源包含html
等文件; -
找到
WebMvcAutoConfiguration
文件以下部分:
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是以jar包形式封装引入前端资源,此处可以从官网取出引入静态资源依赖的代码
if (!registry.hasMappingForPattern("/webjars/**")) {
customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/")
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
/* 首先从mvcProperties对象的类WebMvcProperties文件中找到staticPathPattern变量
其次从resourceProperties对象的类ResourceProperties文件中找到staticLocations变量
*/
if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern) .addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations())) .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
}
-
webjars
引入 Mavenjquery
为例:-
将该段依赖代码放到
pom.xml
文件依赖中并加载相关依赖项,如图:这一段的含义是
localhost:8080/webjars/
路径相当于外部依赖库目录的classpath:/META-INF/resources/webjars/
,因此在网页中输入localhost:8080/webjars/jquery/3.6.0/jquery.js
即可获取到该静态资源,如图所示:
-
-
ResourceProperties
文件静态资源默认路径:- 此处四个路径全部是根目录下
resources
文件下目录,而系统默认生成static
文件夹用以存放静态资源。经过实践发现后三者优先级:/resources > /static > /public
,而第一个路径其实就是外部依赖包路径,参考webjars
; - 且
WebMvcProperties
文件下staticPathPattern
变量的默认地址就是根路径,即根路径下的资源也能直接访问到;
- 此处四个路径全部是根目录下
-
关于在
application.properties
文件中修改资源路径,一般不使用,修改的话直接修改staticPathPattern
变量即可,这样一来默认存放静态资源的路径就会全部失效;
2.定制首页
WebMvcAutoConfiguration
文件中:
/* 此方法用以获取location路径,并调用getIndexHtml方法在默认路径中寻找index.html文件
ResourceProperties文件中staticLocations变量即为静态资源路径,因此首页index.html文件可放在静态资源路径下
不过一般不使用此方法,下述模板引擎会讲到另一种方式
*/
private Optional<Resource> getWelcomePage() {
String[] locations = getResourceLocations(this.resourceProperties.getStaticLocations());
return Arrays.stream(locations).map(this::getIndexHtml).filter(this::isReadable).findFirst();
}
private Resource getIndexHtml(String location) {
return this.resourceLoader.getResource(location + "index.html");
}
private boolean isReadable(Resource resource) {
try {
return resource.exists() && (resource.getURL() != null);
}
catch (Exception ex) {
return false;
}
}
3.模板引擎Thymeleaf
使用模板自动渲染数据生成静态网页
![image-20210305211634119](https://i-blog.csdnimg.cn/blog_migrate/1002d26eab7a70c5803c59c9fab835c1.png)
-
Thymeleaf导入依赖包:
<!-- Thymeleaf --> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-java8time</artifactId> </dependency>
在父配置文件中进入依赖文件可查看Thymeleaf的默认导入版本。
-
首先查看源码,在
ThymeleafProperties
文件(每一个引入依赖都拥有自己的自动装配文件)中看到代码:// 两个变量分别定义了默认前缀和默认后缀,即前缀路径在根目录下resources/templates/目录下,即通过thymeleaf转换的html页面全部存放于该目录下 public static final String DEFAULT_PREFIX = "classpath:/templates/"; public static final String DEFAULT_SUFFIX = ".html";
-
在
templates
目录下新建test.html
文件,并在controller
目录下新建IndexController.java
文件用于测试Thymeleaf:IndexController.java
文件:
package com.kun.demoweb.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; // thymeleaf转换的所有templates目录下页面全部需要通过Controller跳转 @Controller public class IndexController { // 跳转路由 @RequestMapping("/test") public String test(Model model){ // 添加属性值传递到页面中 model.addAttribute("msg","hello,springboot"); // 从此处索引页面文件名 return "test"; } }
test.html
文件:
<!DOCTYPE html> <!-- html引入thymeleaf --> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> <!-- thymeleaf语法,引用传递过来的属性,类似于Vue语法 --> <!-- 在html标签属性前添加th: 所有属性都可以被thymeleaf接管 --> <div th:text="${msg}"></div> </head> <body> </body> </html>
-
Thymeleaf常见属性,此处不细讲,可去官网下载文档具体学习:
-
Thymeleaf常见语法:
4.装配扩展SpringMVC
-
查看官网:
-
创建config包,新建
MyMvcConfig.java
文件用于扩展SpringMVC,并根据官网说明添加注解及接口,且不能使用注解@EnableWebMvc
防止全部接管,由此可以重写一些功能; -
-
如图,示例重写自己的视图解析器:
-
先找到该文件:
/* 1.resolveViewName方法获取所有的候选视图,并从中选择最好的视图返回,此时返回的视图解析器是Thymeleaf的 */ @Override @Nullable public View resolveViewName(String viewName, Locale locale) throws Exception { RequestAttributes attrs = RequestContextHolder.getRequestAttributes(); Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes"); List<MediaType> requestedMediaTypes = getMediaTypes(((ServletRequestAttributes) attrs).getRequest()); if (requestedMediaTypes != null) { List<View> candidateViews = getCandidateViews(viewName, locale, requestedMediaTypes); View bestView = getBestView(candidateViews, requestedMediaTypes, attrs); if (bestView != null) { return bestView; } } String mediaTypeInfo = logger.isDebugEnabled() && requestedMediaTypes != null ? " given " + requestedMediaTypes.toString() : ""; if (this.useNotAcceptableStatusCode) { if (logger.isDebugEnabled()) { logger.debug("Using 406 NOT_ACCEPTABLE" + mediaTypeInfo); } return NOT_ACCEPTABLE_VIEW; } else { logger.debug("View remains unresolved" + mediaTypeInfo); return null; } } /* 2.getCandidateViews方法用以从Bean工具类中获取所有的候选视图 */ private List<View> getCandidateViews(String viewName, Locale locale, List<MediaType> requestedMediaTypes) throws Exception { List<View> candidateViews = new ArrayList<>(); if (this.viewResolvers != null) { Assert.state(this.contentNegotiationManager != null, "No ContentNegotiationManager set"); for (ViewResolver viewResolver : this.viewResolvers) { View view = viewResolver.resolveViewName(viewName, locale); if (view != null) { candidateViews.add(view); } for (MediaType requestedMediaType : requestedMediaTypes) { List<String> extensions = this.contentNegotiationManager.resolveFileExtensions(requestedMediaType); for (String extension : extensions) { String viewNameWithExtension = viewName + '.' + extension; view = viewResolver.resolveViewName(viewNameWithExtension, locale); if (view != null) { candidateViews.add(view); } } } } } if (!CollectionUtils.isEmpty(this.defaultViews)) { candidateViews.addAll(this.defaultViews); } return candidateViews; }
-
将自己重写的视图解析器放入Bean工具类中即可:
package com.kun.demoweb.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.View; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.Locale; @Configuration public class MyMvcConfig implements WebMvcConfigurer { // 将自定义的视图解析器添加进Bean中 @Bean public ViewResolver myViewResolver(){ return new MyViewResolver(); } // 自定义自己的视图解析器,并重写resolveViewName方法 public static class MyViewResolver implements ViewResolver { @Override public View resolveViewName(String viewName, Locale locale) throws Exception { return null; } } }
-
-
Ctrl+shift+N
搜索文件快捷方式;