@

springboot 创建web项目只需要引入对应的web-starter,自己定义好moudel层,再采用相应的模版引擎技术(view层)就可以将数据渲染到模版中,从而生成一个单体的web应用!那这些视图是如何解析的呢?最常用的模版引擎语法有哪些呢?

新建一个空的项目,我们选择对应的web依赖,工具相关我三个都勾选上,数据库驱动选mysql驱动!具体见我的另一篇博客:

springboot集成mybatis和druid监控,此处不再赘述.

创建好项目后,我们来分析下源码

源码分析

首先我们都知道,springboot初始化的项目下面都是没有webapp这样一个模块的,那我们的web相关的一些资源,该放在哪里呢?为何对应的放置就可以生效呢?

我们尝试从源码中寻求答案

SpringMVC 整个 SSM 都是基于它的,所以我们第一步应该去研究 SpringBoot 关于Mvc的自动配置!

  • 1、所有mvc相关的配置都在 WebMvcAutoConfiguration (视图解析器、静态资源过滤!)
  • 2、addResourceHandlers 静态资源处理方法
  1. @Override
  2. public void addResourceHandlers(ResourceHandlerRegistry registry) {
  3. //禁用默认规则的一个配置,如果你手动的添加了资源映射路径的配置,那么这些自动配置就会直接失效!
  4. if (!this.resourceProperties.isAddMappings()) {
  5. logger.debug("Default resource handling disabled");
  6. return;
  7. }
  8. // 缓存控制
  9. Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
  10. CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
  11. // 分析源代码,需要掌握看对象的方法调用!
  12. // localhost:8080/webjars/jquery.js
  13. // 判断是否存在一个映射路径 /webjars/**,
  14. // addResourceHandler 处理逻辑 /webjars/a.js
  15. // addResourceLocations 处理资源的地址 classpath:/META-INF/resources/webjars/a.js
  16. if (!registry.hasMappingForPattern("/webjars/**")) {
  17. customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
  18. .addResourceLocations("classpath:/META-INF/resources/webjars/")
  19. .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
  20. }
  21. // 获取静态资源路径!
  22. String staticPathPattern = this.mvcProperties.getStaticPathPattern(); // localhost:8080/
  23. // 如果访问映射的路径是 staticPathPattern = "/**";
  24. // this.resourceProperties.getStaticLocations())
  25. if (!registry.hasMappingForPattern(staticPathPattern)) {
  26. customizeResourceHandlerRegistration(registry.addResourceHandler("/**")
  27. .addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
  28. .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl)); }
  29. }
  30. // 对应的资源加载先后顺序 优先级:META-INF > resources > static > public
  31. // 对于怎么验证这个优先级,可以建对于的文件加,放些静态资源,页面直接访问测试
  32. private static final String[] CLASSPATH_RESOURCE_LOCATIONS =
  33. {
  34. "classpath:/META-INF/resources/",
  35. "classpath:/resources/",
  36. "classpath:/static/",
  37. "classpath:/public/"
  38. };

我们一句句的解读,就可以读懂源码!可以看到这段源码中就这个webjars我们不怎么熟悉

webjars

什么是 webjars?

webjars官网

webjars是一个前端依赖管理工具,集成了前端主流的一些框架,使得我们只需引入对应的jar包就可以在项目中使用它!

接下来,我们引入jquery的依赖:

  1. <dependency>
  2. <groupId>org.webjars</groupId>
  3. <artifactId>jquery</artifactId>
  4. <version>3.4.1</version>
  5. </dependency>

看下生成的依赖:



我们看下是否可以直接通过路径访问:http://localhost:8080/webjars/jquery/3.4.1/jquery.js



很明显,这样是可以直接访问的。那这些可以常用的框架等静态资源我们可以这样引入,我们自定义的东西例如css 图片等该如何使用呢?

我常用的规则推荐如下:

  1. private static final String[] CLASSPATH_RESOURCE_LOCATIONS =
  2. {
  3. "classpath:/META-INF/resources/", // 在 starter 中使用! SWAGGER-UI
  4. "classpath:/resources/", // 文件资源
  5. "classpath:/static/", // 静态资源
  6. "classpath:/public/" // 公共的,图标......
  7. };

当然我们也可以更改spring的默认资源路径配置:

  1. # 一旦自己配置了 那么默认的就会失效
  2. spring.resources.static-locations=xxx

thymeleaf

引入依赖,在spring中采用jar一般都是使用对应的starter

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-thymeleaf</artifactId>
  4. </dependency>

任何starter都有一个xxxProperties我们去其依赖下看看源码:

  1. @ConfigurationProperties(prefix = "spring.thymeleaf") public class ThymeleafProperties {
  2. private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
  3. public static final String DEFAULT_PREFIX = "classpath:/templates/";
  4. public static final String DEFAULT_SUFFIX = ".html";
  5. ...省略
  6. }

可以看出thymeleaf的默认配置路径是templates下,默认文件格式是.html

我们要改只需要spring.thymeleaf.prefix=xxx,当然更改了默认的便不会生效了。

测试thymeleaf

templates新增一个页面test.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <p>hello,thymeleaf!</p>
  9. </body>
  10. </html>

controller中新增一个接口:

  1. package com.blog.controller;
  2. import org.springframework.stereotype.Controller;
  3. import org.springframework.web.bind.annotation.RequestMapping;
  4. @Controller
  5. public class IndexController {
  6. @GetMapping(value = "/test")
  7. public String test(){
  8. return "test";
  9. }
  10. }

启动项目可见:

thymeleaf语法

了解了基本的页面渲染规则后,我们来看下thymeleaf的语法:

我们还可以编写哪些表达式呢?

Variable Expressions: ${...} 获取一些基本的变量值! OGNL;

  1. 对象的属性,调用方法
  2. 使用内置的基本对象
  1. ${#ctx.locale}
  2. ${param.foo}
  3. ${session.foo}
  4. ${application.foo}
  5. ${#request.getAttribute('foo')}
  6. ${#servletContext.contextPath}
  1. 工具对象
  1. ${#messages.msg('msgKey')}
  2. ${#uris.escapePath(uri)}
  3. ${#conversions.convert(object, 'java.util.TimeZone')}
  4. ${#dates.format(date, 'dd/MMM/yyyy HH:mm')}
  5. ${#calendars.format(cal)}
  6. ${#numbers.formatInteger(num,3)}
  7. ${#strings.toString(obj)}
  8. ${#arrays.toArray(object)}
  9. .....

4.其他

  1. Selection Variable Expressions: *{...} 选择表达式,和 ${} 是一样的;
  2. Message Expressions: #{...} 国际化内容获取!
  3. Link URL Expressions: @{...} URL表达式;th:href=“@{/login}”
  4. Fragment Expressions: ~{...} 组件化表达式;
  5. Literals (字面量);
  6. Text literals: 'one text' , 'Another one!' ,... (字符串)
  7. Number literals: 0 , 34 , 3.0 , 12.3 ,...
  8. Boolean literals: true , false
  9. Null literal: null
  10. Literal tokens: one , sometext , main ,...
  11. Text operations: (文本操作)
  12. String concatenation: +
  13. Literal substitutions: |The name is ${name}| Arithmetic operations: (数学运算)
  14. Binary operators: + , - , * , / , %
  15. Minus sign (unary operator): -
  16. Boolean operations: (布尔运算)
  17. Binary operators: and , or
  18. Boolean negation (unary operator): ! , not
  19. Comparisons and equality: (比较运算)
  20. Comparators: > , < , >= , <= ( gt , lt , ge , le )
  21. Equality operators: == , != ( eq , ne )
  22. Conditional operators: (条件运算符)
  23. If-then: (if) ? (then)
  24. If-then-else: (if) ? (then) : (else)
  25. Default: (value) ?: (defaultvalue)
  26. Special tokens:
  27. Page 17 of 104**No-Operation:** _

springmvc 启动配置原理

我们来看官方文档,虽然都是英文但是不要怂,慢慢的翻的多了也就认识了!

地址:官网

找到对应的Spring MVC Auto-configuration

我们来解读下:

  1. Spring MVC Auto-configuration
  2. // SpringBoot为SpringMVC 提供提供了自动配置,他可以很多好的工作于大多数的应用!
  3. Spring Boot provides auto-configuration for Spring MVC that works well with most applications.
  4. // 自动配置在Spring默认配置的基础上添加了以下功能:
  5. The auto-configuration adds the following features on top of Springs defaults: // 包含视图解析器
  6. Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.
  7. // 支持静态资源文件的路径吗,包含webjar的支持
  8. Support for serving static resources, including support for WebJars (covered later in this document)).
  9. // 自动注册了转换器
  10. // 转换器 网页提交的前端对象,到后台自动封装为具体的对象;"1" 自动转换为 数字 1; // 格式化器Formatter 【2020-03-18 后台可以自动封装为Date】
  11. Automatic registration of Converter, GenericConverter, and Formatter beans. // 支持消息转换
  12. // request、response,对象自动转换为 json对象
  13. Support for HttpMessageConverters (covered later in this document).
  14. // 定错代码生成规则
  15. Automatic registration of MessageCodesResolver (covered later in this document). // 支持首页定制
  16. Static index.html support.
  17. // 支持自定义图标
  18. Custom Favicon support (covered later in this document).
  19. //配置web数据绑定
  20. Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document).
  21. // 如果你希望保持 Spring Boot MVC 一些功能,并且希望添加一些其他的 MVC配置(拦截器、格式化 器、视图控制器、或其他的配置),你可以添加自己的配置类 (类型为WebMvcConfigurer) 需要添加注 解@Configuration ,一定不能拥有注解@EnableWebMvc.
  22. If you want to keep those Spring Boot MVC customizations and make more MVC customizations (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc.
  23. //如果要提供RequestMappingHandlerMapping、RequestMappingHandlerAdapter或ExceptionHandlerExceptionResolver的自定义实例,并且仍然保留Spring Boot MVC自定义,则可以声明WebMVCregistration类型的bean,并使用它来提供这些组件的自定义实例
  24. If you want to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, and still keep the Spring Boot MVC customizations, you can declare a bean of type WebMvcRegistrations and use it to provide custom instances of those components.
  25. // 全面接管Spring MVC,自己配置配置类的时候加上 @EnableWebMvc即可!
  26. If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc, or alternatively add your own @Configuration-annotated DelegatingWebMvcConfiguration as described in the Javadoc of @EnableWebMvc.

我们先分析下为什么加了@EnableWebMvc注解,视图解析器就不生效了,也就是说springmvc这一套东西都不好使了!这个很神奇

源码:

  1. // 如果这个bean不存在,这个类才生效!~
  2. @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
  3. // @EnableWebMvc 源码
  4. @Import(DelegatingWebMvcConfiguration.class)
  5. public @interface EnableWebMvc
  6. // 点进DelegatingWebMvcConfiguration继承了WebMvcConfigurationSupport
  7. public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport
  8. //其实 @EnableWebMvc 就是导入了一个类 WebMvcConfigurationSupport ,但是源码中,一旦导入了 这个类,我们自动配置类就会全部失效!
  9. //如果我们要扩展springmvc
  10. //扩展mvc的方法:
  11. //1、编写一个自己的config配置类
  12. //2、实现一个接口WebMvcConfigurer
  13. //3、重写里面的方法即可!
  14. //@Configuration
  15. //public class MyMvcConfig implements WebMvcConfigurer {
  16. //}

试图解析器

ContentNegotiatingViewResolver

  1. @Bean
  2. @ConditionalOnBean(ViewResolver.class) // 自动配置了 ViewResolver,就是SpringMVC中的视图解析器
  3. @ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class)
  4. public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
  5. ContentNegotiatingViewResolver resolver = new
  6. ContentNegotiatingViewResolver();
  7. resolver.setContentNegotiationManager(beanFactory.getBean(ContentNegotiationMan ager.class));
  8. // ContentNegotiatingViewResolver uses all the other view resolvers to ocate
  9. // a view so it should have a high precedence
  10. // ContentNegotiatingViewResolver 使用其他所有的视图解析器定位视图,因此它应该具有一 个高的优先级!
  11. resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);
  12. return resolver;
  13. }

解析视图名字

resolveViewName

  1. @Override
  2. @Nullable // 参数可以为空
  3. public View resolveViewName(String viewName, Locale locale) throws Exception {
  4. RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
  5. Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
  6. List<MediaType> requestedMediaTypes = getMediaTypes(((ServletRequestAttributes) attrs).getRequest());
  7. if (requestedMediaTypes != null) {
  8. // 获取所有候选的视图!
  9. List<View> candidateViews = getCandidateViews(viewName, locale,
  10. requestedMediaTypes); // 获取最好的视图
  11. View bestView = getBestView(candidateViews, requestedMediaTypes, attrs); // 返回最好的视图
  12. if (bestView != null) {
  13. return bestView;
  14. }
  15. }
  16. String mediaTypeInfo = logger.isDebugEnabled() && requestedMediaTypes != null ? " given " + requestedMediaTypes.toString() : "";
  17. if (this.useNotAcceptableStatusCode) { if (logger.isDebugEnabled()) {
  18. logger.debug("Using 406 NOT_ACCEPTABLE" + mediaTypeInfo); }
  19. return NOT_ACCEPTABLE_VIEW;
  20. }
  21. else {
  22. logger.debug("View remains unresolved" + mediaTypeInfo); return null;
  23. }
  24. }

既然他是从容器中加载所有的视图解析器,那么我们可以猜想,我们自己写一个视图解析器,也可以被 扫描并加载!

  1. // 自己写一个 bean
  2. @Bean
  3. public ViewResolver myViewResolver(){
  4. return new MyViewResolver();
  5. }
  6. private static class MyViewResolver implements ViewResolver{
  7. @Override
  8. public View resolveViewName(String viewName, Locale locale) throws Exception{
  9. return null;
  10. }
  11. }

集成flyway插件

一直知道这么个东西,很好用单独写一篇博客又显得很浪费;那就跟着这篇博客一并说了吧

概念:

Flyway是独立于数据库的应用、管理并跟踪数据库变更的数据库版本管理工具,说白了就是Flyway可以像Git管理不同人的代码那样,管理不同人的sql脚本,从而做到数据库同步

食用方法

如果新建项目可以直接勾选上flyway插件依赖,我们这里没勾选就自己手动添加:

  • 添加依赖
  1. <dependency>
  2. <groupId>org.flywaydb</groupId>
  3. <artifactId>flyway-core</artifactId>
  4. </dependency>
  • 配置
  1. # 默认不开启flyway
  2. spring.flyway.enabled=false
  3. spring.flyway.baseline-on-migrate=true
  4. # flyway字符编码
  5. spring.flyway.encoding=UTF-8
  6. # flyway文件位置
  7. spring.flyway.locations=classpath:db/migration
  8. # ִV1__xxx.sql v开头默认执行一次
  9. # R1__xxx 开头的脚本则会在项目启动时每次都会清除表后执行
  10. spring.flyway.clean-disabled=false
  11. # flyway 历史记录表
  12. spring.flyway.table=flyway_schema_history
  • 新建文件夹

如下图 resource 新增脚本文件(按图所示目录新建,不然无法生成)启动项目可以看到数据库中出现对应的flyway_schema_history表还有按脚本生成的表和数据,flyway_schema_history表中记录的脚本的变更历史

小结:至此我们完成SpringBoot web 项目的搭建,以及thymeleaf 模板的集成和数据库版本管理插件的集成。

springboot web项目创建及自动配置分析(thymeleaf+flyway)的更多相关文章

  1. mc01_IntelliJ IDEA安装与Java项目创建以及Tomcat配置

    IntelliJ IDEA安装与激活 下载地址:http://www.jetbrains.com/idea/ 安装下一步下一步即可,关键是注册激活,该部分分两个步骤: 1. 配置windows hos ...

  2. springBoot高级:自动配置分析,事件监听,启动流程分析,监控,部署

    知识点梳理 课堂讲义 02-SpringBoot自动配置-@Conditional使用 Condition是Spring4.0后引入的条件化配置接口,通过实现Condition接口可以完成有条件的加载 ...

  3. SpringBoot入门(四)——自动配置

    本文来自网易云社区 SpringBoot之所以能够快速构建项目,得益于它的2个新特性,一个是起步依赖前面已经介绍过,另外一个则是自动配置.起步依赖用于降低项目依赖的复杂度,自动配置负责减少人工配置的工 ...

  4. SpringBoot Web项目中中如何使用Junit

    Junit这种老技术,现在又拿出来说,不为别的,某种程度上来说,更是为了要说明它在项目中的重要性. 凭本人的感觉和经验来说,在项目中完全按标准都写Junit用例覆盖大部分业务代码的,应该不会超过一半. ...

  5. 接管SpringBoot对Activiti的数据源自动配置

    SpringBoot的自动配置真的让人又爱又恨,但还是爱更多一点. SpringBoot想要帮我们自动配置好一切,但是有时候配置的却并不是我们需要的,甚至有时候会默默的坑我们. 我的项目是一个多数据源 ...

  6. SpringBoot | 4.1 SpringMVC的自动配置

    目录 前言 1. SpringMVC框架的设计与流程 1.1 SpringMVC框架的示意图 1.2 SpringMVC的组件流程 2. *自动配置的源码分析 2.1 导入Web场景启动器 2.2 找 ...

  7. 如何在spring-boot web项目中启用swagger

    swagger的三个项目及其作用 我们打开swagger的官网,会发现有三个swagger相关的项目,它们分别是 swagger-editor 作用是通过写代码,生成文档描述(一个json文件或其他格 ...

  8. Web —— java web 项目 Tomcat 的配置 与 第一个web 项目创建

    目录: 0.前言 1.Tomcat的配置 2.第一个Web 项目 0.前言 刚刚开始接触web开发,了解的也不多,在这里记录一下我的第一个web项目启动的过程.网上教程很多,使用的java IDE 好 ...

  9. 第三篇 -- IDEA 创建Springboot Web项目并用Jmeter测试

    上一节使用Django写的一个接口程序,这一节讲用IDEA配合Springboot创建web项目.一个是python,一个是java. 参考链接:http://www.uxys.com/html/Ja ...

随机推荐

  1. C 和 C++语言中的内存拷贝函数memcpy()

    memcpy指的是C和C++使用的内存拷贝函数 函数原型为void *memcpy(void *destin, void *source, unsigned n): 函数的功能是从源内存地址的起始位置 ...

  2. Java多线程并发08——锁在Java中的应用

    前两篇文章中,为各位带来了,锁的类型及锁在Java中的实现.接下来本文将为各位带来锁在Java中的应用相关知识.关注我的公众号「Java面典」了解更多 Java 相关知识点. 锁在Java中主要应用还 ...

  3. 再刷JVM-JVM运行时数据区域

    前言 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域有各自的用途,以及创建和销毁的时机,有的区域随着虚拟机进程的启动而一直存在,有些区域则是依赖用户线程 ...

  4. MyBatis框架——快速入门

    主流的ORM框架(帮助开发者实现数据持久化工作的框架): 1.MyBatis: 半自动化ORM框架,半自动:指框架只完成一部分功能,剩下的工作仍需开发者手动完成. MyBatis 框架没有实现 POJ ...

  5. 深夜,我用python爬取了整个斗图网站,不服来斗

    QQ.微信斗图总是斗不过,索性直接来爬斗图网,我有整个网站的图,不服来斗. 废话不多说,选取的网站为斗图啦,我们先简单来看一下网站的结构 网页信息 从上面这张图我们可以看出,一页有多套图,这个时候我们 ...

  6. .NET的资源并不限于.resx文件

    为了构建一个轻量级的资源管理框架以满足简单的本地化(Localization)的需求,我试图直接对现有的Resource编程模型进行扩展.虽然最终没能满足我们的需求,但是这两天也算对.NET如何进行资 ...

  7. 树莓派3B+安装&卸载mysql

    需求 在树莓派上 安装Mysql 服务,并开启远程访问 步骤 安装 mysql server 1 $ sudo apt-get install mysql-server 我以为中间会让我提示输入 数据 ...

  8. 毕业设计——基于ZigBee的智能窗户控制系统的设计与实现

    题目:基于物联网的智能窗户控制系统的设计与实现 应用场景:突降大雨,家里没有关窗而进水:家中燃气泄漏,不能及时通风,威胁人身安全,存在火灾的隐患:家中窗户没关,让坏人有机可乘.长时间呆在人多.封闭的空 ...

  9. JDBC开源框架:DBUtils自定义业务类型相关转换器

    dbutils提供的handler转换不能满足实际业务开发的需求.比如枚举转int,时间类型LocalDateTime,实体对象的属性名与字段未能相对应. mysql表member结构字段: id.m ...

  10. OpenCV-Python 交互式前景提取使用GrabCut算法 | 三十五

    目标 在本章中, 我们将看到GrabCut算法来提取图像中的前景 我们将为此创建一个交互式应用程序. 理论 GrabCut算法由英国微软研究院的Carsten Rother,Vladimir Kolm ...