介紹 SpringBoot並不推薦使用jsp Thymeleaf 是一個跟 Velocity、FreeMarker 相似的模板引擎,它能夠徹底替代 JSP 特色 動靜結合 Thymeleaf 在有網絡和無網絡的環境下皆可運行 它可讓美工在瀏覽器查看頁面的靜態效果,也可讓程序員在服務器查看帶數據的動態頁面效果 這是因爲它支持 html 原型,而後在 html 標籤裏增長額外的屬性來達到模板+數據的展現方式 瀏覽器解釋 html 時會忽略未定義的標籤屬性,因此 thymeleaf 的模板能夠靜態地運行 當有數據返回到頁面時,Thymeleaf 標籤會動態地替換掉靜態內容,使頁面動態顯示 開箱即用 它提供標準和spring標準兩種方言,能夠直接套用模板實現JSTL、 OGNL表達式效果,避免天天套模板、該jstl、改標籤的困擾。 同時開發人員也能夠擴展和建立自定義的方言。 多方言支持 Thymeleaf 提供spring標準方言和一個與 SpringMVC 完美集成的可選模塊,能夠快速的實現表單綁定、屬性編輯器、國際化等功能。 與SpringBoot完美整合 與SpringBoot完美整合,SpringBoot提供了Thymeleaf的默認配置 而且爲Thymeleaf設置了視圖解析器,咱們能夠像之前操做jsp同樣來操做Thymeleaf。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
SpringBoot會自動爲Thymeleaf註冊一個視圖解析器ThymeleafViewResolvercss
還配置了模板文件(html)的位置,與jsp相似的前綴+ 視圖名 + 後綴風格:html
與解析JSP的InternalViewResolver相似,Thymeleaf也會根據前綴和後綴來肯定模板文件的位置:java
@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 DERAULT_SUEEIX=". html"; ...... }
在配置文件中配置緩存,編碼程序員
spring: thymeleaf: cache: false mode: HTML5 encoding: UTF-8
引入名稱空間 <html lang="en" xmlns:th="http://www.thymeleaf.org"> 表達式 ${}:變量表達式 *{} :選擇變量表達式,取出hero對象中的屬性 <div th:object="${hero}"> <p th:text="*{username}"></p> <p th:text="*{phone}"></p> <p th:text="*{id}"></p> <p th:text="${hero.username}"></p> </div> #{...} : Message 表達式 URL 絕對網址 絕對URL用於建立到其餘服務器的連接,它們須要指定一個協議名稱(http://或https://)開頭 <a th:href="@{https://www.itlike.com/}"> 上下文相關URL 與Web應用程序根相關聯URL <a th:href="@{/hello}">跳轉</a> 與服務器相關URL 服務器相關的URL與上下文相關的URL很是類似 <a th:href="@{~/hello}">跳轉</a> 攜帶參數 <a th:href="@{/hero/detail(id=3,action='show_all')}">aa</a> 字面值 有的時候,咱們須要在指令中填寫基本類型如:字符串、數值、布爾等,並不但願被Thymeleaf解析爲變量,這個時候稱爲字面值。(也就是原樣輸出) 字符串字面值 <p> 內容:<span th:text=」'thymeleaf'+1">template</span> </p> 數字字面值 <p> 內容:<span th:text=」2+1">template</span> </p> 布爾字面值 布爾類型的字面值是true或false 拼接 普通字符串與表達式拼接的狀況 <span th:text=」'歡迎您:'+${hero.username}+'!'"></span> 字符串字面值須要用'',拼接起來很是麻煩,Thymeleaf對此進行了簡化,使用一對|便可 <span th:text="|歡迎您:${hero.username}|"></span> 運算符 算術操做符 + - * / % 比較運算 > , <, >= and <= 可是>和<不能直接使用,由於xml會解析爲標籤 > gt < lt >= ge <= le <!-- 返回值爲true --> <h1 th:text=" 1 lt 2"></h1> <!-- 返回值爲假 --> <h1 th:text="1 gt 2 ? '真' : '假'"></h1> 三元運算 condition ? then : else <span th:text="${false}?'男':'女'"></span〉 簡寫 <!-- 默認表達式 變量值爲空 就顯示默認值 不然就顯示變量自己 --> <h1 th:text="${hero.username}?:'我是空值'"></h1> <h1 th:text="${hero.username} != null ? ${hero.username} : '我是空值'"></h1> 內聯寫法 <!--原樣輸出--> <p>pppp-------—-[(${hero.username})]</p> <!--解析內部標籤--> <p>pppp-------—-[[${hero.username}]]</p> 局部變量 <div th:with="heroN = ${allHero[0]}"> <h1 th:text="${heroN.username}"></h1> <h1 th:text="${heroN.phone}"></h1> </div> 判斷 th:if <!--當條件知足時, 纔會顯示標籤--> <h1 th:if="${1 lt 2}">內容1</h1> th:unless <!-- unless是與if相反 不知足條件時,纔會顯示標籤 --> <h1 th:unless="${1 gt 2}">內容2</h1> th:switch <div th:switch="${hero.username}"> <p th:case="'itlike'">itlike</p> <p th:case="'gxq'">gxq</p> <p th:case="*">*爲默認的值,至關於default</p> </div> 迭代 <div> <p th:each="heroItem:${allHero}"> <span th:text="${heroItem.username}"></span> <span th:text="${heroItem.phone}"></span> <span th:text="${#dates.format(heroItem.onlinetime,'yyyy-MM-dd')}"></span> </p> </div> <hr> <div> <p th:each="heroItem,stat:${allHero}"> <span th:text="${heroItem.username}"></span> <span th:text="${heroItem.phone}"></span> <span th:text="${stat.index}"></span> </p> </div> stat對象包含如下屬性 index,從0開始的角標 count,當前遍歷到第幾個元素,從1開始 size,總元素個數 current,當前遍歷到的元素信息 odd/even,返回是否爲奇偶,boolean值 first/last,返回是否爲第一或最後,boolean值 內置對象 環境相關對象 ${#ctx} 上下文對象,可用於獲取其它內置對象。 ${#vars}: 上下文變量。 ${#locale}:上下文區域設置。 ${#request}: HttpServletRequest對象。 ${#response}: HttpServletResponse對象。 ${#session}: HttpSession對象。 ${#servletContext}: ServletContext對象。 全局對象功能 #strings:字符串工具類 #lists:List 工具類 #arrays:數組工具類 #sets:Set 工具類 #maps:經常使用Map方法。 #objects:通常對象類,一般用來判斷非空 #bools:經常使用的布爾方法。 #execInfo:獲取頁面模板的處理信息。 #messages:在變量表達式中獲取外部消息的方法,與使用#{...}語法獲取的方法相同。 #uris:轉義部分URL / URI的方法。 #conversions:用於執行已配置的轉換服務的方法。 #dates:時間操做和時間格式化等。 #calendars:用於更復雜時間的格式化。 #numbers:格式化數字對象的方法。 #aggregates:在數組或集合上建立聚合的方法。 #ids:處理可能重複的id屬性的方法。 示例 ${#strings.abbreviate(str,10)} str截取0-10位,後面的所有用…這個點代替,注意,最小是3位 ${#strings.toUpperCase(name)} 判斷是否是爲空:null: <span th:if="${name} != null">不爲空</span> <span th:if="${name1} == null">爲空</span> 判斷是否是爲空字符串: 「」 <span th:if="${#strings.isEmpty(name1)}">空的</span> 判斷是否相同: <span th:if="${name} eq 'jack'">相同於jack,</span> <span th:if="${name} eq 'ywj'">相同於ywj,</span> <span th:if="${name} ne 'jack'">不相同於jack,</span> 不存在設置默認值: <span th:text="${name2} ?: '默認值'"></span> 是否包含(分大小寫): <span th:if="${#strings.contains(name,'ez')}">包ez</span> <span th:if="${#strings.contains(name,'y')}">包j</span> 是否包含(不分大小寫) <spanth:if="${#strings.containsIgnoreCase(name,'y')}">包</span> ${#strings.startsWith(name,'o')} ${#strings.endsWith(name, 'o')} ${#strings.indexOf(name,frag)}// 下標 ${#strings.substring(name,3,5)}// 截取 ${#strings.substringAfter(name,prefix)}// 從 prefix以後的一位開始截取到最後,好比 (ywj,y) = wj, 若是是(abccdefg,c) = cdefg//裏面有2個c,取的是第一個c ${#strings.substringBefore(name,suffix)}// 同上,不過是往前截取 ${#strings.replace(name,'las','ler')}// 替換 ${#strings.prepend(str,prefix)}// 拼字字符串在str前面 ${#strings.append(str,suffix)}// 和上面相反,接在後面 ${#strings.toUpperCase(name)} ${#strings.toLowerCase(name)} ${#strings.trim(str)} ${#strings.length(str)} ${#strings.abbreviate(str,10)}// str截取0-10位,後面的所有用…這個點代替,注意,最小是3位 佈局 方式1 hello.html <nav th:fragment="header"> <h1>頭部</h1> </nav> base.html <div th:include="{common/base::header}"></div> 方式2 hello.html <footer id="footer"> <h1 th:class="${active == 'footer' ? 'red' : ''}" >尾部---</h1> <p>aaaaaa</p> </footer> base.html <div th:insert="{common/base::#footer}"></div> 引入方式 th:insert 將公共的標籤及內容插入到指定標籤當中 th:replace 將公共的標籤替換指定的標籤 th:include 將公共標籤的內容包含到指定標籤當中 傳值 hello.html <div th:include="~{base::#footer(active='footers')}"></div> base.html <footer id="footer"> <h1 th:class="${active == 'footer' ? 'red' : ''}" >尾部---</h1> <p>aaaaaa</p> </footer> js模板 模板引擎不只能夠渲染html,也能夠對JS中的進行預處理。並且爲了在純靜態環境下能夠運行 在script標籤中經過th:inline="javascript"來聲明這是要特殊處理的js腳本 取值要採用註釋的形式 <script th:inline="javascript"> var username = /*[[${name}]]*/ "myxq"; console.log(username); </script>
引入bootstrap <dependency> <groupId>org.webjars</groupId> <artifactId>bootstrap</artifactId> <version>4.0.0</version> </dependency> 在頁面中引入資源文件 <link rel="stylesheet" href="js/bootstrap/dist/css/bootstrap.css" th:href="@{/webjars/bootstrap/4.0.0/css/bootstrap.css}"> <link rel="stylesheet" href="js/font-awesome/css/font-awesome.css" th:href="@{/css/font-awesome/css/font-awesome.css}"> <link rel="stylesheet" href="css/index.css" th:href="@{/css/index.css}"> <script th:href="@{/webjars/bootstrap/4.0.0/js/bootstrap.js}"></script>
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addVievController("/")).setViewName("login"); registry.addVievController("/index.html")).setViewName("login"); } }
1.編寫國際化配置文件 在資源文件夾resources下,建立一個國際化文件夾i18n 在i18n文件夾中建立一個login.properties文件 建立中文/英文國際化文件 在i18n文件夾中建立一個login_en_US.properties文件 在i18n文件夾中建立一個login_zh_CN.properties文件 點擊Resource Bundle,新建property key name爲login.username 在login.properties窗口下輸入用戶名 login_en_US.properties窗口中輸入username login_zh_CN.properties窗口中輸入用戶 注意 要更改文件編碼 idea中,設置->編譯器->文本編碼屬性文件(*.properties) 設置屬性文件的默認編碼爲UTF-8 2.在springboot中有一個messageSourceAutoConfiguration 會自動管理國際化資源文件 在全局配置文件中設置基礎名 spring: messages: basename: i18n.login 3.在頁面中獲取國際化的值 <!-- 登陸 --> <div class="login"> <div class="login-wrap"> <div class="avatar"> <img src="./images/logo.jpg" class="img-circle" alt=""> </div> <form action="" class="col-md-offset-1 col-md-10"> <div class="input-group input-group-lg"> <span class="input-group-addon"> <i class="fa fa-id-card-o"></i> </span> <input type="text" class="form-control" name="username" th:placeholder="#{login.username}"> </div> <div class="input-group input-group-lg"> <span class="input-group-addon"> <i class="fa fa-key"></i> </span> <input type="password" class="form-control" name="password" th:placeholder="#{login.password}"> </div> <button type="submit" class="btn btn-lg btn-danger btn-block" th:text="#{login.btn}">登 錄</button> <a class="language" th:href="@{/login(lan='zh_CN')}">中文</a>|<a class="language" th:href="@{/login(lan='en_US')}">English</a> </form> </div> </div> 4.切換中英文 默認 自定義 public class MyLocaleResolver implements LocaleResolver { @Override public Locale resolveLocale(HttpServletRequest request){ String lan=request.getParameter("lan"); Locale locale=Locale.getDefault(); if(!StringUtils.isEmpty(lan)){ String[] split=lan.split("_"); locale=new Locale(split[0],split[1]); } return locale; } @Override public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale){ } } @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Bean public LocaleResolver localeResolver() { return new MyLocaleResolver(); } }
MessageSourceAutoConfiguration(自動管理國際化資源文件)
web
默認切換中英文spring
<!-- 登陸 --> <div class="login"> <div class="login-wrap"> <div class="avatar"> <img src="./images/logo.jpg" class="img-circle" alt=""> </div> <form action="" class="col-md-offset-1 col-md-10"> <div class="input-group input-group-lg"> <span class="input-group-addon"> <i class="fa fa-id-card-o"></i> </span> <input type="text" class="form-control" name="username" th:placeholder="#{login.username}"> </div> <div class="input-group input-group-lg"> <span class="input-group-addon"> <i class="fa fa-key"></i> </span> <input type="password" class="form-control" name="password" th:placeholder="#{login.password}"> </div> <button type="submit" class="btn btn-lg btn-danger btn-block" th:text="#{login.btn}">登 錄</button> <a class="language" th:href="@{/login(lan='zh_CN')}">中文</a>|<a class="language" th:href="@{/login(lan='en_US')}">English</a> </form> </div> </div>
@PostMapping("/login") public String login(@RequestParam("username") String username,@RequestParam("password")String password,Model model,HttpSession session){ if(!StringUtils.isEmpty(username)&& "123456".equals(password)){ //登錄成功,防止表單重複提交,能夠重定向到主頁 session.setAttribute("loginUser",username); return "redirect:/main.html"; }else{ //登錄失敗 model.addAttribute("msg","用戶名密碼錯誤"); return "login"; } }
<!--判斷--> <p style="color:red;margin-left:60px;font-size:18px" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
public class LoginHandlerInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException { Object user=request.getSession().getAttribute("loginUser"); if(user==null){ //未登錄,返回登錄頁面 request.setAttribute("msg","沒有權限請先登錄"); request.getRequestDispatcher("/login").forward(request,response); return false; } else{ //已登錄,放行請求 return true; } } }
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**") .excludePathPatterns("/","/1ogin","/main.html","login","/static/**"); } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/**"); WebMvcConfigurer.super.addResourceHandlers(registry); } }
public interface HeroMapper extends Mapper<Hero> { }
@Autowired private MainService mainService; @RequestMapping("/main") public String main(Model mode){ List<Hero> herolist=mainService.getHeroList(); model.addAttribute("heroList",heroList); return"main"; }
<tr th:each="hero:${heroList}"> <td th:text="${hero.id}"></td> <td th:text="${hero.profession}"></td> <td th:text="${hero.username}"></td> <td th:text="${hero.email}"></td> <td th:text="${#dates.format(hero.onlinetime,'yyyy-MM-dd HH:mm')}"></td> <td> <a th:href="@{/edit}" class="btn btn-danger btn-sm">編輯</a> <a href="javascript:;" class="btn btn-warning btn-sm">刪除</a> </td> </tr>
跳轉到添加頁面 <div class="panel-body"> <a href="@{/addPage}" class="btn btn-primary">添加英雄</a> </div> 添加按鈕點擊 <form th:action="@{/addHero}" class="form-horizontal" method="post"> <input type="hidden" name="_method" value="put" th:if="${hero!=null}"/> <input type="hidden" name="id" th:if="${hero!=null}" th:value="${hero.id}"> <div class="form-group"> <label class="col-md-2 control-label">名稱</label> <div class="col-md-6"> <input type="text" name="username" th:value="${hero!=null}?${hero.username}" class="form-control"> </div> </div> <div class="form-group"> <label class="col-md-2 control-label">職業</label> <div class="col-md-6"> <input type="text" name="profession" th:value="${hero!=null}?${hero.profession}" class="form-control"> </div> </div> <div class="form-group"> <label class="col-md-2 control-label">電話</label> <div class="col-md-6"> <input type="text" name="phone" th:value="${hero!=null}?${hero.phone}" class="form-control"> </div> </div> <div class="form-group"> <label class="col-md-2 control-label">郵箱</label> <div class="col-md-6"> <input type="text" name="email" th:value="${hero!=null}?${hero.email}" class="form-control"> </div> </div> <div class="form-group"> <label class="col-md-2 control-label">上線日期</label> <div class="col-md-6"> <input type="text" name="onlinetime" th:value="${hero!=null}?${#dates.format(hero.onlinetime,'yyyy-MM-dd')}" class="form-control"> </div> </div> <div class="modal-footer"> <input type="submit" class="btn btn-danger" th:value="${hero!=null}?'修改':'添加'"> </div> </form> 日期處理(寫在控制器中) @InitBinder public void InitBinder(WebDataBinder dataBinder){ dataBinder.registerCustomEditor(Date.class,new PropertyEditorSupport(){ public void setAsText(String value){ try{ setValue(new SimpleDateFormat("yyyy-MM-dd").parse(value)); } catch(ParseException e){ setValue(null); } } public String getAsText(){ return new SimpleDateFormat("yyyy-MM-dd").format((Date)getValue()); } }); }