I. static resource mapping rules
In the springBoot project, the relevant configuration of springmvc is in the webmvcauautoconfiguration class
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 access=================== if (!registry.hasMappingForPattern("/webjars/**")) { customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**") .addResourceLocations("classpath:/META-INF/resources/webjars/") .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl)); } //===========Static resource access================ String staticPathPattern = this.mvcProperties.getStaticPathPattern(); if (!registry.hasMappingForPattern(staticPathPattern)) { customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern) .addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations())) .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl)); } } //===========Static resource storage file path================ private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" };
1. webjars access
All / webjars /, go to classpath:/META-INF/resources/webjars / to find resources
webjars: introduce static resources as jar packages. Official website
Introduce:
<dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.4.1</version> </dependency>
Directory structure:
Visit:
http://localhost:8080/webjars/jquery/3.4.1/jquery.js
2. Static resource access
/**Access any resources of the current project, and static resources access the file directory:
classpath:/META-INF/resources/, classpath:/resources/, classpath:/static/, classpath:/public/ /
Visit:
3. Mapping of welcome page index
All index.html pages in the static resource folder are mapped by / *
Visit:
http://localhost8080/index.html perhaps 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 Icon
@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); //All * * / 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 enabled by default Storage location: under static resource folder favicon.ico
5. Static resource parameter setting
@ConfigurationProperties(prefix = "spring.resources") public class ResourceProperties { //You can set parameters related to resources, such as cache time, etc } If you want to change the path of the static resource folder, modify the yml: spring.resources.static-locations=classpath:/hello,classpath:/mystatic
Template engine thymeleaf
1. Introduction of thmeleaf
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
Switch the thymeleaf Version (old version of springboot switch)
<properties> <thymeleaf.version>3.0.9.RELEASE</thymeleaf.version> <thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version> </properties>
2. Syntax of Thymeleaf
Automatic configuration file of springboot for thymeleaf
As long as we put the HTML page under classpath:/templates /, it will render automatically
@ConfigurationProperties(prefix = "spring.thymeleaf") public class ThymeleafProperties { private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8; //As long as we put the HTML page under classpath:/templates /, it will render automatically public static final String DEFAULT_PREFIX = "classpath:/templates/"; public static final String DEFAULT_SUFFIX = ".html"; }
2.1) application.yml configuration
###Thymeliaf configuration spring: thymeleaf: #Template mode, support HTML, XML TEXT JAVASCRIPT mode: HTML5 #No configuration for coding encoding: UTF-8 #Content category, can not be configured content-type: text/html #The development configuration is false to avoid modifying the template and restarting the server cache: false #Configure the template path. The default is templates, which can be used without configuration prefix: classpath:/templates ##There may be less strict HTML format in the actual project. At this time, setting mode=HTML5 will report errors for the non strict. Please refer to the following configuration: spring.thymeleaf.mode=LEGACYHTML5 ##You may find that in the default configuration, thmeleaf has strict requirements for. html content, such as < meta charset = "UTF-8" / >, ##If the last label closing symbol / is missing, an error will be reported and the error page will be moved. #Therefore, it is suggested to add the following paragraph: spring.thymeleaf.mode = LEGACYHTML5 ##The default value of spring.thymeleaf.mode is HTML5, which is actually a very strict check. Changing to legacy HTML5 can get a more friendly result ##Friendly format requirements. ##Note that legacy HTML 5 requires an additional library, NekoHTML, to be available. <dependency> <groupId>net.sourceforge.nekohtml</groupId> <artifactId>nekohtml</artifactId> <version>1.9.22</version> </dependency>
Common configurations that can be modified:
# 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) import the namespace of thymeleaf
<html xmlns:th="http://www.thymeleaf.org">
2.3) grammar
Text content (overlay): < div th: text = "${Hello}" > default text content < / div > Replace native attribute values: < div id = "AA" class = "BB" th: id = "{CC}" th: class = "${DD}" > < / div >
①. Assignment and string splicing
+: string concatenation font string
Simplify the splicing operation in characters: (use "|" to surround the string, instead of "'")
<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> //Equivalent to <span th:text="'Welcome to our application, ' + ${user.name} + '!'">
② digital output and calculation
<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>
③ arithmetic expression
*Binary operation +, -, /,%
Boolean expression true, false,!, not
and, or
<span th:text="${user.age} % 2 == 0"> </span> Result: true <span th:text="true"> </span> Result: true <span th:text="!(${user.age} % 2 == 0)"> </span> Result: false <span th:text="(${user.age} % 2 == 0) and true"> </span>Result: true
④ comparison operator
Compare >, [,] =, [= (GT, lt, Ge, Le)
Judgment = =,! = (eq, ne)
<span th:if="${user.age} > 18"> Adult </span> <span th:if="${user.age} != 18"> Adult_no_equality </span>
⑤ condition operator
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}"> //juveniles! </span> <span th:if="${member.name eq 'Ah three'}"> //Welcome to visit! </span> ##Fail to meet the judgment conditions <span th:unless="${member.age gt 18}"> //You're under 18 and can't see a movie! </span> ##switch branch judgment <span th:switch="${member.uid}"> <p th:case="100"> uid For 101 employees </p> <p th:case="99"> uid For 102 employees </p> <p th:case="*"> No matching data! </p> </span>
⑥. Properties of calling object's member variables
<input type="text" name="userName" th:value="${family.father.name}" />
⑦. Call the properties of map object
Get the property name value of the object from the hashMap through the key of the map: you can use ".." or "[]" to get the object value
<input type="text" name="userName" th:value="${hashMap.hashMapKey.name}" /> Equivalent to <input type="text" name="userName" th:value="${hashMap['hashMapKey'].name}" />
⑧ call the properties of list object
<input type="text" name="userName" th:value="${family.childList[0].name}" />
⑨ method of calling attribute
<input type="text" name="userName" th:value="${family.father.name.toUpperCase()}" />
Get the native object
<p th:text="${#httpServletRequest.getRemoteAddr()}"/> <p th:text="${#httpServletRequest.getAttribute('requestMessage')}"/> <p th:text="${#httpSession.getId()}"/> <p th:text="${#httpServletRequest.getServletContext().getRealPath('/')}"/>
(13) generate URL address @ {}
Th: the value generated by the href replaces the value @ {}
Add the variable value (orderId=${id}) to the url as the request parameter of the url
<!-- th:href Generated value substitution<a>Of href value; (orderId=${id})Do as url Request parameters for --> <a th:href="@{http://localhost:8080/order/details(orderId=${id})}">view</a> //Result: <a href="http://localhost:8080/order/details?orderId=123">view</a> <!-- Generation:/order/details?orderId=123 --> <a th:href="@{/order/details(orderId=${id})}">view</a> //Result: <a href="/order/details?orderId=123">view</a> <!-- replace url Medium variable values, generating/order/123/details --> <a th:href="@{/order/{orderId}/details(orderId=${id})}">view</a> //Result: <a href="/order/123/details">view</a>
⑫. Expression tool object
<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>
Iteration
<!-- Common iterations th:each usage --> <tr th:each="user : ${userList}"> <td th:text="${user.name}"></td> <td th:text="${user.age}"></td> <td th:text="${user.isAdmin}"></td> </tr> ##Gets the intermediate state of the iteration, defined in iterStat index : Index of current node, starting from 0 size : Total number of iteration nodes even/odd: Currently even/Odd row boolean value first/last: Today is every day/Last element <!-- Gets the intermediate state of the iteration, defined in iterStat in--> <tr th:each="user,iterStat : ${userList}"> <!-- index: Index of the current iteration --> <td th:text="${iterStat.index }"></td> <!-- first: Current element is the first element; last: Current element is last element --> <td th:text="${iterStat.first } ? 'First element':(${iterStat.last} ? 'Last element':'')" ></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>
⑭. Conditional grammar
**th:if th:unless **
<!-- th:if: If the value is true,Then print<span>Whole node --> <span th:if="${user.isAdmin}" th:text="${user.name} + 'It's the administrator.'"> </span> <!-- th:unless: and th:if Is the opposite function, if the value is false,Then print<span>Whole node --> <span th:unless="not ${user.isAdmin}" th:text="${user.name} + 'It's the administrator.'"> </span> <!-- th:switch / th:case --> <div th:switch="${user.name}"> <p th:case="'admin'">User is an administrator</p> <!-- *: case Default options for --> <p th:case="*">User is some other thing</p> </div>
⑮. template
In web development, we often extract common header, common tail, menu and other parts into templates for other pages to use. In thmeleaf, it is realized by th:fragment, th:include, th:replace, parameterized template configuration, css selector loading code block, etc.
Public page / templates/template/footer.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <meta charset="UTF-8" /> <body> <!-- th:fragment Define blocks for loading --> <span th:fragment="copy"> 2017 hry loaded by fragment=copy</span> <span id="copy-section"> 2017 hry loaded by id=copy-section</span> <!-- When defining a template, you can pass in parameters --> <span th:fragment="frag(month, date) "> <span th:text="'welcome hry come in ' + ${month} + '-' + ${date}"></span> </span> </body> </html>
Load the above code block copy in this page through th:include:
templatename::selector:: "preceded by the template file name, followed by the selector
: selector: write only the selector. Here it refers to the fragment name. Then the corresponding fragment of this page will be loaded
templatename: write only the template file name, then load the entire page
<!-- Syntax specification "::"Template file name followed by selector --> <div th:include="template/footer::copy"></div> <!-- Write only selector fragment Name, the corresponding fragment --> <div th:include="::#thispage"></div> <!-- Write only the template file name, the entire page will be loaded --> <div th:include="template/footer"></div> <!--Load block for this page--> <span id="thispage"> div in this page. </span>
Loading code blocks with th:fragment and css selectors
<! -- load "th:fragment here to define the block to load" -- > <div th:include="template/footer::copy"></div> <! -- load the node with id = copy section -- > <div th:include="template/footer::#copy-section"></div>
th:include and th:replace
##th:include: content of load template: read the content of load node (excluding node name), replace div content ##th:replace: replace the current label with the label in the template. The loaded node will replace the entire div loaded Content of load template: read the content of load node (excluding node name), replace the content of < div > -- > <div th:include="template/footer::copy">1</div> Result: <div> 2017 hry loaded by fragment=copy</div> <! -- replace the current label with the label in the template: the loaded node will replace the whole < div > -- > <div th:replace="template/footer::copy">2</div> Result: <span> 2017 hry loaded by fragment=copy</span>
Pass parameters on template call
<div th:include="template/footer::frag(${month},${date})">...</div>