
简介基于SSMlayuiEcharts的酒店管理系统完整源码与配套数据库面向正在学习JavaWeb的开发者及课程设计学生。项目整合Spring、SpringMVC、MyBatis后端框架采用layui构建管理页面并借助Echarts展现入住统计、订单营收等动态图表覆盖从数据库表设计到前后端数据交互的完整链路。压缩包共523个文件包括103个Java类、28个JSP页面、71个JavaScript脚本、26个CSS样式、30个XML配置以及SQL脚本等整体大小9.88MB目录分层明确、命名规范。数据库脚本中包含用户、房间、预订、订单等核心表的建表语句与初始数据便于快速部署测试。目前已获192人学习下载。通过研读源码可掌握酒店管理中入住、退房、订单、客房管理等核心业务模块并利用AccountVo、ChartsVo等数据传输对象理解分层架构中的VO设计思想同时学习MyBatis的SQL映射方式和Echarts图表的接入细节。对于巩固JavaWeb课程知识、完成毕业设计或提升SSM项目实战能力都很有帮助。1. 基于 SSMLayuiEcharts 的酒店管理系统课程设计选它值不值课程设计周最磨人的不是写代码而是选方向。JavaWeb 里酒店管理系统出现频率极高因为房态、预订、入住、退房、结算这些业务老师一听就懂学生也好演示。基于 SSMLayuiEcharts 的组合在课程设计里几乎是标准配置SSM 负责后端三层架构Layui 负责后台管理界面Echarts 负责把房态分布和营收趋势画成可视化图表。源码加数据库意味着不是只给一个静态页面而是从建表 SQL、MyBatis 映射、SpringMVC 控制器到 Layui 表格、Echarts 图表整条链路都是闭环的。项目导入 Idea、配好数据库就能跑起来沿请求链路拆开读再按自己的想法改需求。适合正在做 JavaWeb 课程设计的学生也适合想用完整案例串起 SSM 前后端交互的入门开发者。下面从项目骨架、数据库表、可视化接入、部署排错四个角度把落地过程完整过一遍。2. SSM 在酒店项目里的真实分工三层架构、依赖与配置文件2.1 为什么课程设计选 SSM 而不是 Spring Boot第一次做 JavaWeb 课程设计的人经常会问外面都用 Spring Boot 了老师还让用 SSM是不是过时了这个想法可以理解但课程设计这个场景下SSM 反而更合适。Spring Boot 把大量配置用自动装配藏起来了Controller 怎么写、请求怎么进、MyBatis 怎么连数据库你在 boot 项目里基本感知不到SSM 则要求你把 Spring 容器、SpringMVC 前端控制器、MyBatis 映射一个个手动配出来配的过程就是理解的过程。答辩时老师问「你的请求是怎么从页面进到数据库的」你能从 web.xml 一路讲到 SQL 语句这个分值和直接跑出页面的 Spring Boot 是完全不同的。另外SSM 是 JavaWeb 课程设计题库里的常青树意味着遇到问题搜「ssm javaweb 报错 xxx」能找到大量和你的项目结构几乎一模一样的帖子版本兼容的坑也基本被前人踩平。Spring 5.2.x、Tomcat 8.5、JDK 1.8 这套组合在学校机房的旧环境里也很稳定。如果你电脑上装的是老版 MyEclipse或者机房给的 JDK 1.7SSM 的兼容性比 Spring Boot 2.x 宽容得多。2.2 Maven 依赖与三种配置文件从 pom.xml 到启动入口SSM 项目一般用 Maven 管理依赖。pom.xml 里的核心依赖是五个spring-context、spring-webmvc、mybatis、mybatis-spring、mysql-connector-java。除此之外建议加一个 Druid 连接池和一个 Jackson 序列化工具前者让数据库连接有池化管理和监控后者负责把 Controller 返回的对象转成 JSON 交给前端。!-- Spring 核心 -- dependency groupIdorg.springframework/groupId artifactIdspring-context/artifactId version5.2.10.RELEASE/version /dependency !-- SpringMVC -- dependency groupIdorg.springframework/groupId artifactIdspring-webmvc/artifactId version5.2.10.RELEASE/version /dependency !-- MyBatis 与 mybatis-spring 整合包 -- dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version3.5.6/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis-spring/artifactId version2.0.6/version /dependency !-- MySQL 驱动与 Druid 连接池 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version5.1.49/version /dependency dependency groupIdcom.alibaba/groupId artifactIddruid/artifactId version1.2.8/version /dependency版本号这里特别说明Spring 5.2.x 配 Tomcat 8.5/9.0 和 JDK 1.8是课程设计里最稳的组合。mybatis-spring 的版本必须和 mybatis 主版本兼容2.0.6 对应 MyBatis 3.5.x如果你把 MyBatis 升到 3.5.10 而 mybatis-spring 还停在 1.3.x启动时大概率报 factory 找不到的异常。MySQL 驱动这里我常用 5.1.49对应 MySQL 5.7本机如果装的是 MySQL 8.x驱动要换成 8.0.33类名从 com.mysql.jdbc.Driver 变成 com.mysql.cj.jdbc.Driver这个坑第五章细讲。pom 配好之后SSM 项目至少需要三个配置文件分工如下配置文件存放位置职责web.xmlsrc/main/webapp/WEB-INF/注册 DispatcherServlet、字符编码过滤器、Spring 容器监听器spring-mvc.xmlsrc/main/resources/开启注解扫描、配置视图解析器、放行静态资源spring-mybatis.xmlsrc/main/resources/配置 Druid 数据源、SqlSessionFactory、Mapper 扫描web.xml 是所有请求的入口。DispatcherServlet 的 url-pattern 配成 /代表所有请求都先进 SpringMVC 前端控制器再由 RequestMapping 分发到具体方法。但这样 Layui 的 CSS、JS、图片也会被拦截必须在 spring-mvc.xml 里用 mvc:resources 把 /static/** 这类路径放行否则页面打开全是 404控制台一片红的 css 报错。提示idea 导入别人给的 SSM 源码时第一步先检查 Project Structure 里的 Artifacts确认 WEB-INF/lib 里有 Maven 依赖。这一步不做后面所有运行都会卡在类找不到。2.3 请求从 Layui 页面到数据库的完整链路理解这条链路是读懂整套源码的钥匙。以房间列表为例完整路径是Layui 的 table.render 通过 Ajax 发 GET 请求到 /room/list?page1limit10DispatcherServlet 根据路径找到 RoomController 的 list 方法Controller 调 RoomService 的 page 方法Service 再调 RoomMapper 的 selectByPageMyBatis 解析 XML 里的 SQL执行查询返回 List 集合Controller 把数据包装成 {code:0, msg:, count:总数, data:列表} 的 JSONJackson 序列化后返回给 Layuitable 组件根据 cols 配置渲染成带分页的表格。这条链路上每一环节出错的表现都不同页面 JS 报 404 是路由或静态资源问题接口返回 500 是 Controller 或 Service 抛异常返回 200 但表格空白是 JSON 结构不符合 Layui 要求。刚上手别急着用断点调试先从浏览器 F12 的 Network 面板看请求状态和响应体再一层层往后端定位。这个习惯比任何调试技巧都省时间。3. 把数据库表跑起来酒店四张核心表的建表 SQL 与数据库增删改查3.1 酒店业务拆成几张表房间、客户、订单、管理员课程设计的酒店系统不需要按真实连锁酒店 ERP 去设计四张表就够房间表 t_room、客户表 t_customer、订单表 t_order、管理员表 t_admin。房间表记录房号、房型、价格、状态客户表记录姓名、手机、身份证号订单表是核心把房间和客户关联起来记录入住日期、退房日期、总价、状态管理员表就是后台登录账号。CREATE DATABASE hotel_db DEFAULT CHARACTER SET utf8mb4; USE hotel_db; CREATE TABLE t_room ( id INT PRIMARY KEY AUTO_INCREMENT, room_number VARCHAR(20) NOT NULL COMMENT 房间号, room_type VARCHAR(20) COMMENT 房型单间/标间/套房, price DECIMAL(10,2) COMMENT 每晚价格, status TINYINT DEFAULT 0 COMMENT 0空闲 1已订 2入住 3维修, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE t_customer ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50), phone VARCHAR(20), id_card VARCHAR(20), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE t_order ( id INT PRIMARY KEY AUTO_INCREMENT, room_id INT, customer_id INT, check_in_date DATE, check_out_date DATE, total_price DECIMAL(10,2), status TINYINT DEFAULT 0 COMMENT 0未入住 1已入住 2已离店 3已取消, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE t_admin ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) UNIQUE, password VARCHAR(64), real_name VARCHAR(50) );状态字段用 TINYINT 数字而不是直接存「空闲」「已订」这种中文原因有两个一是数据库层面数字占 1 字节查询排序比字符串高效二是前端 Layui 的 templet 模板可以把数字映射成带颜色的标签比后端拼好 HTML 再返回灵活得多。注意订单表不建物理外键。课程设计数据量小物理外键在删除房间或客户时会强制检查引用反而让演示流程卡壳。通过 room_id、customer_id 做逻辑关联就够了。3.2 客房管理的 MyBatis 增删改查接口、XML 与 Service 层有了表结构用客房管理把增删改查四件事完整串一遍。MyBatis 的常规做法是 Mapper 接口定义方法、XML 文件写 SQL、Service 层做业务逻辑。客房模块包括分页查询、统计总数、新增、修改、删除五个方法。RoomMapper.java 接口public interface RoomMapper { ListRoom selectByPage(Param(offset) int offset, Param(limit) int limit); long countAll(); int insertRoom(Room room); int updateRoom(Room room); int deleteRoom(Param(id) int id); }RoomMapper.xml 对应实现select idselectByPage resultTypecom.hotel.entity.Room SELECT id, room_number, room_type, price, status, create_time FROM t_room ORDER BY id DESC LIMIT #{offset}, #{limit} /select select idcountAll resultTypelong SELECT COUNT(*) FROM t_room /select insert idinsertRoom parameterTypecom.hotel.entity.Room useGeneratedKeystrue keyPropertyid INSERT INTO t_room (room_number, room_type, price, status) VALUES (#{roomNumber}, #{roomType}, #{price}, #{status}) /insert update idupdateRoom parameterTypecom.hotel.entity.Room UPDATE t_room SET room_number #{roomNumber}, room_type #{roomType}, price #{price}, status #{status} WHERE id #{id} /update delete iddeleteRoom DELETE FROM t_room WHERE id #{id} /delete分页用 LIMIT #{offset}, #{limit} 这种物理分页课程设计的量级完全够不需要引入 PageHelper 插件。offset 由 Service 层计算公式是 (page - 1) * limit。提示LIMIT 的 offset 只能在 Java 代码里先算好再传入MyBatis 的 #{} 不会做乘法运算在 XML 里写 LIMIT #{page} * #{limit} 会直接报语法错误。insertRoom 里的 useGeneratedKeys 表示让数据库自增主键回填到 Room 对象的 id 字段插入后立刻能拿到新房间的 id后续做「新增后自动刷新表格」或跳转详情都会用到。updateRoom 是全字段更新前端表单把五个字段传回来即可不需要动态 SQL。Service 层把数据包装成 Layui 需要的格式返回给 ControllerService public class RoomService { Autowired private RoomMapper roomMapper; public MapString, Object page(int page, int limit) { int offset (page - 1) * limit; ListRoom rooms roomMapper.selectByPage(offset, limit); long total roomMapper.countAll(); MapString, Object result new HashMap(); result.put(code, 0); result.put(msg, ok); result.put(count, total); result.put(data, rooms); return result; } }3.3 Layui 表格对接后端table.render 的字段映射与返回格式后端接口写好后前端用 Layui 的 table 组件几行代码就能渲染出列表layui.use([table, layer, form], function () { var table layui.table; table.render({ elem: #roomTable, url: /room/list, page: true, cols: [[ { field: roomNumber, title: 房间号, width: 120 }, { field: roomType, title: 房型, width: 100 }, { field: price, title: 价格, width: 120, templet: function (d) { return ¥ d.price.toFixed(2); }}, { field: status, title: 状态, width: 100, templet: function (d) { var map {0: 空闲, 1: 已订, 2: 入住, 3: 维修}; return map[d.status] || 未知; }}, { title: 操作, toolbar: #roomBar, width: 160 } ]] }); });几个关键点url 指向的后端接口必须返回 {code:0, msg:, count:总数, data:数组}code 严格等于 0 才被认为是成功——这是 Layui 的固定约定。不少人第一次接 Layui 表格时后端返回 {success:true, data:[]}表格永远空白原因就在这。templet 是字段格式化入口房态数字转中文、价格加货币符号都靠它。toolbar 指向提前定义好的按钮模板Layui 会把行数据绑定到 lay-event 事件上。新增和编辑就是提交表单到 /room/save 或 /room/update然后用 layer.msg 提示成功再调 table.reload 刷新。删除用 layer.confirm 二次确认后发起 POST /room/delete。一套增删改查就通了客户管理、订单管理照同样的套路复制一份改字段即可。4. Echarts 数据可视化接入房态饼图与营收折线图的后端取数与参数配置4.1 后端统计接口按房态分组、按日期聚合营收Echarts 只是前端画图数据得靠后端 SQL 算好。统计接口我习惯单独建一个 StatsController专门暴露房态分布和营收趋势两个查询。房态分布就是从 t_room 表按 status 分组计数营收趋势是把已离店的订单按退房日期分组求和。注意营收的过滤条件是 status 2已离店未入住的预订和进行中的入住都不能算进收入这是统计最容易出错的地方。RestController RequestMapping(/stats) public class StatsController { Autowired private StatsMapper statsMapper; GetMapping(/roomStatus) public ListMapString, Object roomStatus() { return statsMapper.groupByRoomStatus(); } GetMapping(/revenue) public ListMapString, Object revenue(RequestParam String start, RequestParam String end) { return statsMapper.sumRevenueByDay(start, end); } }对应的 MyBatis 映射select idgroupByRoomStatus resultTypemap SELECT status AS name, COUNT(*) AS value FROM t_room GROUP BY status /select select idsumRevenueByDay resultTypemap SELECT DATE(check_out_date) AS day, SUM(total_price) AS revenue FROM t_order WHERE status 2 AND check_out_date BETWEEN #{start} AND #{end} GROUP BY DATE(check_out_date) ORDER BY day /selectresultType 用 map 而不是实体类因为统计结果没有固定结构字段名跟着 SQL 别名走。前端拿到的就是 [{name:0, value:12}, {name:2, value:8}] 这种结构正好是 Echarts 饼图 data 字段的输入格式。MySQL 5.7 及以上默认开启 ONLY_FULL_GROUP_BYSELECT 的字段必须在 GROUP BY 或聚合函数里否则 SQL 直接报错。日期区间用字符串传参只要前端传的是 yyyy-MM-dd 格式MySQL 隐式转换就能正确处理。4.2 Echarts 饼图与折线图的 option 配置渐变、刻度与格式化后端接口就绪前端页面上初始化两个图表。Echarts 的用法固定三步echarts.init 拿到实例请求数据setOption 画图。容器 div 必须有明确高度这是老生常谈但依然是最常见的翻车点。房态分布用环形饼图radius 数组第一个值是内半径、第二个是外半径这种写法让图表中间留白可以放总房间数之类的信息var statusChart echarts.init(document.getElementById(statusChart)); var statusLink {0: 空闲, 1: 已订, 2: 入住, 3: 维修}; $.get(/stats/roomStatus, function (res) { var data res.map(function (item) { return { name: statusLink[item.name] || item.name, value: item.value }; }); statusChart.setOption({ title: { text: 房态分布, left: center }, tooltip: { trigger: item, formatter: {b}: {c} 间 ({d}%) }, legend: { bottom: 10, data: data.map(function (i) { return i.name; }) }, series: [{ name: 房态, type: pie, radius: [40%, 70%], avoidLabelOverlap: true, label: { show: true, formatter: {b}: {c} }, data: data }] }); });营收趋势用折线图x 轴类型用 category数据从后端返回的数组里 map 出来。很多人纠结折线图 x 轴刻度太密跨度大时可以给 xAxis.axisLabel 设置 interval让 Echarts 每隔几个刻度显示一个想让面积图好看给 areaStyle 配渐变色var revenueChart echarts.init(document.getElementById(revenueChart)); $.get(/stats/revenue, { start: 2025-01-01, end: 2025-01-31 }, function (res) { revenueChart.setOption({ tooltip: { trigger: axis }, xAxis: { type: category, boundaryGap: false, data: res.map(function (item) { return item.day; }), axisLabel: { interval: 2 } }, yAxis: { type: value, axisLabel: { formatter: ¥{value} } }, series: [{ name: 营收, type: line, smooth: true, symbol: circle, data: res.map(function (item) { return item.revenue; }), areaStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: rgba(64, 128, 255, 0.45) }, { offset: 1, color: rgba(64, 128, 255, 0.02) } ]) } }] }); });Echarts 柱状图设置渐变色的套路和上面完全一样把 areaStyle 换成 itemStylecolor 用 LinearGradientseries 的 type 改成 bar就是一张带渐变效果的柱状图。这里有个原则要记住series 的 data 必须是纯数组不能在 setOption 里直接传对象引用最稳妥的做法是先 map 一次把字段名统一成 Echarts 认识的 name 和 value。4.3 图表拿不到数据时的三个自查点图表空白时按顺序排查三处。第一F12 的 Network 面板看统计请求是否发出且返回 200如果 404检查 Controller 的 RequestMapping 路径和前端 url 是否一致这是最典型的路径对不上。第二看响应体是不是合法 JSON如果 Controller 忘了加 ResponseBody 或 RestController返回的是一段字符串Echarts 拿不到数据自然白屏。第三确认初始化时机——echarts.init 必须在对应 div 渲染完成之后执行如果你在页面顶部同步 init 而 div 还在后面拿到的是 null 或者宽高为 0 的容器。注意echarts.init 的容器必须有明确高度。用百分比高度时父容器也得有高度否则图表渲染成 0 高度控制台一切正常但就是看不见图这个现象最像玄学。5. 课程设计部署常见问题排查Tomcat 启动失败、MySQL 连接失败与中文乱码的 5 个坑5.1 Tomcat 启动失败ClassNotFoundException 与端口占用现象Idea 里点运行Console 报 java.lang.ClassNotFoundException: org.springframework.web.servlet.DispatcherServlet或者提示 Port 8080 was already in use。原因DispatcherServlet 找不到几乎都是 Maven 依赖没有部署到 Tomcat 的 WEB-INF/lib 目录。这在 Idea 里太常见了——把源码导入后 Project Structure 的 Artifacts 没配好运行时的类路径里根本没有 spring-webmvc.jar。端口占用则是之前关掉的 Tomcat 进程残留后台或者 8080 被别的程序占了。解决File - Project Structure - Artifacts选中项目的 exploded war 输出在 Output Layout 里确认 WEB-INF/lib 存在且包含 Maven 依赖没有就右键添加。端口占用用 netstat -ano | findstr 8080 找到 PID在任务管理器结束进程或者把 Tomcat 的 HTTP 端口改成 8081。这个坑在 Idea 运行 JavaWeb 项目配置里出现频率最高建议拿到任何源码第一时间检查 Artifacts。5.2 MySQL 连接失败驱动类名、useSSL 与 serverTimezone现象启动时报 Communications link failure数据库相关页面打不开或者控制台出现 The server time zone value Öйú±ê׼ʱ¼ä is unrecognized 这种乱码时区报错。原因JavaWeb 连接 MySQL 时驱动类名和连接 URL 跟 MySQL 版本强相关。MySQL 5.x 的驱动类是 com.mysql.jdbc.DriverMySQL 8.x 改成了 com.mysql.cj.jdbc.Driver8.x 还强制要求 URL 里指定 serverTimezone否则报时区错误。那串乱码其实是中文「中国标准时间」按默认编码解析的结果看着吓人本质就是时区没指定。解决先确认本机 MySQL 版本再统一改 jdbc.properties。MySQL 8.x 用这一行jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/hotel_db?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8 jdbc.usernameroot jdbc.password你的密码MySQL 5.7 则把驱动改回 com.mysql.jdbc.DriverURL 去掉 useSSL 和 serverTimezone但 characterEncodingutf8 必须保留否则后面插中文全变问号。如果项目里用了 Druid 连接池initialSize、maxActive 这些参数先按默认走等启动报连接池超时再针对性调整。5.3 中文乱码页面、请求、数据库三处编码不一致现象页面表格显示正常往数据库插中文后读出来是 ??或者新增房间时中文直接报 Incorrect string value。原因乱码是编码不一致的典型症状常见于三处Tomcat 接收请求的编码、服务器返回响应的编码、数据库表的字符集。只要有一处是默认的 ISO-8859-1中文就变问号或火星文。还有个常见漏配web.xml 忘了加 CharacterEncodingFilter前端表单提交的中文在进入 Controller 前就已经错了。解决三处同时改。web.xml 加编码过滤器forceEncoding 设为 true保证请求和响应都强制 UTF-8filter 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数据库侧建库时写了 DEFAULT CHARACTER SET utf8mb4 就不会有问题已经建错的表可以用一条命令补救ALTER TABLE t_room CONVERT TO CHARACTER SET utf8mb4;这句算是修改表结构的后悔药。页面侧保证 Layui 的 HTML 在 head 里声明 且文件保存编码选 UTF-8。5.4 Layui 表格渲染空白返回 JSON 格式不对现象房间列表页面打开后表格一直转圈最后变成空白F12 看请求是 200响应体里也有数据但 Layui 就是不渲染。原因Layui table 组件对后端返回格式有硬性要求必须是 {code:0, msg:, count:总条数, data:数组}。很多人在其他框架里习惯返回 {success:true, rows:[...]}Layui 解析不到 code 为 0 和 data 数组就什么都不画。这个坑第一次接触 Layui 时几乎人人都会踩。解决后端统一包装最简单是像第三章 RoomService 那样用 Map 组装四个字段返回也可以写一个通用 Result 类。如果实在不想改后端前端可以在 table.render 里加 parseData 回调把数据重新映射成 Layui 想要的格式。但课程设计建议改后端因为这是前后端接口规范化的基本意识写进报告里也是加分项。5.5 Echarts 图表不显示容器高度与 DOM 就绪时机现象统计页面打开后图表区域一片空白控制台没有任何 JS 报错Network 里 /stats/roomStatus 也正常返回了数据。原因最常见的是容器高度为 0——div 没设 height或者父容器是 display:none 状态echarts.init 拿到的容器宽高都是 0图表自然画不出来。另一种是初始化时机问题脚本在 div 渲染之前执行了 echarts.init实例化时容器还不存在。解决给图表容器写死高度比如 styleheight: 400px不要依赖内容撑开。脚本执行时机放在 DOM 加载完成后jQuery 的 $(function(){...}) 或把 script 标签放 body 末尾都行。如果图表在 Layui 弹窗里必须在 layer.open 的 success 回调里初始化不能在弹窗打开前就 init切 tab 后再回来对已有实例调用 chart.resize() 重新计算尺寸。6. 答辩前必做的三个验证Postman 自测接口、SQL 日志与图表联动6.1 用 Postman 把后端接口当黑匣子测一遍答辩前把每个 REST 接口用 Postman 过一遍对路径、参数、返回结构做到心里有数。GET /room/list?page1limit10 应该在响应体里看到 count 和 dataPOST /room/save 传 JSON 后数据库能查到新记录。顺手整理一张接口表路径、方法、参数、返回示例。老师问任何一个功能点你能立刻说出对应接口和返回结构这个表现比现场翻代码加分得多。6.2 打开 MyBatis SQL 日志让每条 SQL 现形SSM 的黑匣子有两层SpringMVC 的请求分发、MyBatis 的 SQL 执行。打开 SQL 日志只需在 MyBatis 配置文件里加一个设置configuration settings setting namelogImpl valueSTDOUT_LOGGING/ /settings /configuration启动后控制台会打印每条执行的 SQL 和绑定参数。作用有两个一是验证 #{} 参数绑定是否正确看预编译语句有没有被正常替换二是排查空结果或慢查询时直接看到数据库实际执行了什么而不是对着代码猜。6.3 一个加分技巧点击饼图联动订单表格课程设计如果能演示一个交互联动场景评委印象会明显不一样。Echarts 饼图支持点击事件点击某个房态区块时把对应状态值传给 Layui 表格重新加载比如点击「入住」区块订单表立刻只显示入住中的订单statusChart.on(click, function (params) { var statusValue params.data.statusValue; table.reload(orderTable, { where: { status: statusValue }, page: { curr: 1 } }); });实现关键饼图的 data 里预设好 statusValue 字段比如 {name:入住, value:8, statusValue:2}点击事件里取出来传给 table.reload。这样统计接口、图表、列表三部分就联动起来了不再是各管各的静态页面。我当年做课程设计时在 Echarts 图表不显示这个问题上栽过一次调了一晚上以为数据格式不对最后发现只是 div 没给高度。从那以后养成了习惯任何前端组件不渲染第一步开 F12 看有没有报错第二步看 Network 接口返回两步排查能定位九成问题。希望帮到你。本文还有配套的精品资源点击获取