關於 Thymeleaf


或許你曾經聽說過或看過「JSP 已經過時了」這類的論調,當然,這論調也有許多開發者不認同,你可以在網路上搜尋看看兩造人馬的說法,這邊並不評論 JSP 是否過時了這件事。

不過,JSP 確實不是唯一的頁面呈現技術,如果你瞭解 JSP,有機會也可以接觸其他模版引擎,未來在評估採用何種頁面呈現技術時,總是可以多個選擇。

如果使用 Spring MVC,在模版引擎的選擇上,能見度高的選擇之一是 Thymeleaf,也是 Spring Boot 推薦的模版引擎,它主打的特性之一是自然模版(Natural template),模版頁面本身是只需瀏覽器就可檢視的 HTML,例如:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Gossip 微網誌</title>
        <link rel="stylesheet" href="css/gossip.css" type="text/css">
    </head>
    <body>
        <div id="login">
            <div>
                <img src='images/caterpillar.jpg' alt='Gossip 微網誌'/>
            </div>    
            <a href='register'>還不是會員?</a>
            <p></p>

    <ul th:if="${errors != null}" style='color: rgb(255, 0, 0);'>
        <li th:each="error : ${errors}" th:text="${error}">error message</li>
    </ul> 

            <form method='post' action='login'>
                <table>
                    <tr>
                        <td colspan='2'>會員登入</td>
                    <tr>
                        <td>名稱:</td>
                        <td><input type='text' name='username'
                                   th:value="${param.username}"></td>
                    </tr>
                    <tr>
                        <td>密碼:</td>
                        <td><input type='password' name='password'></td>
                    </tr>
                    <tr>
                        <td colspan='2' align='center'>
                             <input type='submit' value='登入'>
                        </td>
                    </tr>
                    <tr>
                        <td colspan='2'>
                             <a href='forgotPwd.html'>忘記密碼?</a>
                        </td>
                    </tr>
                </table>
            </form>
        </div>
        <div>
            <h1>Gossip ... XD</h1>
            <ul>
                <li>談天說地不奇怪</li>
                <li>分享訊息也可以</li>
                <li>隨意寫寫表心情</li>
            </ul>
          <table style='background-color:#ffffff;'> 
           <thead>
               <tr>
                   <th><hr></th>
                </tr>
            </thead>
            <tbody>

            <tr th:each="message : ${newest}">
                <td style='vertical-align: top;'>
                  <span th:text="${message.username}">user name</span><br> 
                  <span th:utext="${message.blabla}">blabla</span><br>
                  <span th:text="${message.localDateTime}">time here</span>         
                        <hr>
                </td>            
            </tr>               

        </tbody>
         </table>

        </div>
    </body>
</html>

這是一個完全合法的 HTML 文件,直接在瀏覽器上開啟,也可以顯示原型頁面:

關於 Thymeleaf

如果沒有在 Web 容器上運行,使用瀏覽器來直接開啟一個 JSP 檔案,只會直接顯示 JSP 原始碼內容而已。

如果想在 Spring MVC 中改用 Thymeleaf 模版作為呈現技術,可以在 build.gradle 裏頭加入:

compile 'org.thymeleaf:thymeleaf-spring5:3.0.11.RELEASE'

並在 WebConfig 中替換 ViewResolver 實作:

package cc.openhome.web;

...略

@Configuration
@EnableWebMvc
@PropertySource("classpath:path.properties")
@ComponentScan("cc.openhome.controller")
public class WebConfig implements WebMvcConfigurer, ApplicationContextAware {
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }  

    ...略

    @Bean
    public ITemplateResolver templateResolver() {
        // 透過此實例進行相關設定,後續用來建立模版引擎物件
        SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
        resolver.setApplicationContext(applicationContext);

        // 開發階段可設定為不快取模版內容,修改模版才能即時反應變更
        resolver.setCacheable(false);
        // 搭配控制器傳回值的前置名稱
        resolver.setPrefix("/WEB-INF/templates/");
        // 搭配控制器傳回值的後置名稱
        resolver.setSuffix(".html");
        // HTML 頁面編碼
        resolver.setCharacterEncoding("UTF-8");
        // 這是一份 HTML 文件
        resolver.setTemplateMode(TemplateMode.HTML);
        return resolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
        // 建立與設定模版引擎
        SpringTemplateEngine engine = new SpringTemplateEngine();
        engine.setEnableSpringELCompiler(true);
        engine.setTemplateResolver(templateResolver);
        return engine;
    }

    @Bean
    public ViewResolver viewResolver(SpringTemplateEngine engine) {
        // 建立ViewResolver實作物件並設置模版引擎實例
        ThymeleafViewResolver resolver = new ThymeleafViewResolver();
        resolver.setTemplateEngine(engine);
        // 回應內容編碼
        resolver.setCharacterEncoding("UTF-8");
        resolver.setCache(false);
        return resolver;
    }    
}

接下來,就可以將 JSP 頁面,逐一改造為 Thymeleaf 的 HTML 模版,詳細說明 Thymeleaf 的 HTML 模版如何撰寫,不在這系列的文件設定範圍內,然而,若有 JSTL 或其他模版引擎的使用經驗,學習 Thymeleaf 模版的撰寫並不困難,這部份可參考官方文件〈Tutorial: Using Thymeleaf〉。

雖然不打算說明如何撰寫 Thymeleaf 的 HTML 模版,然而 gossip 中已經將全部的 JSP 改寫為 Thymeleaf 的 HTML 模版,可作為參考之用。