使用SpringBoot + Thymeleaf + MyBatisPlus实现一个简单的书籍管理系统-demo2

news/2025/10/21 18:20:00/文章来源:https://www.cnblogs.com/smalldong/p/19156133

一 准备环境

1 数据库环境搭建

CREATE DATABASE IF NOT EXISTS db_book;
USE db_book;CREATE TABLE book (id INT PRIMARY KEY AUTO_INCREMENT COMMENT '书籍唯一标识',name VARCHAR(255) NOT NULL COMMENT '书籍名称',author VARCHAR(100) NOT NULL COMMENT '作者',press VARCHAR(100) NOT NULL COMMENT '出版社',status VARCHAR(20) NOT NULL COMMENT '书籍状态(例如:在库、借出、已预订等)'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='书籍信息表';

2 Java环境搭建

3 Maven环境搭建

二 实验过程

1 实验目的

  1. 掌握 MyBatis-Plus 的基本配置与使用方法
  2. 理解并实践基于 MyBatis-Plus 的 CRUD 操作
  3. 学会使用 MyBatis-Plus 的条件构造器进行复杂查询
  4. 掌握分页查询的实现方式
  5. 理解实体类与数据库表的映射关系
  6. 培养基于 SpringBoot+MyBatis-Plus 进行实际项目开发的能力

2 实验要求

  1. 创建一个图书管理系统,实现图书信息的增删改查功能
  2. 使用 MyBatis-Plus 简化数据访问层代码
  3. 实现按图书名称、作者、类别等条件进行查询
  4. 实现图书信息的分页展示
  5. 对图书信息进行必要的验证(如非空验证)
  6. 代码结构清晰,符合 SpringBoot 开发规范
  7. 编写必要的测试用例验证功能正确性

3 实验过程

image-20251021175822158

1. 创建 Maven 项目

使用 IDEA 创建名为E3-BookManagementSystem的Maven项目,pom.xml依赖如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.4</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.yqd</groupId><artifactId>E3-BookManagementSystem</artifactId><version>0.0.1-SNAPSHOT</version><name>E3-BookManagementSystem</name><description>E3-BookManagementSystem</description><properties><java.version>17</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- MyBatisPlus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3.1</version></dependency><!-- MySQL驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.37</version><scope>runtime</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
2. 配置文件(application.properties)

src/main/resources下创建配置文件:

spring:application:name: E3-BookManagementSystemdatasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/db_book?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghaiusername: root  # 替换为你的数据库用户名password: 123456  # 替换为你的数据库密码# MyBatisPlus配置
mybatis-plus:mapper-locations: classpath:mapper/*.xml  # mapper.xml存放路径
type-aliases-package: com.yqd.entity  # 实体类包路径
configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  # 打印SQL日志(可选)server:port: 8081
3 启动类
package com.yqd;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@MapperScan("com.yqd.mapper") // 扫描Mapper接口所在包
public class E3BookManagementSystemApplication {public static void main(String[] args) {SpringApplication.run(E3BookManagementSystemApplication.class, args);}}
4. 实体类(Book.java)
package com.yqd.entity;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book {private Integer id;private String name;private String author;private String press;private String status;
}
5. Mapper 接口
package com.yqd.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yqd.entity.Book;
import org.apache.ibatis.annotations.Mapper;@Mapper  // 标记为MyBatis的Mapper接口
public interface BookMapper extends BaseMapper<Book> {// 无需手动编写CRUD方法,BaseMapper已提供
}
6. 服务层接口(BookService.java)
package com.yqd.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.yqd.entity.Book;import java.util.List;public interface BookService extends IService<Book> {// 继承IService,获得更多增强CRUD方法// 在BookService接口中添加List<Book> findByStatus(String status);
}
7. 服务层实现(BookServiceImpl.java)
package com.yqd.service.impl;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yqd.entity.Book;
import com.yqd.mapper.BookMapper;
import com.yqd.service.BookService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;import java.util.List;@Service  // 标记为服务层组件
public class BookServiceImpl extends ServiceImpl<BookMapper, Book> implements BookService {@Overridepublic List<Book> findByStatus(String status) {// 使用QueryWrapper构建条件QueryWrapper<Book> queryWrapper = new QueryWrapper<>();queryWrapper.eq("status", status);  // 等价于 WHERE status = ?return baseMapper.selectList(queryWrapper);}
}
8. 控制器(BookController.java)

实现增删改查接口:

package com.yqd.controller;import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yqd.entity.Book;
import com.yqd.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;import java.util.HashMap;
import java.util.List;
import java.util.Map;@Controller
@RequestMapping("/books")
public class BookController {@Autowiredprivate BookService bookService;// 1. 查询所有书籍(列表页)@GetMappingpublic String list(Model model) {// MyBatis-Plus的list()方法等价于JPA的findAll()List<Book> books = bookService.list();model.addAttribute("books", books);return "book/list";}// 2. 跳转新增/编辑页@GetMapping("/form")public String form(@RequestParam(required = false) Integer id, Model model) {if (id != null) {// MyBatis-Plus的getById()等价于JPA的findById()Book book = bookService.getById(id);model.addAttribute("book", book != null ? book : new Book());} else {model.addAttribute("book", new Book());}return "book/form";}// 3. 保存书籍(新增/更新)@PostMapping("/save")public String save(Book book) {// MyBatis-Plus的saveOrUpdate()方法自动判断新增/更新(根据ID是否为空)bookService.saveOrUpdate(book);return "redirect:/books";}// 4. 异步删除书籍@DeleteMapping("/{id}")@ResponseBodypublic Map<String, Object> delete(@PathVariable Integer id) {Map<String, Object> result = new HashMap<>();try {// MyBatis-Plus的removeById()等价于JPA的deleteById()boolean success = bookService.removeById(id);result.put("success", success);result.put("msg", success ? "删除成功" : "删除失败:书籍不存在");} catch (Exception e) {result.put("success", false);result.put("msg", "删除失败:" + e.getMessage());}return result;}// 5. 异步查询单本书籍@GetMapping("/{id}")@ResponseBodypublic Book getBookById(@PathVariable Integer id) {return bookService.getById(id);}// 6. 分页查询示例(在Controller中)@GetMapping("/page")@ResponseBodypublic IPage<Book> getPage(@RequestParam(defaultValue = "1") Integer pageNum,@RequestParam(defaultValue = "10") Integer pageSize) {Page<Book> page = new Page<>(pageNum, pageSize);return bookService.page(page); // 返回分页结果(包含总条数、当前页数据等)}
}
9. 前端页面实现(Thymeleaf + jQuery)
9.1 页面目录结构

src/main/resources/templates下创建:

templates/
├── index.html         // 首页
└── book/├── list.html      // 书籍列表页└── form.html      // 新增/编辑页
9.2 首页(index.html)
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>首页</title>
</head>
<body>
<h1 style="text-align: center; margin-top: 100px;"><a href="/books">进入书籍管理系统</a>
</h1>
</body>
</html>
9.3 书籍列表页(list.html)
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>书籍列表</title><script th:src="@{js/jquery.min.js}"></script><style>table { width: 80%; margin: 20px auto; border-collapse: collapse; }th, td { border: 1px solid #ccc; padding: 10px; text-align: center; }.btn { padding: 5px 10px; margin: 0 5px; cursor: pointer; }.add-btn { margin: 20px 0 0 10%; }/* 新增消息样式 */.msg {padding: 10px;margin: 10px 0;border-radius: 4px;text-align: center;}.success-msg { background: #d5f5e3; color: #27ae60; }.error-msg { background: #fadbd8; color: #e74c3c; }</style>
</head>
<body>
<h1 style="text-align: center;">书籍管理系统</h1>
<!-- 在list.html的.container内添加以下代码(h1标签下方) -->
<div th:if="${not #strings.isEmpty(successMsg)}" class="msg success-msg" th:text="${successMsg}"></div>
<div th:if="${not #strings.isEmpty(errorMsg)}" class="msg error-msg" th:text="${errorMsg}"></div>
<button class="btn add-btn" onclick="window.location.href='/books/form'">新增书籍</button><table><tr><th>ID</th><th>书名</th><th>作者</th><th>出版社</th><th>状态</th><th>操作</th></tr><tr th:each="book : ${books}"><td th:text="${book.id}"></td><td th:text="${book.name}"></td><td th:text="${book.author}"></td><td th:text="${book.press}"></td><td th:text="${book.status}"></td><td><button class="btn edit-btn" th:data-id="${book.id}">编辑</button><button class="btn delete-btn" th:data-id="${book.id}">删除</button></td></tr>
</table><script>$(function() {// 编辑按钮点击事件$('.edit-btn').click(function() {const id = $(this).data('id');window.location.href = `/books/form?id=${id}`; // 跳转到编辑页});// 删除按钮点击事件$('.delete-btn').click(function() {const id = $(this).data('id');if (confirm(`确定删除ID为${id}的书籍吗?`)) {deleteBook(id, $(this).closest('tr'));}});});// 异步删除书籍function deleteBook(id, $tr) {$.ajax({url: `/books/${id}`,type: 'DELETE',success: function(res) {if (res.success) {alert(res.msg);$tr.remove(); // 移除当前行} else {alert(res.msg);}},error: function() {alert('删除失败,请重试');}});}<!-- 消息自动消失脚本 -->$(function() {// 3秒后自动隐藏提示消息setTimeout(() => {$('.msg').fadeOut(1000);}, 3000);});
</script>
</body>
</html>
9.4 新增 / 编辑页(form.html)
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title th:text="${book.id != null ? '编辑书籍' : '新增书籍'}"></title><script th:src="@{js/jquery.min.js}"></script><style>.container { width: 500px; margin: 50px auto; }h2 { text-align: center; margin-bottom: 30px; }.form-group { margin: 15px 0; }label { display: inline-block; width: 100px; text-align: right; margin-right: 10px; }input, select { width: 300px; padding: 8px; border: 1px solid #ddd; border-radius: 4px; }.msg {padding: 10px;margin: 10px 0;border-radius: 4px;text-align: center;}.success-msg { background: #d5f5e3; color: #27ae60; } /* 成功提示 */.error-msg { background: #fadbd8; color: #e74c3c; }   /* 错误提示 */.btn-group { margin-top: 20px; margin-left: 110px; }.btn { padding: 8px 20px; border: none; border-radius: 4px; cursor: pointer; }.save-btn { background: #3498db; color: white; margin-right: 10px; }.cancel-btn { background: #95a5a6; color: white; }.save-btn:disabled { background: #95a5a6; cursor: not-allowed; }</style>
</head>
<body>
<div class="container"><h2 th:text="${book.id != null ? '编辑书籍' : '新增书籍'}"></h2><form id="bookForm" th:action="@{/books/save}" method="post"><!-- 隐藏域:用于传递ID(编辑时需要) --><input type="hidden" name="id" th:value="${book.id}"><div class="form-group"><label for="name">书名:</label><input type="text" id="name" name="name" th:value="${book.name}" required></div><div class="form-group"><label for="author">作者:</label><input type="text" id="author" name="author" th:value="${book.author}" required></div><div class="form-group"><label for="press">出版社:</label><input type="text" id="press" name="press" th:value="${book.press}" required></div><div class="form-group"><label for="status">状态:</label><select id="status" name="status" required><option value="在库" th:selected="${book.status == '在库'}">在库</option><option value="借出" th:selected="${book.status == '借出'}">借出</option><option value="已预订" th:selected="${book.status == '已预订'}">已预订</option></select></div><div class="form-group"><button type="submit" class="btn save-btn" id="saveBtn">保存</button><button type="button" class="btn" onclick="window.location.href='/books'">取消</button></div></form>
</div>
<script>// 防止重复提交:点击保存后禁用按钮$(function() {$('#bookForm').submit(function() {$('#saveBtn').prop('disabled', true).text('保存中...');return true; // 允许表单提交});// 3秒后自动隐藏提示消息setTimeout(() => {$('.msg').fadeOut(1000);}, 3000);});
</script>
</body>
</html>

4 运行与测试

1. 启动项目

运行E3BookManagementSystemApplication.javamain方法,控制台显示如下信息表示启动成功:

o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8081 (http) with context path ''
2. 访问系统

打开浏览器,输入http://localhost:8081,点击 "进入书籍管理系统" 进入书籍列表页。

3. 功能测试
(1)新增书籍
  • 点击 "新增书籍" 按钮,填写表单(如书名 "Java 编程"、作者 "张三"、出版社 "编程出版社"、状态 "在库")。
  • 点击 "保存",页面跳转至列表页,显示 "新增成功",列表中出现新增的书籍。
(2)编辑书籍
  • 点击某条书籍的 "编辑" 按钮,修改表单内容(如修改状态为 "借出")。
  • 点击 "保存",页面跳转至列表页,显示 "更新成功",列表中数据已更新。
(3)删除书籍
  • 点击某条书籍的 "删除" 按钮,确认后弹出 "删除成功" 提示,列表中该书籍消失。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/942552.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025年深圳离婚律所电话推荐:家理福田诺德中心婚姻家事专线

您正在寻找能够在深圳本地高效、合规地处理离婚事务的律师事务所,核心诉求是“可靠、可验证、可直接联系”。为此,我交叉比对了深圳市律师协会官网公示信息、中国裁判文书网近三年的婚姻家事案例数据,以及公开工商登…

生日

RT。十六岁了。常有欣喜,常有感叹;岁岁更进,年年生辉。别的话也不多说,继续加油,即使孤身一人,即使前路茫然。又有何妨?问路在何处?路在脚下。

2025年润滑油厂家权威推荐榜:工业润滑油,汽车润滑油,发动机润滑油,甲醇发动机润滑油,全合成润滑油,长效发动机润滑油品牌深度解析

2025年润滑油厂家权威推荐榜:工业润滑油,汽车润滑油,发动机润滑油,甲醇发动机润滑油,全合成润滑油,长效发动机润滑油品牌深度解析 行业背景与发展趋势 随着全球工业化和汽车产业的快速发展,润滑油行业正经历着深…

2025固定资产管理系统电话推荐:公贝资产全周期管理方案

您正在寻找一套能够把采购、折旧、盘点、报废串成一条线的固定资产管理平台,希望先通过电话快速验证产品边界、实施周期和后续服务。为了节省您首轮筛选时间,我依据公开招投标信息、工信部备案数据以及企业官网披露资…

如果使用 vxe-table 实现全键盘操作,按键切换复选框单选框的选中状态

如果使用 vxe-table 实现全键盘操作,按键切换复选框单选框的选中状态,当遇到特点需求,比如需要通过按键来选中复选框或单选框时,该功能就非常有用了。 查看官网:https://vxetable.cn gitbub:https://github.com/…

2025年超声波清洗机厂家电话推荐:广东洁泰设备选型与联系指引

您正在寻找一家在超声波清洗领域有真实量产经验、能提供非标定制且售后响应可验证的国内厂家。为了避免信息碎片化带来的比对偏差,我调取了工商注册信息、专利公示库、环保备案号及第三方行业报告,把能交叉验证的线索…

2025年超声波清洗机厂家电话推荐:广东洁泰超声设备有限公司

您正在寻找一家在超声波清洗领域拥有长期沉淀、能够提供非标定制且售后响应迅速的国内厂家,核心诉求集中在技术可靠性、行业案例与后续服务保障。为确保信息可交叉验证,我仅以公开工商登记、专利数据库、第三方行业报…

2025年上海装修公司电话推荐:极家与俞润本土双选参考

您正在寻找在上海本地具备规模、资质与口碑的装修服务商,希望先通过电话沟通快速了解设计能力、施工标准与售后政策,再决定是否深入面谈。以下两家企业均持有国家二级及以上施工资质,门店与展厅可公开参观,联系方式…

2025年激光切割机厂家电话推荐:济南邦德激光4009917771技术对接通道.

您正在寻找可直接沟通的激光切割设备源头厂家,核心诉求是快速验证企业真实性与技术实力,并获取官方售前支持。为此,我交叉比对了海关总署出口名录、全国工商联装备业分会年报、以及上交所科创板公开问询回复,筛选出…

2025年岗亭定制厂家电话推荐:法利莱集团连锁服务网络覆盖多省市

您正在寻找一家能把图纸变成实物、把工期写进合同、把售后落到网点的岗亭定制厂家,核心诉求无非三点:方案可靠、价格透明、响应及时。为了把“听起来不错”变成“看得见摸得着”,我调取了行业协会近三年的会员名录、…

各项任务完成时间统计

计划:大约2天左右调查背景和构思 开发:约1天整 记录用时:总计3天左右 事后总结:完成代码时注释十分必要,有助于他人理解和自己回顾,同时软件文档的撰写也是很重要的

AI转型困境:仅13%企业实现技术落地

最新研究报告显示,尽管87%企业高管认为AI将在未来一年彻底改变组织架构,但仅13%企业成功落实AI转型。调查发现企业普遍存在技术基础设施不完善、员工技能不足等实施障碍,揭示了AI愿景与现实落地之间的巨大差距。多方…

软件工程结对项目-小学四则运算题目生成与判题程序

软件工程结对项目-小学四则运算题目生成与判题程序软件工程结对项目 一、项目参与成员 计算机科学与技术3班 许晓喆 3223004302这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScie…

哑演算基础理论

the-umbral-calculus前言: 这篇文章基本是关于 Steven Roman, The Umbral Calculus 1~3 章的中文翻译(其实可能不太算翻译了,改的原文结构还是挺多的),原文可从 Z-Library 下载 . 有问题请在评论区反馈!\[\newco…

2025年激光切割机厂家电话推荐:济南邦德激光股份有限公司4009917771

您正在寻找一台性能稳定、售后响应及时的激光切割机,并希望直接对接具备规模与出口经验的厂家。为了降低信息噪音,我调阅了海关总署、山东省工信厅公开数据,以及近五年《中国激光产业发展报告》中“金属成形激光设备…

实用指南:Python全栈(基础篇)——Day05:后端内容(dict与set+while循环+for循环+实战演示+每日一题)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

在AI技术唾手可得的时代,挖掘新需求成为开发者核心竞争力——某知名API学习平台需求洞察

本文深入分析了一个开源API学习平台的核心功能和应用场景,通过系统梳理用户反馈和功能需求,揭示了在AI技术快速发展的背景下,如何识别和满足开发者真实需求的重要性,为技术产品规划提供参考价值。a.内容描述核心功…

KeyShot许可安全性保障

在数字化时代,软件的安全性成为了企业和个人选择软件的关键因素之一。KeyShot作为一款广受欢迎的3D渲染软件,深知安全性对于用户的重要性。为了确保您的KeyShot许可安全无忧,我们采取了一系列严格的安全措施,为您的…

maven添加自己下载的jar到本地仓库

1、 打开Maven中央仓库网站: https://mvnrepository.com/ 或者阿里云 https://maven.aliyun.com/mvn/guide 搜索并下载对应的jar到本地 2、 运行Maven命令,以确保JAR文件已成功安装到本地仓库。 例:mvn install:ins…

2025年防静电/劳保/国网/餐厅/工厂/电工/防酸碱/电力/车间/航空/员工广告衫,文化衫/t恤/polo衫/冲锋衣厂家推荐排行榜

2025年防静电/劳保/国网/餐厅/工厂/电工/防酸碱/电力/车间/航空/员工广告衫,文化衫/t恤/polo衫/冲锋衣厂家推荐排行榜 行业背景与发展趋势 随着产业升级和安全生产意识的提升,特种工装与职业服饰市场正迎来新一轮发展…