ZetCode

Spring FreeMarker

最后修改于 2023 年 10 月 18 日

Spring FreeMarker 教程展示了如何在经典的 Spring 应用程序中使用 FreeMarker 模板引擎。

Spring 是一个流行的 Java 应用程序框架,用于创建企业级应用程序。

FreeMarker

FreeMarker 是一个服务器端 Java 模板引擎,可用于 Web 和独立环境。模板使用 FreeMarker 模板语言 (FTL) 编写,这是一种简单、专业的语言。FreeMarker 模板具有 .ftlh 扩展名。

Spring FreeMarker 示例

以下应用程序使用 FreeMarker 来生成视图。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           ├───controller
│   │           │       MyController.java
│   │           └───service
│   │                   WordService.java
│   └───resources
│       │   logback.xml
│       └───templates
│               index.ftlh
│               showWords.ftlh
└───test
    └───java

这是项目结构。

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>springfreemarkerex</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <spring-version>5.3.23</spring-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.4.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.31</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.3.2</version>
            </plugin>

            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.49.v20220914</version>
            </plugin>
        </plugins>
    </build>
</project>

pom.xml 中,我们有必要的依赖项。

resources/logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml 是 Logback 日志库的配置文件。

com/zetcode/config/MyWebInitializer.java
package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

@Configuration
public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {

        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {

        return new String[]{"/"};
    }
}

MyWebInitializer 注册了 Spring DispatcherServlet,它是 Spring Web 应用程序的前端控制器。

@Override
protected Class<?>[] getServletConfigClasses() {

    return new Class[]{WebConfig.class};
}

getServletConfigClasses 返回一个 Web 配置类。

com/zetcode/config/WebConfig.java
package com.zetcode.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig implements WebMvcConfigurer {

    @Bean
    public FreeMarkerViewResolver freemarkerViewResolver() {

        var resolver = new FreeMarkerViewResolver();
        resolver.setCache(true);
        resolver.setSuffix(".ftlh");
        return resolver;
    }

    @Bean
    public FreeMarkerConfigurer freemarkerConfig() {

        var freeMarkerConfigurer = new FreeMarkerConfigurer();
        freeMarkerConfigurer.setTemplateLoaderPath("classpath:/templates/");
        return freeMarkerConfigurer;
    }
}

WebConfig 配置 FreeMarker 模板引擎。我们将模板文件的位置设置为类路径下的 templates 目录。(resources 目录位于类路径上。)

com/zetcode/service/WordService.java
package com.zetcode.service;

import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class WordService {

    private final List<String> words = List.of("pen", "sky",
            "rock", "forest", "falcon", "eagle");

    public List<String> all() {

        return words;
    }
}

WordService 返回一些单词。

com/zetcode/controller/MyController.java
package com.zetcode.controller;

import com.zetcode.service.WordService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class MyController {

    @GetMapping(value = "/")
    public String home() {

        return "index";
    }

    @GetMapping(value = "/words")
    public String showWords(Model model, WordService wordService) {

        var words = wordService.all();
        model.addAttribute("words", words);

        return "showWords";
    }
}

MyController 提供请求路径和处理程序方法之间的映射。我们有两个映射:home 页面和 showWords 页面。

var words = wordService.all();
model.addAttribute("words", words);

我们使用 wordService 检索所有单词,并将其放入模型中。模型将传递给 FreeMarker,它将处理模板中的数据。

resources/templates/index.ftlh
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Home page</title>
</head>
<body>

<p>
    <a href="words">Show words</a>
</p>

</body>
</html>

主页包含一个显示所有单词的链接。

resources/templates/showWords.ftlh
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Show words</title>
</head>
<body>

<h2>List of words</h2>

<ul>
<#list words as word>
    <li>${word}</li>
</#list>
</ul>

</body>
</html>

使用 FreeMarker 的 list 指令,我们在 HTML 列表中显示所有单词。

$ mvn jetty:run

我们运行服务器并访问 localhost:8080 来获取主页,其中包含链接。

在本文中,我们与经典的 Spring 应用程序中的 FreeMarker 模板引擎进行了交互。

作者

我叫 Jan Bodnar,我是一名充满激情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。迄今为止,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有超过十年的经验。

列出 所有 Spring 教程