当前位置: 首页 > article >正文

SpringBoot + Thymeleaf + Bootstrap5 整合 MyBatis-Plus 和 MySQL 实现动态分类标签渲染教程

教程概述

继上一篇文章SpringBoot整合Thymeleaf与Bootstrap5:快速构建导航栏并抽取公共代码,教学了SpringBoot整合Thymeleaf与Bootstrap5快速的实现了一个网站的导航栏,当然,只是一个展示。本教程接上一个项目,实现整合MyBatisPlus、MySQL,将标签分类信息存放于数据库,完成网站中分类标签的动态模板渲染。

原文链接:SpringBoot+Thymeleaf+Bootstrap5整合MyBatisPlus、MySQL实现分类标签的动态渲染

最后的结果如下图

1

教程步骤

1.导入MyBatisPlus、MySQL依赖

2.创建Mapper的目录

3.配置MySQL、MyBatisPlus

4.创建标签页面,并在主页引入

5.创建数据库、建表,构造数据

6.创建视图对象

7.创建响应数据工具类

8.修改主页的控制器

9.查看主页

10.修改标签页动态获取分类标签

步骤1:导入MyBatisPlus、MySQL依赖

导入如下依赖,这里还需要额外导入jackson-core的依赖,因为本教程的分类子标签是以json形式存放于数据库中,需要使用该库对其进行转换

<!-- MyBatis-Plus Starter -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.1</version>
</dependency>
<!-- MySQL Connector -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<!--jackson-core-->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
</dependency>

如图

2

步骤2:创建Mapper的目录

在resources目录下,我这里创建了一个名为dao的目录,用于存放mapper的xml文件,如图

3

步骤3:配置MySQL、MyBatisPlus

在application.yaml中,添加上mysql的配置与mybatisplus的配置,接上次的thymeleaf完整如下,注意将mysql信息配置正确

spring:
  thymeleaf:
    cache: false
    encoding: UTF-8
    prefix: classpath:/templates/
    suffix: .html
    mode: HTML5
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/you_resource?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: root
    password: 159357
mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true
  mapper-locations: classpath:/dao/*.xml

如图

4

步骤4:创建标签页面

虽然称为标签页面,但是是用于给主页引入的,之所以抽取出来,是考虑到后续其他页面可能会使用,甚至表的结构也会修改,当然现在不考虑那么多,怎么块怎么来。

在templates/front/commons下创建NavTab.html,内容如下

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
</head>
<body>
    <div class="container mt-4 bg-white p-4 rounded">
        <ul class="nav nav-pills flex-wrap list-unstyled mb-4">
            <!-- 独立的一行,显示 A分类 -->
            <li  class="nav-item w-100 border-bottom pb-2 mb-3">
                <span class="nav-link p-0 m-0 d-flex align-items-center text-dark">
                    <i class="bi bi-align-bottom me-2" style="font-size: 1.25rem;"></i>
                    <span>源码分类</span>
                </span>
            </li>

            <!-- 其他分类项 -->
            <li class="nav-item border-end pe-3 me-3">
                <a class="text-dark text-decoration-none" href="#">分类1</a>
            </li>
            <li class="nav-item border-end pe-3 me-3">
                <a class="text-dark text-decoration-none" href="#">分类2</a>
            </li>
            <li class="nav-item border-end pe-3 me-3">
                <a class="text-dark text-decoration-none" href="#">分类3</a>
            </li>
        </ul>

        <ul class="nav nav-pills flex-wrap list-unstyled mb-4">
            <!-- 独立的一行,显示 A分类 -->
            <li  class="nav-item w-100 border-bottom pb-2 mb-3">
                <span class="nav-link p-0 m-0 d-flex align-items-center text-dark">
                    <i class="bi bi-align-bottom me-2" style="font-size: 1.25rem;"></i>
                    <span>网创分类</span>
                </span>
            </li>

            <!-- 其他分类项 -->
            <li class="nav-item border-end pe-3 me-3">
                <a class="text-dark text-decoration-none" href="#">分类1</a>
            </li>
            <li class="nav-item border-end pe-3 me-3">
                <a class="text-dark text-decoration-none" href="#">分类2</a>
            </li>
            <li class="nav-item border-end pe-3 me-3">
                <a class="text-dark text-decoration-none" href="#">分类3</a>
            </li>
        </ul>
    </div>
</body>
</html>

在主页,也就是index.html中引入该文件

主要是这一句

<div th:replace="~{front/commons/NavTab.html}"></div>

完整代码为

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>test</title>
    <link rel="stylesheet" href="/bootstrap-5.3.0/css/bootstrap.css">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
</head>
<body>
    <nav th:replace="~{front/commons/HeadNav.html}"></nav>

    <!-- 使用Bootstrap的容器 -->
    <div class="container-fluid p-0">
        <!-- Banner容器 -->
        <div class="position-relative">
            <!-- 图片 -->
            <img src="/front/banner1.webp" class="img-fluid w-100" alt="Banner Image" style="height: 200px; object-fit: cover;">

            <!-- 文字覆盖 -->
            <div class="position-absolute top-50 start-50 translate-middle text-center text-white">
                <h1 class="fw-bold">欢迎来到我们的站点</h1>
                <p class="lead">这是一个精美的横幅展示区域</p>
            </div>
        </div>
    </div>

    <div th:replace="~{front/commons/NavTab.html}"></div>

    <!--卡片-->
    <div class="row row-cols-1 row-cols-md-3 g-4">

    </div>

    <script src="/bootstrap-5.3.0/js/bootstrap.js"></script>
</body>
</html>

此时你还无法启动项目,因为我们配置了数据库信息并且还没有创建对应的数据库,启动是不会成功的

步骤5:创建数据库、建表,构造数据

我这里使用的MySQL数据库版本为5.7,当然用8.0更好,数据库名和yaml中配置的名称一样,名为you_resource,创建一张表,名为nav_tab,我这里直接将该表的SQL脚本放出来,直接使用即可

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for nav_tab
-- ----------------------------
DROP TABLE IF EXISTS `nav_tab`;
CREATE TABLE `nav_tab`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'NavTab分类id',
  `item_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '分类名称',
  `item_info` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '子分类项信息',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `create_user` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人名称',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `update_user` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新人名称',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'NavTab分类表\r\nid为大分类的id\r\nitem_name为大分类的名称\r\nitem_info为小分类项的信息,以json形式,包括了分类项的名称、超链接地址' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of nav_tab
-- ----------------------------
INSERT INTO `nav_tab` VALUES (1, '源码分类', '[{\"item_name\": \"java源码\", \"item_href\": \"http://www.youluoyuan.com\"}, {\"item_name\": \"html源码\", \"item_href\": \"http://www.baidu.com\"}, {\"item_name\": \"PHP源码\", \"item_href\": \"http://www.baidu.com\"}]', '2024-12-27 16:56:27', '1', '2024-12-30 15:21:20', '1');
INSERT INTO `nav_tab` VALUES (2, '网创分类', '[{\"item_name\": \"自媒体\", \"item_href\": \"http://www.youluoyuan.com\"}, {\"item_name\": \"短视频\", \"item_href\": \"http://www.baidu.com\"}]', '2024-12-30 13:29:28', NULL, '2024-12-30 13:29:56', NULL);

SET FOREIGN_KEY_CHECKS = 1;

库、表创建导入完成后,你应当看到这样的内容,如图

5

步骤6:创建视图对象

因为分类标签表中子标签是以json格式存储,直接使用实体返回的信息无法直接应用于模板,因此在domain中创建vo目录,建立模板所需的视图对象,如图,在vo中创建NavTabVo,内容如下,如果你的lombok无法使用,可自行将注解替换生成get和set方法(我这里就是)

@Data
@NoArgsConstructor
@AllArgsConstructor
public class NavTabVo {
    private Long id;
    private String itemName;
    private List<HashMap<String,String>> itemInfo;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
    private Date createTime;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
    private Date updateTime;
    private String createUser;
    private String updateUser;
}

6

步骤7:创建响应数据工具类

在后端处理数据,不一定总是成功的,因此有必要创建一个统一的响应数据格式,创建utils目录,添加名为Res的java文件,内容如下

public class Res<T> {
    private int code;  // 0 表示失败,1 表示成功
    private String msg;  // 错误或成功消息
    private T data;  // 返回的数据

    private Res(int code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public static <T> Res<T> success(T data) {
        return new Res<T>(1,"成功",data);
    }

    public static <T> Res<T> error(String msg) {
        return new Res<T>(0,msg,null);
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public Res() {
    }
}

步骤8:修改主页的控制器

上篇文章创建的主页控制器,只是用于处理跳转到主页,现在需要增加分类标签数据的响应

来到FrontPageCon,修改我们的FrontIndex接口,这里就要用到jackson和上面创建的Res了,以及对数据库的操作

接口内容如下

FrontPageCon.java

@Controller
@RequestMapping("/")
public class FrontPageCon {

    @Resource
    NavTabService navTabService;

    @GetMapping("/")
    public String FrontIndex(Model model) {
        List<NavTab> navTabs = navTabService.getNavTabs();
        List<NavTabVo> navTabVos = new ArrayList<>();
        for (NavTab navTab : navTabs) {
            NavTabVo navTabVo = new NavTabVo();
            navTabVo.setId(navTab.getId());
            navTabVo.setItemName(navTab.getItemName());
            navTabVo.setCreateTime(navTab.getCreateTime());
            navTabVo.setUpdateTime(navTab.getUpdateTime());
            navTabVo.setCreateUser(navTab.getCreateUser());
            navTabVo.setUpdateUser(navTab.getUpdateUser());
            String itemInfoStr = navTab.getItemInfo();
            try {
                ObjectMapper objectMapper = new ObjectMapper();
                // 将 JSON 字符串转换为 List<Map<String, String>>
                TypeReference<List<HashMap<String, String>>> typeReference = new TypeReference<List<HashMap<String, String>>>() {};
                List<HashMap<String, String>> itemInfo = objectMapper.readValue(itemInfoStr,typeReference);
                navTabVo.setItemInfo(itemInfo);
            } catch (Exception e) {
                model.addAttribute("res", Res.error(e.getMessage()));
                return "front/index";
            }
            navTabVos.add(navTabVo);
        }
        model.addAttribute("res", Res.success(navTabVos));
        return "front/index";
    }
}

NavTabService我就不说了(直接点击生成的东西),这里放出对应实现类内容

NavTabServiceImpl.java

@Service("navTabService")
public class NavTabServiceImpl extends ServiceImpl<NavTabDao,NavTab> implements NavTabService {

    @Resource
    NavTabDao navTabDao;

    @Override
    public List<NavTab> getNavTabs() {
        return navTabDao.getNavTabs();
    }
}

NavTabDao.java,这里我没有使用注解的方式,因此还是有必要贴出

@Mapper
public interface NavTabDao extends BaseMapper<NavTab> {
    List<NavTab> getNavTabs();
}

到了dao这里,然后在resources的dao下创建NavTabDao.xml,内容如下

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.you_resource.dao.NavTabDao">
    <!--List<NavTab> getNavTabs();-->
    <select id="getNavTabs" resultType="com.you_resource.domain.pojo.NavTab">
        select * from nav_tab
    </select>
</mapper>

步骤9:查看主页

在前面的步骤,后端的相关内容都做好了,但是标签页还没有做处理,可以先启动项目看看显示是否正常,如果没问题,将会是如图的效果 (中间那个彩色的区域是一张图,你可以替换为其他图片)

7

步骤10:修改标签页动态获取分类标签

将NavTab.html内容替换为如下

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
</head>
<body>
<div class="container mt-4 bg-white p-4 rounded">
    <div th:if="${res.getCode() == 0}">
        <strong>错误:</strong> <span th:text="${res.getMsg()}"></span>
    </div>
    <ul th:each="navTabVo : ${res.getData()}" class="nav nav-pills flex-wrap list-unstyled mb-4">
        <!-- 独立的一行,显示 A分类 -->
        <li  class="nav-item w-100 border-bottom pb-2 mb-3">
                <span class="nav-link p-0 m-0 d-flex align-items-center text-dark">
                    <i class="bi bi-align-bottom me-2" style="font-size: 1.25rem;"></i>
                    <span th:text="${navTabVo.getItemName()}"></span>
                </span>
        </li>
​
        <!-- 其他分类项 -->
        <li class="nav-item border-end pe-3 me-3" th:each="itemInfo : ${navTabVo.getItemInfo()}" >
            <a class="text-dark text-decoration-none" th:href="${itemInfo['item_href']}" th:text="${itemInfo['item_name']}"></a>
        </li>
    </ul>
</div>
</body>
</html>

可以看到,内容省略了不少,且这里利用thymeleaf的语法动态的获取的接口中响应的数据,再次启动项目,结果如下

8

补充说明

补充1.代码中的错误处理解释

我们提到了响应的数据问题,如果后台处理数据错误时总不可能直接给用户展示个例如500的错误吧,比如如下图

9

接口中在可能出现错误的地方,也就是json解析那块,做了异常捕获,并响应对应的错误信息,我们可以在try中故意制造个除以0的错误看看效果,如图,还算不错

10

补充2.解读thymeleaf的模板渲染

首先是响应的数据中,可以看到是一个Res包含了code、msg、data的,且data是一个List<NavTabVo>对象,且每个NavTabVo中有个比较特殊的属性itemInfo,其类型是List<HashMap<String,String>>,这也是为了应付json数据转化为java对象,因为模板只可解析java对象

11

在NavTab.html中,以下代码做了对后端出异常的处理显示

<div th:if="${res.getCode() == 0}">
    <strong>错误:</strong> <span th:text="${res.getMsg()}"></span>
</div>

ul中,${res.getData()}对应着Res对象的getData方法,这里使用了javabean模式的获取数据的方法,th:each表示遍历获取每个对象并命名为navTabVo,后面的th:text="${navTabVo.getItemName()}"是一样的,使用java对象的get方法。

再往下,可以看到a标签中的获取数据方式与上面不同,是这样的 th:href="${itemInfo['item_href']}" th:text="${itemInfo['item_name']}" ,因为这里的每个itemInfo在接口中可以看到是一个个Map,因此需用此方式来获取对应的值

<ul th:each="navTabVo : ${res.getData()}" class="nav nav-pills flex-wrap list-unstyled mb-4">
        <!-- 独立的一行,显示 A分类 -->
        <li  class="nav-item w-100 border-bottom pb-2 mb-3">
                <span class="nav-link p-0 m-0 d-flex align-items-center text-dark">
                    <i class="bi bi-align-bottom me-2" style="font-size: 1.25rem;"></i>
                    <span th:text="${navTabVo.getItemName()}"></span>
                </span>
        </li>

        <!-- 其他分类项 -->
        <li class="nav-item border-end pe-3 me-3" th:each="itemInfo : ${navTabVo.getItemInfo()}" >
            <a class="text-dark text-decoration-none" th:href="${itemInfo['item_href']}" th:text="${itemInfo['item_name']}"></a>
        </li>
    </ul>

结语

以上是幽络源的SpringBoot+Thymeleaf+Bootstrap5整合MyBatisPlus、MySQL实现分类标签的动态渲染的java教程,如感兴趣、有不懂之处可加群交流。


http://www.kler.cn/a/460412.html

相关文章:

  • Oracle 23ai 图形界面安装
  • Dell服务器升级ubuntu 22.04失败解决
  • leetcode 面试经典 150 题:同构字符串
  • python中常用的内置函数介绍
  • Docker学习相关笔记,持续更新
  • LabVIEW 使用 Resample Waveforms VI 实现降采样
  • 郑州时空-TMS运输管理系统 GetDataBase 信息泄露漏洞复现
  • 深信服云桌面系统的终端安全准入设置
  • JavaWeb开发(三)Servlet技术-手动、自动创建Servlet
  • Elasticsearch-搜索推荐:Suggest
  • 记一次 .NET某汗液测试机系统 崩溃分析
  • HTML5 开关(Toggle Switch)详细讲解
  • 如何将联系人从 iPhone 转移到华为 [4 种方法]
  • 【SQLi_Labs】Basic Challenges
  • 网络游戏之害
  • 智能工厂的设计软件 应用场景的一个例子:为AI聊天工具添加一个知识系统 之9 重新开始 之2
  • 半导体数据分析: 玩转WM-811K Wafermap 数据集(一) AI 机器学习
  • 机器学习DAY9:聚类(K-means、近邻传播算法、谱聚类、凝聚聚类、兰德指数、调整互信息、V−mearure、轮廓系数)
  • Python爬虫入门实例:Python7个爬虫小案例(附源码)
  • 解锁节日季应用广告变现潜力,提升应用广告收入
  • Flink读写Kafka(DataStream API)
  • springboot523基于Spring Boot的大学校园生活信息平台的设计与实现(论文+源码)_kaic
  • 【数据库系统概念】期末复习笔记
  • Spring MVC (下)小项目实战
  • SD卡恢复数据:快速找回丢失文件!
  • ABP框架8——仓储的作用及其基础Demo