Spring Boot图书管理系统实战:从数据建模到部署的完整指南
简介这是一份基于Springboot与Vue开发的图书管理系统完整项目源码主要面向正在做课程设计、毕业设计或入门Java全栈开发的读者。系统采用B/S架构整合Maven、MySQL与MyBatisPlus覆盖用户信息管理、图片素材管理、视频素材管理、公告信息管理等典型功能模块有助于熟悉前后端分离项目的整体开发流程。压缩包共743个文件大小约19.72MB其中93个Java文件承担后端业务逻辑52个Vue组件与157个JS文件构建前端交互页面SVG/CSS等静态资源用于界面样式XML/YML配置负责环境准备同时提供安装、启动、打包工具脚本和docx项目文档便于快速部署调试。资源目录按后端、前端、配置和文档分层组织便于按模块查找代码。目前已有104人学习资源内另附演示媒体素材可辅助理解功能效果与数据库关系适合需要参考完整实现并自行扩展的开发者。1. 基于Springboot的图书管理系统真正交付的是一套能跑通闭环的Java Web代码“基于Springboot的图书管理系统”这个标题看着像课设题目实际上它背后是一套很标准的Java Web项目形态Spring Boot提供后端接口MySQL存数据浏览器页面负责借书、还书、查书、管理读者。图书本身只是个业务载体真正练到的是Spring Boot配置、MyBatis数据访问、前端页面联动这一整条链路。适合正在学Java的人拿来做课程设计或者当毕业设计的第一版底子也适合想快速搭一个后台管理网站练手的开发者。2. 先建表再写代码数据模型与建表SQL决定这套系统一半的命运很多人拿到“图书管理系统”第一反应是打开IDEA新建项目这恰恰是最大的坑。业务逻辑还没理清楚就写实体类后面每加一个功能都要回头改表越改越乱。我一般先花半小时把数据模型定下来再做编码。数据模型不要求多华丽但四张表的分工要清楚后面所有Controller都只是在搬这几张表的数。2.1 把业务需求拆成四张表读者、图书、借阅记录、管理员各管一段图书管理系统的核心域拆开就是两个“主数据”加一个“行为数据”。主数据是图书和读者行为数据是借阅记录最后再加一张管理员表做登录支撑。大多数课设级别的系统只需要这四张表不需要订单、支付、库存流水这类过度设计。图书表负责存书的基本信息和库存ISBN、书名、作者、出版社、分类、总册数、当前可借库存。读者表负责借书人借书证号、姓名、电话、邮箱、状态。借阅记录表是核心业务表每次借书生成一条记录还书时更新这条记录的归还时间和状态。管理员表只做一件事登录校验。四张表的责任边界很清楚写代码时“哪个功能查哪张表”不会纠结。如果后续要给系统加分可以扩预约表、罚款表但那是第二步的事。先把这四张表的字段定准。2.2 借阅流程就靠状态和时间两个字段库存、期限与逾期的设计借阅记录表里最关键的字段不是主键而是状态和时间。状态字段用整数区分0借出中、1已归还、2已续借。时间字段有三个借出时间、应还时间、实际归还时间。应还时间在借书时算好默认是借出时间加30天存进表里。这样后续查询不用每次都做日期加减。逾期判断也依赖时间字段不需要写定时任务查询时直接比较应还时间和当前时间就能得出结果。这个点很多人没想到借阅记录列表页要展示“是否逾期”在SQL里加一个条件即可。库存扣减的逻辑同样简单借书时book表的stock减1还书时加1。要注意的是并发问题比如两个人同时借最后一本书扣库存前先判断stock大于0再把减库存和新增借阅记录放到同一个事务里。2.3 一份可以直接落库的建表SQL下面的SQL是我常用的一版字段命名采用下划线风格正好和MyBatis-Plus的驼峰映射对齐。注意不要加物理外键借阅记录里的book_id、reader_id只做逻辑关联真的加了外键删除读者或图书时会有一堆级联报错。CREATE DATABASE IF NOT EXISTS library_system DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE library_system; CREATE TABLE admin ( id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT 管理员ID, username VARCHAR(32) NOT NULL UNIQUE COMMENT 登录名, password VARCHAR(128) NOT NULL COMMENT 密码建议存BCrypt哈希, role VARCHAR(16) NOT NULL DEFAULT ADMIN COMMENT 角色, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT管理员表; CREATE TABLE reader ( id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT 读者ID, card_no VARCHAR(20) NOT NULL UNIQUE COMMENT 借书证号, name VARCHAR(50) NOT NULL COMMENT 姓名, phone VARCHAR(20) DEFAULT COMMENT 电话, email VARCHAR(64) DEFAULT COMMENT 邮箱, status TINYINT NOT NULL DEFAULT 1 COMMENT 状态1正常0停用, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 注册时间 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT读者表; CREATE TABLE book ( id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT 图书ID, isbn VARCHAR(32) NOT NULL COMMENT ISBN号, name VARCHAR(128) NOT NULL COMMENT 书名, author VARCHAR(64) DEFAULT COMMENT 作者, publisher VARCHAR(64) DEFAULT COMMENT 出版社, category VARCHAR(32) DEFAULT COMMENT 分类, total INT NOT NULL DEFAULT 1 COMMENT 总册数, stock INT NOT NULL DEFAULT 1 COMMENT 当前可借库存, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 入库时间 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT图书表; CREATE TABLE borrow_record ( id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT 记录ID, reader_id BIGINT NOT NULL COMMENT 读者ID逻辑关联reader表, reader_name VARCHAR(50) NOT NULL COMMENT 冗余读者姓名列表页免联表, book_id BIGINT NOT NULL COMMENT 图书ID逻辑关联book表, book_name VARCHAR(128) NOT NULL COMMENT 冗余书名, borrow_time DATETIME NOT NULL COMMENT 借出时间, due_time DATETIME NOT NULL COMMENT 应还时间, return_time DATETIME DEFAULT NULL COMMENT 实际归还时间NULL表示未还, status TINYINT NOT NULL DEFAULT 0 COMMENT 状态0借出中1已归还2已续借, KEY idx_status_due (status, due_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT借阅记录表; INSERT INTO book (isbn, name, author, publisher, category, total, stock) VALUES (9787115428028, Spring Boot实战, Craig Walls, 人民邮电出版社, 计算机, 3, 3), (9787302460406, Java核心技术卷I, Cay S. Horstmann, 机械工业出版社, 计算机, 2, 2); INSERT INTO reader (card_no, name, phone, email) VALUES (R20230001, 张小明, 13800000001, zhangxmexample.com), (R20230002, 李华, 13800000002, lihuaexample.com);来说几个关键参数。id统一用BIGINT自增别用int图书数量稍大就可能溢出。characterEncodingutf8mb4在库、表、连接串三处都要设置少一处中文就是问号这个在第5章还会展开。borrow_record表里冗余了reader_name和book_name这是故意的列表页展示时不需要JOIN两张主表查询速度快代码也简单。如果你追求范式严格可以把这两列去掉但课设和实际小项目里冗余字段是常见做法。3. 用Spring Boot把核心接口跑起来创建项目到第一个查询接口数据模型定了代码层就变成“体力活”。用IDEA创建Spring Boot项目时新手最容易在依赖选择上翻车。不要用最新版本追高也不用刻意用旧版关键是让Spring Boot版本、JDK版本、MyBatis-Plus版本三者对得上具体对应关系在第5章说。这一章先解决“能不能跑起来”的问题。3.1 IDEA里创建Spring Boot项目的三个关键动作依赖、配置、启动类用IDEA创建Spring Boot项目的方式很简单New Project里选Spring InitializrJDK选8或17都行然后在Dependencies里勾选Spring Web、MySQL Driver、Validation。IDEA会自动生成启动类但依赖列表里还差两个常用的东西一个是MyBatis-Plus另一个是Lombok这两个要手动加进pom.xml。下面的依赖片段可以直接粘进pom.xml的dependencies标签里。dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version /dependency dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependencyMyBatis-Plus是现在做课设和业务系统最常见的持久层框架它把单表CRUD的代码几乎全省了实体类一写Mapper接口继承BaseMapper增删改查方法直接继承过来不用手写SQL。mysql-connector-j注意包名Spring Boot 2.7.x里还叫mysql-connector-javaSpring Boot 3.x改成了mysql-connector-j这是个容易踩的版本坑。Lombok用Data注解省掉getter/setter少写很多重复代码。依赖加好接着写application.yml。这个文件是所有配置的集中地数据源、端口、模板引擎、MyBatis-Plus都在这里。下面的配置可以直接用注意把数据库密码改成你自己的。server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/library_system?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: deletedurl里那三个参数一个都不能少。useUnicode和characterEncoding保证中文正常读写不管后端还是数据库都统一utf8mb4乱码问题基本绝迹。serverTimezoneAsia/Shanghai解决时间差8小时的问题如果漏掉这个参数LocalDateTime存取会和数据库差8个小时查出来总觉得时间不对。log-impl配成stdout控制台能看到每条SQL和参数排错时极其好用。启动类保持IDEA生成的样子就行只需要确认一个点启动类所在的包路径必须是所有Mapper和Controller所在包的父级。比如启动类在com.example.library下Controller在com.example.library.controllerMapper在com.example.library.mapper这样默认的组件扫描才能覆盖全部。包结构不对的话第5章那条404的坑就是你。3.2 图书模块的四件套写法实体类、Mapper、Service、Controller从这一节开始进入“抄作业”环节四个类一套跑通图书的分页查询。先写实体类对应book表。Data TableName(book) public class Book { TableId(type IdType.AUTO) private Long id; private String isbn; private String name; private String author; private String publisher; private String category; private Integer total; private Integer stock; private LocalDateTime createTime; }TableName指定表名TableId标记主键并设置自增策略。因为yml里配了map-underscore-to-camel-case数据库的create_time自动映射成createTime实体类里不需要任何转换注解。接下来写Mapper接口这是MyBatis-Plus最省事的地方。Mapper public interface BookMapper extends BaseMapperBook { }这个接口什么都不用写继承BaseMapper后insert、deleteById、selectById、selectPage这些方法全是现成的。如果你只做单表操作整个项目甚至可以不写一行SQL。但在真实维护里我还是建议在XML里留几个复杂查询的位置比如多条件组合搜索写在注解里不如XML好调试。Service层按项目规范分接口和实现但不强制。我这里写一个带分页和关键字查询的Service接口及实现把业务逻辑留在这一层。public interface BookService extends IServiceBook { IPageBook pageBooks(long current, long size, String keyword); }Service public class BookServiceImpl extends ServiceImplBookMapper, Book implements BookService { Override public IPageBook pageBooks(long current, long size, String keyword) { LambdaQueryWrapperBook wrapper new LambdaQueryWrapper(); if (StringUtils.isNotBlank(keyword)) { wrapper.and(w - w.like(Book::getName, keyword) .or().like(Book::getAuthor, keyword) .or().like(Book::getIsbn, keyword)); } return page(new Page(current, size), wrapper); } }ServiceImpl是MyBatis-Plus提供的通用实现继承它就等于把save、removeById、page这些方法都拿来了。LambdaQueryWrapper用来构造查询条件like是模糊匹配。注意keyword判断用isNotBlank而不是isNotEmpty空字符串和纯空格都会被过滤掉。这里的and包裹很重要三个or条件必须在一个and组里否则和后续其他条件拼接时SQL逻辑会乱。这是一个特别典型的写法坑很多人直接.wrapper.like(...).or().like(...)结果条件一多就查错数据。Controller层提供REST接口。为了返回结构统一我会加一个Result类来包code、msg、data。Data public class ResultT { private Integer code; private String msg; private T data; public static T ResultT ok(T data) { ResultT r new Result(); r.code 200; r.msg ok; r.data data; return r; } }RestController RequestMapping(/api/book) public class BookController { Autowired private BookService bookService; GetMapping(/page) public ResultIPageBook page( RequestParam(defaultValue 1) long current, RequestParam(defaultValue 10) long size, RequestParam(required false) String keyword) { return Result.ok(bookService.pageBooks(current, size, keyword)); } }三个参数说明一下current是页码从1开始size是每页条数keyword是搜索词可传可不传。defaultValue保证前端不传参时也有合理默认值。到这里启动项目访问http://localhost:8080/api/book/page?current1size10keywordSpring就能看到JSON格式的图书分页数据。第一个接口跑通后面所有模块都是复制这套四件套。3.3 分页与模糊搜索的落地MyBatis-Plus分页插件配置与调用参数直接使用上一节代码里的page方法你会发现数据能返回但total总是0records里也可能拿不到数据。这是因为MyBatis-Plus的分页功能默认不生效必须显式配置分页插件。新增一个配置类即可。Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }这个配置类的作用是给MyBatis-Plus装上分页拦截器PaginationInnerInterceptor会把Page参数翻译成LIMIT语句。DbType.MYSQL指定数据库方言不同数据库分页语法不一样。配置好后重启项目list接口的响应里total就有值了SQL日志里也会看到LIMIT ?。分页插件还有一个参数值得关注maxLimit。如果不想让某次请求一次性查出全表可以在PaginationInnerInterceptor构造时设置上限比如new PaginationInnerInterceptor(DbType.MYSQL, 500L)。这属于防御性配置课设里不要求但放到生产环境是必须的。到这里后端接口已经能支撑业务页面的数据需求下一章把页面挂上去。4. 把接口变成网站页面Thymeleaf模板与服务端渲染的完整联动标题里带了“网站”说明最终交付物必须能在浏览器里点着用。后端接口只是JSON离“网站”还差一层页面。常见做法有两条路一是前后端分离Vueaxios调接口二是服务端渲染用Thymeleaf模板直接输出HTML。做图书管理系统这个体量的项目我建议走Thymeleaf路线。4.1 服务端渲染还是前后端分离课设场景下选Thymeleaf的理由很多同学一上来就想用Vue理由是大厂都在用。但大厂的场景是多团队协作、前端独立部署、接口复用图书管理系统这种单人开发的小型网站根本用不上这整套复杂度。对比项Thymeleaf服务端渲染Vue前后端分离开发环境只要IDEA和浏览器额外需要Node.js环境数据获取后端Model直接返回需要处理跨域或接口代理页面跳转Controller返回视图名路由配置答辩演示一个Spring Boot进程搞定前后端两个进程学习成本类似JSP容易上手需要理解组件和生命周期最直接的理由是省事。Thymeleaf的模板可以直接写HTML后端把数据塞进Model模板用th:each、th:text取出来展示。前后端分离要处理跨域配置要在前端项目里配axios拦截器答辩时还要同时开两个服务。有些极端情况笔记本上没装Node或者换机器演示时环境缺失当场就很尴尬。当然如果做这个项目是为了求职时展示前后端分离能力那是另一回事投入产出比不同。4.2 手写一个借阅记录页模板文件、循环渲染与数据回填选Thymeleaf就需要在pom.xml里加一个依赖spring-boot-starter-thymeleaf。加完依赖后页面文件放在src/main/resources/templates/目录下Controller直接返回视图名Spring Boot自动去这个目录找HTML。下面的模板展示借阅记录列表。注意Controller方法要返回字符串而不是返回Result对象这是RestController和Controller的一个区别。Controller RequestMapping(/borrow) public class BorrowController { Autowired private BorrowRecordService borrowRecordService; GetMapping(/list) public String list(RequestParam(defaultValue 1) long current, RequestParam(defaultValue 10) long size, Model model) { IPageBorrowRecord page borrowRecordService.pageRecords(current, size); model.addAttribute(page, page); return borrow/list; } }HTML模板文件在templates/borrow/下命名为list.html。!DOCTYPE html html langzh xmlns:thhttp://www.thymeleaf.org head meta charsetUTF-8 title借阅记录/title link relstylesheet th:href{/css/common.css} /head body h2借阅记录/h2 table border1 tr th读者/th th图书/th th借出时间/th th应还时间/th th状态/th /tr tr th:eachr : ${page.records} td th:text${r.readerName}/td td th:text${r.bookName}/td td th:text${#temporals.format(r.borrowTime, yyyy-MM-dd)}/td td th:text${#temporals.format(r.dueTime, yyyy-MM-dd)}/td td th:text${r.status 0 ? 借出中 : 已归还}/td /tr /table /body /html变量是从Controller里model.addAttribute传过来的模板里直接用${page.records}访问。th:each是循环语法冒号后面是循环变量和集合。#temporals是Thymeleaf的时间格式化工具LocalDateTime不能直接toString展示必须格式化。静态资源如CSS、JS要放在src/main/resources/static目录下和templates是平级关系。访问/css/common.css时不需要带上static前缀Thymeleaf的{/css/common.css}会自动处理。这个页面能跑通后整个网站的基本形态就出来了地址栏输入/borrow/list返回一个完整HTML页面表格里展示从数据库查出来的借阅记录。后面所有列表页都是同一个套路。4.3 表单提交、删除确认与重定向页面操作怎么对应Controller方法列表能看之后要做新增和删除。新增图书的表单用一个普通HTML form提交到/book/save后端接收后重定向回列表页。这里有一个很多人没注意的细节新增成功后不要直接返回视图名而是返回redirect:/book/list。直接返回视图名会让浏览器地址栏停留在/save上刷新页面会重复提交表单产生重复数据。重定向是给浏览器的“后悔药”提交后重新请求列表页刷新也是安全的。form th:action{/book/save} methodpost input typetext nameisbn placeholderISBN required input typetext namename placeholder书名 required input typetext nameauthor placeholder作者 input typetext namepublisher placeholder出版社 input typetext namecategory placeholder分类 input typenumber nametotal placeholder总册数 value1 min1 button typesubmit保存/button /formPostMapping(/book/save) public String save(Book book) { book.setStock(book.getTotal()); bookService.save(book); return redirect:/book/list; }form里的name属性必须和后端Book实体字段一一对应Spring MVC会自动把请求参数绑定到Book对象上。total是总册数新书入库时库存等于总册数。注意新增时页面没提交stock字段所以要在后端setStock初始化不然后面借书时扣减库存会从NULL变成减1直接报错。删除操作不需要单独做删除页列表页每行放一个“删除”按钮用JS的confirm弹窗做二次确认。这是课设里最常见的实现方式简单可靠不需要引入弹窗组件。删除成功后同样重定向回列表页。表单提交和重定向这套流程熟练后整个系统的增删改查页面就都能自己写了。5. 避坑手册图书管理系统开发中常见的五个翻车点下面这几个坑是我自己在做类似Spring Boot管理系统时反复遇到的也是带学生做课设时出现频率最高的几个问题。每一个都按现象、原因、解决三步说清照着排错能省半天时间。其中不少问题跟Spring Boot版本和本机环境有关属于“配置一分钟排错两小时”的典型例子。5.1 启动直接报Failed to configure a DataSource数据源三件套没到齐现象项目一启动就报错提示Failed to configure a DataSource: url attribute is not specified。页面和接口全都起不来。原因是项目里加了数据源相关依赖但配置文件里没有完整的连接信息或者说根本没有引入MySQL驱动。我见过有同学把spring-boot-starter-jdbc加进依赖却忘了加mysql-connector-j结果就是启动失败。解决方法是回application.yml检查三个点driver-class-name、url、username和password是否齐全。单有配置没有驱动启动一样报这个错。还有一种情况是yml文件里缩进写错了Spring Boot没有读到datasource配置也会报同样的错。判断方法是看控制台的启动日志里有没有加载数据源的记录没有就是配置没生效。5.2 页面404接口也404Controller没被扫描到的包结构问题现象启动类正常启动没有报错但访问任何接口都是404。原因基本只有一个启动类的位置放错了。Spring Boot默认扫描启动类所在的包以及子包如果把启动类放在com.example下而Controller放在com.example.library.controller下那没问题。反过来如果启动类在com.example.library下Controller却放在了com.example.controller下就扫描不到。解决方法是把启动类移到所有源码包的顶层父包或者通过ComponentScan指定扫描路径。这里有个快速判断方法启动日志里会打印RequestMapping的映射路径如果日志里看不到自己的Controller路径基本上就是扫描问题。5.3 中文写入MySQL变成问号字符集与连接串参数现象页面显示正常通过页面表单新增一条中文书名刷新页面变成一排问号。原因分三层数据库连接串没加characterEncoding参数或者MySQL库表的默认字符集不是utf8mb4又或者IDEA里的文件编码是GBK。最常见的是建库时直接用了默认latin1中文存不进去。解决办法是从上到下排查改库表字符集可以用ALTER语句也可以在navicat里右键修改。连接串加useUnicodetruecharacterEncodingutf8IDEA的Settings里把File Encodings三处全部设为UTF-8。注意MySQL 8默认字符集就是utf8mb4但如果你用的库是用旧版本建的还是要确认一下。5.4 时间字段少了8小时时区参数与数据库时区现象借阅记录的borrow_time存进去的是14点查出来变6点。原因几乎永远是时区不一致。MySQL连接串里没有指定serverTimezone时驱动会拿JVM默认时区和数据库时区做转换两边不一致就差了8小时。解决方法是url里固定写serverTimezoneAsia/Shanghai同时MySQL的time_zone变量也设成08:00保证两边统一。另外要注意一点不要在代码里对时间做加减处理先查数据库时区再改连接串90%的八小时问题都能消失。依然不对的话在sql里执行select now()看当前数据库时间比正常时间差几个小时就能定位是哪一侧的问题。5.5 Spring Boot 3.x版本太高导致的javax变成jakarta现象从网上下载的Spring Boot 2.x老项目强行升到Spring Boot 3.x编译报错找不到javax.servlet.*运行报NoClassDefFoundError。原因是Spring Boot 3.x基于Jakarta EE 9把javax包名整体改成了jakarta这是一个破坏性变更。这不是Spring Boot版本“太高”的问题而是依赖也跟着换名字的问题。解决方法是老项目不要升3.x继续用2.7.x。新项目如果确定用3.x所有import javax.servlet改成import jakarta.servletMyBatis-Plus也要换成mybatis-plus-spring-boot3-starter。还有mysql驱动从mysql-connector-java变成mysql-connector-j。在做图书管理系统这种小项目时最多余的精力就是花在解决版本兼容上我的建议是能用稳定旧版就别追新。6. 从“能跑”到“能演示”登录拦截、Excel导出与一键部署的做法系统功能齐全不等于能拿出来演示。答辩现场最怕两种状况一是页面没登录就能访问显得没有权限控制二是演示环境数据库配置和别人不一样启动不起来。这一章把这三个问题一次解决。6.1 用拦截器统一收口登录校验别在每个Controller里复制粘贴登录校验最自然的做法是写一个HandlerInterceptor拦截器统一处理所有页面请求而不是在每个Controller方法里重复判断session。登录成功后把管理员对象放进session拦截器每次请求前检查session里的admin属性是否存在。不存在就重定向到登录页。public class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object admin request.getSession().getAttribute(admin); if (admin null) { response.sendRedirect(/admin/login); return false; } return true; } }配置拦截器要写一个WebConfig类实现WebMvcConfigurer注册拦截器并指定放行路径。登录页本身和所有静态资源必须放行否则会出现死循环登录页也跳转登录页。Configuration public class WebConfig implements WebMvcConfigurer { Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()) .addPathPatterns(/**) .excludePathPatterns(/admin/login, /css/**, /js/**); } }addPathPatterns是拦截路径/。表示所有路径。excludePathPatterns放行登录页面和静态资源。如果之后要做PDF上传这类功能XSS过滤建议放在过滤器阶段统一处理字符转义不要在拦截器里做拦截器只管登录状态职责分开代码才不乱。6.2 导出借阅记录、Docker部署与一张最小验收清单导出功能是答辩加分项。用EasyExcel导出借阅记录代码量比POI少得多。给BorrowRecord实体上标注好Excel列名注解然后用一行代码写响应输出流。GetMapping(/borrow/export) public void export(HttpServletResponse response) throws IOException { response.setContentType(application/vnd.openxmlformats-officedocument.spreadsheetml.sheet); response.setCharacterEncoding(utf-8); String fileName URLEncoder.encode(借阅记录.xlsx, UTF-8); response.setHeader(Content-disposition, attachment;filename fileName); EasyExcel.write(response.getOutputStream(), BorrowRecord.class) .sheet(借阅记录) .doWrite(borrowRecordService.listRecords()); }部署到演示机器时我习惯打jar包而不是用IDEA直接运行。命令行里cd到仓库根目录执行mvn clean package -DskipTests等target目录出现jar文件在服务器上执行java -jar。如果目标机器没有Java环境先检查java和mvn命令在命令行里可用没配JAVA_HOME或者PATH少了bin目录打包这一步就会直接报“不是内部或外部命令”。用Docker部署Spring Boot项目的Dockerfile也很短FROM openjdk:17-jdk-alpine WORKDIR /app COPY target/library-0.0.1-SNAPSHOT.jar app.jar EXPOSE 8080 ENTRYPOINT [java, -jar, app.jar]数据库连接串里的localhost要改成宿主机的局域网IP或者通过docker run的--network参数连到同一个自定义网络这一点最容易忽略配置不对容器起来也连不上库。最后整理一张最小验收清单演示前挨个走一遍这个表比临时点页面靠谱得多验收项操作路径预期结果管理员登录访问登录页输入admin账号密码跳转到首页新增图书首页进入图书管理表单提交列表出现新书库存等于总册数借书进入借阅管理选择读者和图书生成借阅记录库存减1还书点击还书操作记录状态变为已归还库存加1分页搜索输入书名关键字只显示匹配的书目导出Excel点击导出按钮下载xlsx文件我第一次拿图书管理系统做课设时就是被数据源报错糊了一脸后来才明白所有坑在本地都能提前暴露先把环境变量配齐版本对齐SQL先跑通再写业务代码。这个顺序省了我大量时间。做这个项目最忌讳的是拿到标题就开始敲键盘把数据模型和版本兼容性放在前面反而跑得快。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联
返回资讯列表 →