JSP/FreeMarker 等传统视图技术在 Spring Boot 中集成

好的,没问题。下面是一篇关于在Spring Boot中集成JSP和FreeMarker等传统视图技术的文章,力求幽默风趣、通俗易懂,并包含丰富的代码示例。

Spring Boot 遇上老朋友:JSP 和 FreeMarker 的浪漫邂逅

各位看官,今天咱们聊点怀旧的,啊不,是经典的!在Spring Boot的世界里,它就像一个精力充沛的年轻人,拥抱各种新技术,玩转各种花样。但有时候,咱们这些老家伙(JSP和FreeMarker)也想出来溜达溜达,回忆回忆当年叱咤风云的岁月。

Spring Boot 呢,也很 open-minded,它说:“没问题,来吧,老朋友,我给你们安排!” 所以,今天咱们就来聊聊如何在 Spring Boot 里,让 JSP 和 FreeMarker 焕发第二春。

1. JSP:那个熟悉的味道

JSP (JavaServer Pages) 这玩意儿,估计是不少 Java 程序员的初恋。当年写个页面,Servlet 里拼 HTML 字符串那叫一个酸爽。有了 JSP,总算能把 Java 代码和 HTML 分开了,虽然还是有点藕断丝连,但也算进步了。

1.1 引入依赖

首先,咱们得告诉 Spring Boot,我们要用 JSP。在 pom.xml 里加入以下依赖:

<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
</dependency>
  • tomcat-embed-jasper: 这个是 Tomcat 内嵌的 JSP 引擎,负责解析和执行 JSP 页面。注意 scopeprovided,意思是编译时需要它,但运行时 Tomcat 会提供,Spring Boot 打包的时候就不用把它打进去了,避免冲突。
  • jstl: JSP Standard Tag Library,JSP 标准标签库,提供了一堆常用的标签,比如 c:forEachc:if,让 JSP 页面更简洁。

1.2 配置 JSP 视图解析器

Spring Boot 默认情况下,会使用 Thymeleaf 作为视图引擎。要让它认识 JSP,我们需要配置一下视图解析器。在 application.propertiesapplication.yml 里添加以下配置:

spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
  • spring.mvc.view.prefix: JSP 页面存放的目录。这里我们约定放在 /WEB-INF/jsp/ 目录下。这个目录放在 webapp 下,这样才能被 Tomcat 正确加载。
  • spring.mvc.view.suffix: JSP 页面的后缀名,一般是 .jsp

1.3 创建 JSP 页面

src/main/webapp/WEB-INF/jsp/ 目录下,创建一个 JSP 页面,比如 hello.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Hello JSP</title>
</head>
<body>
    <h1>Hello, ${name}!</h1>
    <c:if test="${age > 18}">
        <p>你已经成年了!</p>
    </c:if>
    <c:forEach var="item" items="${items}">
        <p>${item}</p>
    </c:forEach>
</body>
</html>
  • <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>: 引入 JSTL 核心标签库。
  • ${name}: EL 表达式,用于获取 Model 中的数据。
  • <c:if>: JSTL 条件判断标签。
  • <c:forEach>: JSTL 循环标签。

1.4 Controller 代码

写一个 Controller,把数据传递给 JSP 页面:

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.Arrays;
import java.util.List;

@Controller
public class HelloController {

    @GetMapping("/hello")
    public String hello(Model model) {
        model.addAttribute("name", "张三");
        model.addAttribute("age", 20);
        List<String> items = Arrays.asList("苹果", "香蕉", "橘子");
        model.addAttribute("items", items);
        return "hello"; // 返回 JSP 页面名称,不包含前缀和后缀
    }
}
  • @Controller: 声明这是一个 Controller。
  • @GetMapping("/hello"): 映射 /hello 请求到 hello 方法。
  • Model model: 用于向视图传递数据。
  • return "hello";: 返回 JSP 页面名称。Spring Boot 会根据 spring.mvc.view.prefixspring.mvc.view.suffix 自动拼接成完整的 JSP 路径 /WEB-INF/jsp/hello.jsp

1.5 运行测试

启动 Spring Boot 应用,访问 http://localhost:8080/hello,就能看到 JSP 页面了。

1.6 注意事项

  • JSP 页面存放位置: 必须放在 src/main/webapp/WEB-INF/jsp/ 目录下,否则 Tomcat 找不到。
  • 依赖冲突: 如果项目中使用了其他视图引擎,可能会和 JSP 引擎冲突。需要仔细检查依赖,排除冲突。
  • 性能问题: JSP 在运行时需要编译成 Servlet,性能相对较低。在高并发场景下,建议使用更高效的视图引擎,比如 Thymeleaf 或 FreeMarker。

2. FreeMarker:模板界的常青树

FreeMarker 是一个模板引擎,它可以把数据和模板结合起来,生成各种文本格式的文件,比如 HTML、XML、JSON 等。它的语法比较简洁,功能也很强大,在模板界也算得上是常青树了。

2.1 引入依赖

pom.xml 里加入 FreeMarker 的依赖:

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

Spring Boot 已经集成了 FreeMarker,所以只需要引入 spring-boot-starter-freemarker 就可以了。

2.2 配置 FreeMarker

Spring Boot 默认情况下,会自动配置 FreeMarker。如果需要自定义配置,可以在 application.propertiesapplication.yml 里添加以下配置:

spring.freemarker.template-loader-path=classpath:/templates/
spring.freemarker.suffix=.ftl
spring.freemarker.cache=false
  • spring.freemarker.template-loader-path: FreeMarker 模板存放的目录。这里我们约定放在 classpath:/templates/ 目录下,也就是 src/main/resources/templates/ 目录下。
  • spring.freemarker.suffix: FreeMarker 模板的后缀名,一般是 .ftl
  • spring.freemarker.cache: 是否开启缓存。在开发环境下,建议关闭缓存,方便修改模板后立即生效。在生产环境下,可以开启缓存,提高性能。

2.3 创建 FreeMarker 模板

src/main/resources/templates/ 目录下,创建一个 FreeMarker 模板,比如 hello.ftl

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Hello FreeMarker</title>
</head>
<body>
    <h1>Hello, ${name}!</h1>
    <#if age > 18>
        <p>你已经成年了!</p>
    </#if>
    <ul>
        <#list items as item>
            <li>${item}</li>
        </#list>
    </ul>
</body>
</html>
  • ${name}: FreeMarker 表达式,用于获取 Model 中的数据。
  • <#if>: FreeMarker 条件判断指令。
  • <#list>: FreeMarker 循环指令。

2.4 Controller 代码

写一个 Controller,把数据传递给 FreeMarker 模板:

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.Arrays;
import java.util.List;

@Controller
public class HelloController {

    @GetMapping("/hello")
    public String hello(Model model) {
        model.addAttribute("name", "李四");
        model.addAttribute("age", 25);
        List<String> items = Arrays.asList("西瓜", "葡萄", "草莓");
        model.addAttribute("items", items);
        return "hello"; // 返回 FreeMarker 模板名称,不包含后缀
    }
}
  • @Controller: 声明这是一个 Controller。
  • @GetMapping("/hello"): 映射 /hello 请求到 hello 方法。
  • Model model: 用于向视图传递数据。
  • return "hello";: 返回 FreeMarker 模板名称。Spring Boot 会根据 spring.freemarker.template-loader-pathspring.freemarker.suffix 自动拼接成完整的模板路径 classpath:/templates/hello.ftl

2.5 运行测试

启动 Spring Boot 应用,访问 http://localhost:8080/hello,就能看到 FreeMarker 页面了。

2.6 FreeMarker 的高级用法

FreeMarker 的功能非常强大,除了基本的变量输出和条件判断,还可以使用宏、函数、自定义指令等高级特性。

  • 宏 (Macro): 类似于函数,可以封装一段模板代码,方便重复使用。

    <#macro greet name>
        <h1>Hello, ${name}!</h1>
    </#macro>
    
    <@greet name="王五" />
  • 函数 (Function): 可以调用 Java 代码,实现更复杂的逻辑。

    // 定义一个函数
    public String formatDate(Date date, String pattern) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(date);
    }
    
    // 在 FreeMarker 配置中注册函数
    configuration.setSharedVariable("formatDate", new TemplateMethodModelEx() {
        @Override
        public Object exec(List arguments) throws TemplateModelException {
            Date date = (Date) ((TemplateDateModel) arguments.get(0)).getWrappedObject();
            String pattern = arguments.get(1).toString();
            return formatDate(date, pattern);
        }
    });
    
    // 在模板中使用函数
    ${formatDate(now, "yyyy-MM-dd")}
  • 自定义指令 (Custom Directive): 可以自定义模板指令,实现更灵活的布局和组件化。

    // 定义一个自定义指令
    public class MyDirective implements TemplateDirectiveModel {
        @Override
        public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException {
            String name = params.get("name").toString();
            env.getOut().write("<h1>Hello, " + name + "!</h1>");
            if (body != null) {
                body.render(env.getOut());
            }
        }
    }
    
    // 在 FreeMarker 配置中注册自定义指令
    configuration.setSharedVariable("myDirective", new MyDirective());
    
    // 在模板中使用自定义指令
    <@myDirective name="赵六">
        <p>这是一个自定义指令的内容。</p>
    </@myDirective>

2.7 注意事项

  • 模板存放位置: 默认情况下,FreeMarker 模板放在 src/main/resources/templates/ 目录下。
  • 语法错误: FreeMarker 的语法比较严格,如果写错了,会抛出异常。
  • 性能优化: FreeMarker 的性能相对较高,但如果模板过于复杂,也会影响性能。可以通过开启缓存、优化模板结构等方式来提高性能。

3. JSP vs FreeMarker:谁更胜一筹?

JSP 和 FreeMarker 都是优秀的视图技术,各有优缺点。

特性 JSP FreeMarker
语法 混合了 Java 代码和 HTML 类似于脚本语言,更简洁
性能 较低,需要编译成 Servlet 较高,模板引擎直接解析
功能 依赖 JSTL 等标签库,功能较简单 功能强大,支持宏、函数、自定义指令
适用场景 小型项目,对性能要求不高 中大型项目,需要更灵活的模板引擎
学习曲线 较陡峭,需要熟悉 Java 和 JSTL 较平缓,语法简洁易懂

总结一下:

  • 如果你是一个 Java 老鸟,喜欢在页面里写点 Java 代码,那就选 JSP。
  • 如果你追求简洁、高效,喜欢用模板引擎来分离前后端,那就选 FreeMarker。
  • 当然,你也可以根据项目的具体情况,选择最合适的视图技术。

4. Spring Boot 的选择:拥抱未来,不忘初心

Spring Boot 作为一个现代化的框架,鼓励使用更先进的视图技术,比如 Thymeleaf、React、Vue 等。但它也并没有抛弃 JSP 和 FreeMarker 这些老朋友,而是提供了良好的集成支持。

Spring Boot 的理念是:拥抱未来,不忘初心。它既能让你体验最新的技术,也能让你在熟悉的环境中继续开发。

所以,无论你选择 JSP 还是 FreeMarker,Spring Boot 都会给你提供最好的支持。

5. 总结

今天咱们聊了聊如何在 Spring Boot 中集成 JSP 和 FreeMarker。虽然它们都是比较传统的视图技术,但在某些场景下仍然很有用。

希望这篇文章能帮助你更好地理解 Spring Boot 的视图技术,并在项目中做出正确的选择。

记住,技术没有好坏之分,只有适用与不适用。选择最适合你的,才是最好的!

好了,今天就到这里。各位看官,下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注