Spring Boot 整合 Freemarker,50 多行配置是怎麼省略掉的?

江南一點雨發表於2019-07-05

Spring Boot2 系列教程接近完工,最近進入修修補補階段。Freemarker 整合貌似還沒和大家聊過,因此今天把這個補充上。

已經完工的 Spring Boot2 教程,大家可以參考這裡:

  1. 乾貨|最新版 Spring Boot2.1.5 教程+案例合集

Freemarker 簡介

這是一個相當老牌的開源的免費的模版引擎。通過 Freemarker 模版,我們可以將資料渲染成 HTML 網頁、電子郵件、配置檔案以及原始碼等。Freemarker 不是面向終端使用者的,而是一個 Java 類庫,我們可以將之作為一個普通的元件嵌入到我們的產品中。

來看一張來自 Freemarker 官網的圖片:

Spring Boot 整合 Freemarker,50 多行配置是怎麼省略掉的?

可以看到,Freemarker 可以將模版和資料渲染成 HTML 。

Freemarker 模版字尾為 .ftl(FreeMarker Template Language)。FTL 是一種簡單的、專用的語言,它不是像 Java 那樣成熟的程式語言。在模板中,你可以專注於如何展現資料, 而在模板之外可以專注於要展示什麼資料。

好了,這是一個簡單的介紹,接下來我們來看看 Freemarker 和 Spring Boot 的一個整合操作。

實踐

在 SSM 中整合 Freemarker ,所有的配置檔案加起來,前前後後大約在 50 行左右,Spring Boot 中要幾行配置呢? 0 行!

1.建立工程

首先建立一個 Spring Boot 工程,引入 Freemarker 依賴,如下圖:

Spring Boot 整合 Freemarker,50 多行配置是怎麼省略掉的?

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

工程建立完成後,在 org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration 類中,可以看到關於 Freemarker 的自動化配置:

@Configuration
@ConditionalOnClass({ freemarker.template.Configuration.class, FreeMarkerConfigurationFactory.class })
@EnableConfigurationProperties(FreeMarkerProperties.class)
@Import({ FreeMarkerServletWebConfiguration.class, FreeMarkerReactiveWebConfiguration.class,
                FreeMarkerNonWebConfiguration.class })
public class FreeMarkerAutoConfiguration {
}

從這裡可以看出,當 classpath 下存在 freemarker.template.Configuration 以及 FreeMarkerConfigurationFactory 時,配置才會生效,也就是說當我們引入了 Freemarker 之後,配置就會生效。但是這裡的自動化配置只做了模板位置檢查,其他配置則是在匯入的 FreeMarkerServletWebConfiguration 配置中完成的。那麼我們再來看看 FreeMarkerServletWebConfiguration 類,部分原始碼如下:

@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass({ Servlet.class, FreeMarkerConfigurer.class })
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
class FreeMarkerServletWebConfiguration extends AbstractFreeMarkerConfiguration {
        protected FreeMarkerServletWebConfiguration(FreeMarkerProperties properties) {
                super(properties);
        }
        @Bean
        @ConditionalOnMissingBean(FreeMarkerConfig.class)
        public FreeMarkerConfigurer freeMarkerConfigurer() {
                FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
                applyProperties(configurer);
                return configurer;
        }
        @Bean
        @ConditionalOnMissingBean(name = "freeMarkerViewResolver")
        @ConditionalOnProperty(name = "spring.freemarker.enabled", matchIfMissing = true)
        public FreeMarkerViewResolver freeMarkerViewResolver() {
                FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
                getProperties().applyToMvcViewResolver(resolver);
                return resolver;
        }
}

我們來簡單看下這段原始碼:

  1. @ConditionalOnWebApplication 表示當前配置在 web 環境下才會生效。
  2. ConditionalOnClass 表示當前配置在存在 Servlet 和 FreeMarkerConfigurer 時才會生效。
  3. @AutoConfigureAfter 表示當前自動化配置在 WebMvcAutoConfiguration 之後完成。
  4. 程式碼中,主要提供了 FreeMarkerConfigurer 和 FreeMarkerViewResolver。
  5. FreeMarkerConfigurer 是 Freemarker 的一些基本配置,例如 templateLoaderPath、defaultEncoding 等
  6. FreeMarkerViewResolver 則是檢視解析器的基本配置,包含了viewClass、suffix、allowRequestOverride、allowSessionOverride 等屬性。

另外還有一點,在這個類的構造方法中,注入了 FreeMarkerProperties:

@ConfigurationProperties(prefix = "spring.freemarker")
public class FreeMarkerProperties extends AbstractTemplateViewResolverProperties {
        public static final String DEFAULT_TEMPLATE_LOADER_PATH = "classpath:/templates/";
        public static final String DEFAULT_PREFIX = "";
        public static final String DEFAULT_SUFFIX = ".ftl";
        /**
         * Well-known FreeMarker keys which are passed to FreeMarker's Configuration.
         */
        private Map<String, String> settings = new HashMap<>();
}

FreeMarkerProperties 中則配置了 Freemarker 的基本資訊,例如模板位置在 classpath:/templates/ ,再例如模板字尾為 .ftl,那麼這些配置我們以後都可以在 application.properties 中進行修改。

如果我們在 SSM 的 XML 檔案中自己配置 Freemarker ,也不過就是配置這些東西。現在,這些配置由 FreeMarkerServletWebConfiguration​ 幫我們完成了。

2.建立類

首先我們來建立一個 User 類,如下:

public class User {
    private Long id;
    private String username;
    private String address;
    //省略 getter/setter
}

再來建立 UserController

@Controller
public class UserController {
    @GetMapping("/index")
    public String index(Model model) {
        List<User> users = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setId((long) i);
            user.setUsername("javaboy>>>>" + i);
            user.setAddress("www.javaboy.org>>>>" + i);
            users.add(user);
        }
        model.addAttribute("users", users);
        return "index";
    }
}

最後在 freemarker 中渲染資料:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<table border="1">
    <tr>
        <td>使用者編號</td>
        <td>使用者名稱稱</td>
        <td>使用者地址</td>
    </tr>
    <#list users as user>
        <tr>
            <td>${user.id}</td>
            <td>${user.username}</td>
            <td>${user.address}</td>
        </tr>
    </#list>
</table>
</body>
</html>

執行效果如下:

Spring Boot 整合 Freemarker,50 多行配置是怎麼省略掉的?

其他配置

如果我們要修改模版檔案位置等,可以在 application.properties 中進行配置:

spring.freemarker.allow-request-override=false
spring.freemarker.allow-session-override=false
spring.freemarker.cache=false
spring.freemarker.charset=UTF-8
spring.freemarker.check-template-location=true
spring.freemarker.content-type=text/html
spring.freemarker.expose-request-attributes=false
spring.freemarker.expose-session-attributes=false
spring.freemarker.suffix=.ftl
spring.freemarker.template-loader-path=classpath:/templates/

配置檔案按照順序依次解釋如下:

  1. HttpServletRequest的屬性是否可以覆蓋controller中model的同名項
  2. HttpSession的屬性是否可以覆蓋controller中model的同名項
  3. 是否開啟快取
  4. 模板檔案編碼
  5. 是否檢查模板位置
  6. Content-Type的值
  7. 是否將HttpServletRequest中的屬性新增到Model中
  8. 是否將HttpSession中的屬性新增到Model中
  9. 模板檔案字尾
  10. 模板檔案位置

好了,整合完成之後,Freemarker 的更多用法,就和在 SSM 中使用 Freemarker 一樣了,這裡我就不再贅述。

結語

本文和大家簡單聊一聊 Spring Boot 整合 Freemarker,算是對 Spring Boot2 教程的一個補充(後面還會有一些補充),有問題歡迎留言討論。

本專案案例,我已經上傳到 GitHub 上,歡迎大家 star:https://github.com/lenve/javaboy-code-samples

關注公眾號【江南一點雨】,專注於 Spring Boot+微服務以及前後端分離等全棧技術,定期視訊教程分享,關注後回覆 Java ,領取鬆哥為你精心準備的 Java 乾貨!
Spring Boot 整合 Freemarker,50 多行配置是怎麼省略掉的?

相關文章