2020:0626---05--SpringBoot与Web开发

344 阅读11分钟

主要内容

1. Thymeleaf
2. web定制
3. 容器定制

1. SpringBoot对静态资源的映射规则

1.1 创建SpringBoot项目

    1). 创建SpringBoot应用,选中我们需要的模块
    2). SpringBoot已经默认将这些场景配置好了,只需要在配置文件中指定少量配置就可
        以运行起来
    3). 自己编写业务代码
    
    
    自动配置原理:我们要明白
        每引入一个场景,SpringBoot帮我们配置了什么?能不能修改?能修改哪些配置?...
    
    A: xxxxAutoConfiguration:帮我们给容器中自动配置组件
    B:xxxxProperties:配置类来封装配置文件的内容。

1.2 SpringBoot对静态资源的映射规则:webjars

    1).WebMvcAutoConfiguration 自动配置类下的这段代码:
@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();
	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));
	}
}
    定义了映射规则:
    A: 所有/webjars/**请求, 都去classpath:/META-INF/resources/webjars/找资源
    
        webjars:以jar包的方式引入静态资源。

参考webjars官网

        webjars:可以将jquery/bootstrap以maven依赖的方式交给我们。
        
        比如导入jquery的坐标,我们就可以通过/webjars/**请求访问jquery包中的资源

    B:这个jar包的项目结构,正好对应着SpringBoot对静态资源的映射规则

        比如:localhost:8080/webjars/jquery/3.3.1/jquery.js这个请求,
        都去classpath:/META-INF/resources/webjars/目录下找资源。

    2). properties类用来封装配置文件的内容
        我们可以修改默认的配置----来自这个类
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties {
}
1.2.1 测试一下
    1.引入JQuery的依赖坐标:
        <!--引入JQuery的webjar-->  在访问的时候只需要写webjars下面的资源名称即可
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.3.1</version>
        </dependency>
    2.启动项目
    
    3.请求localhost:8080/webjars/jquery/3.3.1/jquery.js

    4.请求成功

1.3. 非webjars 静态资源怎么访问

    另一种映射规则:/** 

    访问当前项目的任何资源,如果没人处理默认都去哪找?

    把静态资源放到这些文件夹中,如果没人处理,都会到这些文件夹下找内容。
        "classpath:/META-INF/resources/", 
        "classpath:/resources/",
        "classpath:/static/", 
        "classpath:/public/" 
        "/":当前项目的根路径
    resources是类路径的根目录,所以对应这几个文件夹:

    访问时不加静态资源文件夹名:
    localhost:8080/abc  === 回去静态资源里面找abc资源
    
    测试一下:http://localhost:8080/asserts/js/Chart.min.js
    访问成功,注意Maven clean一下。

1.4 欢迎页的映射和favicon.ico小图标

1)
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
		FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
	WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
			new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
			this.mvcProperties.getStaticPathPattern());
	welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
	welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations());
	return welcomePageHandlerMapping;
}
欢迎页:静态资源文件夹下的所有index.html被 /** 映射

localhost:8080/

测试一下:localhost:8080

2) 
    所有的**/favicon.ico 都是在静态资源文件下找

1.4.1 手动配置映射规则
手动配置映射规则    
这些静态资源资源映射配置都可以通过:staticLocation属性在主配置文件中进行配置
spring.resources.staticLocation=classpath:/xx/xx

2 Thymeleaf模版引擎

2.1 Thymeleaf概述

    Thymeleaf是一款用于渲染XML/XHTML/HTML5内容的模版引擎。类似JSP,Velocity,
FreeMaker等,它可以轻易的与Spring MVC等Web框架进行集成做为Web应用的模版引擎。与
其他模版引擎相比,Thymeleaf最大的特点是能够直接在浏览器中打开并正确显示模版页面,
而不需要启动整个web应用
    SpringBoot推荐使用Thymeleaf,Freemarker等后现代的模版引擎技术;一旦导入相关
依赖,会自动配置ThymeleafAutoConfiguration,FreeMarkerutoConfiguration。

2.2 课程背景

    在我们继续学习时,有一个非常严重的问题。
    
    我们用的前端页面是html页面,如果是以前我们的开发习惯,是要将其转成JSP页面。
原因是为了方便使用其中的<c:foreach> <c:if>等逻辑代码。
    
    但是我们现在用的是SpringBoot创建的项目默认打包方式是jar方式,不是web方式。
第二我们用的还是嵌入式的tomcat,所以是不支持JSP的。所以如果用纯静态页面方式开发
会带来非常大的麻烦。

    所以SpringBoot推荐我们来使用模版引擎Thymeleaf。  

2.3 模版引擎的作用

    比如我们写一个页面模版,比如有些值是动态的,我们写一些表达式。这些值从哪来呢?
我们组装一些数据我们把这些数据得到。然后我们将模版和得到的数据交给模版引擎。
    模版引擎按照数据将模版中的表达式解析,填充到指定的位置。然后把数据最终生成一个
正确的内容,然后写出去。

2.4 Thymeleaf模版引擎

2.4.1 Thymeleaf模版引擎的引入
        引入Thymleaf:引入对应场景的starter
        spring-boot-starter-thymeleaf
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        查看一下默认导入的Thymeleaf版本和响应的布局版本是否合适
    
        布局功能的适配:
            Thymeleaf3主程序    layout2以上版本
            Thymeleaf2          larout1

        通过spring-boot-starter-parent到spring-boot-dependencies我们发现自导配
    置的Thymeleaf版本符合适配要求。
    
        如果适配不满足,我们可以在<properties/>标签中修改。
<properties>
		<thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
		<!-- 布局功能的支持程序  thymeleaf3主程序  layout2以上版本 -->
		<!-- thymeleaf2   layout1-->
		<thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
  </properties>
2.4.2 Thymeleaf使用
1.  找到自动配置原理中的Properties对象
    我们按照SpringBoot的自动配置原理看一下Thymeleaf的自动配置规则来使用。
        
    在自动配置扩展包org/springframework/boot/autoconfigure里面能找到
thymeleaf的相关配置类  ThymeleafAutoConfiguration.java  。
    自动配置类就是为IOC添加一些组建,而添加的这些组件,或者说返回值一般都是来自于
一个Properties对象。我们要找到这个Properties对象,里面就有Thymeleaf具体的配置
规则。找打ThymeleafProperties 

2.  看一下Properties对象和配置文件绑定的具体规则        
    
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {

	private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;

	public static final String DEFAULT_PREFIX = "classpath:/templates/";

	public static final String DEFAULT_SUFFIX = ".html";
    1.  默认的前后缀:视图解析器的规则
        classpath:/templates/
        .html"
        
        只要我们把html页面放到classpath:/templates/,Thymeleaf就会帮我们自动
    渲染我们的字符串返回值。
        解析成:classpath:/templates/success.html页面
        
    2.  测试一下:
        A: 将页面放到类路径下的/templates

        B:  Controller代码
            @RequestMapping("/success")
            public String success(){
                //解析成:classpath:/templates/success.html页面
                return "success";
            }
        C:  访问请求:http://localhost:8080/success

    3.  Thymleaf使用起来就一句话:  
        只要我们把HTML页面放在classpath:/templates/目录下,Thymleaf就会自动帮
    我们渲染。
2.4.3 Thymleaf的案例
    1.  Controller代码
        //查出一些数据,在页面显示
        @RequestMapping("/success")
        public String success(Map<String, Object> map){
    
            //数据默认会被放在请求域中:SpringBoot底层实现了,这里暂时不深究
            map.put("hello","你好");
    
            //解析成:classpath:/templates/success.html页面
            return "success";
        }
    2.  在html页面导入Thymeleaf的语法空间
        <html xmlns:th="http://www.thymeleaf.org">
    
    3.  success.html
    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org">
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>success</title>
    </head>
    <body>
    
        <h1>成功666!</h1>
        <!--th:text="${hello}":将div里面的文本内容替换为${hello}-->
        <div th:text="${hello}">这里是被替换的信息</div>
    
    </body>
    </html>
    4.  分析一下:
        Controller中的代码会将map.put("hello","你好");数据默认会被放在请求域中
    具体实现是SpringBoot底层的,这里暂时不深究。
        返回值是:return "success";会被SpringBoot解析成响应的资源:
        classpath:/templates/success.html。
        
        success.html代码:
        展示一个<h1>成功666!</h1>
        展示一个<div th:text="${hello}">这里是被替换的信息</div>
            原本展示的静态页面展示的是:这里是被替换的信息
            Thymeleaf改变当前元素里面的文本内容,Controller中map存的数据。
2.4.4 Thymleaf的语法规则
1)  th:text:改变当前元素里面的文本内容
    
    1.  th: 替换元素标签的原生属性的值
        演示:

<div id="div1" class="myDiv" th:id="${hello}" th:class="${hello}" th:text="${hello}">这里是被替换的信息</div>

        将id="div1" class="myDiv"改成 id="你好" class="你好"

    2.  th的所有的语法

2) Thymeleaf表达式
    Simple expressions:(5种表达式语法)
        Variable Expressions: ${...}${} 获取变量值,底层是OGNL
        1).获取对象的属性,调用方法
            调用方法:
            ${person.createCompleteName()}
            ${person.createCompleteNameWithSeparator('-')}
        2).使用内置的基本对象
            #ctx : the context object.      上下文对象
            #vars: the context variables.   
            #locale : the context locale.
            #request : (only in Web Contexts) the HttpServletRequest object.
            #response : (only in Web Contexts) the HttpServletResponse object.
            #session : (only in Web Contexts) the HttpSession object.
            #servletContext : (only in Web Contexts) the ServletContext object.
            
            用法示例在附录中:You can read the full reference of these objects in Appendix A.
            手册P86
            
        3). 使用内置的工具对象。
            #execInfo : information about the template being processed.
            #messages : methods for obtaining externalized messages inside variables expressions, in the same way as they
            would be obtained using #{…} syntax.
            #uris : methods for escaping parts of URLs/URIs
            #conversions : methods for executing the configured conversion service (if any).
            #dates : methods for java.util.Date objects: formatting, component extraction, etc.
            #calendars : analogous to #dates , but for java.util.Calendar objects.
            #numbers : methods for formatting numeric objects.
            #strings : methods for String objects: contains, startsWith, prepending/appending, etc.
            #objects : methods for objects in general.
            #bools : methods for boolean evaluation.
            #arrays : methods for arrays.
            #lists : methods for lists.
            #sets : methods for sets.
            #maps : methods for maps.
            #aggregates : methods for creating aggregates on arrays or collections.
            #ids : methods for dealing with id attributes that might be repeated (for example, as a result of an iteration).
            
            具体演示在附录中:You can check what functions are offered by each of these utility objects in the Appendix B.
            P95
                
        Selection Variable Expressions: *{...}: *{} 变量的选择表达式
            和${}在功能上是一样的,只不过有一个补充功能,配和th:object使用
            
            示例:
            <div th:object="${session.user}">
            <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
            <p>Surname: <span th:text="*{lastName}">Pepper</span>.</p>
            <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
            </div>
            分析:
            <div th:object="${session.user}">:取出user对象放到object中
            
            <span th:text="*{firstName}">:*就代表着刚才取出的对象,等价
            <span th:text="${session.user.firstName}">
            
        Message Expressions: #{...}:*{}获取国际化内容的
        
        Link URL Expressions: @{...}: @{}定义url链接的
        
        <!-- 访问 'http://localhost:8080/gtvg/order/details?orderId=3'-->
        <a href="details.html"
            th:href="@{http://localhost:8080/gtvg/order/details(orderId=${o.id})}">view</a>
            
        Fragment Expressions: ~{...}: ~{} 片段引用的表达式
            <div th:insert="~{commons :: main}">...</div>
            
            
    Literals(字面量)
        Text literals: 'one text' , 'Another one!' ,…
        Number literals: 0 , 34 , 3.0 , 12.3 ,…
        Boolean literals: true , false
        Null literal: null
        Literal tokens: one , sometext , main ,…
        
    Text operations:(文本操作)
        String concatenation: +
        Literal substitutions: |The name is ${name}|
        
    Arithmetic operations:(数学运算)
        Binary operators: + , - , * , / , %
        Minus sign (unary operator): -
        
    Boolean operations:(布尔运算)
        Binary operators: and , or
        Boolean negation (unary operator): ! , not
        
    Comparisons and equality:(比较运算)
        Comparators: > , < , >= , <= ( gt , lt , ge , le )
        Equality operators: == , != ( eq , ne )
        
    Conditional operators:(条件判断)
        If-then: (if) ? (then)
        If-then-else: (if) ? (then) : (else)  --- 三元运算符
        Default: (value) ?: (defaultvalue)
        
    Special tokens:(特殊操作)
        No-Operation: _

2.5 Thymleaf一个小案例

1. Controller代码:
    @Controller
    public class HelloWorld {
    
        //查出一些数据,在页面显示
        @RequestMapping("/success")
        public String success(Map<String, Object> map){
    
            //数据默认会被放在请求域中:SpringBoot底层实现了,这里暂时不深究
            map.put("hello","<h1>你好</h1>");
            map.put("users", Arrays.asList("zhangsan","lisi","wangwu"));
    
            //解析成:classpath:/templates/success.html页面
            return "success";
        }
    }
2.success.html代码
<body>

    <h1>成功666!</h1>
    <div id="div1" class="myDiv" th:id="${hello}" th:class="${hello}" th:text="${hello}">
        这里是被替换的信息
    </div>

    <!--map.put("hello","<h1>你好</h1>");,th:text将标签中的空值替换成${hello}-->
    <div th:text="${hello}"></div> 
    <div th:utext="${hello}"></div>
    <hr/>

    <!--遍历:map.put("users", Arrays.asList("zhangsan","lisi","wangwu"));-->
    <!--th:each写在哪个标签上,每遍历一次都会生成一个标签-->
    <h4 th:text="${user}" th:each="user:${users}"></h4>
    <hr/>

    <!--3个span标签-->
    <h4>
        <span th:each="user:${users}">
            <!--行内表达式写法:[[...]] [(...)] :   th:text th:utext-->
            [[${user}]]
        </span>
    </h4>
</body>
    3.测试结果

3 SpringMVC自动配置

SpringMVC的自动配置在:WebMvcAutoConfiguration这个类中
org.springframework.boot.autoconfigure.web:web的所有自动配置场景

27.1.1. Spring MVC自动配置

Spring Boot为Spring MVC提供的auto-configuration适用于大多数应用,并在Spring默认
功能上添加了以下特性:

以下是SpringBoot对SpringMVC的默认配置:
    
    引入ContentNegotiatingViewResolver和BeanNameViewResolver beans。
        自动配置了ViewResolver视图解析器bean,视图解析器根据方法的返回值得到视图
        对象View,视图对象决定如何渲染(转发?重定向?...)
        
        ContentNegotiatingViewResolver:组合所有的视图解析器
        
        定制:我们可以给自己的容器中添加一个试图解析器,ContentNegotiatingViewResolver
        会自动将其组合进来,放到IOC中。
        
        
    对静态资源的支持,包括对WebJars的支持。
    对静态index.html的支持。
    对自定义Favicon的支持。
        
    自动注册Converter,GenericConverter,Formatter beans。
        Converter转换器
        Formatter格式化器:日期和字符串
        
        如果主配置文件中有:spring.mvc.date-format=xxxx,这个Formatter格式化器
        Bean就会被加到IOC中:
		@Bean
		@ConditionalOnProperty(prefix = "spring.mvc", name = "date-format")//在文件中配置日期格式化的规则
		public Formatter<Date> dateFormatter() {
			return new DateFormatter(this.mvcProperties.getDateFormat());//日期格式化组件
		}
        自己添加的格式化转换器,我们只需要放在容器中即可。
        
    对HttpMessageConverters的支持。
    
        * HttpMessageConverters:SpringMVC中用来转换Http请求和响应的
        比如:将user对象以json形式写出去。那么就需要一个HttpMessageConverters。
        * HttpMessageConverters是从容器中确定,获取所有的HttpMessageConverters
        * 自己给容器中添加HttpMessageConverters,只需要将自己的组件注册到容器中
        (@Bean,@Component)
        
    自动注册MessageCodeResolver。
        定义错误代码生成规则。

    自动使用ConfigurableWebBindingInitializer bean。
        我们可以配置一个ConfigurableWebBindingInitializer来替换默认的(添加到容器中)
        
        初始化WebDataBinder:web数据绑定器
        web数据绑定:把请求数据绑定到JavaBean中。
        
        
    如果保留Spring Boot MVC特性,你只需添加其他的MVC配置(拦截器,格式化处理器,
视图控制器等)。你可以添加自己的WebMvcConfigurer类型的@Configuration类,
而不需要注解@EnableWebMvc。如果希望使用自定义的RequestMappingHandlerMapping,
RequestMappingHandlerAdapter,或ExceptionHandlerExceptionResolver,你可以声明
一个WebMvcRegistrationsAdapter实例提供这些组件。
    
    
    
    如果想全面控制Spring MVC,你可以添加自己的@Configuration,并使用@EnableWebMvc
注解。

4. 如何修改SpringBoot的默认配置

4.1 修改SpringBoot的默认配置

模式:
    1.  SpringBoot在自动配置很多组件时,先看容器有没有用户自己配。(@Bean,@Component)
        如果有就用用户配置的,没有就自动配置。
        如果有些组件可以有多个,将用户配置的和自己默认的组合起来。

4.2 扩展SpringMVC的自动配置

    扩展SpringMVC的自动配置
        <mvc:view-controller path="/hello" view-name="success"/>
        <mvc:interceptors>
            <mvc:interceptor>
                <mvc:mapping path="/hello"/>
                <bean></bean>
            </mvc:interceptor>
        </mvc:interceptors
    1.编写一个配置类(@Configuration),是WebMvcConfigurer类型;不能标注@EnableWebMvc
        //使用WebMvcConfigurer来扩展SpringMVC的自动配置
        @Configuration
        public class MyConfig implements WebMvcConfigurer {
            //注意2.0以上不再实现WebMvcConfigurerAdapter
        
            
        }
    2.要什么功能,就重写WebMvcConfigurer中的方法
      ctrl+o:打开可以重写的方法列表

    3.比如我们要添加一个视图映射
        //使用WebMvcConfigurer来扩展SpringMVC的自动配置
        @Configuration
        public class MyConfig implements WebMvcConfigurer {
            //注意2.0以上不再实现WebMvcConfigurerAdapter
        
            //添加一个自定义的视图映射
            @Override
            public void addViewControllers(ViewControllerRegistry registry) {
                //定义规则:哪些请求访问哪些页面。
                //如果仅仅只是访问页面,不传数据的话,就可以配置这个,不用在controller在写空方法了
                registry.addViewController("/atguigu").setViewName("success");
            }
        }
    扩展SpringMVC自动配置,即保留了所有的自动配置,也能用我们扩展的配置。

4.3 全面接管SpringMVC

    SpringBoot对SpringMVC的自动配置不需要了,所有的都是我们自己配置。
    
    我们需要在配置类中添加@EnableWebMvc,所有的SpringMVC场景的自动配置都失效了。

5. 注意 xxxConfigurer

    在SpringBoot中会有非常多的xxxConfigurer帮助我们进行扩展配置。