J2EE实验

实验二: Thymeleaf的使用

实验过程

  1. 引入 Thymeleaf 模板引擎

首先,在项目中引入 Thymeleaf 依赖,使 Spring Boot 支持模板渲染:

打开pom.xml文件

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
  • 使项目能够解析 templates 目录下的 HTML 文件
  • 支持 th:* 语法
  1. 调整项目结构

将原有静态页面从 static 目录移动到:

plain 复制代码
src/main/resources/templates/

并将文件命名为:

plain 复制代码
wuziqi.html
  • static → 纯静态页面(不会走 Thymeleaf)
  • templates → 模板页面(由 Thymeleaf解析)
  1. 编写 Controller(核心步骤)

创建控制器 PageController,用于:

  • 初始化棋盘
  • 接收用户点击坐标
  • 更新棋盘状态
  • 判断胜负
  • 向前端传递数据

完整代码文件:

java 复制代码
package com.wuziqi.java.shiyan1.controller;

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

import java.util.ArrayList;
import java.util.List;

@Controller
public class PageController {

    private final List<List<Integer>> board = new ArrayList<>();
    private int currentPlayer = 1;
    private String winner = null;

    @GetMapping("/game")
    public String gamePage(
            @RequestParam(required = false) Integer x,
            @RequestParam(required = false) Integer y,
            Model model) {

        // 初始化
        if (board.isEmpty()) {
            for (int i = 0; i < 15; i++) {
                List<Integer> row = new ArrayList<>();
                for (int j = 0; j < 15; j++) {
                    row.add(0);
                }
                board.add(row);
            }
        }

        // 落子(+胜负判断)
        if (x != null && y != null && winner == null) {
            if (board.get(x).get(y) == 0) {

                board.get(x).set(y, currentPlayer);

                // 胜负判断
                if (win(x, y)) {
                    winner = currentPlayer == 1 ? "黑棋胜利!" : "白棋胜利!";
                } else {
                    currentPlayer = 3 - currentPlayer;
                }
            }
        }

        model.addAttribute("board", board);
        model.addAttribute("currentPlayer", currentPlayer == 1 ? "黑棋" : "白棋");
        model.addAttribute("message", "欢迎你");
        model.addAttribute("winner", winner);

        return "wuziqi";
    }

    // 极简胜负判断
    private boolean win(int x, int y) {
        int p = board.get(x).get(y);
        int[][] d = {{1,0},{0,1},{1,1},{1,-1}};

        for (int[] dir : d) {
            int count = 1;

            for (int k = 1; k < 5; k++) {
                int nx = x + dir[0]*k, ny = y + dir[1]*k;
                if (nx<0||ny<0||nx>=15||ny>=15||board.get(nx).get(ny)!=p) break;
                count++;
            }

            for (int k = 1; k < 5; k++) {
                int nx = x - dir[0]*k, ny = y - dir[1]*k;
                if (nx<0||ny<0||nx>=15||ny>=15||board.get(nx).get(ny)!=p) break;
                count++;
            }

            if (count >= 5) return true;
        }
        return false;
    }
}

核心代码逻辑

(1)初始化棋盘

java 复制代码
if (board.isEmpty()) {
    for (int i = 0; i < 15; i++) {
        List<Integer> row = new ArrayList<>();
        for (int j = 0; j < 15; j++) {
            row.add(0);
        }
        board.add(row);
    }
}

生成 15×15 棋盘

(2)处理点击落子

java 复制代码
if (x != null && y != null && winner == null) {
    if (board.get(x).get(y) == 0) {
        board.get(x).set(y, currentPlayer);
    }
}

根据点击坐标更新棋盘

(3)胜负判断

java 复制代码
if (win(x, y)) {
    winner = currentPlayer == 1 ? "黑棋胜利!" : "白棋胜利!";
}

判断是否形成五子连珠

(4)切换玩家

java 复制代码
currentPlayer = 3 - currentPlayer;

黑白轮流

(5)向页面传递数据

java 复制代码
model.addAttribute("board", board);
model.addAttribute("currentPlayer", ...);
model.addAttribute("message", "欢迎你");
model.addAttribute("winner", winner);

供 Thymeleaf 使用

  1. 编写 Thymeleaf 页面

wuziqi.html 中使用 Thymeleaf 指令实现动态页面。

完整代码文件:

html 复制代码
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>五子棋</title>

    <style>
        body {
            text-align: center;
            font-family: "Microsoft YaHei";
            background: #f5e1b5;
        }

        .board {
            position: relative;
            width: 420px;
            height: 420px;
            margin: 30px auto;
            background: #deb887;
        }

        /* 横线 */
        .line-h {
            position: absolute;
            left: 0;
            width: 100%;
            height: 1px;
            background: #333;
        }

        /* 竖线 */
        .line-v {
            position: absolute;
            top: 0;
            height: 100%;
            width: 1px;
            background: #333;
        }

        /* 交叉点 */
        .point {
            position: absolute;
            width: 20px;
            height: 20px;
            transform: translate(-50%, -50%);
        }

        .point a {
            display: block;
            width: 100%;
            height: 100%;
        }

        .piece {
            width: 18px;
            height: 18px;
            border-radius: 50%;
            margin: auto;
        }

        .black {
            background: black;
        }

        .white {
            background: white;
            border: 1px solid #999;
        }
    </style>
</head>

<body>

<h1>五子棋</h1>
<h2 th:text="${message}"></h2>
<p>当前玩家:<span th:text="${currentPlayer}"></span></p>
<h2 th:if="${winner != null}"
    th:text="${winner}"
    style="color:red;"></h2>
<div class="board">

    <!-- 横线 -->
    <div th:each="i : ${#numbers.sequence(0,14)}"
         class="line-h"
         th:style="|top:${i * 30}px|"></div>

    <!-- 竖线 -->
    <div th:each="i : ${#numbers.sequence(0,14)}"
         class="line-v"
         th:style="|left:${i * 30}px|"></div>

    <!-- 所有交叉点 -->
    <div th:each="row,rowStat : ${board}">
        <div th:each="cell,colStat : ${row}"
             class="point"
             th:style="|top:${rowStat.index * 30}px; left:${colStat.index * 30}px|">

            <a th:href="@{/game(x=${rowStat.index}, y=${colStat.index})}">

                <div th:if="${cell == 1}" class="piece black"></div>
                <div th:if="${cell == 2}" class="piece white"></div>

            </a>

        </div>
    </div>

</div>

</body>
</html>

(1)显示文本信息

html 复制代码
<h2 th:text="${message}"></h2>
<p>当前玩家:<span th:text="${currentPlayer}"></span></p>

显示后端数据

(2)胜负提示

html 复制代码
<h2 th:if="${winner != null}" th:text="${winner}"></h2>

条件显示胜利信息

(3)生成棋盘(双层循环)

html 复制代码
<div th:each="row,rowStat : ${board}">
    <div th:each="cell,colStat : ${row}">

根据二维数组动态生成棋盘

(4)棋子显示

html 复制代码
<div th:if="${cell == 1}" class="black"></div>
<div th:if="${cell == 2}" class="white"></div>

判断显示黑棋或白棋

(5)点击落子(核心交互)

html 复制代码
<a th:href="@{/game(x=${rowStat.index}, y=${colStat.index})}">

点击棋盘发送坐标到后端

(6)动态样式(定位棋盘)

html 复制代码
th:style="|top:${rowStat.index * 30}px; left:${colStat.index * 30}px|"

计算每个交叉点位置

  1. 页面运行与测试

启动项目后,在浏览器访问:

plain 复制代码
http://localhost:8080/game

介绍这个实验

一、Thymeleaf 是什么

Thymeleaf 是一种 Java Web 模板引擎,主要用于在服务器端将数据渲染到 HTML 页面中。用于将后端数据动态渲染到 HTML 页面中的模板引擎,实现了页面与数据的解耦。

简单理解:

  • Controller 负责数据
    Thymeleaf 负责把数据"填进 HTML"

核心特点

  1. 服务端渲染
    • 页面在服务器生成后再返回浏览器
  2. HTML友好
    • 页面本身仍然是合法HTML
  3. 使用 th: 语法操作数据
    • th:textth:eachth:if

二、本项目整体说明

本项目实现了一个基于 Spring Boot 的五子棋游戏,主要结构如下:

  1. Controller(后端逻辑)

负责:

  • 初始化棋盘
  • 处理落子
  • 判断胜负
  • 向页面传递数据

例如:

java 复制代码
model.addAttribute("board", board);
model.addAttribute("currentPlayer", ...);
model.addAttribute("message", "欢迎你");
model.addAttribute("winner", winner);

这些数据会被 Thymeleaf 使用

  1. HTML(前端模板)

负责:

  • 显示棋盘
  • 显示棋子
  • 显示当前玩家、胜负结果

但不是写死的,而是通过 Thymeleaf 动态生成

  1. 数据流
plain 复制代码
用户点击 → /game?x=..&y=..
→ Controller处理
→ Model传数据
→ Thymeleaf渲染HTML
→ 页面更新

三、项目中使用 Thymeleaf 的地方

  1. th:text(显示数据)
html 复制代码
<h2 th:text="${message}"></h2>
<p>当前玩家:<span th:text="${currentPlayer}"></span></p>
  • 把 Controller 传来的数据显示出来

举例

Controller:

java 复制代码
model.addAttribute("message", "欢迎你");

页面:

html 复制代码
<h2 th:text="${message}"></h2>

页面显示:欢迎你

  1. th:if(条件渲染)
html 复制代码
<h2 th:if="${winner != null}" th:text="${winner}"></h2>
  • 只有胜利时才显示文字

效果

winner 页面
null 不显示
黑棋胜利 显示
  1. th:each(循环渲染棋盘)
html 复制代码
<div th:each="row,rowStat : ${board}">
    <div th:each="cell,colStat : ${row}">
  • 遍历二维数组(棋盘)

对应后端

java 复制代码
List<List<Integer>> board

通过循环生成 15×15 棋盘

  1. th:style(动态样式)
html 复制代码
th:style="|top:${rowStat.index * 30}px; left:${colStat.index * 30}px|"
  • 根据坐标计算位置
  • 实现棋盘"交叉点布局"
  1. th:href(点击落子)
html 复制代码
<a th:href="@{/game(x=${rowStat.index}, y=${colStat.index})}">
  • 点击棋盘时发送请求
  • 把坐标传给 Controller

实际效果----点击某个点:

plain 复制代码
/game?x=7&y=8
  1. th:if(棋子显示)
html 复制代码
<div th:if="${cell == 1}" class="piece black"></div>
<div th:if="${cell == 2}" class="piece white"></div>
  • 判断当前位置是什么棋子
  • 决定显示黑棋还是白棋

总结:

本项目中使用了 Thymeleaf 模板引擎,实现了后端数据向前端页面的动态渲染。在控制器中通过 Model 传递棋盘数据、当前玩家和胜负信息,在 HTML 页面中通过 th:text、th:each、th:if、th:href 等指令实现数据展示、循环生成棋盘、条件渲染棋子以及点击交互。相比传统静态页面,Thymeleaf 能够实现页面与数据分离,提高代码的可维护性和动态性。

相关推荐
NGC_66112 小时前
深度解析 ConcurrentHashMap 1.8:put 与 get 核心流程全解
java·开发语言
福运常在2 小时前
股票数据API如何获取(20)炸板股池数据
java·python·maven
2501_941982052 小时前
企微私域:实现企业通讯工具外部群消息的自动化主动推送
java·前端·javascript
等风来Boy2 小时前
CAS客户端退出登录
java·cas
禾小西2 小时前
Knife4j 快速入门:集Swagger2 和 OpenAPI3 为一体的增强解决方案
java·spring boot·后端
心勤则明2 小时前
Spring AI Alibaba MCP 协议的全链路安全与动态鉴权
java·安全·spring
sonnet-10292 小时前
堆排序算法
java·c语言·开发语言·数据结构·python·算法·排序算法
我是咸鱼不闲呀2 小时前
力扣Hot100系列24(Java)——[回溯]总结(下)(括号生成,单词搜索,分割回文串)
java·算法·leetcode
升鲜宝供应链及收银系统源代码服务2 小时前
生鲜配送供应链管理系统源代码之升鲜宝社区团购商城小程序(一)
java·前端·数据库·小程序·notepad++·供应链系统源代码·多门店收银系统