SpringBoot from getting started to giving up, Chapter 3

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:

http://localhost:8080/abc

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

Official website address

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} &gt; 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>

Keywords: Programming Thymeleaf Spring Fragment html5

Added by themistral on Wed, 13 Nov 2019 12:02:12 +0200