Spring Boot與Web開發(fā),thymeleaf模板語言的使用

使用Spring Boot
  1. 創(chuàng)建Spring Boot應(yīng)用,選擇我們需要的模塊。
  2. Spring Boot已經(jīng)默認將這些場景給配置好了。只需要在配置文件中指定少量配置就可以運行起來。
  3. 自己編寫業(yè)務(wù)代碼。
自動配置原理:

這個場景Spring Boot幫我們配置了什么?能不能修改?能修改哪些配置?能不能擴展?……

xxxAutoConfiguration:幫我們給容器中自動配置組件。
xxxxProperties:配置類來封裝配置文件中的內(nèi)容。

Spring Boot對靜態(tài)資源的映射規(guī)則

  1. 所有的/webjars/**,都去classpath:/META-INF/resources/webjars/找資源。
    webjars:以jar包的反式引入靜態(tài)資源。webjars官網(wǎng)
    例如:jquery的webjars
    jquery的webjars.png

    訪問他的路徑為:
    localhost:8080/webjars/jquery/3.5.1/jquery.js
  2. "/**"訪問當前項目下的任何資源(靜態(tài)資源的文件夾)

類路徑指:main下的java文件夾或resources文件夾
"classpath:/META-INF/resources/":類路徑下的/META-INF/resources/
"classpath:/resources/":類路徑下的/resources/
"classpath:/static/":類路徑下的/static/ 一般放css,js等
"classpath:/public/":類路徑下的/public/
"/":當前項目的根目錄路徑

localhost:8080/xxxx ----> 沒人處理就會去靜態(tài)資源中去找對應(yīng)的資源

  1. 歡迎頁:靜態(tài)資源文件夾下的所有index.html頁面。被"/**"映射。
  2. 所有的**/favicon.ico 都是在靜態(tài)資源文件下找。命名為:favicon.ico
########自己定義靜態(tài)資源文件夾
spring.web.resources.static-locations=classpath:/hello/
########spring.web.resources是一個數(shù)組,可以寫多個文件夾,用逗號分隔開

模板引擎

JSP、Velocity、Freemarker、Thymelef(Spring Boot推薦使用的)、……
Spring Boot推薦的模板引擎:Thymelef
語法更簡單、功能更強大。

使用方法

1. 引入Thymelef:
<!--引入spring-boot中的thymeleaf模板引擎-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
2. 使用Thymelef中的&語法
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {
    private static final Charset DEFAULT_ENCODING;
    public static final String DEFAULT_PREFIX = "classpath:/templates/";
    public static final String DEFAULT_SUFFIX = ".html";
    private boolean checkTemplate = true;
    private boolean checkTemplateLocation = true;
    private String prefix = "classpath:/templates/";
    private String suffix = ".html";
    private String mode = "HTML";
    private Charset encoding;
    private boolean cache;
    private Integer templateResolverOrder;
    private String[] viewNames;
    private String[] excludedViewNames;
    private boolean enableSpringElCompiler;
    private boolean renderHiddenMarkersBeforeCheckboxes;
    private boolean enabled;
    private final ThymeleafProperties.Servlet servlet;
    private final ThymeleafProperties.Reactive reactive;

只要我們把html放在classpath:/templates/,thymeleaf就能自動渲染。
使用:

  1. 導(dǎo)入thymeleaf的命名空間
<html lang="en" xmlns:th="http://www.thymeleaf.org">
  1. 使用thymeleaf的語法:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>成功</title>
</head>
<body>
<h1>成功</h1>
<!--th:text 將div中的文本內(nèi)容設(shè)置為-->
<div th:text="${hello}">這是顯示歡迎信息</div>
</body>
</html>
  1. 語法規(guī)則
  • th:text 改變當前元素里面的文本內(nèi)容。
    可以使用th:任意html屬性。使用th:任意屬性來替換原生對應(yīng)屬性。
    thymeleaf標簽.png
  • 表達式語法?
變量表達式:$ {...}
    1.獲取對象的屬性、調(diào)用方法
    2.使用內(nèi)置對象
    3.內(nèi)置的工具對象
選擇變量表達式:\* {...}:和${…}在功能上是一樣
    補充:配合 th:object=${" "}使用
消息表達式:#{...}:獲取國際化內(nèi)容
鏈接網(wǎng)址表達式:@{…}:定義url鏈接
    @{localhost:8080/order/buy(name=${obj.name,type=true})}
片段表達式:~{…}
    <div th:insert="~{commons :: main}">…</div>

表達式支持:
    1.字面量
    2.文本操作
        字符串連接:+
        文本替換:|The name is ${name}|
    3.數(shù)學運算
        二進制運算符:+ 、 - 、 \* 、 / 、 %
    4.負號(一元運算符):-
    5.布爾運算
        二進制運算符:and、or
        布爾否定(一元運算符):!、not
    6.比較和相等運算符
        比較運算符:&gt; 、&lt; 、&gt =、&lt =(gt、lt、ge、le)
        相等運算符:==、!=(eq、ne)
    7.條件運算符:(三元運算)
        If-then:(if) ? (then)
        If-then-else:(if) ? (then) :(else)
        Default:(value) ?: (defaultvalue)
    8.特殊符號
        啞操作符:_

測試一:

//控制層
//查出用戶數(shù)據(jù),在頁面展示
    @RequestMapping("/success")
    public String success(Map<String, Object> map) {
        map.put("hello", "<h1>你好</h1>");
        map.put("users", Arrays.asList("zhangsan","lisi","王五",3));
        return "success";
    }

//頁面
<!DOCTYPE html>
<!--聲明命名空間 xmlns:th="http://www.thymeleaf.org" -->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>成功</title>
</head>
<body>
<!--對應(yīng)<h1>你好<h1>-->
<div th:text="${hello}"></div>
<!--用utext會轉(zhuǎn)義特殊字符及html標簽中的<h1>你好<h1>-->
<div th:utext="${hello}"></div>
<br>
<!--遍歷數(shù)組 ["zhangsan","lisi","王五",3]-->
<!--th:each=""每次遍歷都會生成一個標簽  3個h4-->
<h4 th:each="user:${users}" th:text="${user}"></h4>
<br>
<h4>
    <!--th:each=""每次遍歷都會生成一個標簽  3個span-->
    <span th:each="user:${users}"> [[${user}]] </span>
</h4>
</body>
</html>

測試二:改變thymeleaf文件的默認位置,外加一些spring Boot中thymeleaf的屬性

########設(shè)置日志的級別
logging.level.cn.fantuan=trace
########設(shè)置控制臺打印的日志格式
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} | %highlight(%-5level) | %boldYellow(%thread)  %logger === %highlight(%msg%n)
########設(shè)置靜態(tài)資源的文件路徑
spring.web.resources.static-locations=classpath:/webapp/

#########使用了thymeleaf之后mvc的視圖解析器就沒有好大的作用了
#########設(shè)置視圖解析器的前綴
#spring.mvc.view.prefix=/pages/
#########設(shè)置視圖解析器的后綴
#spring.mvc.view.suffix=.html

########設(shè)置thymeleaf可以解析的視圖名稱的逗號分隔列表,指的是html文件名稱
#spring.thymeleaf.view-names=success,*
########關(guān)閉頁面緩存
spring.thymeleaf.cache=false
########構(gòu)建URL時附加到查看名稱的前綴。
spring.thymeleaf.prefix=classpath:/templates/pages/
########構(gòu)建URL時附加到查看名稱的后綴。
spring.thymeleaf.suffix=.html




########啟用模板緩存。
#spring.thymeleaf.cache = true
########在呈現(xiàn)模板之前檢查模板是否存在。
#spring.thymeleaf.check-template = true
########檢查模板位置是否存在。
#spring.thymeleaf.check-template-location = true
########Content-Type值。
#spring.thymeleaf.content-type = text / html
########啟用MVC Thymeleaf視圖分辨率。
#spring.thymeleaf.enabled = true
########模板編碼。
#spring.thymeleaf.encoding = UTF-8
########應(yīng)該從解決方案中排除的視圖名稱的逗號分隔列表。
#spring.thymeleaf.excluded-view-names =
########應(yīng)用于模板的模板模式。另請參見StandardTemplateModeHandlers。
#spring.thymeleaf.mode = HTML5
########在構(gòu)建URL時預(yù)先查看名稱的前綴。
#spring.thymeleaf.prefix = classpath:/ templates /
########構(gòu)建URL時附加到查看名稱的后綴。
#spring.thymeleaf.suffix = .html
########鏈中模板解析器的順序。
#spring.thymeleaf.template-resolver-order =
########可以解析的視圖名稱的逗號分隔列表。/ templates / #在構(gòu)建URL時先查看名稱的前綴。
#spring.thymeleaf.view-names =
########構(gòu)建URL時附加到查看名稱的后綴。
#spring.thymeleaf.suffix = .html
########鏈中模板解析器的順序。
#spring.thymeleaf.template-resolver-order =
########可以解析的視圖名稱的逗號分隔列表。/ templates / #在構(gòu)建URL時先查看名稱的前綴。
#spring.thymeleaf.view-names =
########構(gòu)建URL時附加到查看名稱的后綴。
#spring.thymeleaf.suffix = .html
########鏈中模板解析器的順序。
#spring.thymeleaf.template-resolver-order =
########可以解析的視圖名稱的逗號分隔列表。
#spring.thymeleaf.view-names =



#########控制器
package cn.fantuan.springboot02.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Arrays;
import java.util.Map;

@Controller
public class HelloController {
    //控制層
    //查出用戶數(shù)據(jù),在頁面展示
    @RequestMapping("/suc")
    public String success(Map<String, Object> map) {
        System.out.println("success");
        map.put("hello", "<h1>你好</h1>");
        map.put("users", Arrays.asList("zhangsan","lisi","王五",3));
        return "success";
    }
    @RequestMapping("/vip")
    public String vip(Map<String, Object> map) {
        System.out.println("vip");
        map.put("hello", "<h1>你好</h1>");
        map.put("users", Arrays.asList("zhangsan","lisi","王五",3));
        return "vip/vip";
    }
    @RequestMapping("/user")
    public String user(Map<String, Object> map) {
        System.out.println("user");
        map.put("hello", "<h1>你好</h1>");
        map.put("users", Arrays.asList("zhangsan","lisi","王五",3));
        return "user/user";
    }
}

文件目錄層級關(guān)系


文件目錄層級關(guān)系
擴展Spring MVC:
<!--請求處理-->
<mvc:view-controller path="/hello" view-name="success"/>
<!--攔截器-->
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/hello"/>
        <bean></bean>
    </mvc:interceptor>
</mvc:interceptors>

編寫一個配置類(@Configuration),是WebMvcConfigurer類型的。不能標準@EnableWebMvc注解 。
既保留了所有的自動配置,也能用我們來擴展配置。

package cn.fantuan.springboot03webrestcrud.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

//使用WebMvcConfigurer可以用來擴展SpringMvc的功能
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    //視圖映射
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //瀏覽器發(fā)送/hellos請求,來到success
        //可以直接用這種方法來處理只是跳轉(zhuǎn)頁面的請求
        registry.addViewController("/hellos").setViewName("success");
    }
}

原理:

  1. WebMvcAutoConfiguration是SpringMVC的自動配置類
  2. 在做其他自動配置時
    @Configuration(proxyBeanMethods = false)
    public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {

    //從容器中獲取所有的WebMvcConfigurer賦值到configurers里面
    @Autowired(required = false)
    public void setConfigurers(List<WebMvcConfigurer> configurers) {
        if (!CollectionUtils.isEmpty(configurers)) {
            this.configurers.addWebMvcConfigurers(configurers);
            //一個參考實現(xiàn),將所有的WebMvcConfigurer相關(guān)的配置都一起調(diào)用
            protected void addViewControllers(ViewControllerRegistry registry) {
                this.configurers.addViewControllers(registry);
            }
        }

    }
  1. 容器中所有的WebMvcConfigurer都會一起起作用。
  2. 我們自己寫的配置類也會被調(diào)用。

效果:
SpringMVC的自動配置和擴展配置都會起作用。

全面接管SpringMVC:

Spring Boot對SpringMVC的自動配置不需要了,所有的都是我們自己配。
我們只需要加一個@EnableWebMvc注解在配置類即可。
不推薦使用@EnableWebMvc來全面接管。

package cn.fantuan.springboot03webrestcrud.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

//Spring Boot自動配置的SpringMVC就失效了,全部由自己配置
@EnableWebMvc
//使用WebMvcConfigurer可以用來擴展SpringMvc的功能
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    //視圖映射
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //瀏覽器發(fā)送/hellos請求,來到success
        //可以直接用這種方法來處理只是跳轉(zhuǎn)頁面的請求
        registry.addViewController("/hellos").setViewName("success");
    }
}

國際化

  1. 編寫國際化配置文件
  2. 使用ResourceBundleMessageSource管理國際化資源文件
  3. 在頁面中使用fmt.message取出國際化資源文件內(nèi)容

步驟:

  1. 編寫國際化配置文件,抽取頁面需要顯示的國際化信息


    國際化.png
  2. springBoot自動配置好了國際化資源文件的組件
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(name = {"messageSource"},search = SearchStrategy.CURRENT)
@AutoConfigureOrder(-2147483648)
@Conditional({MessageSourceAutoConfiguration.ResourceBundleCondition.class})
@EnableConfigurationProperties
public class MessageSourceAutoConfiguration {
    private static final Resource[] NO_RESOURCES = new Resource[0];

    public MessageSourceAutoConfiguration() {}

    @Bean
    @ConfigurationProperties(prefix = "spring.messages")
    public MessageSourceProperties messageSourceProperties() {
        return new MessageSourceProperties();
    }

    @Bean
    public MessageSource messageSource(MessageSourceProperties properties) {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        if (StringUtils.hasText(properties.getBasename())) {
            messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(properties.getBasename())));
        }

        if (properties.getEncoding() != null) {
            messageSource.setDefaultEncoding(properties.getEncoding().name());
        }

        messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale());
        Duration cacheDuration = properties.getCacheDuration();
        if (cacheDuration != null) {
            messageSource.setCacheMillis(cacheDuration.toMillis());
        }

        messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat());
        messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage());
        return messageSource;
    }

    protected static class ResourceBundleCondition extends SpringBootCondition {
        private static ConcurrentReferenceHashMap<String, ConditionOutcome> cache = new ConcurrentReferenceHashMap();

        protected ResourceBundleCondition() {}

        public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
            String basename = context.getEnvironment().getProperty("spring.messages.basename", "messages");
            ConditionOutcome outcome = (ConditionOutcome)cache.get(basename);
            if (outcome == null) {
                outcome = this.getMatchOutcomeForBasename(context, basename);
                cache.put(basename, outcome);
            }

            return outcome;
        }

        private ConditionOutcome getMatchOutcomeForBasename(ConditionContext context, String basename) {
            Builder message = ConditionMessage.forCondition("ResourceBundle", new Object[0]);
            String[] var4 = StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(basename));
            int var5 = var4.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                String name = var4[var6];
                Resource[] var8 = this.getResources(context.getClassLoader(), name);
                int var9 = var8.length;

                for(int var10 = 0; var10 < var9; ++var10) {
                    Resource resource = var8[var10];
                    if (resource.exists()) {
                        return ConditionOutcome.match(message.found("bundle").items(new Object[]{resource}));
                    }
                }
            }
            //指定自己寫的國際化配置文件,去掉語言國家代碼的
            return ConditionOutcome.noMatch(message.didNotFind("bundle with basename " + basename).atAll());
        }

        private Resource[] getResources(ClassLoader classLoader, String name) {
            String target = name.replace('.', '/');

            try {
                return (new PathMatchingResourcePatternResolver(classLoader)).getResources("classpath*:" + target + ".properties");
            } catch (Exception var5) {
                return MessageSourceAutoConfiguration.NO_RESOURCES;
            }
        }
    }
}
########配置文件設(shè)置國際化配置文件路徑
spring.messages.basename=i18n.login
  1. 去頁面獲取國際化的值
########行內(nèi)寫法
[[#{login.username}]]
########普通寫法
th:text="#{login.password}"
th:placeholder="#{login.code}"

出現(xiàn)亂碼??


Idea中全局默認設(shè)置.png

效果:根據(jù)瀏覽器語言設(shè)置的信息切換了國際化
原理:
國際化Locale(區(qū)域信息對象);LocaleResolver(獲取區(qū)域信息對象)

        @Bean
        @ConditionalOnMissingBean
        public LocaleResolver localeResolver() {
            if (this.webProperties.getLocaleResolver() == org.springframework.boot.autoconfigure.web.WebProperties.LocaleResolver.FIXED) {
                return new FixedLocaleResolver(this.webProperties.getLocale());
            } else if (this.mvcProperties.getLocaleResolver() == org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties.LocaleResolver.FIXED) {
                return new FixedLocaleResolver(this.mvcProperties.getLocale());
            } else {
                AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
                Locale locale = this.webProperties.getLocale() != null ? this.webProperties.getLocale() : this.mvcProperties.getLocale();
                localeResolver.setDefaultLocale(locale);
                return localeResolver;
            }
        }
//默認的就是根據(jù)請求頭帶來的區(qū)域信息獲取Locale進行國際化

點擊鏈接卻換國際化

package cn.fantuan.springboot04weblayuimini.component;

import org.springframework.web.servlet.LocaleResolver;
import org.thymeleaf.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;

/**
 * 可以在鏈接上攜帶區(qū)域信息
 */
public class MyLocaleResolver implements LocaleResolver {
    //解析區(qū)域信息
    @Override
    public Locale resolveLocale(HttpServletRequest httpServletRequest) {
        String l = httpServletRequest.getParameter("l");
        //設(shè)置區(qū)域信息為系統(tǒng)默認的
        Locale locale=Locale.getDefault();
        //判斷鏈接是否帶由區(qū)域信息
        if(!StringUtils.isEmpty(l)){
            String[] split = l.split("_");
            //帶由區(qū)域信息就覆蓋系統(tǒng)默認的區(qū)域信息
            locale = new Locale(split[0], split[1]);
        }
        return locale;
    }

    //設(shè)置區(qū)域信息
    @Override
    public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {

    }
}


 //給容器中添加自己的區(qū)域信息
    @Bean
    public LocaleResolver localeResolver(){
        return new MyLocaleResolver();
    }

頁面代碼:

<a th:href="@{/login.html(l='en_US')}" th:text="#{login.forgetPassword}" class="forget-password">忘記密碼?</a>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容