教程概述
继上一篇文章 SpringBoot整合Thymeleaf与Bootstrap5:快速构建导航栏并抽取公共代码,教学了SpringBoot整合Thymeleaf与Bootstrap5快速的实现了一个网站的导航栏,当然,只是一个展示。本教程接上一个项目,实现整合MyBatisPlus、MySQL,将标签分类信息存放于数据库,完成网站中分类标签的动态模板渲染。
最后的结果如下图
教程步骤
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><!-- 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><!-- 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:创建Mapper的目录
在resources目录下,我这里创建了一个名为dao的目录,用于存放mapper的xml文件,如图
步骤3:配置MySQL、MyBatisPlus
在application.yaml中,添加上mysql的配置与mybatisplus的配置,接上次的thymeleaf完整如下,注意将mysql信息配置正确
spring:thymeleaf:cache: falseencoding: UTF-8prefix: classpath:/templates/suffix: .htmlmode: HTML5datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/you_resource?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghaiusername: rootpassword: 159357mybatis-plus:configuration:map-underscore-to-camel-case: truemapper-locations: classpath:/dao/*.xmlspring: 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/*.xmlspring: 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:创建标签页面
虽然称为标签页面,但是是用于给主页引入的,之所以抽取出来,是考虑到后续其他页面可能会使用,甚至表的结构也会修改,当然现在不考虑那么多,怎么块怎么来。
在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><!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><!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><div th:replace="~{front/commons/NavTab.html}"></div><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><!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><!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;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;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;
库、表创建导入完成后,你应当看到这样的内容,如图
步骤6:创建视图对象
因为分类标签表中子标签是以json格式存储,直接使用实体返回的信息无法直接应用于模板,因此在domain中创建vo目录,建立模板所需的视图对象,如图,在vo中创建NavTabVo,内容如下,如果你的lombok无法使用,可自行将注解替换生成get和set方法(我这里就是)
@Data@NoArgsConstructor@AllArgsConstructorpublic 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;}@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; }@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; }
步骤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() {}}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() { } }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 {@ResourceNavTabService 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";}}@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"; } }@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 {@ResourceNavTabDao navTabDao;@Overridepublic List<NavTab> getNavTabs() {return navTabDao.getNavTabs();}}@Service("navTabService") public class NavTabServiceImpl extends ServiceImpl<NavTabDao,NavTab> implements NavTabService { @Resource NavTabDao navTabDao; @Override public List<NavTab> getNavTabs() { return navTabDao.getNavTabs(); } }@Service("navTabService") public class NavTabServiceImpl extends ServiceImpl<NavTabDao,NavTab> implements NavTabService { @Resource NavTabDao navTabDao; @Override public List<NavTab> getNavTabs() { return navTabDao.getNavTabs(); } }
NavTabDao.java,这里我没有使用注解的方式,因此还是有必要贴出
@Mapperpublic interface NavTabDao extends BaseMapper<NavTab> {List<NavTab> getNavTabs();}@Mapper public interface NavTabDao extends BaseMapper<NavTab> { List<NavTab> getNavTabs(); }@Mapper public interface NavTabDao extends BaseMapper<NavTab> { List<NavTab> getNavTabs(); }
到了dao这里,然后在resources的dao下创建NavTabDao.xml,内容如下
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapperPUBLIC "-//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><?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><?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:查看主页
在前面的步骤,后端的相关内容都做好了,但是标签页还没有做处理,可以先启动项目看看显示是否正常,如果没问题,将会是如图的效果 (中间那个彩色的区域是一张图,你可以替换为其他图片)
步骤10:修改标签页动态获取分类标签
将NavTab.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的语法动态的获取的接口中响应的数据,再次启动项目,结果如下
补充说明
补充1.代码中的错误处理解释
我们提到了响应的数据问题,如果后台处理数据错误时总不可能直接给用户展示个例如500的错误吧,比如如下图
接口中在可能出现错误的地方,也就是json解析那块,做了异常捕获,并响应对应的错误信息,我们可以在try中故意制造个除以0的错误看看效果,如图,还算不错
补充2.解读thymeleaf的模板渲染
首先是响应的数据中,可以看到是一个Res包含了code、msg、data的,且data是一个List<NavTabVo>对象,且每个NavTabVo中有个比较特殊的属性itemInfo,其类型是List<HashMap<String,String>>,这也是为了应付json数据转化为java对象,因为模板只可解析java对象
在NavTab.html中,以下代码做了对后端出异常的处理显示
<div th:if="${res.getCode() == 0}"><strong>错误:</strong> <span th:text="${res.getMsg()}"></span></div><div th:if="${res.getCode() == 0}"> <strong>错误:</strong> <span th:text="${res.getMsg()}"></span> </div><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><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><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>
结语
暂无评论内容