SpringBoot从入门到放弃,第三章

原创
2019/11/13 17:39
阅读数 146

SpringBoot从入门到放弃,第三章

一、静态资源映射规则

在springBoot项目中,springmvc的相关配置都在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访问===================
    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));
    }
}

//===========静态资源存放文件路径================
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
"classpath:/resources/", 
 "classpath:/static/", 
 "classpath:/public/" 
};

1、webjars访问

所有/webjars/ ,都去classpath:/META-INF/resources/webjars/找资源

​ webjars:以jar包的方式引入静态资源。官网

引入:

<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、静态资源访问

/**访问当前项目的任何资源,静态资源访问文件目录:

classpath:/META-INF/resources/,
classpath:/resources/,
classpath:/static/, 
classpath:/public/
/

访问:

http://localhost:8080/abc

3、欢迎页index的映射

静态资源文件夹下所有index.html页面,被/**映射

访问:

http://localhost8080/index.html 或者 http://localhost8080/

@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(...) {
    
    WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
        new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
        this.mvcProperties.getStaticPathPattern());
    welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
    return welcomePageHandlerMapping;
}



private Optional<Resource> getWelcomePage() {
			String[] locations = getResourceLocations(this.resourceProperties.getStaticLocations());
			return Arrays.stream(locations).map(this::getIndexHtml).filter(this::isReadable).findFirst();
		}

4、favicon图标

@Configuration
@ConditionalOnProperty(value = "spring.mvc.favicon.enabled", matchIfMissing = true)
public static class FaviconConfiguration {

    private final ResourceProperties resourceProperties;

    public FaviconConfiguration(ResourceProperties resourceProperties) {
        this.resourceProperties = resourceProperties;
    }

    @Bean
    public SimpleUrlHandlerMapping faviconHandlerMapping() {
        SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
        mapping.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
        //所有  **/favicon.ico 
        mapping.setUrlMap(Collections.singletonMap("**/favicon.ico",
                                                   faviconRequestHandler()));
        return mapping;
    }

    @Bean
    public ResourceHttpRequestHandler faviconRequestHandler() {
        ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler();
        requestHandler
            .setLocations(this.resourceProperties.getFaviconLocations());
        return requestHandler;
    }

}
spring.mvc.favicon.enabled=true默认启用

存放位置:静态资源文件夹下
favicon.ico

5、静态资源参数设置

@ConfigurationProperties(prefix = "spring.resources")
public class ResourceProperties {
    //可以设置和资源有关的参数,如缓存时间等
}

如果想改变静态资源文件夹的路径,修改yml:
spring.resources.static-locations=classpath:/hello,classpath:/mystatic

二、模板引擎thymeleaf

1、引入thymeleaf

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

切换thymeleaf版本(旧版本的springboot切换)

<properties>
    <thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
    <thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
</properties>

2、Thymeleaf使用语法

官网地址

springboot对thymeleaf的自动配置文件

表示:只要我们把HTML页面放在classpath:/templates/下,就可以自动渲染了

@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {

	private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;

    //表示:只要我们把HTML页面放在classpath:/templates/下,就可以自动渲染了
	public static final String DEFAULT_PREFIX = "classpath:/templates/";
	public static final String DEFAULT_SUFFIX = ".html";
}

2.1)、application.yml配置

###ThymeLeaf配置
spring:
  thymeleaf:
    #模板的模式,支持 HTML, XML TEXT JAVASCRIPT
    mode: HTML5
    #编码 可不用配置
    encoding: UTF-8
    #内容类别,可不用配置
    content-type: text/html
    #开发配置为false,避免修改模板还要重启服务器
    cache: false
    #配置模板路径,默认是templates,可以不用配置
    prefix: classpath:/templates
    
##实际项目中可能会有不太严格的HTML格式,此时设置mode=HTML5将会对非严格的报错,可以参考以下配置:
spring.thymeleaf.mode=LEGACYHTML5
##你可能会发现在默认配置下,thymeleaf对.html的内容要求很严格,比如<meta charset="UTF-8" />,
##如果少最后的标签封闭符号/,就会报错而转到错误页。
#因此,建议增加下面这段:

spring.thymeleaf.mode = LEGACYHTML5
##spring.thymeleaf.mode的默认值是HTML5,其实是一个很严格的检查,改为LEGACYHTML5可以得到一个可能更友好
##亲切的格式要求。

##需要注意的是,LEGACYHTML5需要搭配一个额外的库NekoHTML才可用。
<dependency>  
       <groupId>net.sourceforge.nekohtml</groupId>  
       <artifactId>nekohtml</artifactId>  
       <version>1.9.22</version>  
</dependency> 

常见的一些可以被修改的配置:

# THYMELEAF (ThymeleafAutoConfiguration)
spring.thymeleaf.cache=true 
spring.thymeleaf.check-template=true 
spring.thymeleaf.check-template-location=true
spring.thymeleaf.enabled=true 
spring.thymeleaf.enable-spring-el-compiler=false 
spring.thymeleaf.encoding=UTF-8 
spring.thymeleaf.excluded-view-names= 
spring.thymeleaf.mode=HTML
spring.thymeleaf.prefix=classpath:/templates/ 
spring.thymeleaf.reactive.chunked-mode-view-names=
spring.thymeleaf.reactive.full-mode-view-names= 
spring.thymeleaf.reactive.media-types= 
spring.thymeleaf.suffix=.html 
spring.thymeleaf.template-resolver-order= 
spring.thymeleaf.view-names=

2.2)、导入thymeleaf的名称空间

<html xmlns:th="http://www.thymeleaf.org">

2.3)、语法

文本内容(覆盖):<div th:text="${hello}">默认文本内容</div>

替换原生属性值:<div id="aa" class="bb" th:id="#{cc}" th:class="${dd}"></div>

①、 赋值、字符串拼接

+:字符串拼接字体串

简化字符中拼接操作:(使用”|”包围字符串,不需要对字符串使用”’”)

<input type="text" name="userName" value="James Carrot" th:value="${user.name}" />
<span th:text="'The name of the user is ' + ${user.name}" ></span>
<span th:text="'The name of the user is ' + ${user.name} + '_' + ${user.age}"> </span>
<span th:text="|Welcome to our application, ${user.name}!|"></span>
等价于
<span th:text="'Welcome to our application, ' + ${user.name} + '!'">

②、数字输出和计算

<span th:text="2013">1492</span>
<span th:text="2013 + 2">1494</span>
<span th:if="${user.isAdmin()} == false"> false </span>
<span th:if="${user.other} == null"> null</span>

③、算术表达式

*二进制运算 +, -, , /, %

布尔表达式 true, false, !, not

以及 and, or

<span th:text="${user.age} % 2 == 0"> </span>			结果:true
<span th:text="true"> </span>							结果:true
<span th:text="!(${user.age} % 2 == 0)"> </span>		结果:false
<span th:text="(${user.age} % 2 == 0) and true"> </span>结果:true

④、比较操作符

比较 >, <, >=, <= (gt, lt, ge, le)

判断 ==, != (eq, ne)

<span th:if="${user.age} &gt; 18"> 大人 </span>
<span th:if="${user.age} != 18"> 大人_no_equality </span>

⑤、条件操作符

If-then: (if) ? (then)

If-then-else: (if) ? (then) : (else)

<span th:text="${user.age}%2 == 0 ? 'even'"> </span>
<span th:text="${user.age}%2 == 0 ? 'even' : 'odd'"> </span>

<span th:if="${member.age lt 18}">
	未成年人!
</span>
<span th:if="${member.name eq '啊三'}">
	欢迎小三来访问!
</span>

##不满足判断条件
<span th:unless="${member.age gt 18}">
	你还不满18岁,不能够看电影!
</span>

##switch分支判断
<span th:switch="${member.uid}">
    <p th:case="100">	uid为101的员工来了	</p>
    <p th:case="99">	uid为102的员工来了	</p>
    <p th:case="*">	没有匹配成功的数据!	</p>
</span>

⑥、调用对象的成员变量的属性

<input type="text" name="userName" th:value="${family.father.name}" />

⑦、调用map对象的属性

通过map的key从hashMap获取对象的属性name值: 可以使用”.”或者使用”[]”获取对象值

<input type="text" name="userName" th:value="${hashMap.hashMapKey.name}" />
等价于
<input type="text" name="userName" th:value="${hashMap['hashMapKey'].name}" />

⑧、调用list对象的属性

<input type="text" name="userName" th:value="${family.childList[0].name}" />

⑨、调用属性的方法

<input type="text" name="userName" th:value="${family.father.name.toUpperCase()}" />

⑩、获取原生对象

<p th:text="${#httpServletRequest.getRemoteAddr()}"/>

<p th:text="${#httpServletRequest.getAttribute('requestMessage')}"/>

<p th:text="${#httpSession.getId()}"/>

<p th:text="${#httpServletRequest.getServletContext().getRealPath('/')}"/>

⑪、生成URL地址@{}

th:href生成的值替换的href值 @{}

url中加入变量值(orderId=${id})做为url的请求参数

<!-- th:href生成的值替换<a>的href值; (orderId=${id})做为url的请求参数 -->
<a th:href="@{http://localhost:8080/order/details(orderId=${id})}">view</a>
结果:
<a href="http://localhost:8080/order/details?orderId=123">view</a>


<!-- 生成:/order/details?orderId=123 -->
<a th:href="@{/order/details(orderId=${id})}">view</a>
结果:
<a href="/order/details?orderId=123">view</a>


<!-- 替换url中变量值,生成/order/123/details -->
<a th:href="@{/order/{orderId}/details(orderId=${id})}">view</a>
结果:
<a href="/order/123/details">view</a>

⑫、表达式工具对象

<body>
    <p th:text="${#dates.format(mydate,'yyyy-MM-dd')}"/>
    <p th:text="${#dates.format(mydate,'yyyy-MM-dd HH:mm:ss.SSS')}"/>
    <hr/>
    <p th:text="${#strings.replace('www.baidu.cn','.','$')}"/>
    <p th:text="${#strings.toUpperCase('www.baidu.cn')}"/>
    <p th:text="${#strings.trim('www.baidu.cn')}"/>
    <hr/>
    <p th:text="${#sets.contains(names,'boot-0')}"/>
    <p th:text="${#sets.contains(names,'boot-9')}"/>
    <p th:text="${#sets.size(names)}"/>
    <hr/>
    <p th:text="${#sets.contains(ids,0)}"/>
    <p th:text="${ids[1]}"/>
    <p th:text="${names[1]}"/>
</body>

⑬、迭代

<!-- 常用的迭代 th:each 用法 -->
<tr th:each="user : ${userList}">
    <td th:text="${user.name}"></td>
    <td th:text="${user.age}"></td>
    <td th:text="${user.isAdmin}"></td>
</tr>


##获取迭代的中间的状态,定义在iterStat中
    index :当前节点的索引,从0开始
    size : 迭代节点总数
    even/odd:当前是偶数/奇数行,boolean值
    first/last:当前是每天/最后一个元素

<!-- 获取迭代的中间的状态,定义在iterStat中-->
<tr th:each="user,iterStat : ${userList}">
    <!-- index: 当前迭代的索引 -->
    <td th:text="${iterStat.index }"></td>
    <!-- first: 当前元素是第一个元素; last: 当前元素是最后个元素 -->
    <td th:text="${iterStat.first } ? '第一个元素':(${iterStat.last} ? '最后一个元素':'')" ></td>
    <!--  -->
    <td th:text="${iterStat.odd} ? 'odd' : 'even'" ></td>
    <td th:text="${user.name}"></td>
    <td th:text="${user.age}"></td>
    <td th:text="${user.isAdmin}"></td>

</tr>

⑭、条件语法

**th:if th:unless **

<!-- th:if:如果值是true,则打印<span>整个节点  -->
<span th:if="${user.isAdmin}" th:text="${user.name} + '是管理员'">  </span>


<!-- th:unless: 和th:if是相反功能,如果值为false,则打印<span>整个节点  -->
<span th:unless="not ${user.isAdmin}" th:text="${user.name} + '是管理员'"> </span>


<!-- th:switch / th:case -->
<div th:switch="${user.name}">
  <p th:case="'admin'">User is an administrator</p>
  <!-- *: case的默认的选项 -->
  <p th:case="*">User is some other thing</p>
</div>

⑮、模板template

在web开发中,我们经常会将公共头,公共尾,菜单等部分提取成模板供其它页面使用。在thymeleaf中,通过th:fragment、th:include、th:replace、参数化模板配置、css选择器加载代码块等实现。

公共页 /templates/template/footer.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<meta charset="UTF-8" />
<body>
    
    <!-- th:fragment 定义用于加载的块 -->
    <span th:fragment="copy"> 2017 hry loaded by fragment=copy</span>

    <span id="copy-section"> 2017 hry loaded by id=copy-section</span>

    <!-- 定义模板时,可以传入参数 -->
    <span th:fragment="frag(month, date) "> 
        <span th:text="'welcome hry come in ' + ${month} + '-' + ${date}"></span>
	</span>

</body>
</html>

通过th:include在本页中加载以上的代码块copy :

templatename::selector:”::”前面是模板文件名,后面是选择器

::selector:只写选择器,这里指fragment名称,则加载本页面对应的fragment

templatename:只写模板文件名,则加载整个页面

<!--  语法说明  "::"前面是模板文件名,后面是选择器 -->
<div th:include="template/footer::copy"></div>

<!-- 只写选择器,这里指fragment名称,则加载本页面对应的fragment -->
<div th:include="::#thispage"></div>

<!-- 只写模板文件名,则加载整个页面 -->
<div th:include="template/footer"></div>

<!--本页面的加载块-->
<span id="thispage">
    div in this page.
</span>

通过th:fragment和css选择器加载代码块

<!-- 这里加载”th:fragment 定义用于加载的块“ -->
<div th:include="template/footer::copy"></div>

<!-- 这里加载”id=copy-section“的节点 -->
<div th:include="template/footer::#copy-section"></div> 

th:include 和 th:replace

## th:include:加载模板的内容: 读取加载节点的内容(不含节点名称),替换div内容
## th:replace:替换当前标签为模板中的标签,加载的节点会整个替换掉加载他的div

<!-- 加载模板的内容: 读取加载节点的内容(不含节点名称),替换<div>的内容 -->
<div th:include="template/footer::copy">1</div>
结果:
<div> 2017 hry loaded by fragment=copy</div>


<!-- 替换当前标签为模板中的标签: 加载的节点会整个替换掉加载他的<div>  -->
<div th:replace="template/footer::copy">2</div>
结果:
<span> 2017 hry loaded by fragment=copy</span>

调用模板时传递参数

<div th:include="template/footer::frag(${month},${date})">...</div>
展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部