ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

SSM图书管理系统实战:MVC分层、JSP渲染与事务控制

SSM图书管理系统实战:MVC分层、JSP渲染与事务控制 简介本资源是一份面向计算机专业本科生的Java Web开发毕业设计文档聚焦SSM框架在图书管理场景中的工程化落地适用于课程设计、毕设参考与Java后端入门实践。文档完整呈现系统需求分析、SSM技术选型依据SpringSpringMVCMyBatis、MySQL数据库设计、核心功能模块图书CRUD、借阅归还流程、教师信息审核、公告发布实现逻辑及安全优化方案附有摘要、关键词、中英文目录与规范章节结构。资源为单个Word文档.doc格式文件大小1.07MB内容排版规范含技术原理简述、系统架构图示意及关键代码片段说明便于快速理解整体设计思路与开发要点。目前已有136人学习下载适合希望掌握SSM整合开发流程、积累真实项目文档撰写经验的学习者参考使用。1. 这不是又一个“图书管理系统”Demo它是一份能过答辩、可部署、带完整MVC分层逻辑的SSM实战样本很多同学拿到“基于Java的图书管理系统”这个毕业设计题目时第一反应是百度搜源码、改改数据库字段、套个EasyUI皮肤就交差。结果答辩被问“Controller里为什么用ModelAndView而不是String返回值”“MyBatis的#{}和${}在什么场景下必须用前者”当场卡壳。其实这个标题背后真正考察的是你能否用SSMSpring SpringMVC MyBatis三件套把一个真实业务场景——图书借阅全流程——拆解成可测试、可维护、符合分层架构规范的Web应用。它不追求炫酷前端但要求DAO层有事务控制、Service层有接口抽象、Controller层有参数校验与状态码返回它不强制用Redis缓存但必须体现JSP页面如何接收Model数据并安全渲染它不是玩具项目而是你Java Web工程能力的一次结构化验证。适合正在准备毕业答辩、需要快速搭建可演示系统、同时想补全SSM核心链路认知的本科及专升本同学。2. 搭建SSM骨架从IntelliJ IDEA创建项目到Tomcat成功启动JSP页面2.1 创建标准Maven Web项目并配置JDK与Facet在IntelliJ IDEA中新建Project选择Maven→ 勾选Create from archetype→ 选用maven-archetype-webapp。注意不要直接选Spring Initializr因为毕业论文需体现手动整合过程且JSP依赖需显式声明。项目名设为book-management-systemGroupID按学校/学院惯例填写如edu.school.cs。创建后右键项目 →Open Module Settings→Project页确认SDK为JDK 8SSM主流兼容版本再进入Modules→Web→ 点击添加WebFacet指定Web resource directory为src/main/webappWeb.xml路径自动识别为src/main/webapp/WEB-INF/web.xml。此步若漏掉Facet配置后续JSP将无法被Tomcat识别为Servlet资源。提示IDEA中若Color Scheme里没有JSP高亮选项说明未启用Java EE支持。需进入Settings → Plugins搜索并启用Java EE: Web和JavaScript插件重启IDEA后JSP文件才会显示语法着色。2.2 引入SSM核心依赖与JSP运行时库在pom.xml中声明以下关键依赖版本锁定为稳定组合properties spring.version5.3.30/spring.version mybatis.version3.5.13/mybatis.version mybatis-spring.version2.1.0/mybatis-spring.version jstl.version1.2/jstl.version servlet-api.version4.0.1/servlet-api.version /properties dependencies !-- Spring Core MVC -- dependency groupIdorg.springframework/groupId artifactIdspring-context/artifactId version${spring.version}/version /dependency dependency groupIdorg.springframework/groupId artifactIdspring-webmvc/artifactId version${spring.version}/version /dependency !-- MyBatis Spring整合 -- dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version${mybatis.version}/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis-spring/artifactId version${mybatis-spring.version}/version /dependency !-- 数据库驱动以MySQL为例 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency !-- JSP支持 -- dependency groupIdjavax.servlet/groupId artifactIdjstl/artifactId version${jstl.version}/version /dependency dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version${servlet-api.version}/version scopeprovided/scope /dependency !-- 日志 -- dependency groupIdlog4j/groupId artifactIdlog4j/artifactId version1.2.17/version /dependency /dependencies关键点说明scopeprovided/scope用于javax.servlet-api因Tomcat已提供Servlet容器实现打包时排除避免冲突jstl必须引入否则JSP中c:if等标签无法解析MyBatis版本与Spring版本需匹配mybatis-spring 2.1.0明确支持Spring 5.3.x避免NoSuchBeanDefinitionException。2.3 配置web.xml加载SpringMVC DispatcherServletsrc/main/webapp/WEB-INF/web.xml是整个Web应用的入口配置?xml version1.0 encodingUTF-8? web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd version4.0 !-- 加载Spring容器 -- context-param param-namecontextConfigLocation/param-name param-valueclasspath:spring-context.xml/param-value /context-param listener listener-classorg.springframework.web.context.ContextLoaderListener/listener-class /listener !-- 配置SpringMVC前端控制器 -- servlet servlet-namedispatcher/servlet-name servlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-class init-param param-namecontextConfigLocation/param-name param-valueclasspath:spring-mvc.xml/param-value /init-param load-on-startup1/load-on-startup /servlet servlet-mapping servlet-namedispatcher/servlet-name url-pattern//url-pattern /servlet-mapping !-- 字符编码过滤器 -- filter filter-nameencodingFilter/filter-name filter-classorg.springframework.web.filter.CharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param init-param param-nameforceEncoding/param-name param-valuetrue/param-value /init-param /filter filter-mapping filter-nameencodingFilter/filter-name url-pattern/*/url-pattern /filter-mapping /web-app逻辑说明ContextLoaderListener加载根容器Service/DAO层Bean配置文件为spring-context.xmlDispatcherServlet加载Web层容器Controller/ViewResolver配置文件为spring-mvc.xmlCharacterEncodingFilter必须置于所有Filter之前确保POST请求中文参数不乱码url-pattern//url-pattern表示拦截所有请求静态资源需在spring-mvc.xml中单独放行。2.4 编写第一个JSP页面并验证Tomcat部署在src/main/webapp下创建index.jsp% page contentTypetext/html;charsetUTF-8 languagejava % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % html head title图书管理系统首页/title /head body h1欢迎使用图书管理系统/h1 p当前时间% new java.util.Date() %/p a href${pageContext.request.contextPath}/book/list查看全部图书/a /body /html配置Tomcat ServerRun → Edit Configurations → → Tomcat Server → LocalDeployment → → Artifact → book-management-system:war explodedApplication context设为/book避免根路径冲突启动后访问http://localhost:8080/book/应看到带时间戳的首页。若出现HTTP Status 404检查Artifact是否勾选Exploded模式若JSP报错The absolute uri: http://java.sun.com/jsp/jstl/core cannot be resolved确认jstl.jar已打入WEB-INF/libMaven会自动处理但需检查Target目录是否存在该jar。3. 实现图书核心业务从数据库建模到JSP页面联动的完整闭环3.1 设计符合借阅逻辑的MySQL表结构与MyBatis映射图书管理系统需支撑“图书管理”与“借阅管理”双主线。创建以下三张表-- 图书表 CREATE TABLE t_book ( id INT PRIMARY KEY AUTO_INCREMENT, isbn VARCHAR(20) NOT NULL UNIQUE, title VARCHAR(100) NOT NULL, author VARCHAR(50), publisher VARCHAR(50), publish_date DATE, price DECIMAL(8,2), stock INT DEFAULT 0, status TINYINT DEFAULT 1 COMMENT 1-在馆, 0-已借出 ); -- 用户表简化版仅含基础字段 CREATE TABLE t_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(20) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL COMMENT SHA-256加密, real_name VARCHAR(20), role TINYINT DEFAULT 1 COMMENT 1-读者, 2-管理员 ); -- 借阅记录表 CREATE TABLE t_borrow_record ( id INT PRIMARY KEY AUTO_INCREMENT, book_id INT NOT NULL, user_id INT NOT NULL, borrow_date DATETIME DEFAULT CURRENT_TIMESTAMP, return_date DATETIME NULL, status TINYINT DEFAULT 1 COMMENT 1-已借出, 2-已归还, FOREIGN KEY (book_id) REFERENCES t_book(id), FOREIGN KEY (user_id) REFERENCES t_user(id) );对应MyBatis的BookMapper.xml位于src/main/resources/mapper/?xml version1.0 encodingUTF-8? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.example.mapper.BookMapper !-- 查询全部图书带状态筛选 -- select idselectAll resultTypecom.example.entity.Book SELECT id, isbn, title, author, publisher, publish_date, price, stock, status FROM t_book WHERE status #{status} ORDER BY id DESC /select !-- 根据ID查询单本图书 -- select idselectById parameterTypeint resultTypecom.example.entity.Book SELECT * FROM t_book WHERE id #{id} /select !-- 新增图书 -- insert idinsert parameterTypecom.example.entity.Book useGeneratedKeystrue keyPropertyid INSERT INTO t_book (isbn, title, author, publisher, publish_date, price, stock, status) VALUES (#{isbn}, #{title}, #{author}, #{publisher}, #{publishDate}, #{price}, #{stock}, #{status}) /insert !-- 更新图书库存与状态 -- update idupdateStockAndStatus parameterTypemap UPDATE t_book SET stock stock - #{borrowCount}, status #{newStatus} WHERE id #{bookId} /update /mapper参数说明useGeneratedKeystrue使MyBatis自动获取MySQL自增主键避免SELECT LAST_INSERT_ID()parameterTypemap用于多参数更新需在Service层封装为MapString, ObjectresultType指向实体类全限定名确保包路径正确如com.example.entity.Book。3.2 编写分层代码Controller接收请求、Service编排逻辑、DAO执行SQLController层定义RESTful风格URL与状态码Controller RequestMapping(/book) public class BookController { Autowired private BookService bookService; // GET /book/list → 返回图书列表JSP GetMapping(/list) public String listBooks(Model model) { ListBook books bookService.findAllAvailable(); model.addAttribute(bookList, books); return book/list; // 对应 /WEB-INF/jsp/book/list.jsp } // POST /book/add → 处理新增图书表单 PostMapping(/add) public String addBook(Valid Book book, BindingResult result, Model model) { if (result.hasErrors()) { model.addAttribute(error, 请检查ISBN或书名是否为空); return book/add; } try { bookService.addBook(book); return redirect:/book/list; } catch (Exception e) { model.addAttribute(error, 添加失败 e.getMessage()); return book/add; } } }关键点Valid触发JSR-303校验需在Book实体类字段上加NotBlank等注解BindingResult必须紧跟Valid参数后否则校验异常抛出redirect:前缀防止表单重复提交Post-Redirect-Get模式。Service层事务控制与业务规则封装Service Transactional public class BookServiceImpl implements BookService { Autowired private BookMapper bookMapper; Override public ListBook findAllAvailable() { return bookMapper.selectAll(1); // status1 表示在馆 } Override public void addBook(Book book) { // 业务规则ISBN不能重复数据库已建唯一索引此处双重保障 Book existing bookMapper.selectByIsbn(book.getIsbn()); if (existing ! null) { throw new RuntimeException(ISBN已存在 book.getIsbn()); } bookMapper.insert(book); } }注意Transactional注解在类上生效要求方法为public且调用必须通过Spring代理即不能在本类内直接调用this.addBook()。DAO层MyBatis接口与XML映射绑定BookMapper.java接口public interface BookMapper { ListBook selectAll(Param(status) int status); Book selectById(int id); Book selectByIsbn(String isbn); // 需在XML中补充此SQL void insert(Book book); void updateStockAndStatus(Param(bookId) int bookId, Param(borrowCount) int borrowCount, Param(newStatus) int newStatus); }3.3 开发JSP页面用JSTLEL表达式安全渲染数据与表单/WEB-INF/jsp/book/list.jsp% page contentTypetext/html;charsetUTF-8 languagejava % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % % taglib prefixfmt urihttp://java.sun.com/jsp/jstl/fmt % html head title图书列表/title style table { border-collapse: collapse; width: 100%; } th, td { border: 1px solid #ddd; padding: 8px; text-align: left; } th { background-color: #f2f2f2; } /style /head body h2馆藏图书列表/h2 a href${pageContext.request.contextPath}/book/add添加新书/a brbr c:if test${not empty bookList} table tr thID/ththISBN/thth书名/thth作者/thth出版社/th th出版日期/thth价格/thth库存/thth操作/th /tr c:forEach items${bookList} varbook tr td${book.id}/td td${book.isbn}/td td${book.title}/td td${book.author}/td td${book.publisher}/td tdfmt:formatDate value${book.publishDate} patternyyyy-MM-dd//td td¥${book.price}/td td${book.stock}/td td a href${pageContext.request.contextPath}/book/detail?id${book.id}详情/a a href${pageContext.request.contextPath}/book/edit?id${book.id}编辑/a /td /tr /c:forEach /table /c:if c:if test${empty bookList} p暂无图书数据/p /c:if /body /html安全要点说明${book.title}自动进行HTML转义防止XSS攻击如标题含script会被转为lt;scriptgt;fmt:formatDate确保日期格式统一避免toString()产生Mon Jan 01 00:00:00 CST 2024这类不可读字符串c:if判断空集合避免NullPointerException所有URL使用${pageContext.request.contextPath}动态获取上下文路径适配不同部署路径。4. 关键配置与调试技巧让JSP编译可见、SQL日志可查、事务回滚可控4.1 查看JSP编译后的Java源码定位渲染问题Tomcat在运行时会将JSP编译为Servlet Java文件默认存于{tomcat_home}/work/Catalina/localhost/{context_path}/org/apache/jsp/。例如访问/book/list后可在该目录找到类似list_jsp.java的文件。打开它可看到JSP中的EL表达式${book.title}被编译为java.lang.String.valueOf(((com.example.entity.Book)pageContext.findAttribute(book)).getTitle())c:forEach被编译为标准Java for循环若页面报错Unable to compile class for JSP直接查看此.java文件的第N行比JSP原始行数更准确定位语法错误如漏写%、变量未声明。提示修改JSP后若页面未更新先清空work目录再重启Tomcat也可在conf/context.xml中添加Context reloadabletrue/启用热加载仅开发环境。4.2 配置MyBatis日志输出SQL与参数绑定在src/main/resources/log4j.properties中添加# MyBatis SQL日志 log4j.logger.org.apache.ibatisDEBUG log4j.logger.java.sql.ConnectionDEBUG log4j.logger.java.sql.StatementDEBUG log4j.logger.java.sql.PreparedStatementDEBUG log4j.logger.java.sql.ResultSetDEBUG # Spring JDBC日志可选 log4j.logger.org.springframework.jdbc.core.JdbcTemplateDEBUG启动应用后控制台将输出类似内容DEBUG [http-nio-8080-exec-1] o.a.i.t.jdbc.JdbcTransaction - Opening JDBC Connection DEBUG [http-nio-8080-exec-1] o.a.i.p.t.s.PreparedStatementLogger - Preparing: SELECT id, isbn, title, ... FROM t_book WHERE status ? DEBUG [http-nio-8080-exec-1] o.a.i.p.t.s.PreparedStatementLogger - Parameters: 1(Integer) DEBUG [http-nio-8080-exec-1] o.a.i.p.t.r.ResultSetLogger - Columns: id, isbn, title, ... DEBUG [http-nio-8080-exec-1] o.a.i.p.t.r.ResultSetLogger - Row: 1, 978-7-04-050694-1, Java编程思想, ...此日志可验证SQL语句是否按预期生成如WHERE status ?而非硬编码WHERE status 1参数是否正确绑定Parameters: 1(Integer)结果集列名与实体属性是否匹配避免Column xxx not found in ResultSet。4.3 控制事务边界在Service层精准捕获异常并回滚常见误区是认为Transactional能捕获所有异常。实际上只有unchecked exceptionRuntimeException及其子类才会触发回滚而checked exception如IOException默认不回滚。图书借阅业务中需主动控制Service public class BorrowService { Transactional public void borrowBook(int userId, int bookId) throws BusinessException { // 1. 检查用户是否存在 User user userMapper.selectById(userId); if (user null) { throw new BusinessException(用户不存在); // 自定义checked异常 } // 2. 检查图书库存 Book book bookMapper.selectById(bookId); if (book.getStock() 0) { throw new BusinessException(图书库存不足); } // 3. 执行借阅更新库存插入记录 try { bookMapper.updateStockAndStatus(bookId, 1, 0); // stock-1, status0已借出 borrowRecordMapper.insert(new BorrowRecord(userId, bookId)); } catch (Exception e) { // 显式回滚抛出RuntimeException throw new RuntimeException(借阅失败 e.getMessage(), e); } } }参数说明BusinessException继承Exception需在Transactional(rollbackFor BusinessException.class)中显式声明throw new RuntimeException(...)是最简方式确保Spring AOP代理捕获并回滚e作为cause传入保留原始堆栈信息便于排查。4.4 解决IntelliJ IDEA中JSP文件创建与编码问题当在IDEA中右键New → JSP File失败或新建JSP后中文显示为乱码执行以下步骤File → Settings → Editor → File EncodingsGlobal Encoding设为UTF-8Project Encoding设为UTF-8Default encoding for properties files勾选Transparent native-to-ascii conversionFile → Project Structure → Modules → Sources确认src/main/webapp标记为Resources若JSP仍无语法提示在Settings → Languages Frameworks → Java → Web → JSP中勾选Enable JSP supportJSP version选2.3与Tomcat 9兼容Tag libraries点击添加JSTL 1.2路径指向WEB-INF/lib/jstl-1.2.jar。完成上述配置后新建login.jsp时输入c:会自动提示JSTL标签% new Date()会显示Java语法高亮。5. 毕业论文写作与答辩准备从代码截图到UML图谱的交付物组织策略5.1 论文核心章节代码截图规范突出SSM分层与JSP交互逻辑毕业论文中“系统实现”章节的代码截图必须体现技术深度而非堆砌。推荐以下三类截图组合截图类型位置必含要素说明分层调用链BookController.javaBookService.javaBookMapper.java箭头标注Autowired注入关系、Transactional注解、Select/Insert注解展示MVCDAO三层如何协作避免只贴DAO层SQLJSP与Model绑定list.jsp片段 BookController.listBooks()方法圈出model.addAttribute(bookList, books)与JSP中${bookList}对应关系证明MVC数据传递正确性非硬编码HTML关键配置文件spring-mvc.xml中bean classorg.springframework.web.servlet.view.InternalResourceViewResolver段落红框标出prefix/WEB-INF/jsp/和suffix.jsp解释JSP路径解析机制说明为何页面放在/WEB-INF/jsp/提示截图宽度不超过页面80%代码字体设为10号关键行用黄色高亮如Transactional、model.addAttribute避免整屏代码截图。5.2 绘制专业级UML图用例图聚焦借阅角色、类图体现SSM组件关系用例图推荐用draw.io绘制参与者读者借书/还书/查书、管理员增删改图书/用户/统计报表用例借阅图书扩展用例检查库存、生成借阅记录、归还图书扩展用例更新库存、计算逾期关系读者与借阅图书间实线连接管理员与管理图书间实线连接include关联检查库存到借阅图书。类图重点展示SSM框架类BookController类 listBooks(): String关联BookServiceBookService类 findAllAvailable(): ListBook关联BookMapperBookMapper接口 selectAll(status: int): ListBook关联Book实体类Book类属性private String title; private BigDecimal price;方法 getTitle(): String框架类DispatcherServlet依赖HandlerMapping、ViewResolver、SqlSessionFactory依赖DataSource。此图需体现Controller不直接调用Mapper而是通过Service中介实体类属性与数据库字段一一对应框架类作为依赖存在不实现业务逻辑。5.3 答辩高频问题预演直击SSM整合本质与JSP局限性根据近年答辩记录以下问题出现率超70%需准备技术细节回答Q1为什么用SSM而不是Spring Boot答“毕业设计要求体现框架整合能力。SSM手动配置web.xml、spring-context.xml、spring-mvc.xml能清晰看到IoC容器初始化、DispatcherServlet注册、ViewResolver设置等底层流程。Spring Boot的自动配置虽快但隐藏了这些关键环节不利于理解MVC生命周期。”Q2JSP有哪些安全风险你们做了哪些防护答“主要风险是XSS和SQL注入。防护措施① JSP中所有EL表达式${xxx}默认HTML转义阻断脚本注入② MyBatis使用#{}参数占位符杜绝拼接SQL③ 用户密码采用SHA-256加盐存储DigestUtils.sha256Hex(password salt)不在数据库明文保存。”Q3如果要支持并发借阅当前事务隔离级别够吗答“当前MySQL默认REPEATABLE READ级别可防止脏读与不可重复读但存在幻读。针对‘库存扣减’场景我们在updateStockAndStatus语句中添加SELECT ... FOR UPDATE锁需在Mapper XML中写SELECT * FROM t_book WHERE id #{id} FOR UPDATE将行锁升级为写锁确保同一图书不会被超借。”Q4JSP页面如何实现权限控制比如读者不能访问管理员页面。答“在BookController中添加RequestMapping拦截PreAuthorize(hasRole(ADMIN))需启用Spring Security或在JSP中用c:if test${sessionScope.user.role 2}控制按钮显示。更健壮的做法是在Service层校验if (user.getRole() ! 2) throw new AccessDeniedException(权限不足)。”最后一步导出WAR包Build → Build Artifacts → book-management-system:war → Build得到book-management-system.war。将其复制到Tomcat的webapps目录启动后访问http://localhost:8080/book-management-system/即可演示完整系统。此时你的毕业论文不仅是一份文档更是一个可验证、可运行、可讲解的技术作品。本文还有配套的精品资源点击获取
返回列表