ARTICLE DETAIL

资讯详情

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

SSM+JSP校园二手书交易平台实战:架构拆解、功能实现与避坑指南

SSM+JSP校园二手书交易平台实战:架构拆解、功能实现与避坑指南 简介基于SSM框架与JSP技术构建的校园二手书交易平台是一套面向Java方向毕业设计的高分项目资源。内容涵盖完整源码、数据库脚本、使用文档与部署教程实现图书发布、分类检索、在线下单、留言反馈、公告管理、用户管理等典型业务模块前台展示与后台管理分离结构清晰适合用于毕设答辩、课程设计或期末作业。压缩包共1242个文件包含JSP页面、Java源文件、XML配置、SQL脚本以及大量HTML/CSS/JS前端资源整体约18.6MB目录划分明确便于定位核心代码与二次修改。项目已在Windows10/11环境严格调试下载后按部署文档配置即可直接运行已获导师认可并取得97分答辩成绩。目前已有130人学习下载适合需要现成可用、结构规范且可继续扩展的毕业设计学习者参考。1. 校园二手书交易平台这套 SSMJSP 源码值不值得拿来当毕业设计拿到一个“高分项目”压缩包第一反应往往是解压、导入、点启动。校园二手书交易平台正是 SSMJSP 方向里最典型的一套后端用 SSM也就是 Spring SpringMVC MyBatis页面用 JSP 渲染附带 MySQL 数据库脚本和完整使用文档。它要解决的是 Java 学习者最常见的困境有语言基础但没有完整 Web 项目经验不知道登录、发布商品、下单这些功能在真实代码里怎么串起来。适用场景很明确课程设计、毕业设计以及“Java 找实习前补一个拿得出手的项目”。我的建议是别急着看功能列表先搞清楚它的代码分层、数据库表关系和事务边界答辩时这几样远比“做了十个页面”更值钱。2. 拆解项目结构SSMJSP 的代码分层与数据库设计2.1 SSM 整合 JSP 时三层架构和 JSP 视图层怎么分工SSM 不是一个新的框架而是三个框架的分工Spring 管 Service 层 BeanSpringMVC 管 URL 到 Controller 的映射MyBatis 管 SQL 和 Java 对象的转换。JSP 在这条链里只负责“最后一公里”把 Controller 放进 Model 的数据渲染成 HTML。看一个 SSMJSP 项目的源码先找这几个入口基本就不会迷路。常见项目目录是这样组织的book_trade/ ├── pom.xml ├── src/main/java/com/campus/trade/ │ ├── controller/ # SpringMVC 控制器接收参数、调用 Service │ ├── service/ # 业务逻辑层事务放在这一层 │ ├── mapper/ # MyBatis 的 Mapper 接口 │ ├── entity/ # 数据表对应的 JavaBean │ └── common/ # 分页、返回结果等工具类 ├── src/main/resources/ │ ├── jdbc.properties │ ├── spring-mybatis.xml │ └── mapper/ # 与 Mapper 接口对应的 XML 文件 └── src/main/webapp/ ├── WEB-INF/ │ ├── web.xml │ └── jsp/ # 登录、图书列表、订单等页面 └── static/ # css/js/images包名不一定是com.campus.trade但分层思路几乎一样。Controller 层只做参数接收和视图跳转Service 层写业务规则Mapper 接口只声明方法真正的 SQL 在 resources/mapper 下的 XML 里。这样设计的好处是出问题时不用从前端一路翻到 SQL先看异常报在哪一层再缩小范围。这里有个容易被忽略的点JSP 页面放在WEB-INF/jsp下而不是直接放webapp根目录。放在WEB-INF下的页面不能通过 URL 直接访问必须经过 Controller 返回这样才能配合登录拦截器避免绕过登录页打开首页或订单页。很多低分项目的通病就是把 JSP 和静态资源混放在根目录用户猜到路径直接访问权限形同虚设。2.2 数据库表设计用户、图书、订单、交易记录怎么建模这个项目的核心实体不多但表关系决定了后面所有功能是否好写。常见校园二手书平台最少需要三张表用户表、图书表、订单表留言和收藏可以作为扩展但不影响主链路。先用这三张表把流程跑通。核心建表脚本一般是这样的CREATE DATABASE IF NOT EXISTS book_trade DEFAULT CHARACTER SET utf8mb4; USE book_trade; CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL COMMENT 存储密文, nickname VARCHAR(30), phone VARCHAR(20), campus VARCHAR(50), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE book ( id INT PRIMARY KEY AUTO_INCREMENT, seller_id INT NOT NULL, title VARCHAR(100) NOT NULL, author VARCHAR(50), publisher VARCHAR(50), original_price DECIMAL(10,2), price DECIMAL(10,2) NOT NULL, degree TINYINT COMMENT 成色 1-5, description TEXT, status TINYINT DEFAULT 0 COMMENT 0在售 1下架 2已卖出, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_seller_status (seller_id, status) ); CREATE TABLE trade_order ( id INT PRIMARY KEY AUTO_INCREMENT, order_no VARCHAR(32) NOT NULL, book_id INT NOT NULL, seller_id INT NOT NULL, buyer_id INT NOT NULL, price DECIMAL(10,2) NOT NULL, status TINYINT DEFAULT 0 COMMENT 0等待确认 1交易中 2已完成 3已关闭, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, pay_time DATETIME, finish_time DATETIME );金额字段一定要用DECIMAL(10,2)不要用float或double否则会出现0.1 0.2 ! 0.3的精度问题这是 Java 面试题里常问的基础点也是答辩老师容易追问的地方。订单号order_no用VARCHAR(32)业务上要保证唯一不能拿自增主键直接当订单号展示。book表里的seller_id对应用户 ID但不需要建外键约束。课程设计项目里用外键会遇到“删除用户时图书被锁住”“数据导入顺序严格”等麻烦实际开发里也普遍用逻辑外键、靠 SQL 关联查询。只建普通索引idx_seller_status按卖家 ID 和状态查列表就够快。trade_order表用book_id关联图书一本书在任意时刻只应该对应一单有效订单这个约束放到 Service 层保证比数据库层更容易解释。2.3 MySQL 数据库连接池与 SSM 配置文件参数怎么设不翻车数据库设计完接下来最影响运行稳定的是数据库连接池。很多 SSMJSP 项目使用 Druid 连接池它同时提供连接池监控和基本防注入能力。配置数据库连接池时JDBC 驱动、连接参数、连接池阈值三个节点缺一个都会在第一次访问数据库时翻车。jdbc.properties 里的关键配置jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/book_trade?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltrue jdbc.usernameroot jdbc.passwordrootMySQL 8 以上必须用com.mysql.cj.jdbc.Driver老项目里的com.mysql.jdbc.Driver在新驱动下会直接报错。serverTimezoneAsia/Shanghai解决 MySQL 时区与 JVM 不一致导致的日期偏移allowPublicKeyRetrievaltrue解决 MySQL 8 默认认证插件导致的公钥获取失败这个问题在第 5 章会专门讲。Spring 的 applicationContext.xml 里数据源和 MyBatis 工厂是绑定在一起的context:property-placeholder locationclasspath:jdbc.properties/ bean iddataSource classcom.alibaba.druid.pool.DruidDataSource destroy-methodclose property namedriverClassName value${jdbc.driver}/ property nameurl value${jdbc.url}/ property nameusername value${jdbc.username}/ property namepassword value${jdbc.password}/ property nameinitialSize value2/ property nameminIdle value2/ property namemaxActive value20/ property namemaxWait value60000/ property namevalidationQuery valueSELECT 1/ /bean bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBean property namedataSource refdataSource/ property namemapperLocations valueclasspath:mapper/*.xml/ /bean mybatis:scan base-packagecom.campus.trade.mapper/连接池参数不是越大越好。毕业设计并发量低maxActive20足够initialSize2让启动时懒加载两个连接maxWait60000表示拿连接最多等 60 秒超过就抛异常。validationQuerySELECT 1用来定时探测失效连接MySQL 连接被数据库服务端断开后连接池能自动剔除不会等到使用时才发现连接已死。mybatis:scan负责把 Mapper 接口注册成 Spring BeanmapperLocations指向 XML 文件目录这两处路径不一致就会出现第 5 章提到的 BindingException。3. 在本地把 SSMJSP 项目跑起来从导入源码到第一次启动3.1 环境准备JDK、Maven、Tomcat、MySQL 版本怎么配把 SSMJSP 项目跑起来的首要任务是版本匹配。我一般会用 JDK 8 Tomcat 8.5/9 Maven 3.6 MySQL 5.7/8这个组合在 Java 课程设计和毕业设计里最常见网上能查到的经验最多。如果本机装了 JDK 17要额外改 pom 里的编译版本还要确认 Tomcat 和 Spring 版本兼容为了不给自己找麻烦先用 JDK 8 跑通。pom.xml 里常见的版本声明properties maven.compiler.source1.8/maven.compiler.source maven.compiler.target1.8/maven.compiler.target project.build.sourceEncodingUTF-8/project.build.sourceEncoding spring.version5.3.31/spring.version mybatis.version3.5.16/mybatis.version /propertiesSpring 5.x 需要 JDK 8 以上Tomcat 9 完全兼容。注意不要用 Spring 6因为 Spring 6 要求 JDK 17并且把javax包改成jakartaSSMJSP 的老写法会大面积报错。如果你在 IDEA 里新建 JSP 项目时看到页面模板用的是 Jakarta说明版本太新不适合这套源码。Maven 会从中央仓库拉依赖第一次导入需要几分钟看到下载进度条卡住不要立刻关 IDEA等 1 到 2 分钟再看。3.2 导入数据库把 .sql 脚本正确加载进 MySQL拿到源码包里的数据库脚本后不要用图形工具里的“执行 SQL”一次性粘贴大文件容易因为中途报错中断。推荐用命令行导入。Windows 和 Linux 通用写法是先建库再导入mysql -u root -p -e CREATE DATABASE IF NOT EXISTS book_trade DEFAULT CHARACTER SET utf8mb4; mysql -u root -p book_trade /path/to/db/book_trade.sql如果在 Windows cmd 下直接重定向不生效可以进入 mysql 后用 source 命令mysql -u root -p source C:/path/to/db/book_trade.sql导入完成后检查表数量SHOW TABLES; SELECT COUNT(*) FROM book;book表初始数据应该是 0 条如果脚本里带了测试数据那就有数值。这里要特别提醒导入 SQL 前先看脚本开头是否有CREATE DATABASE如果有不要手动建库直接mysql -u root -p book_trade.sql即可。数据库连接池连接的是localhost:3306/book_trade库名不一致会导致后续启动后登录页打不开。3.3 IDEA 导入 SSM 项目和配置 Tomcatwar 包部署的正确姿势拿到源码不要双击 index.jsp 来打开浏览器SSMJSP 项目必须经过 Tomcat 启动。IDEA 里的常见做法是选择 pom.xml 导入 Maven 项目等依赖刷新完成然后新增一个 Tomcat Server Local 运行配置。在 Deployment 页签把构建产物加进去这里有一个概念传统 JSP 项目打包 war 和调试时用 war exploded 的差别。war 包适合最终交付war exploded 适合日常开发。用 war exploded 时改 JSP 页面后刷新浏览器就能生效不用重新打包用完整 war 包部署每次改代码都要重新 build效率很低。命令行打包命令是后面交付源码压缩包时用的mvn clean package -DskipTests执行完会在 target 目录生成book_trade.war也可以把这个文件丢到 Tomcat 的 webapps 目录下启动 Tomcat 自动解压部署。IDEA 里如果导入项目后没有自动识别成 Maven 项目右键 pom.xml 选择 Add as Maven Project否则所有依赖都会标红。导入源码后的第一件事应该是看 Maven 面板有没有依赖报错再启动 Tomcat不要跳过这一步。3.4 第一次启动后如何验证登录、首页和后台启动成功不代表项目能跑。浏览器访问http://localhost:8080/项目名/如果项目 context root 是/book_trade完整地址就是http://localhost:8080/book_trade/。这时应该跳转到登录页或首页控制台不能有异常堆栈。数据库脚本通常会初始化一个管理员账号如果脚本里没有手动插入一条INSERT INTO user (username, password, nickname, campus) VALUES (admin, e10adc3949ba59abbe56e057f20f883e, 管理员, 本部校区);这里的e10adc3949ba59abbe56e057f20f883e是字符串123456的 MD5 值。很多课程设计项目登录校验直接比对 MD5如果源码里就是这么写的保持一致性即可不要自己改成 BCrypt否则原登录逻辑会全部失效。改为 BCrypt 是加分项但要连同登录注册代码一起改工作量不小。第一次要跑通的完整链路是注册或登录进入首页看到在售图书点击详情并“购买”能在卖家订单列表看到这笔订单。能走通这条链路说明数据库连接池、MyBatis 映射、JSP 视图解析全部正常。4. 二次开发必会的改动发布、下单、在售列表的 SSM 调用链4.1 发布图书功能Controller、Service、Mapper 三层代码怎么写拿到源码后最常见的需求是加字段、改流程、调整页面。我一般建议先照着“发布图书”读一遍调用链它覆盖了从 JSP 表单到 MySQL 的完整路径。Controller 层代码类似这样Controller RequestMapping(/book) public class BookController { Autowired private BookService bookService; PostMapping(/add) public String add(Book book, HttpSession session) { User loginUser (User) session.getAttribute(loginUser); if (loginUser null) { return redirect:/user/login; } book.setSellerId(loginUser.getId()); book.setStatus(0); bookService.addBook(book); return redirect:/book/list; } }PostMapping限定 POST 请求防止用户直接通过 URL 访问发布接口。卖家 ID 必须从 session 取不能信任 JSP 表单里传的sellerId否则用户可以伪造任意卖家发布图书这是项目里的一个经典安全漏洞。setStatus(0)表示新发布的图书是“在售”状态。Service 层实现Service public class BookServiceImpl implements BookService { Autowired private BookMapper bookMapper; Override Transactional(rollbackFor Exception.class) public void addBook(Book book) { bookMapper.insert(book); } }虽然单条 insert 用不上事务但把所有写操作放到 Service 层并加Transactional是一个好习惯。rollbackFor Exception.class表示遇到任何异常都回滚Throws 默认只对 RuntimeException 回滚遇到受检异常可能不生效。面试里问“Spring 事务什么时候回滚”就是这里。Mapper 对应的 XMLinsert idinsert parameterTypecom.campus.trade.entity.Book useGeneratedKeystrue keyPropertyid INSERT INTO book (seller_id, title, author, publisher, original_price, price, degree, description, status) VALUES (#{sellerId}, #{title}, #{author}, #{publisher}, #{originalPrice}, #{price}, #{degree}, #{description}, #{status}) /insertuseGeneratedKeystrue让 MyBatis 把数据库自增 ID 回填到book.id属性里后续“发布成功跳详情页”就能直接用这个 ID。所有参数都用#{}不要用${}拼接否则会引入 SQL 注入这是 JavaWeb 方向的高频面试题。4.2 下单和状态同步如何在 Service 层用事务保住数据一致性这个平台最有答辩价值的点是下单。二手书只有一本两个买家同时购买时只能成功一个。很多简单项目只做“页面看不出错”直接 UPDATE结果并发时一本书被卖两次。正确写法是行锁 状态条件 事务。Override Transactional(rollbackFor Exception.class) public void buy(Integer bookId, Integer buyerId) { Book book bookMapper.selectByIdForUpdate(bookId); if (book null || book.getStatus() ! 0) { throw new BusinessException(该图书已下架或已被购买); } TradeOrder order new TradeOrder(); order.setOrderNo(UUID.randomUUID().toString().replace(-, )); order.setBookId(bookId); order.setSellerId(book.getSellerId()); order.setBuyerId(buyerId); order.setPrice(book.getPrice()); order.setStatus(0); tradeOrderMapper.insert(order); bookMapper.updateStatus(bookId, 2); }selectByIdForUpdate用SELECT ... FOR UPDATE对 book 行加锁同一个事务内另一个事务会卡在 SELECT 上直到当前事务提交或回滚。这是悲观锁方案单机 MySQL 下最简单直观。updateStatus里再带状态条件等于双重保险。对应的 MyBatis 写法select idselectByIdForUpdate resultTypecom.campus.trade.entity.Book SELECT * FROM book WHERE id #{id} FOR UPDATE /select update idupdateStatus UPDATE book SET status #{status} WHERE id #{id} AND status 0 /updateUPDATE 语句里的status 0很关键如果一本书已经被改成 2这次更新的影响行数就是 0程序可以通过返回值判断是否真的抢到了单。这里也没有使用外键约束book_id在逻辑上依赖图书表但删除图书时可能连带存在订单所以用逻辑关联不在数据库里建物理外键。注意FOR UPDATE必须在事务中才有效。如果调用 buy 方法时没有Transactional数据库会在第一条 UPDATE 后自动提交锁全部白加。项目里如果出现并发时还是超卖先检查 Service 方法上有没有事务注解再看事务管理器有没有在 Spring 配置里启用。4.3 列表和筛选Mapper 动态 SQL 配合 JSP 的 EL/JSTL首页图书列表是买家第一个接触的页面也是二次开发里最常改的搜索功能。在 Mapper XML 里用动态 SQL 根据关键字、价格区间拼接查询条件select idselectOnSale parameterTypemap resultTypecom.campus.trade.entity.Book SELECT * FROM book where status 0 if testkeyword ! null and keyword ! AND (title LIKE CONCAT(%, #{keyword}, %) OR author LIKE CONCAT(%, #{keyword}, %)) /if if testminPrice ! null AND price gt; #{minPrice} /if if testmaxPrice ! null AND price lt; #{maxPrice} /if /where ORDER BY create_time DESC LIMIT #{offset}, #{pageSize} /selectwhere标签会自动去掉第一个条件前面的 AND所以status 0写在最前面后面加条件不用手动拼。XML 里大于号要写成gt;小于号写成lt;否则 XML 解析报错。分页的 offset 计算一般是(pageNum - 1) * pageSize不要在前端传死值也不要依赖内存分页。JSP 页面里的循环用 JSTL% taglib prefixc urihttp://java.sun.com/jsp/jstl/core % c:forEach items${page.list} varb div classbook-card h3 a href${pageContext.request.contextPath}/book/detail?id${b.id} ${b.title} /a /h3 p${b.author} / ${b.publisher}/p p成色${b.degree} · ${b.price}/p a href${pageContext.request.contextPath}/book/detail?id${b.id}查看详情/a /div /c:forEachEL 表达式${b.title}调用的是 Book 对象的 getTitle 方法不是直接访问字段。${pageContext.request.contextPath}会动态输出当前项目名避免把路径写死导致部署后 404。如果列表页面数据为空先看 Controller 里放进 Model 的 key 是不是page再看 list 是否有记录JSP 本身报错信息很少查后端日志更直接。5. 避坑/常见问题/排查SSMJSP 项目最容易翻车的 5 个点以下问题不是来自某个特定源码而是我帮人查 SSMJSP 项目时最常见的 5 个问题。按现象、原因、解决展开每个都值得在演示前检查一遍。5.1 数据库中文乱码不只是 jdbc.properties 的锅现象页面上书名、作者、留言全部显示成问号或者写入数据库就变成乱码。原因四层编码不一致。MySQL 客户端导入时用了默认字符集表本身建成了 latin1JDBC 连接 URL 没指定编码JSP 页面响应用的编码也不对。很多同学只改 jdbc.properties 一处所以问题反复出现。解决统一使用 utf8mb4。JDBC URL 里加characterEncodingutf8JSP 页面头部加% page contentTypetext/html;charsetUTF-8 languagejava pageEncodingUTF-8 %导入 SQL 时显式指定mysql -u root -p --default-character-setutf8mb4 book_trade book_trade.sql建表语句也应该在CREATE DATABASE里就设计好utf8mb4。如果表已经建错执行ALTER TABLE book CONVERT TO CHARACTER SET utf8mb4;可以补救但有风险改之前先备份数据。中文乱码这种问题答辩时被问一句“为什么 utf8 不行”能讲清楚反而变成加分点。5.2 Tomcat 启动就报 ClassNotFoundException依赖没进到 war 里现象IDEA 里没有编译错误启动 Tomcat 时却报java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener。原因Maven 依赖没有导入到 Artifacts或者传统 JSP 项目的WEB-INF/lib目录缺少 Spring、SpringMVC、MyBatis 的 jar 包。很多“源码包”是从课程作业里拷贝的web.xml 还保留着 Spring 监听器配置但依赖已经不完整。解决Maven 项目在 IDEA 右侧 Maven 面板点刷新让它重新下载依赖如果还不行打开 Project Structure 检查 Artifacts 有没有把 Maven 依赖加进去。用命令检查 war 包内容jar tf target/book_trade.war | grep spring-web能输出spring-web-xxx.jar说明依赖打进去了没有就说明 war 包不完整。不要在演示现场重新下依赖提前检查这一步能省很多事。5.3 页面能打开但 CSS/JS 全挂F12 一排 404现象登录页只有纯文本和按钮没有任何样式控制台 Network 面板里 css/js 文件全是 404。原因web.xml 里 DispatcherServlet 的 URL 拦截配置成/把静态资源请求也拦下来了。SpringMVC 控制器不认识这些静态文件于是返回 404。解决在 SpringMVC 配置文件中加一行静态资源映射mvc:resources location/static/ mapping/static/**/JSP 里引用静态资源时不要写相对路径要用项目根路径link relstylesheet href${pageContext.request.contextPath}/static/css/index.css如果项目目录是webapp/staticslocation改成/statics/mapping对应/statics/**。这个问题最容易在演示时翻车因为功能还能用但页面丑到没有说服力。5.4 MyBatis 报 BindingException: Invalid bound statement (not found)现象调用用户登录或图书列表时控制台抛org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)。原因Mapper 接口的方法在 resources 下的 XML 里找不到对应语句。常见是 XML 文件的 namespace 写错或 Mapper 接口和 XML 文件名不对应或 XML 没有复制到target/classes目录里。解决确保 Mapper 接口的全限定名和 XML 的 namespace 一模一样。比如接口是com.campus.trade.mapper.BookMapperXML 的 namespace 就是com.campus.trade.mapper.BookMapper方法 id 等于接口方法名。如果 Maven 把 XML 排除了在 pom.xml 里补resources resource directorysrc/main/resources/directory includes include**/*.xml/include /includes /resource /resources调试时直接看target/classes/mapper/BookMapper.xml是否存在。不存在就是没打进去存在但仍报错就打开 XML 检查 namespace 和 id。这是 SSM 项目里最典型的新手杀手。5.5 MySQL 8 驱动报 Public Key Retrieval is not allowed现象Tomcat 启动正常第一次访问数据库时抛SQLNonTransientConnectionException: Public Key Retrieval is not allowed。原因MySQL 8 默认认证插件是caching_sha2_password高版本驱动连接时默认不检索服务端公钥导致认证失败。解决在 JDBC URL 中追加jdbc.urljdbc:mysql://localhost:3306/book_trade?useSSLfalseallowPublicKeyRetrievaltrueserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue在开发环境里很常见生产环境需要谨慎评估公钥安全。如果排查时只注意到驱动类而忽略 URL 参数这个问题会反复出现。和数据库连接池结合时还要看连接池日志Druid 初始化失败时最底层的 Caused by 才是真正的密码错误或公钥问题。6. 最后的加分项把 SSMJSP 从“能跑”做到“能答辩”6.1 演示前必做的三个验证让评审看到的不只是页面三十分钟演示能讲清楚三个点就够并发下单、事务回滚、状态流转。开两个浏览器用两个账号同时买同一本书第一个成功第二个应该看到“已下架”。如果原代码没有加锁用第 4 章的FOR UPDATE方式补上这是最容易被提问的扩展点。第二步是验证事务回滚。在buy()方法的订单插入后人为抛一个RuntimeException再调用一次看图书状态是否仍然在售。如果订单和图书状态都没变说明Transactional配置正确这个实验能直观证明你对 Spring 事务不是背概念。第三步是检查整体状态分布SELECT b.status, COUNT(*) AS cnt FROM book b GROUP BY b.status;能准确说出 0 是在售、1 是下架、2 是已卖出并且能讲出每个状态是由哪个方法修改的比背 Spring 生命周期更能说明你真正读过源码。图书表、订单表、用户表的关联关系也可以通过这条 SQL 现场展示评审会认为你对数据库设计有把握。我自己的习惯是演示前一天把数据库重新导入一遍从头走到下单不清缓存、不换浏览器确保现场不会有“上次明明能跑”的尴尬。这套 SSMJSP 源码能不能拿高分不取决于压缩包里有多少文件而取决于你能不能把“事务、锁、状态流转”这三件事讲清楚。希望帮到你。本文还有配套的精品资源点击获取
返回列表