尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
SSM+JSP酒店客房预定系统开发全攻略:从环境搭建到避坑指南
简介面向Java毕业设计与课程设计场景的酒店客房预定管理系统完整项目基于SSMSpringSpringMVCMyBatis与JSP技术栈覆盖管理员与用户两类角色。管理员端包含个人中心、用户管理、客房类型管理、酒店客房管理、客房预定管理、开房记录管理、退房结账管理及系统管理用户端支持首页浏览、酒店客房查看、系统公告、个人中心与后台管理功能链路完整适合作为毕设选题、课程设计或SSM框架综合练手。资源包共1253个文件以java源码、jsp页面、js脚本、css样式、sql数据库脚本及png/gif图片素材为主压缩后约18.15MB包含完整源码、说明文档、LW文档和PPT演示文稿可直接参考部署、二次开发与答辩展示。目前已有208人学习下载对需要快速搭建酒店客房预定管理系统、梳理SSM项目结构的同学有直接帮助可结合自身数据库环境导入SQL并配置运行。1. 酒店客房预定系统拆箱ssmjsp这套组合到底解决什么问题大学最后一个学期很多人拿到的毕业设计题目就是“酒店客房预定管理系统”技术栈写着 java ssm jsp压缩包里附完整源码、说明文档、LW论文和答辩 PPT。第一个疑问通常是这套东西到底做什么、能不能跑通、做出来长什么样。实际做完之后我的判断是它是一款标准且上限清晰的后台管理项目适合练手也适合稳稳当当过答辩。业务闭环是这样——JSP 页面负责展示客房列表和订单表格普通用户登录后选空闲房间提交预定管理员在后台处理入住、退房、取消订单SSM 三个框架各管一段Spring 管对象和事务SpringMVC 接页面请求MyBatis 读写数据库。它最难的部分不在某个高深技术而在于让订单状态和房间状态在每一步都保持一致这恰恰是答辩时最能讲出深度的地方。2. 环境选型与整合骨架JDK8、Tomcat9、Maven、MySQL 这套组合为什么能少踩一半坑2.1 版本搭配毕业设计环境不是越新越好做 SSM JSP 项目我一般会直接锁定一套“老牌但稳定”的组合JDK 8、Tomcat 9.0.x、Maven 3.6、MySQL 5.7 或 8.0、Spring 5.2.x、MyBatis 3.5.x。这个搭配不是随便选的理由很直接组件推荐版本原因JDK1.8Spring 5.2 在 JDK 8 下不需要额外兼容参数本地编译、服务器部署行为一致Tomcat9.0.xJSP 走 javax.servlet 包名Tomcat 10 以后全改成 jakarta.servlet旧项目直接翻车Maven3.6对旧仓库和私有依赖的兼容性最好3.9 在某些网络环境下反而容易卡下载MySQL5.7 / 8.0单机毕设量级两者都够注意驱动版本和连接串要与数据库版本匹配Spring / MyBatis5.2.x / 3.5.xSSM 整合资料最多、踩坑记录最全的版本段这里的血泪经验是Tomcat 10 之后不再支持 javax.servlet老项目里几乎所有 Filter、Servlet、JSP 内建对象都会报 ClassNotFoundException 或者 NoClassDefFoundError。如果你把 JDK 也升到 17Spring 5.2 默认的 CGLIB 代理还会遇到反射权限问题启动期就开始折腾。与其和框架版本搏斗不如老老实实锁 JDK 8 Tomcat 9。2.2 pom.xml一套能过编译的依赖清单新建 Maven 项目后第一步是把依赖补齐。下面这份 pom.xml 核心片段是 SSM 毕业设计最常见的最小集合每一个依赖都有明确职责properties project.build.sourceEncodingUTF-8/project.build.sourceEncoding maven.compiler.source1.8/maven.compiler.source maven.compiler.target1.8/maven.compiler.target /properties dependencies !-- Spring MVC 与 Spring 核心 -- dependency groupIdorg.springframework/groupId artifactIdspring-webmvc/artifactId version5.2.22.RELEASE/version /dependency !-- MyBatis 框架 -- dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version3.5.6/version /dependency !-- MyBatis 与 Spring 整合的桥梁 -- dependency groupIdorg.mybatis/groupId artifactIdmybatis-spring/artifactId version2.0.6/version /dependency !-- MySQL 驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version5.1.49/version scoperuntime/scope /dependency !-- 阿里 Druid 连接池 -- dependency groupIdcom.alibaba/groupId artifactIddruid/artifactId version1.1.21/version /dependency !-- 返回 JSON 数据时使用 -- dependency groupIdcom.fasterxml.jackson.core/groupId artifactIdjackson-databind/artifactId version2.11.4/version /dependency !-- Servlet API编译时需要Tomcat 里已经带了一份所以用 provided -- dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version4.0.1/version scopeprovided/scope /dependency !-- JSTL 1.2 直接解决 JSP 中用不了 c:forEach 的坑 -- dependency groupIdjstl/groupId artifactIdjstl/artifactId version1.2/version /dependency /dependencies两个参数最容易出错servlet-api 的 scope 必须是 provided否则打包后和 Tomcat 自带的类冲突JSTL 建议直接引 1.2 这一个坐标不要分别引 jstl-api 和 jstl-impl否则页面里经常出现 “Cannot find the tag library descriptor for http://java.sun.com/jsp/jstl/core”。依赖配完后执行mvn clean package如果能顺利打出 war 包环境就算立住了。2.3 SSM 的三个关键配置web.xml、springmvc.xml、applicationContext.xmlSSM 的配置文件数量多但职责一定要分清。web.xml 是 Web 容器的入口里面注册 SpringMVC 的前端控制器 DispatcherServlet 和 Spring 的监听器!-- web.xml 核心配置 -- filter filter-nameencoding/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-nameencoding/filter-name url-pattern/*/url-pattern /filter-mapping listener listener-classorg.springframework.web.context.ContextLoaderListener/listener-class /listener context-param param-namecontextConfigLocation/param-name param-valueclasspath:applicationContext.xml/param-value /context-param servlet servlet-namedispatcher/servlet-name servlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-class init-param param-namecontextConfigLocation/param-name param-valueclasspath:springmvc.xml/param-value /init-param load-on-startup1/load-on-startup /servlet servlet-mapping servlet-namedispatcher/servlet-name url-pattern//url-pattern /servlet-mapping注意几个细节url-pattern/*/url-pattern会把所有请求都过一遍编码过滤器其中forceEncoding设为 true 很关键否则只对 POST 请求生效load-on-startup1/load-on-startup表示 Tomcat 启动时就初始化 SpringMVC 容器不加这个的话第一次请求才会初始化浏览器要等很久。springmvc.xml 只管 Controller 层和视图解析!-- springmvc.xml -- context:component-scan base-packagecom.hotel.controller/ mvc:annotation-driven/ !-- JSP 视图解析器 -- bean classorg.springframework.web.servlet.view.InternalResourceViewResolver property nameprefix value/WEB-INF/views// property namesuffix value.jsp/ /bean !-- 静态资源放行/static 下的 js、css、图片 -- mvc:default-servlet-handler/ mvc:resources mapping/static/** location/static//视图解析器的前缀和后缀是一对容易写错的地方Controller 返回room/list最终页面路径是/WEB-INF/views/room/list.jsp。因为页面放在 WEB-INF 下浏览器不能直接输入地址访问必须由 Controller 转发进来这也避免了未登录的人直接打开某个管理页面。applicationContext.xml 负责数据源和 MyBatis 工厂和 SpringMVC 的包扫描要分开!-- applicationContext.xml -- context:component-scan base-packagecom.hotel.service/ context:property-placeholder locationclasspath:jdbc.properties/ bean iddataSource classcom.alibaba.druid.pool.DruidDataSource property namedriverClassName value${jdbc.driver}/ property nameurl value${jdbc.url}/ property nameusername value${jdbc.username}/ property namepassword value${jdbc.password}/ /bean bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBean property namedataSource refdataSource/ property nametypeAliasesPackage valuecom.hotel.entity/ property namemapperLocations valueclasspath:mapper/*.xml/ /bean bean classorg.mybatis.spring.mapper.MapperScannerConfigurer property namebasePackage valuecom.hotel.mapper/ property namesqlSessionFactoryBeanName valuesqlSessionFactory/ /bean包扫描上有一个经典坑Service 和 Controller 的 base-package 必须错开。如果 springmvc.xml 把com.hotel全包扫描了Transactional 注解会失效事务管理会变成只读配置下单和房间状态更新中间一旦报错数据就会裂开。2.4 jdbc.properties 与字符集约定连接数据库的参数通常单独放在 jdbc.properties 里jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/hotel_db?characterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai jdbc.usernameroot jdbc.password123456这里强烈建议把characterEncodingutf8写进连接串。很多人只在 web.xml 里配了编码过滤器结果数据库连接用的还是默认字符集页面上输中文存进 MySQL 就变成问号。serverTimezoneAsia/Shanghai是 MySQL 8.0 驱动必须带的参数不带会报时区错误5.7 老驱动则无所谓。useSSLfalse 是为了省去证书握手本机开发不需要加密链路。3. 数据模型与业务实现订单表设计、Mapper 映射与 ssm 常用注解的组合用法3.1 数据表设计订单表跟房间状态字段怎么配合酒店客房预定管理系统在数据层面至少要有这几张表用户表区分管理员和普通会员、客房类型表、客房表、订单表。其中客房表和订单表是核心房间状态和订单状态必须一一对应。订单表的建表语句我一般这样写CREATE TABLE orders ( id int(11) NOT NULL AUTO_INCREMENT COMMENT 主键, order_no varchar(32) NOT NULL COMMENT 订单号业务上唯一, user_id int(11) NOT NULL COMMENT 下单用户id, room_id int(11) NOT NULL COMMENT 房间id, check_in date NOT NULL COMMENT 入住日期, check_out date NOT NULL COMMENT 退房日期, total_price decimal(10,2) NOT NULL COMMENT 订单总金额, status int(1) NOT NULL DEFAULT 0 COMMENT 0待支付 1已预订 2已入住 3已退房 4已取消, create_time datetime NOT NULL, remark varchar(255) DEFAULT NULL, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT订单表;注意我把订单金额用了decimal而不是double。金额做浮点运算会出现 0.1 0.2 不等于 0.3 的问题毕业设计答辩时被老师追问一句就很麻烦。order_no字段加唯一索引是为了防止两个人同时提交订单时生成重复订单号这也是数据一致性的第一道保障。客房表里对应地需要room_no、room_type_id、price、state字段state 用 0 表示空闲、1 表示已预订、2 表示已入住。这张表和订单表的关系是每生成一个有效订单room.state 就要跟着变化。订房后变 1入住后变 2退房后变 0取消订房恢复 0。弄清楚这个状态联动关系业务逻辑就完成了一半。3.2 实体类与 Mapper 接口resultMap 不是每个查询都需要MyBatis 的实体类字段尽量和数据库列名保持下划线转驼峰的关系。在 sqlSessionFactory 里开启mapUnderscoreToCamelCasecheck_in列就能自动映射到checkIn属性少写很多 resultMap。public class Order { private Integer id; private String orderNo; private Integer userId; private Integer roomId; private Date checkIn; private Date checkOut; private BigDecimal totalPrice; private Integer status; private Date createTime; private String remark; // 关联查询的冗余字段订单列表页要展示用户名和房号 private String userName; private String roomNo; // getter / setter 省略 }展示字段userName和roomNo是刻意加的列表冗余字段查询时通过 join 把用户表的昵称和客房表的 room_no 带出来页面不用再循环查数据库。这是后台系统最常见的空间换时间写法。与它配套的 Mapper 接口写法上只定义抽象方法SQL 放在 XML 里public interface OrderMapper { int insert(Order order); ListOrder selectByUserId(Integer userId); ListOrder selectAll(); int updateStatus(Param(id) Integer id, Param(status) Integer status); }Mapper 接口里参数名要加 Param否则 XML 里#{userId}可能解析不到。updateStatus 返回 int是 MyBatis 的惯例返回受影响行数。后面 Service 里可以通过这个返回值判断“是否有行被更新”如果为 0 说明房间状态已经变了应该终止后续逻辑。3.3 从 Controller 到 Service常用注解的实战组合下单是整个系统的核心业务代码也最能体现 ssm 常用注解的用法。Controller 层负责接收参数和做最基础的校验Controller RequestMapping(/order) public class OrderController { Autowired private OrderService orderService; /** * 提交预定订单 */ PostMapping(/add) public String addOrder(SessionAttribute(loginUser) User loginUser, RequestParam Integer roomId, RequestParam DateTimeFormat(pattern yyyy-MM-dd) Date checkIn, RequestParam DateTimeFormat(pattern yyyy-MM-dd) Date checkOut, RedirectAttributes ra) { // 日期合法性校验入住必须早于退房 if (checkIn.after(checkOut)) { ra.addFlashAttribute(msg, 入住日期不能晚于退房日期); return redirect:/room/detail/ roomId; } Order order new Order(); order.setUserId(loginUser.getId()); order.setRoomId(roomId); order.setCheckIn(checkIn); order.setCheckOut(checkOut); order.setOrderNo(H System.currentTimeMillis() (int) (Math.random() * 1000)); order.setStatus(1); // 已预订 orderService.createOrder(order); ra.addFlashAttribute(msg, 预订成功); return redirect:/order/list; } }几个注解说明一下类型转换逻辑SessionAttribute(loginUser)直接从 session 里取登录对象没登录会抛异常后面在全局异常处理器里统一返回登录页DateTimeFormat把页面传来的 “2024-05-20” 字符串转成 java.util.Date不写这个注解SpringMVC 会直接报参数类型不匹配RedirectAttributes的 addFlashAttribute 是 POST 重定向时带提示消息的标准做法避免表单重复提交。Service 层才是下单事务的真正边界Service public class OrderServiceImpl implements OrderService { Autowired private OrderMapper orderMapper; Autowired private RoomMapper roomMapper; Override Transactional(rollbackFor Exception.class) public void createOrder(Order order) { // 1. 插入订单记录 orderMapper.insert(order); // 2. 把客房状态置为已预订 int updated roomMapper.updateState(order.getRoomId(), 1); // 3. 如果房间状态已经变化抛异常强制回滚 if (updated ! 1) { throw new RuntimeException(房间状态已变化请刷新后重试); } } }注意这里是两个表的写操作必须放在同一个事务里。Transactional(rollbackFor Exception.class)的意思是任何异常都回滚包括 RuntimeException 和受检异常。默认的 TransactionAttribute 只回滚运行时异常如果你把自定义的 checked exception 抛出去事务不会回滚房间状态就错乱了。这个设置是 java 如何保证数据一致性的标准答案之一。3.4 条件查询与分页动态 SQL 的 where/if 组合客房列表页通常要支持按类型筛选和关键字搜索。用 MyBatis 的where和if动态拼接 SQL 是最常见的做法比在 Java 代码里拼字符串安全得多select idselectRoomPage resultTypecom.hotel.entity.Room select * from room where if testroomTypeId ! null and room_type_id #{roomTypeId} /if if testkeyword ! null and keyword ! and (room_no like concat(%, #{keyword}, %) or room_name like concat(%, #{keyword}, %)) /if /where order by id desc /select这里有两个容易忽视的细节。#{keyword}用的是预编译占位符不要写成${keyword}后者会把用户输入直接拼进 SQL存在注入风险。LIKE 的模糊匹配用concat(%, #{keyword}, %)不能直接在 XML 里写like %${keyword}%一是注入风险二是同样无法走索引。分页我一般用 PageHelper依赖一行配置就能接管查询PageHelper.startPage(pageNum, pageSize); ListRoom roomList roomMapper.selectRoomPage(roomTypeId, keyword); PageInfoRoom pageInfo new PageInfo(roomList);startPage 之后的第一个查询会被自动拼上 limit。PageInfo 里封装了总记录数、总页数、当前页数据列表直接把 pageInfo 放进 ModelJSP 页面就可以渲染分页导航条。注意PageHelper.startPage必须紧跟 Mapper 查询语句中间不能插入其他数据库操作否则分页会作用到错误的查询上。4. jsp 页面与交互列表渲染、表单回显、路径与权限一次讲清4.1 用 EL 和 JSTL 渲染客房列表JSP 页面最大的原则是不写 Java 小脚本只写 EL 表达式和 JSTL 标签。客房列表页的核心渲染片段% taglib prefixc urihttp://java.sun.com/jsp/jstl/core % % taglib prefixfmt urihttp://java.sun.com/jsp/jstl/fmt % table tr th房号/th th房型/th th价格/th th状态/th th操作/th /tr c:forEach items${pageInfo.list} varroom tr td${room.roomNo}/td td${room.roomTypeName}/td td${room.price} 元/晚/td td c:choose c:when test${room.state 0} span classtag-green空闲/span /c:when c:when test${room.state 1} span classtag-red已预订/span /c:when c:otherwise span classtag-gray已入住/span /c:otherwise /c:choose /td td c:if test${room.state 0} a href${ctx}/room/detail/${room.id}去预定/a /c:if /td /tr /c:forEach /table${pageInfo.list}是 Controller 放进 Model 里的分页数据c:forEach遍历房间列表c:choose是 JSTL 里的 switch 结构比连着写多个c:if清爽。${ctx} 是项目上下文的缩写具体怎么设置在下一节讲。这个页面的展示逻辑要记住一个边界按钮的显示和隐藏由房间状态决定但后端在真正执行下单时还必须再校验一次房间是否空闲。前端控制只是体验后端校验才是数据安全。4.2 表单回显与个人信息展示页面“jsp 个人信息展示页面”这个需求在毕设里几乎是必出现项。最常见做法是用 session 里的登录用户直接回填表单编辑之后提交更新c:if test${not empty sessionScope.loginUser} form action${ctx}/user/update methodpost input typehidden nameid value${sessionScope.loginUser.id}/ label昵称/label input namenickname value${sessionScope.loginUser.nickname}/ label手机号/label input namephone value${sessionScope.loginUser.phone}/ button typesubmit保存/button /form /c:if表单回显有两个坑。第一个是value属性里直接写 EL如果用户昵称里含引号页面可能被截断稳妥做法是用c:out value${...}/做 HTML 转义。第二个是保存成功后session 里的 loginUser 仍然是旧数据必须在 Controller 的 update 方法里重新 set 一次 session 属性否则页面上显示的还是旧昵称典型的数据不一致表现。个人中心页面的日期、金额字段也建议用fmt:formatDate和fmt:formatNumber格式化数据库里的 datetime 原样输出会是一长串带时间戳的数字用户根本看不懂。4.3 上下文路径与静态资源图片和 CSS 挂掉的根因JSP 页面里写死/css/style.css和/static/img/room1.jpg在本地开发时通常没问题项目一部署到 Tomcat 的 webapps 下如果应用名是hotel真实路径就变成了/hotel/css/style.css所有静态资源 404。标准做法是在每个页面顶部声明一个上下文变量c:set varctx value${pageContext.request.contextPath}/ link relstylesheet href${ctx}/static/css/style.css/ img src${ctx}/static/img/room-pic.png/${pageContext.request.contextPath}会动态输出部署的应用名本地是空字符串发布后是/hotel。所有 img 和 a 标签的路径都以${ctx}开头这套页面换部署环境就不用改代码。如果你后续想对客房图片做交互式查看比如点击图片看放大细节那就涉及“jsp 图片如何对坐标定位”这一类前端交互问题了。思路不是在 JSP 里写死坐标而是由后端返回图片地址和热点区域数据前端用 JavaScript 的 offset 计算相对位置。毕设阶段通常只需要做到图片上传和滚动展示即可。4.4 菜单权限session 里那个 role 字段的 JSP 判断用户表里一般用一个 role 字段区分管理员和普通会员这个字段在 JSP 里能直接控制菜单可见性c:if test${sessionScope.loginUser.role 0} lia href${ctx}/admin/userList用户管理/a/li lia href${ctx}/admin/orderList全部订单/a/li /c:if c:if test${sessionScope.loginUser.role 1} lia href${ctx}/order/list我的订单/a/li /c:if这是行级权限在页面层的最小实现普通用户只能看到“我的订单”管理员可以看到全部订单。对应的后端也要做同样事——OrderMapper.selectByUserId 负责拦截普通用户的数据范围管理员调用 selectAll。只做前端隐藏不做后端过滤是权限设计最典型的反面教材答辩时老师经常会追问这一条。5. 避坑排查ssmjsp 毕设最容易踩的 5 个运行时问题5.1 Tomcat 10 启动后项目直接 404 或 JSP 报错现象项目在 IDEA 里能编译通过用 Tomcat 10 启动后地址栏输入首页地址返回 404 或者页面报出 java.lang.NoClassDefFoundError: javax/servlet/xxx。原因Tomcat 10 开始把 servlet 包名从 javax.servlet 换成 jakarta.servletSSM 依赖的 Spring 5.2 和 JSP 内建对象全都基于旧包名。这个不是代码 bug是整个运行环境不兼容。解决换回 Tomcat 9.0.x不要去改代码适配 jakarta否则一堆第三方库都要跟着升级。版本选型要放在项目搭建的第一步而不是最后部署时才发现。5.2 启动报 Mapped Statements collection already contains value现象Tomcat 启动过程中抛Mapped Statements collection already contains value for com.hotel.mapper.RoomMapper.selectRoomPage或者类似提示应用启动失败。原因同一个 statement id 被重复注册。常见是 Mapper XML 文件被放了多份或者 mapperLocations 的通配路径重复扫到了同一个 XML。解决检查classpath:mapper/*.xml是否覆盖了 target/classes 下残留的旧文件执行mvn clean清掉再看 XML 里 namespace 写的是不是接口全限定名如果 namespace 和 id 组合不唯一同样会冲突。清理之后一般都能解决。5.3 中文乱码玄学问题但三个位置必须同时检查现象用户在页面提交“张三”控制台打印正常存入数据库变成“å¼ ä¸‰”或“”。原因字符集链路有三跳——HTTP 请求到 SpringMVC 的编码过滤器、JDBC 连接串的 characterEncoding、MySQL 表自身的字符集。任何一跳没配 UTF-8最终入库就是乱码。解决web.xml 里 CharacterEncodingFilter 的 forceEncoding 设为 truejdbc.properties 连接串带characterEncodingutf8建表语句统一DEFAULT CHARSETutf8mb4。三个位置都改完后重启 Tomcat再重新插入数据测试。乱码最怕只改一个位置改完还是乱扭头就不知道查哪了。5.4 SQL 在 Navicat 里能跑Java 一执行就报表或字段不存在现象产品列表查询在 Navicat 里执行没问题MyBatis 执行时报Bad SQL grammar或Unknown column desc。原因表字段名和数据库保留字撞了。desc、order、group、state 里 state 不是保留字但 desc 和 order 是直接写进 SQL 会被数据库解析成排序或分组关键字。字段命名时图省事用了缩写排查起来最耗时间。解决字段名避免使用 desc、order、level、index 这类词。如果表已经建好不好改就在 XML 的列名上加反引号比如\desc。这个经验也说明建表时多想想比事后补反引号省事得多。5.5 JSP 里图片和 CSS 全部 404但浏览器地址是对的现象登录页能打开但所有样式和图片都不加载F12 看请求路径是/static/css/style.css返回 404浏览器直接访问这个地址也 404。原因两个可能。一是 DispatcherServlet 映射了/把静态资源请求也当成 Controller 请求处理了二是 JSP 写的是绝对路径没有带部署上下文。解决springmvc.xml 里加mvc:resources mapping/static/** location/static//确保静态文件能被直接放行页面里所有静态资源路径按 4.3 节那样拼上${pageContext.request.contextPath}。两个不冲突全部做掉最稳。6. 答辩前的半小时验收把系统盘到“无懈可击”的具体清单答辩不是把功能演示一遍就结束的老师会围绕项目边界提问。我的习惯是答辩前用半小时跑一张验收清单把每个功能点的正常路径和异常路径都过一遍顺便对着清单思考“这个功能为什么这么做”。验收项操作方式常见疏漏点登录与角色分离用管理员和会员分别登录管理员和会员看到的是不是各自的菜单集客房检索按房型筛选、关键字搜索、翻页筛选条件翻页后是否丢失预定主流程选空闲房间提交预定订单生成后房间 state 是否同步变更预定异常支线打开两个页面同时抢同一间房是否出现脏数据或重复下单管理端状态流转执行入住、退房、取消订单状态和房间状态是否一一对应个人中心修改昵称手机号保存后 session 是否同步更新强制刷新连续 F5 刷新页面是否出现重复提交或页面报错如果你还想让项目超出其他同学一截我建议挑两个点深化。第一是给订单加“超时未支付自动取消”的定时任务Spring 提供 Scheduled 注解写一个每隔五分钟扫一次待支付订单的方法把超时订单置为取消并释放对应房间即可。第二是把订单状态从散落的魔法数字收敛成状态类或枚举用常量名代替 0、1、2、3 四个数字代码可读性会明显上一个台阶。验收完成后再用 IDEA 的mvn clean package打一次 war部署到独立的 Tomcat 下确认能跑。我当年吃过一次亏本地 IDEA 内置 Tomcat 一切正常同学电脑部署后 CSS 全挂就是因为路径里没加应用上下文。后来养成了一个固定习惯每修一个 bug就在项目根目录的笔记文件里记一行“现象、原因、解决”答辩前翻一遍这些记录比背诵框架原理有用得多因为这些才是你真正做过的东西。这个习惯希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

储能柜效率差,问题可能藏在电池簇DC/DC里

储能柜效率差,问题可能藏在电池簇DC/DC里

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/9 1:02:08
Linux PM QoS 功耗管理:约束聚合机制与驱动开发实践

Linux PM QoS 功耗管理:约束聚合机制与驱动开发实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/9 1:02:08
模型服务规模化:调度、KV Cache 与资源池化的系统之道

模型服务规模化:调度、KV Cache 与资源池化的系统之道

SOSP 的 Session 1A 开场就是 Model Serving at Scale,这个安排本身就很能说明问题。这几年我和团队一直在做 LLM 推理服务化,眼看着这个方向从"AI 实验室里的小工具"变成了"真正意义上的系统软件"——调度、缓存、资源池化、故障恢…

📅 2026/10/9 0:57:08
MORE NEWS

更多资讯

📰

Gemini对话、AI历史搜索、DevTools AI一网打尽:enable-chrome-ai解锁的3大Chrome隐藏功能实测

Gemini对话、AI历史搜索、DevTools AI一网打尽:enable-chrome-ai解锁的3大Chrome隐藏功能实测 【免费下载链接】enable-chrome-ai Enable Gemini in Chrome, AI Powered History search, DevTools Al Innovations in Google Chrome without cleaning data and reins…

📰

微信 openclaw 插件接入 TaoToken 统一 Key:Python CLI 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

串口为何在IIoT底层长盛不衰:从RS485偏置电阻到Linux丢数据实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

导师说选题太宽泛、创新点不足怎么办?academic-ai-prompt的6个应急修改Prompt清单

导师说选题太宽泛、创新点不足怎么办?academic-ai-prompt的6个应急修改Prompt清单 【免费下载链接】academic-ai-prompt 一套为研究生和学术研究者设计的完整AI Prompt库 📖 包含内容: ✨ 40 精心设计的AI Prompt ✨ 论文选题系统方法&#x…

📰

Suricata IP Reputation(IP 信誉)机制完全指南:配置、数据格式与 iprep 规则实战

网络安全 【免费下载链接】suricata Suricata is a network Intrusion Detection System, Intrusion Prevention System and Network Security Monitoring engine developed by the OISF and the Suricata community. 项目地址: https://gitcode.com/gh_mirrors/su/…

📰

universal-modder 中 Unreal 4/5 游戏的 Mod 实战:引擎识别、UE4SS 钩子、Pak 替换与调校路线

【免费下载链接】universal-modder Point Claude at any game. Skills, tools and the fal MCP that let Claude Code mod almost any PC game you own: recon, reverse engineering, fal-generated art/3D/audio, in-game testing, showcase videos. 项目地址: htt…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬