第一个功能–>展示内容 – 团队成员列表

QcrTiMo 发布于 9 天前 19 次阅读


现在我们已经成功实现了一个简单应用-->打印Hello World在我们的浏览器上面,但是这远远不够,我们的目的是编写一个网站后端!

但是一上来就说要编写一个网站后端听起来就不现实,在实现复杂的后台管理之前,我们先让网站能展示一些内容。比如,从后端获取一个团队成员列表,并在网页上显示出来。这需要用到模板引擎

Spring Boot 常用的模板引擎:

  • Thymeleaf (推荐): 功能强大,与 Spring Boot 集成良好,可以直接在 HTML 文件中嵌入逻辑,并且这些 HTML 文件在浏览器中也能以静态方式打开(便于设计师协作)。
  • FreeMarker
  • Velocity
  • Mustache

本次实战以及教程将用到Thymeleaf

使用 Thymeleaf 展示动态数据

要使用Thymeleaf,我们需要在依赖中添加它。

首先,我们要给IDEA装上Edit Starters插件,它可以方便我们快速增删依赖。

打开 文件--> 设置 --> 编辑器 --> 插件,然后在Marketplace中搜索Edit Starters,下载该插件。

下载完成之后,我们打开pom.xml,右键视图,点击生成。

选择Edit Starters

在搜索框中搜索Thymeleaf,然后在Starters栏中选中Thymeleaf,将Thymeleaf添加到我们的Selected依赖列表中。

然后点击OK,这样IDEA就自动帮我们配置好了Thymeleaf依赖。

创建数据模型(Model) - TeamMember.java

我们需要一个类来表示团队成员。

  • 在你的主包 (例如 com.NZI.web) 下创建一个新的子包,比如 model。
  • 在 model 包下,创建一个名为 TeamMember.java 的类:
// TeamMember.java
package com.NZI.web.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data    // Lombok: 自动生成 getter, setter, toString, equals, hashCode
@NoArgsConstructor    // Lombok: 自动生成无参构造函数
@AllArgsConstructor    // Lombok: 自动生成全参构造函数
public class TeamMember {
    private Long id;
    private String name;
    private String role;
    private String bio;      // 简介
    private String imageUrl; // 成员头像图片URL (暂时先用URL)
}
  • @Data: Lombok 注解,它会为所有字段自动生成 getter, setter,以及 equals(), hashCode(), toString() 方法。
  • @NoArgsConstructor: 生成一个无参数的构造函数。
  • @AllArgsConstructor: 生成一个包含所有字段的构造函数。

创建控制器 - TeamController.java

我们将创建一个新的控制器来处理与团队成员相关的请求。

  • 在你的Controller包下,创建一个名为 TeamController.java 的类:
//TeamController.java
package com.NZI.web.Controller;
import com.NZI.web.model.TeamMember;
import org.springframework.stereotype.Controller; 
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.ArrayList;
import java.util.List;
@Controller // 1. 使用 @Controller 而不是 @RestController
public class TeamController {
    @GetMapping("/team") // 2. 映射到 /team 路径
    public String showTeamPage(Model model) { // 3. 注入 Model 对象
        // 4. 创建一些示例数据 (将来会从数据库获取)
        List<TeamMember> teamMembers = new ArrayList<>();
        teamMembers.add(new TeamMember(1L, "Alice Wonder", "Lead Game Designer", "Loves creating imaginative worlds.", "images/default-avatar.png"));
        teamMembers.add(new TeamMember(2L, "Bob The Builder", "Chief Programmer", "Can fix anything, especially code.", "images/default-avatar.png"));
        teamMembers.add(new TeamMember(3L, "Carol Artista", "Lead Artist", "Brings characters and environments to life.", "images/default-avatar.png"));
        // 5. 将数据添加到 Model 中,使其在模板中可用
        model.addAttribute("members", teamMembers); // "members" 是在模板中引用的名字
        model.addAttribute("pageTitle", "我们的团队");
        return "team"; // 6. 返回模板的名称 (team.html)
    }
}

为什么使用 @Controller 而不是 @RestController?

@Controller: 与 @RestController 不同,@Controller 通常用于返回一个视图(比如 HTML 页面),而不是直接返回数据。Spring Boot 会查找与返回的字符串同名的模板文件。

public String showTeamPage(Model model)是什么?

  • 方法返回 String,这个字符串是模板文件的名称(不带 .html 后缀)。
  • Model model: Spring MVC 会自动注入一个 Model 对象。你可以用它来传递数据给视图(模板)。

这里我们硬编码了一些 TeamMember 对象。在后续步骤中,我们会从数据库加载这些数据。

model.addAttribute("members", teamMembers);是什么?

  • 将 teamMembers 列表添加到 Model 中。
  • 在模板中,我们可以通过键名 "members" 来访问这个列表。
  • 同样,我们添加了一个 "pageTitle"。

return "team";是什么?

  • 这告诉 Spring Boot 去查找名为 team.html 的模板文件。
  • 根据默认配置,Spring Boot 会在 src/main/resources/templates/ 目录下查找这个文件。

创建 Thymeleaf 模板 - team.html

  • 在 src/main/resources/templates/ 目录下创建一个名为 team.html 的文件。
    • 如果 templates 目录不存在,请手动创建它。
  • 编辑 team.html 内容如下:

关于HTML模板部分需要掌握HTML基本语法,本教程将不再赘述。

team.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title th:text="${pageTitle}">团队页面</title> <!--使用从Controller传递过来的pageTitle-->
    <style>
        body { font-family: sans-serif; margin: 20px; background-color: #f4f4f4; }
        .container { background-color: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px rgba(0,0,0,0.1); }
        h1 { color: #333; }
        .team-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 20px; margin-top: 20px; }
        .member-card { border: 1px solid #ddd; border-radius: 8px; padding: 15px; background-color: #fff; text-align: center; }
        .member-card img { width: 100px; height: 100px; border-radius: 50%; object-fit: cover; margin-bottom: 10px; border: 2px solid #eee; }
        .member-card h3 { margin: 10px 0 5px 0; color: #555; }
        .member-card p { font-size: 0.9em; color: #777; }
        .role { font-style: italic; color: #007bff; font-size: 0.95em; margin-bottom: 5px;}
    </style>
</head>
<body>
<div class="container">
    <h1 th:text="${pageTitle}">我的团队</h1>

    <div class="team-grid" th:if="${not #lists.isEmpty(members)}">
        <!--遍历从Controller传递过来的members列表-->
        <div class="member-card" th:each="member : ${members}">
            <!--图片放在src/main/resources/static/images/目录下-->
            <img th:if="${member.imagePath != null}" th:src="@{${'/' + member.imagePath}}" th:alt="${member.name} + ' photo'"/>
            <img th:unless="${member.imagePath != null}" th:src="@{/images/default-avatar.png}" alt="Default avatar"/> <!--备用图片-->

            <h3 th:text="${member.name}">Member Name</h3>
            <p class="role" th:text="${member.role}">Member Role</p>
            <p th:text="${member.bio}">Member Bio</p>
        </div>
    </div>

    <div th:if="${#lists.isEmpty(members)}">
        <p>没有成员</p>
    </div>
</div>
</body>
</html>

Thymeleaf 关键点解释:

  • xmlns:th="http://www.thymeleaf.org": 声明 Thymeleaf 命名空间,这样才能使用 th:* 属性。
  • th:text="${pageTitle}": 将 <title> 和 <h1> 标签的内容替换为从 Model 中获取的 pageTitle 变量的值。
  • th:if="${not #lists.isEmpty(members)}": 条件渲染。只有当 members 列表不为空时,才显示包含团队成员卡片的 div。#lists 是 Thymeleaf 提供的一个工具类。
  • th:each="member : ${members}": 循环遍历 members 列表。对于列表中的每个元素,它会创建一个 member-card div。当前的元素可以在循环内部通过变量 member 来访问。
  • th:text="${member.name}"th:text="${member.role}", th:text="${member.bio}": 显示 member 对象的属性。
  • th:src="@{${'/' + member.imageUrl}}": 设置图片源。
    • @{...} 是 Thymeleaf 的 URL 表达式。
    • 我们的图片会放在 src/main/resources/static/images/ 目录下。例如,如果 member.imageUrl 是 images/alice.jpg,那么最终 URL 会是 /images/alice.jpg。
    • 创建图片目录和占位图片:
      • 在 src/main/resources/static 目录下创建 images 目录。
      • 你可以随意放一些图片进去,比如 alice.jpg, bob.jpg, carol.jpg,或者创建一个 default-avatar.png。

运行

刷新IDEA与浏览器,填入用户名与密码,我们能看到最终成果:

到这里,我们已经创建了一个简单的数据模型 TeamMember,创建了一个 @Controller ,它准备数据并将其传递给 Thymeleaf 模板,创建了一个 HTML 模板 (team.html),使用 Thymeleaf 的指令来动态显示从控制器传递过来的数据。

接下来的任务

硬编码是十分麻烦且低效率的事,而且网站怎么可能都是自己手动添加信息,这时候就得用到数据库和表单了,我们将团队成员信息存储到PostgreSQL数据库中,而不是硬编码。我们还会创建一个表单来添加新的团队成员。

更为重要的是,我们希望用户不会访问到我们的后端,然后哐哐改我们的数据,所以我们需要用到Spring Security这个依赖,保护添加、编辑、删除成员的页面,只允许管理员访问。

斯哈斯哈斯哈,佳代子啊啊啊啊啊啊ᕕ(◠ڼ◠)ᕗᕕ(◠ڼ◠)ᕗᕕ(◠ڼ◠)ᕗᕕ(◠ڼ◠)ᕗᕕ(◠ڼ◠)ᕗ
最后更新于 2025-05-19