简介一份基于SSM框架SpringSpringMVCMyBatis与MySQL数据库结合JSP页面实现的酒店预订管理系统完整项目适合JavaWeb学习者、毕业设计选题学生及需要信息化管理的中小型酒店参考也是理解SSM整合开发的典型练习项目。系统按角色分为前台用户与后台管理员前台覆盖注册登录、客房模糊搜索、在线预订、订单查看与个人资料维护后台包含系统设置、用户与日志管理、楼层房型房间管理、客户与预订入住管理、营业统计等模块业务闭环清晰覆盖面较广。zip压缩包约35.29MB包含完整项目源码、毕业论文及开发报告论文部分阐述开发背景、需求分析、系统设计与测试过程报告则说明功能与操作流程方便对照学习、快速上手和二次开发。目前已有83人浏览学习适合用来梳理SSM项目结构、数据库表设计及酒店业务模块的落地实现。1. 用 SSM 搭酒店预订系统一个能写进简历也能当毕设的完整方案如果你正在做毕业设计或者在 Java 课程项目里选了一个“酒店预订管理系统”大概率是因为这个题目业务足够常见用户注册登录、浏览客房、下单预订、后台管理订单和房态一套下来把 Web 开发的增删改查全占了。标题里的“SSM 框架 mysql jsp”是这套系统最常见的技术组合Spring 管对象、SpringMVC 管请求、MyBatis 管 SQLMySQL 存数据JSP 直接渲染页面。它不需要额外构建前端工程也不用维护前后端接口一个 Tomcat 跑起来就是完整的系统。这篇笔记的目标很直接帮你把这个项目从零搭起来数据库表怎么设计、SSM 整合配置哪些关键参数、预订流程的代码怎么写、部署会遇到哪些坑以及最终怎么和毕业论文、报告放在一起交付。如果你手上已经有源码这套笔记也能帮你把代码吃透因为很多源码包里的注释和配置文件并不完整能跑通和能讲清楚之间还差一段距离。下面从技术选型讲起逐步落到代码和踩坑记录。2. 先拆技术选型SSM MySQL JSP 为什么还是经典组合2.1 三层框架各自干的事Spring 管对象、SpringMVC 管路由、MyBatis 管 SQLSSM 不是一个框架而是三个框架的分工协作。Spring 负责依赖注入和事务管理也就是说Service 层需要哪些对象一律通过注解或 XML 注入不需要在代码里 new。SpringMVC 是对 Servlet 的封装它把 URL 请求分发到 Controller 的某个方法再由 Controller 调用 Service最后返回一个视图名或 ModelAndView。MyBatis 则是半自动的 ORM 框架你写 SQL它负责把结果集映射成 Java 对象比 Hibernate 更直观也更容易排查 SQL 性能问题。理解这个分工对后面的配置很重要。很多新手把 SSM 整合看成“三个配置文件改来改去”其实核心只有几件事Spring 容器要扫哪些包、SpringMVC 只接管 Controller、MyBatis 的 SqlSessionFactory 怎么和 Spring 的上下文绑定。这三件事搞定了剩下的就是业务代码。2.2 JSP 在前后端分离时代仍然合适的场景现在一说 Web 开发就是 Vue React 前后端分离但 JSP 依然有它的场景JSP 可以直接在页面里写 EL 表达式和 JSTL 标签把 Controller 放进去的 Model 数据直接循环输出不需要额外封装 JSON 接口再让前端调对于学生项目和毕业设计答辩时老师不会追问“你为什么不做前后端分离”而是更关注你的业务流程是否完整、数据库设计是否合理。如果你选择 JSP页面渲染逻辑和 Java 代码隔离得比较清楚也能减少工作量。一个容易被忽略的点是 JSP 的乱码问题。它不是框架层面的事而是编码没统一。后面我们会专门讲你现在只需要记住项目目录编码、JSP 页面头部 pageEncoding、web.xml 里的编码过滤器、MySQL 连接 URL 里的 useUnicode 和 characterEncoding这四处必须同时保持一致。2.3 酒店预订系统用得上的核心数据表设计含字段表这类系统常见的表有管理员表、用户表、客房类型表、客房表、订单表有的还加一张评论表。我不建议一开始就设计太多表先把主流程跑通后面再加功能。房间和订单是核心房间表和订单表是典型的一对多关系订单里保存用户 id 和房间 id然后冗余一份房间号和价格这样订单列表查询不用每次都 join。一个精简但完整的表结构可以这样设计admin管理员登录字段 admin_id, username, passworduser用户信息字段 user_id, username, password, phone, real_nameroom_type房型表字段 type_id, type_name, price, bed_info, area, max_peopleroom房间表字段 room_id, room_number, type_id, status0 空闲 1 已入住order订单表字段 order_id, user_id, room_id, check_in_date, check_out_date, total_price, status0 待支付 1 已完成 2 已取消comment评论表选做字段 comment_id, order_id, user_id, content, create_time如果你手里有一份现成的源码先打开数据库脚本看这六张表是否存在再对照字段理解业务。很多源码包自带的 SQL 脚本只建了部分表或者缺少外键关联运行的时候单独做测试数据没问题但前后端逻辑一接就发现查不到数据。建议自己用下面的建表语句把核心表清一遍。下面是用户表和订单表的 DDL注意字段类型和默认值。CREATE TABLE user ( user_id INT(11) NOT NULL AUTO_INCREMENT, username VARCHAR(50) NOT NULL, password VARCHAR(255) NOT NULL, phone VARCHAR(20) DEFAULT NULL, real_name VARCHAR(50) DEFAULT NULL, PRIMARY KEY (user_id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE order ( order_id INT(11) NOT NULL AUTO_INCREMENT, user_id INT(11) NOT NULL, room_id INT(11) NOT NULL, check_in_date DATE NOT NULL, check_out_date DATE NOT NULL, total_price DECIMAL(10,2) NOT NULL, status TINYINT(4) NOT NULL DEFAULT 0, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (order_id), KEY idx_user_id (user_id), KEY idx_room_id (room_id), CONSTRAINT fk_order_user FOREIGN KEY (user_id) REFERENCES user (user_id), CONSTRAINT fk_order_room FOREIGN KEY (room_id) REFERENCES room (room_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;字段说明里有几个细节值得注意username 加唯一键是为了登录查询可以用索引也避免注册同名用户status 用 TINYINT 而不是字符串是为了后面用数字状态流转total_price 用 DECIMAL(10,2) 而不是 FLOAT因为涉及金额计算浮点误差必须避免。外键约束在订单表上加但实际项目里外键经常不用因为业务层已经在做校验外键在批量插入时会影响性能毕业设计建议保留外键老师会觉得你的库设计更完整。如果你想在此基础上加“房源管理”的复杂逻辑可以再把每日房价单独拆一张表或者引入房间状态变更日志但那是后话。先保证六张表能支撑用户、房型、房间、订单这条主线。3. 从零搭好工程SSM 集成 MySQL 与 JSP 的最小配置3.1 用 Maven 建工程pom.xml 里必须有的依赖创建工程建议直接用 Maven webapp 骨架避免手动往 WEB-INF 里塞 lib 包。用骨架生成的src/main/webapp/WEB-INF/web.xml是存在但骨架版本偏老你需要自己写配置。关键依赖如下版本选择我一般用 Spring 5.3.x、MyBatis 3.5.x、mysql-connector-java 8.0.x兼容 Tomcat 8.5 到 9.0 都没有问题。注意 servlet-api 和 jsp-api 的 scope 必须是 provided因为 Tomcat 自带这些类如果打成包含依赖的 war 反而会类冲突。dependencies dependency groupIdorg.springframework/groupId artifactIdspring-webmvc/artifactId version5.3.21/version /dependency dependency groupIdorg.springframework/groupId artifactIdspring-jdbc/artifactId version5.3.21/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version3.5.10/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis-spring/artifactId version2.0.7/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.30/version scoperuntime/scope /dependency dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version4.0.1/version scopeprovided/scope /dependency dependency groupIdjavax.servlet/groupId artifactIdjsp-api/artifactId version2.0/version scopeprovided/scope /dependency dependency groupIdjavax.servlet/groupId artifactIdjstl/artifactId version1.2/version /dependency /dependencies版本号是最容易翻车的地方。比如 mybatis-spring 如果是 2.0 以下配 SqlSessionFactoryBean 的时候构造参数名称对不上mysql 驱动如果是 5.1.x连接 MySQL 8 数据库会出现认证插件不兼容的问题。如果拿到的源码里依赖版本很老建议统一升级到上面这组版本再改少量 API 就能跑通。3.2 Spring SpringMVC 配置web.xml 和 spring-mvc.xml 的关键项web.xml 要干三件事启动 Spring 根容器、配置 DispatcherServlet 拦截所有请求、加字符编码过滤器。注意 DispatcherServlet 的映射层级/会覆盖 Tomcat 的静态资源映射所以静态 css、js、images 要么走单独映射要么在 Spring 配置里加mvc:resources。我一般把接口和 JSP 都走 DispatcherServlet再把静态资源放在/static/**下单独放行。!-- web.xml 关键片段 -- context-param param-namecontextConfigLocation/param-name param-valueclasspath:applicationContext.xml/param-value /context-param listener listener-classorg.springframework.web.context.ContextLoaderListener/listener-class /listener 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 servlet servlet-namespringMVC/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-namespringMVC/servlet-name url-pattern//url-pattern /servlet-mappingCharacterEncodingFilter 这一步不能少。forceEncoding 设为 true 表示无论请求还是响应都强制用 UTF-8 编码否则 JSP 表单提交中文时即使页面编码对了POST 请求体还是会按平台默认编码解析。有的源码里省略了这个过滤器于是中文乱码时你会在 Service 层怎么找都找不到原因。spring-mvc.xml 里要开启注解驱动、扫描 controller 包、配置视图解析器。视图解析器的前缀后缀决定了 Controller 返回的字符串会落进哪个 JSP不是固定写死的但这是最常见的约定。!-- spring-mvc.xml -- mvc:annotation-driven mvc:message-converters bean classorg.springframework.http.converter.StringHttpMessageConverter property namesupportedMediaTypes list valuetext/html;charsetUTF-8/value /list /property /bean /mvc:message-converters /mvc:annotation-driven context:component-scan base-packagecom.hotel.controller/ mvc:resources mapping/static/** location/static// bean classorg.springframework.web.servlet.view.InternalResourceViewResolver property nameprefix value/WEB-INF/jsp// property namesuffix value.jsp/ /beanmvc:annotation-driven里的 message-converters 配置经常被人忽略。如果你在 Controller 里直接返回 JSON 给前端这时候需要 Jackson 的依赖但在 JSP 项目里更常见的是返回字符串、返回 ModelAndView用不上 JSON。所以不要为了“前后端分离”硬在 SSM 项目里加 JSON 转换增加复杂度还容易报错。3.3 MyBatis 连接 MySQL数据源与 mapper 扫包的参数怎么设MyBatis 整合进 Spring 时你不需要自己创建 SqlSessionFactory而是用org.mybatis.spring.SqlSessionFactoryBean交给 Spring 管理。数据源可以用 spring-jdbc 带的DriverManagerDataSource也可以用数据库连接池比如 HikariCP 或 DBCP。毕业设计用 HikariCP 是最省事的性能好配置也短。下面这是applicationContext.xml里的一段整合配置。!-- applicationContext.xml 中 MyBatis 配置 -- bean iddataSource classcom.zaxxer.hikari.HikariDataSource property namedriverClassName valuecom.mysql.cj.jdbc.Driver/ property namejdbcUrl valuejdbc:mysql://localhost:3306/hotel?useUnicodetrueamp;characterEncodingutf8amp;serverTimezoneAsia/Shanghai/ property nameusername valueroot/ property namepassword value123456/ property namemaximumPoolSize value10/ /bean bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBean property namedataSource refdataSource/ property namemapperLocations valueclasspath:mapper/*.xml/ property nametypeAliasesPackage valuecom.hotel.entity/ /bean bean classorg.mybatis.spring.mapper.MapperScannerConfigurer property namebasePackage valuecom.hotel.mapper/ /bean连接 URL 里的serverTimezoneAsia/Shanghai是 MySQL 8 必须加的不加的话驱动会报时区错误。useUnicodetruecharacterEncodingutf8要写在 XML 里就得把转义成amp;这是新手最容易看漏的地方写了会导致 XML 解析直接报错。如果你拿到的源码是 MySQL 5.7 的库驱动可以换回com.mysql.jdbc.Driver连接 URL 里的时区参数也可以去掉但推荐统一用 MySQL 8,因为 5.7 的驱动类在 8.0 驱动里已被移除不能混用。MapperScannerConfigurer 负责扫描com.hotel.mapper包下的接口如果你 Mapper 接口没放在这个包里或者Mapper注解没加Spring 容器启动时会正常但一调用就提示找不到 bean。我一般习惯同时扫描包并在接口上加Mapper注解双保险。到这里SSM 的整合骨架已经搭好。你可以启动 Tomcat 做一个健康的测试随便写一个 Controller 返回字符串看能不能通。不要直接开始写业务先用一个空接口验证 Spring 容器、数据库连接、JSP 视图三层都正常后面排查问题会省很多时间。4. 把预订流程跑起来从用户登录到订单生成的关键代码4.1 用户登录与权限拦截Filter 或拦截器怎么配登录是几乎所有管理系统的入口。用 SpringMVC 的拦截器来检查 session 里有没有用户对象比在每个 Controller 里重复判断要干净得多。先写一个实现HandlerInterceptor的类只拦截需要登录才能访问的路径比如/user/**下修改个人信息的请求还有/admin/**下的后台操作。public class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session request.getSession(); Object user session.getAttribute(loginUser); if (user null) { response.sendRedirect(request.getContextPath() /login.jsp); return false; } return true; } }在 spring-mvc.xml 里注册拦截器注意 excludePathPatterns 要把登录接口和注册接口排除掉否则用户还没登录就被拦住了。mvc:interceptors mvc:interceptor mvc:mapping path/user/**/ mvc:mapping path/admin/**/ mvc:exclude-mapping path/user/login/ mvc:exclude-mapping path/user/register/ mvc:interceptor bean classcom.hotel.interceptor.LoginInterceptor/ /mvc:interceptor /mvc:interceptor /mvc:interceptors这段配置有几个容易踩的细节。第一个是response.sendRedirect的地址必须带request.getContextPath()否则系统部署到非根路径下时会跳到错误的地址。第二个是拦截器只拦截 Controller 层的请求不拦截 JSP 直接访问如果你把 JSP 放在/WEB-INF/jsp下外部无法直接访问就必须走 Controller 转发这样拦截器才生效。第三个是登录成功后一定要session.setAttribute(loginUser, user)并且把用户存到 session 里而不是 request 里因为 request 在跳转后就会丢失。4.2 客房列表与条件查询Mapper 动态 SQL 的写法酒店前台最常见的功能是按照入住日期、房型、价格范围筛选可订房间。这个查询不能把条件写死要用 MyBatis 的动态 SQL。下面是一个 Mapper 接口和对应的 XML 映射。public interface RoomMapper { ListRoom selectAvailableRooms(Param(typeId) Integer typeId, Param(maxPrice) Double maxPrice); }!-- RoomMapper.xml -- mapper namespacecom.hotel.mapper.RoomMapper select idselectAvailableRooms resultTypecom.hotel.entity.Room SELECT r.room_id, r.room_number, r.status, t.type_name, t.price FROM room r LEFT JOIN room_type t ON r.type_id t.type_id where r.status 0 if testtypeId ! null AND r.type_id #{typeId} /if if testmaxPrice ! null AND t.price lt; #{maxPrice} /if /where ORDER BY t.price ASC /select /mapperwhere标签的作用是自动去掉第一个多余的 AND 或 ORif里的 test 判断的是 Java 参数值不是 SQL 列名。price 字段用了lt;是因为 XML 里不能直接写小于号,必须转义。如果你在这里直接写XML 解析会报错控制台会提示 “Element type ... must be terminated by the matching end-tag”。动态 SQL 的边界条件一定要考虑 null 字符串的情况。比如前端没选房型时传过来的可能是空字符串而不是 null此时if testtypeId ! null依然成立查出来的结果就不对。解决办法是在 Controller 里把空白串转成 null或者在if里同时判断typeId ! null and typeId ! 。我一般两处都做Controller 负责干净的参数Mapper 再兜底。4.3 提交订单与事务控制Transactional 的生效边界用户下单这个动作至少要操作两张表向订单表插入一条记录同时把房间表的状态改成已入住。这两步不能拆开否则会出现订单插进去了房间状态没改或者反过来房间被占了但订单没生成的脏数据。在 Service 方法上加上Transactional是最常见的做法。Service public class OrderServiceImpl implements OrderService { Autowired private OrderMapper orderMapper; Autowired private RoomMapper roomMapper; Override Transactional(rollbackFor Exception.class) public boolean createOrder(Order order) { if (orderMapper.insertSelective(order) 0) { return false; } Room room new Room(); room.setRoomId(order.getRoomId()); room.setStatus(1); return roomMapper.updateStatus(room) 0; } }这里必须写rollbackFor Exception.class,如果事务方法抛出的是运行时异常以外的异常比如 SQLException 被包装成了受检异常Spring 默认不会回滚。我见过很多毕设里事务方法贴着Transactional但rollbackFor没写然后数据处于不一致状态排查问题时发现日志里根本没有回滚记录。更大的坑是同类调用导致事务失效。如果你的 Controller 调用了 Service 的 A 方法A 方法里调用了同类的 B 方法而 B 上标着Transactional那这个事务是无效的因为 Spring 事务基于代理同类内的this调用绕过了代理对象。解决方案是不在同类里自我调用把 B 放到另一个 Service或者用AopContext.currentProxy()。捕获异常也会让事务失效——如果你在方法内把数据库操作包在 try-catch 里吞掉了异常Spring 看到方法正常返回自然就不回滚了。我自己写业务时事务方法里尽量不 catch 业务异常要么向外抛要么在 catch 里再抛一个 RuntimeException 作为信号。订单流程里还有一件容易被忽略的事计算订单总价。比较安全的做法是在 Service 层根据房间表里的房型价格和入住晚数现场算而不是从前端传入的 totalPrice 直接入库因为前端传的价格可以被篡改。下单接口里重新查一次房间数据再按(checkOut - checkIn) / 86400000 * price计算总价这样即使有人绕过页面直接 POST 请求也改不了价格。5. 酒店预订系统最常见的 5 个坑排查与避坑笔记5.1 JSP 页面中文乱码现象页面上的标题、房型名称、用户姓名全部显示成问号或乱码数据库里存的中文是正常的Controller 接收到的中文参数却变成乱码。原因三个地方的编码不一致。JSP 文件本身的编码、服务器渲染时的 response 编码、数据库连接的字符集参数。很多源码项目里 JSP 顶部只有% page contentTypetext/html;charsetUTF-8 %但文件本身在 Windows 下可能是 GBK 保存的于是页面内容直接用操作系统默认编码读取中文就乱了。解决统一用 UTF-8。JSP 头部写% page languagejava contentTypetext/html; charsetUTF-8 pageEncodingUTF-8 %idea 或 Eclipse 里把文件编码改成 UTF-8web.xml 里的 CharacterEncodingFilter 不要删MySQL 连接 URL 加上useUnicodetruecharacterEncodingutf8。检查顺序也是这个先看文件再看过滤器和连接串。5.2 Mapper 接口找不到或 SQL 语句报错现象Tomcat 启动不报错但请求某个接口时抛Invalid bound statement (not found)异常或者控制台打出 SQL 的语法错误。原因Invalid bound statement是 Mapper.xml 文件没有被扫描到。要么 mapperLocations 的路径写错了要么 Mapper.xml 里的 namespace 和接口全限定名不匹配。SQL 语法报错一般是 XML 里把大于小于号直接写出来或者表名用了 MySQL 关键字没有加反引号。解决先确认MapperScannerConfigurer的 basePackage 包名和接口所在包是否一致再看mapperLocationsclasspath:mapper/*.xml是否真的在 resources 目录下有 mapper 子目录。检查 namespace 是否能和接口路径对上比如com.hotel.mapper.RoomMapper就必须完整写在mapper namespacecom.hotel.mapper.RoomMapper。SQL 报错时把日志打印的语句复制到 Navicat 里手动执行定位到具体哪个符号解析不了。5.3 Transactional 不生效数据只写了一半现象下单后订单表新增了记录但房间状态没变成已入住或者反过来。查看数据库时发现两表数据不一致。原因事务没有真正生效最常见的是同类内部调用或者方法被private修饰或者rollbackFor没配。Spring 的事务代理只拦截通过代理调用的方法本类里的this调用不会经过代理。另一个原因是数据库表引擎是 MyISAM它不支持事务InnoDB 才能回滚。解决检查 Service 方法是不是public不要把this.save()这样的同类调用放到事务方法里把Transactional加到方法上并配置rollbackFor Exception.class。确认 MySQL 表的引擎是 InnoDB用SHOW TABLE STATUS LIKE order;查看 Engine 字段。排查时最简单的方法是在事务方法里故意抛出一个 RuntimeException看数据库是否回滚如果不回滚就是配置或调用方式出了问题。5.4 MySQL 连接不上或者连接池耗尽现象启动项目时提示UnknownHostException或者Connection refused也可能项目跑了一会儿接口变慢日志里出现Connection is not available, request timed out。原因jdbcUrl的 IP、端口、数据库名写错MySQL 8 驱动连接时少了serverTimezone参数导致建立连接直接失败连接池配置太小订单高峰期请求并发一大连接被占完后面的请求排队超时。解决先用命令行或 Navicat 本地确认mysql -u root -p -h localhost -P 3306能连上再检查驱动类名是com.mysql.cj.jdbc.DriverMySQL 8还是com.mysql.jdbc.DriverMySQL 5.7 驱动类和数据库版本要匹配。连接池maximumPoolSize建议不小于 10项目里如果有定时任务也要把连接池大小算进去。另外MySQL 8 默认密码插件是 caching_sha2_password如果用户密码还是老的 mysql_native_password驱动 8.0 也能连但某些 5.x 驱动不行升级驱动是首选。5.5 JSP 里 EL 表达式不显示现象页面在浏览器里直接显示${room.price}这样的字符串而不是循环输出的价格列表或者循环标签直接变成一大段 JSTL 源码。原因JSP 页面被认为不支持 EL原因通常是 web.xml 里配置了web-app版本太老2.3 以前或者 JSP 头部有isELIgnoredtrue或者 web.xml 用的 xsd 声明让容器默认关闭 EL。还有一种是缺少 JSTL 依赖导致c:forEach标签无法解析。解决确认 web.xml 的根元素是web-app版本 3.0 以上比如使用/schema/web-app_3_1.xsd在 JSP 页面头部显式加入% page isELIgnoredfalse %保证 EL 立刻开启pom.xml 里引入javax.servlet:jstl:1.2同时确认页面里写了% taglib prefixc urihttp://java.sun.com/jsp/jstl/core %。如果还不行重启 Tomcat 并清一下缓存因为 JSP 预编译缓存偶尔会保存旧版本。6. 让这个毕设项目真正可交付打包部署与毕业论文的衔接6.1 项目部署到 Tomcat 的两种方式本地开发时直接在 IDEA 里配置 Tomcat Server 调试是最方便的。需要把 Artifact 选择成 war exploded然后添加上下文路径/hotel启动后访问http://localhost:8080/hotel/。如果用的是 Eclipse配置 Server Runtime Environment 和 Deploy Path 也一样。交给老师或上传到服务器时用 Maven 的package命令打出 war 包把target/hotel.war丢到 Tomcat 的webapps目录下Tomcat 会自动解压。注意密码不要写在代码里写死用 jdbc.properties 配置并在打包时排除避免代码泄露。6.2 毕业论文里怎么描述系统架构和数据库设计毕业论文不需要写完整的代码但必须能把系统架构讲清楚。建议正文里画三张图系统功能模块图、系统架构图、数据库 E-R 图。架构图就按 SSM 分层画从上到下是 View 层JSP、Controller 层、Service 层、DAO 层MyBatis、数据库 MySQL。数据库设计部分不要只贴 SQL 脚本要说清楚每张表的作用核心字段如订单状态的含义以及表之间的关系。报告的重点则是把需求梳理清楚用户角色有顾客和管理员用例有注册登录、查询客房、在线预订、后台管理、订单处理。你手上如果有源码包里的论文模板不要直接整段抄模板老师查重时最敏感的是设计说明和结论部分。把系统的具体流程、表字段设计、功能截图放进去再配合这中间讲过的几个踩坑点写成“系统测试与问题分析”这部分反而是答辩时最能体现真实完成度的内容。6.3 一套可复用的自测清单与验收要点系统交付前自己按这个清单走一遍能避免答辩时现场翻车。前台流程用户注册、登录、修改个人信息、按条件搜索客房、提交预订、取消订单后台流程管理员登录、新增房型、新增房间、处理订单、查看评论异常流程不登录直接访问预订接口、重复预订同一房间、提交的订单价格被篡改。每一项验证完成之后在报告里写清楚测试步骤和预期结果。建议把数据库备份文件也放进“数据库脚本”目录并在交付文档里写清楚安装步骤先建库、再导入 SQL、修改 jdbc.properties、部署 war。我当年第一次交付项目因为忘了写部署步骤老师导入了一个空的数据库页面全是查询错误后来我习惯把每一步验证截图放进报告这个习惯让我后面两次交付都很顺利。做这类管理系统最大的教训不是技术细节写不出而是把代码跑通之后没有反向梳理整个流程导致答辩时只能照着 PPT 念。现在你手上有这套配置、代码和踩坑清单建议把每个功能从页面到 Controller 再到 Mapper 走一遍边看不明白的地方边对照源码。读代码的时候先看配置文件再看表结构最后才看业务方法这样效率最高。希望这篇笔记能帮你把这个项目做成一个真正讲得清楚、改得动代码的毕业设计作品。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?