ARTICLE DETAIL

资讯详情

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

基于SSM的酒店管理系统毕业设计:从环境搭建到答辩加分

基于SSM的酒店管理系统毕业设计:从环境搭建到答辩加分 简介这是一套面向高校毕业设计场景的Java酒店管理系统完整项目包基于SSM框架与MySQL数据库开发适合计算机相关专业学生用于选题参考、功能扩展和答辩准备。系统按前台与后台划分前台面向住客提供客房信息、餐品信息、酒店介绍、温馨服务、折扣活动等功能后台面向管理人员覆盖系统用户管理、商家管理、客房管理、餐品管理、酒店管理等核心模块能较完整地体现SSM分层开发流程。资源包共1061个文件大小约90.69MB主要包含Java源码、JSP页面、class编译文件、XML与properties配置、JS/CSS前端资源及HTML页面同时附有SQL脚本、项目文档、PPT和演示视频便于本地搭建运行与理解整体结构。目前已有196人学习浏览内容覆盖数据库设计、后端接口、前台展示等关键环节可为毕业设计写作和二次开发提供可参考的工程模板。1. 拿到Java毕业设计基于ssm酒店管理系统(源码文档PPT录像演示).zip之后先别急着解压很多同学拿到这个zip做的第一件事是双击解压然后直接冲进源码目录试图从第一行代码开始读。但这类基于ssm框架的酒店管理系统毕业设计真正卡住人的从来不是代码而是环境JDK版本、Maven仓库、Tomcat配置、MySQL驱动哪一个对不上登录页都看不到。它解决的是酒店行业里最日常的需求——客房浏览、在线预订、入住退房、后台订单管理、房态统计技术栈用SpringSpringMVCMyBatis串成一条完整的请求链路。适合三类人正在做毕业设计的学生需要Java课程设计案例源码的初学者以及想快速把SSM整合流程跑一遍的转行开发。源码只是答案文档和录像才是地图。我会按替人排查这类项目的顺序展开先看懂结构再把它跑起来改出你自己的功能最后绕开那些让所有人翻车的坑。2. 先把SSM酒店管理系统的架构看懂一张订单背后的请求链路2.1 为什么毕业设计选SSM而不是Spring BootSSM是SpringSpringMVCMyBatis的缩写三个框架各管一段Spring负责对象创建、依赖注入和事务SpringMVC负责把浏览器的URL请求分发给Controller再返回视图MyBatis负责把Java方法和SQL映射起来。这个组合在java面试题里出镜率极高IOC、AOP、DispatcherServlet、#{}和${}的区别都是常客。很多学校把SSM当课程设计主推不是因为它是主流酒店管理系统的首选后台方案而是因为这套框架每一层都是显式配置你可以在答辩时清楚说出请求怎么进来、数据怎么查出来、事务什么时候提交。Spring Boot开发快但自动配置把细节都藏住了老师一问你的DispatcherServlet在哪注册的容易把自己问住。所以毕业设计选SSM本质上是选一个适合讲原理的舞台。更现实的原因是市面上大量Java课程设计案例源码和毕业设计模板都还跑在SSM上。你拿到的这个zip大概率是几年前的项目pom.xml里还是spring-webmvc、mybatis-spring、javax.servlet-api这一批坐标。如果以后要做智慧酒店管理系统这类进阶项目SSM这套分层也能平滑迁移到Spring Boot因为Service和Mapper层几乎不需要动变的只是Controller的注解和配置方式。拿到源码后先打开pom.xml看三个东西spring版本、mybatis版本、servlet-api的scope。常见的老项目spring版本是4.xmybatis-spring是1.xservlet-api是provided。这时候你本机的Tomcat版本不能太新Tomcat 9配Servlet 3.1没问题Tomcat 10如果用的还是javax而不是jakarta命名空间启动大概率直接报错。这个版本匹配关系就是环境玄学的源头。对比项SSMSpringSpringMVCMyBatisSpring Boot配置方式XML注解混合配置可见自动配置细节被隐藏打包方式war包部署到Tomcatjar内嵌容器学习成本高但原理清楚低上手快答辩体验每个环节都能讲容易讲成配置一下就通了2.2 从数据库表到页面客房、预订、入住、退房的数据流这类酒店管理系统的表设计通常围绕一个核心词房态。常见表有管理员表admin、用户表user或member、房型表room_type、客房表room、订单表orders或reserve还可能有一张会员表。订单表是连接前台操作和后台房态的中枢它至少要有用户ID、房间ID、入住日期、退房日期、订单状态字段。数据流可以这样走前台用户在客房列表页点预订JSP表单把roomId和日期提交给OrderController.save()Controller调用OrderService.bookRoom()Service先通过RoomMapper.selectById()查房再判断房间状态是否为0空闲然后OrderMapper.insert()写订单最后RoomMapper.updateStatus()把房间改成1已订。任何一步失败整个操作要回滚这就是为什么SSM里Service层要加Transactional。反向的读操作更简单页面发起GET请求SpringMVC根据RequestMapping找到Controller方法方法调用Mapper层查数据库返回的ModelAndView把数据填进JSP。MyBatis的Mapper XML里写SQLJava接口里写方法签名两者通过namespace和方法名一一对应。源码阅读的捷径是先把表关系画出来我一般会在纸上画一个mini ER图room_type是room的父表room是orders的父表user是orders的另一个父表。这个ER图画完整个系统就变成了房间有类型订单关联房间和用户这么一句话。表里的状态字段建议全部用数字枚举比如room.status0空闲、1已订、2入住、3维修order.status0待确认、1已确认、2已入住、3已退房。这些数字会在后面写SQL时反复出现建议写成一个StatusConst常量类而不是在Service里直接写裸数字。答辩时如果你能说出我为什么把状态抽成常量这是加点项。订单状态含义关联房间状态0待确认0空闲1已预订1已订2已入住2入住3已退房0空闲2.3 跑通最小流程用Maven命令验证依赖和环境在IDEA里点绿色三角形启动之前我一般会先在命令行跑一次Maven打包。这个动作能一次性暴露JDK版本、Maven仓库、依赖下载三个问题比在IDE里反复重启快得多。mvn clean package -DskipTestsclean会删除target目录package会执行编译并打成war包-DskipTests跳过测试类避免环境差异导致测试挂掉。如果这一步抛Cannot resolve symbol或者下载卡住多半是Maven的中央仓库连不上。本地项目里常见做法是在settings.xml里配置阿里云镜像mirror idaliyunmaven/id urlhttps://maven.aliyun.com/repository/public/url mirrorOfcentral/mirrorOf /mirror参数说明mirrorOf填central表示只镜像Maven中央仓库不会干扰其他私有仓库url走国内镜像下载速度会明显改善。这个配置要放在本机的{MAVEN_HOME}/conf/settings.xml不是项目里。如果项目里还有自己的私有仓库mirrorOf要改成external:*或者直接注释掉避免冲突。把mvn clean package -DskipTests跑通后你会得到一个war包这是整个项目的编译产物。如果这一步报了[ERROR] Failed to execute goal ... Unsupported Java说明pom.xml里的maven.compiler.source和target版本与你本机JDK不一致。改法是在pom.xml的properties里加properties maven.compiler.source1.8/maven.compiler.source maven.compiler.target1.8/maven.compiler.target /properties参数说明1.8代表Java 8字节码级别配合IDEA的Project SDK一起看。有些老项目用source1.7/source如果本机只有JDK8也可以直接改成1.8基本不影响运行。打包成功代表环境可信环境可信之后后面所有报错都可以放心地往代码逻辑上找。3. 用IDEA把zip工程跑起来从解压到看到登录页的四步3.1 导入项目前先做三件事JDK版本、Maven仓库、编码格式拿到解压后的源码不要直接双击pom.xml。先做三件小事能省掉后面80%的报错。第一确认JDK版本。SSM老项目十有八九基于JDK1.8你本机如果装了JDK17甚至21编译时会出现source option 7 is no longer supported或者com.sun.*相关错误。在IDEA的Project Structure里把Project SDK和Project language level统一设在1.8同时检查pom.xml里的maven.compiler.source和maven.compiler.target保持跟本机一致。这里有血泪经验语言级别设对了还不够Maven的settings.xml里如果锁定了JDK profile也会覆盖项目配置所以改了IDEA还报错就去翻settings.xml。第二确认Maven仓库。打开settings.xml看本地仓库路径是否存在镜像是否配好。很多机器第一次跑项目下载几百MB依赖需要很久这不是卡住是仓库里什么都没有。等的时候可以开mvn -U强制更新快照但正常配置不需要。如果IDEA里一直提示Cannot resolve org.springframework:spring-webmvc:4.3.18.RELEASE先去本地仓库目录找这个jar在不在不要在代码里找原因。第三统一编码格式。IDEA右下角把Global Encoding、Project Encoding、Properties Files都改成UTF-8否则JSP页面上的中文会变成乱码而且这个乱码是编译期写入的运行期再改后端的编码过滤器都救不回来。我见过的翻车案例里编码问题排第二仅次于版本问题。改完编码后把src/main/webapp/WEB-INF/web.xml打开看一眼里面如果配置了CharacterEncodingFilter它的encoding参数也得是UTF-8。3.2 修改数据库连接配置jdbc.properties里不止有密码SSM项目典型结构是src/main/resources下放着jdbc.properties或db.properties。打开它你会看到类似下面的内容jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/hotel?useUnicodetruecharacterEncodingutf8useSSLfalse jdbc.usernameroot jdbc.password123456最容易踩坑的是MySQL 8。如果本机装的是MySQL 8.x驱动类名要改成com.mysql.cj.jdbc.Driver并且URL要加serverTimezoneAsia/Shanghai。老项目写的com.mysql.jdbc.Driver在MySQL 8里虽然还能加载但会抛Communications link failure原因不是网络而是驱动版本跟服务端认证协议不匹配。characterEncodingutf8是给中文用的useSSLfalse是为了免去SSL证书握手。如果你用的MySQL 8驱动还需要考虑allowPublicKeyRetrievaltrue否则连接时偶尔会报Public Key Retrieval is not allowed。参数说明useUnicodetrue要和characterEncodingutf8成对出现serverTimezone必须填否则默认取服务器时区中国时区的时间会偏8小时。改完连接配置再启动项目数据库问题基本能消灭一半。如果项目里用了数据库连接池比如dbcp或c3p0还要检查最大连接数配置默认值太小会偶发连接超时。# 示例MySQL 8的完整配置 jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/hotel?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue jdbc.usernameroot jdbc.password1234563.3 初始化数据库用SQL文件建库别用GUI工具导错字符集源码包里的文档部分一般会附带一份hotel.sql这是整间酒店管理系统的地基。先在MySQL里建一个库再导入CREATE DATABASE IF NOT EXISTS hotel DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE hotel; source /path/to/hotel.sql;utf8mb4比utf8能多存一些生僻字和emojiutf8mb4_general_ci是大小写不敏感的排序规则。source是MySQL命令行导入命令文件路径用绝对路径最稳。如果文件太大也可以用mysql -u root -p hotel hotel.sql但导入前务必先建好库。常见错误是用Navicat的运行SQL文件导入结果发现所有中文字段变成问号。原因通常是SQL文件本身是UTF-8而GUI工具的连接字符集默认不是UTF-8。我一般会在GUI工具的连接属性里显式设置encodingutf8再导入。导入成功后别急着看效果先跑一条SELECT * FROM admin验证中文是否正常。数据是乱码的话后面所有功能都是带病运行。建议导入后顺手检查三张表admin里有没有管理员账号、room_type里有没有房型、room里有没有房间样本数据。有些精简版SQL只建表不插数据导致登录后页面空空如也。如果发现表是空的别慌用INSERT补几行测试数据。比如给room_type插入标准间大床房给room插入几间对应房号的房间酒店管理系统立刻就有演示素材了。3.4 启动Tomcat并验证登录日志里这两行是关键IDEA里配置Tomcat我通常走三条配置Run-Edit Configurations--Tomcat Server在Deployment页签里把项目Artifact加进去Application context填/hotel在Server页签里把URL改成http://localhost:8080/hotel。这里的/hotel就是你后续访问的根路径如果填成/所有页面里的相对路径都会乱。然后点Debug启动。启动日志里出现INFO: Server startup in [xxx] milliseconds说明Tomcat起来了如果出现SEVERE: Exception starting filter [encoding]则是filter初始化失败。更常见的是端口被占用日志末尾会提示Port 8080 was already in use解决办法是改Tomcat的server.xml里的Connector端口或者在IDEA里换HTTP port。如果项目日志里出现ClassNotFoundException: org.springframework.web.context.ContextLoaderListener说明Spring的jar没有进入Tomcat的webapp目录。去Project Structure-Artifacts里看是否有lib目录把Maven依赖的Output Layout加进去重新构建后再启动。看到登录页后先用文档里给的管理员账号登录后台。如果密码不对去数据库的admin表用UPDATE admin SET password123456 WHERE id1重置。注意SSM项目很多密码存的是MD5你看到字段值是32位字符串时别手改成明文得先算好MD5(123456)再写进去。登录成功后立刻去看房间管理页如果列表正常显示说明数据库连接、Mapper扫描、JSP渲染这一整条链路都通了后面就是业务层面的调优。4. 把功能改成自己的从房间管理到订单状态的完整链路4.1 前后台功能清单拆解先找准主链路SSM酒店管理系统毕业设计的功能一般分两半。前台给顾客用注册登录、客房列表、按日期和房型查询、在线预订、我的订单。后台给管理员用房间类型管理、客房信息维护、订单审核、入住/退房操作、会员管理、统计报表。拿到源码后不要每个页面都点一遍先走通一条主链路用户注册 - 用户登录 - 浏览客房 - 提交预订 - 管理员登录 - 看到新订单 - 确认入住 - 办理退房 - 房间恢复空闲。这条链路跑通项目就活了。其余功能都是在这条链上加权限、加校验、加统计。选主链路时有个判断标准看订单表。订单表是整张ER图的中心状态字段一般用数字表示0待处理、1已预订、2已入住、3已退房每变一次关联的房间状态也要同步变。你只要读懂这条状态流转答辩时被追问任何数据表关系都能答上来。如果源码里前后台访问权限是通过HandlerInterceptor控制的还要找出拦截器配置的excludePathPatterns。前台登录页、注册页、静态资源css/js/images都应该放行否则游客连查看客房列表都会被重定向到登录页。这个拦截器配置也值得在答辩时展示它是没写配置文件就会导致404的典型知识点。4.2 订单状态机预订、入住、退房的状态流转与SQL边界状态机是这类系统里最值得讲给评委听的点。我用文字描述一遍顾客点预订时Controller把roomId、userId、开始日期和结束日期送给Service。Service先查房间房间状态必须是0才能下单。下单成功后订单状态从0变成1房间状态从0变成1这个动作必须在一个事务里完成。Transactional(rollbackFor Exception.class) public int bookRoom(Order order) { Room room roomMapper.selectById(order.getRoomId()); if (room null || room.getStatus() ! 0) { return -1; // 房间不可订 } int r1 orderMapper.insert(order); // 写订单 int r2 roomMapper.updateStatus(order.getRoomId(), 1); // 锁房 if (r1 0 r2 0) { return 1; } else { return -1; } }Transactional(rollbackFor Exception.class)表示方法内任何异常都会触发回滚。roomMapper.updateStatus的SQL一般写成UPDATE room SET status #{status} WHERE id #{id} AND status 0后面这个AND status 0很关键它相当于一个乐观锁防止两个人同时订同一间房。如果SQL只写WHERE id #{id}并发场景下第二次预订会把第一次的房态覆盖掉这就是超卖。退房流程反过来先改订单状态为3再把房间状态改回0。入住流程是把订单状态从1改成2同时给房间绑定入住人信息。建议把状态值写成一个常量类OrderStatus而不是在Service里散落魔法数字。如果原始项目里没有常量类你加一个然后替换掉所有数字这会是很容易被老师看到的改进点。public final class OrderStatus { public static final int WAITING 0; public static final int BOOKED 1; public static final int CHECKED_IN 2; public static final int CHECKED_OUT 3; }4.3 给会员折扣加一个字段从数据库到JSP要动十层老师最常见的改需求是给系统加个会员折扣。这个需求看起来简单但SSM的每一层都要动改错一层功能就悄悄坏掉。先在数据库加列ALTER TABLE room_type ADD COLUMN discount DECIMAL(3,2) NOT NULL DEFAULT 1.00; ALTER TABLE member ADD COLUMN discount DECIMAL(3,2) NOT NULL DEFAULT 0.95;然后按这个顺序改代码实体类加属性如RoomType.discount、Mapper接口加方法int updateDiscount(Param(id) int id, Param(discount) BigDecimal discount)、Mapper XML写update room_type set discount #{discount} where id #{id}、Service加对应方法和Transactional、Controller加RequestMapping接收参数、页面加表单。每改一层都要注意类型转换——DECIMAL对应BigDecimal别用double接否则金额计算会出精度问题。MyBatis的传参有个易错点多参数时必须在接口方法上用Param注解否则XML里#{discount}会报BindingException。单参数且是JavaBean时可以直接用属性名这是SSM框架里很经典的面试题。如果这个折扣参数需要在预订时参与金额计算那更要检查Service里计算价格的那段代码别把折扣只存没用。改页面时room_type_list.jsp里要加一个输入框RoomTypeController里要加一个RequestMapping(/editDiscount)。JSP表单的name属性必须和Controller参数名一致比如namediscount对应RequestParam(discount)。如果对不上浏览器提交过来就是null数据库字段不会有变化但也不报错这种静默失败最头疼。4.4 给答辩留一手把统计报表换成ECharts很多SSM酒店管理系统的后台自带一个简单的报表页面数据往往是后端拼好List然后循环输出成HTML表格。答辩时你可以把它升级成ECharts图表这一步很加分因为评委看到的不是会用框架而是会做前后端数据对接。后端改动核心是提供一个返回JSON的接口Controller RequestMapping(/statistic) public class StatisticController { Autowired private RoomMapper roomMapper; RequestMapping(/occupancy) ResponseBody public ListMapString, Object occupancy() { ListMapString, Object list roomMapper.countByStatus(); return list; } }ResponseBody会把返回值自动转成JSON项目里如果配了Jackson或fastjson。Mapper的SQL可以写成select idcountByStatus resultTypejava.util.HashMap SELECT room_status AS name, COUNT(*) AS value FROM room GROUP BY room_status /select前端用$.ajax拿到数组填进ECharts的series.data。这里要注意Map作为resultType时列别名必须写清楚否则前端拿不到name和value。这个接口改完你就能在现场把入住率统计从一个表格变成一张动态饼图视觉冲击力完全不一样。如果项目里用的是JSPjQuery前端代码可以这样起$.ajax({ url: ${pageContext.request.contextPath}/statistic/occupancy, type: GET, dataType: json, success: function (data) { var chart echarts.init(document.getElementById(chart)); chart.setOption({ series: [{ type: pie, data: data }] }); } });注意${pageContext.request.contextPath}是JSP里取上下文路径的标准写法别硬编码/hotel否则改部署路径又要崩。5. 毕业设计避坑指南从环境搭建到答辩演示的5个常见问题以下五条是我每次帮别人看这类项目时几乎都会遇到的高频问题。每条按现象、原因、解决三步写照着处理就行。5.1 现象IDEA里Tomcat能启动但页面404原因项目Artifact没有把src/main/webapp作为Web资源目录或Application context配错。很多SSM工程是从别人电脑拷贝来的IDEA的Project Structure里Web Resources路径指向了原来的C:\xxx换机器就失效。解决在Project Structure里找到Web模块把Web Resource Directory手动改成src/main/webappDeployment里的Application context改成/hotel。注意改完后要重新打war包旧的Artifact不清理会继续用老路径。如果用的是Tomcat的Exploded方式还要检查target/classes里有没有编译产物。出现404后先在浏览器地址栏确认URL是否带了项目名这一步就能排除一半问题。5.2 现象数据库能连上但页面中文全是问号原因连接串缺少characterEncodingutf8或建库时字符集不是utf8mb4或JSP页面本身的编码不是UTF-8。三个环节任何一个断掉都乱码。解决重新检查jdbc.properties和建库语句全文搜索characterEncoding关键字。JSP页面顶部如果有pageEncodingISO-8859-1全部改成UTF-8。这三处统一后中文乱码基本可以根治。如果页面已经有中文了把URL加参数连接串再重启不要只改数据库端因为HTTP响应头的编码由服务器或Filter决定。5.3 现象Mapper方法报Invalid bound statement (not found)原因Mapper接口的方法在XML里没有对应id或namespace写错或XML文件没有被打进classes目录。SSM项目里XML默认放在src/main/java下面的话Maven打包时不会拷贝导致运行时找不到SQL。解决把Mapper XML移到src/main/resources并保持包路径一致在pom.xml里加resources配置显式包含**/*.xml。还要查Spring配置里的mapperLocations路径比如classpath:mapper/*.xml确保扫描到。这类问题报错信息看似复杂其实定位起来最快先看编译产物里有没有同名XML再看namespace的最后一段是不是接口全限定名。5.4 现象预订房间后再次查询房间状态没变原因Service方法上的Transactional没加或者加了但updateStatus的SQL写得太宽松——WHERE id ?没有带status 0条件导致并发时两次预订都成功第二次覆盖第一次。解决在bookRoom()上补Transactional并在更新SQL里加状态条件。如果想要更强的并发控制可以给表加version字段做乐观锁每次更新时version version 1。这个坑在答辩演示时很可能被老师提问提前处理能顺畅回答。排查时可以故意开两个浏览器窗口快速点两次预订如果能生成两笔订单就是事务或状态条件的问题。5.5 现象录像演示里功能都正常自己跑却报错原因录像演示用的环境是下载者电脑的旧快照常见的版本错配包括JDK高版本编译了低版本字节码、Tomcat版本过老不支持Servlet 3.1、MySQL驱动版本和数据库不匹配。录像本身是对的但环境是黑匣子。解决先按文档核对三个版本号JDK 1.8、Tomcat 8.5或9、MySQL 5.7或8。如果找不到依赖版本直接在pom.xml里看spring-framework和mybatis-spring的版本再按官方兼容矩阵调整。我自己的经验是用Tomcat 8.5配JDK 1.8是最省心的组合。另外录像演示的作用是让你知道功能全貌不是让你对着操作抄真正跑通时多踩几个环境问题反而是好事。6. 从能跑到能讲把SSM酒店管理系统变成答辩加分项6.1 用日志和断点验证订单流程调试SSM项目我最依赖两样东西MyBatis的SQL日志和Controller入口的断点。先打开MyBatis日志在mybatis-config.xml里配置settings setting namelogImpl valueSTDOUT_LOGGING/ /settings这样控制台会打印每个Mapper方法的SQL和参数。你预订房间后去日志里找update room set status...确认这个语句真的跑了。断点位置放三个Controller方法的入参处、Service调用Mapper的前一行、Mapper XML执行完回来之后。用IDEA的Debug模式跑一遍能看到一个请求从URL到SQL的完整旅程这比读十遍代码都直观。6.2 加一个入住率统计接口在4.4基础上可以进一步统计本月每天入住率。SQL写法SELECT DATE(check_in_time) AS day, COUNT(*) AS cnt FROM orders WHERE pay_status 1 AND check_in_time BETWEEN 2025-01-01 AND 2025-01-31 GROUP BY DATE(check_in_time)接口层返回ListMap前端用ECharts折线图展示。注意日期过滤别用字符串拼接用#{}传参避免SQL注入。做这个功能时日期参数从Controller接收后要在Service里做一次校验防止非法格式。这个接口能体现你对SQL分组聚合和前后端分离的理解比增删改查更有含金量。6.3 打包部署到服务器的检查清单答辩前如果想把项目部署到云服务器或者同学电脑上按这个清单检查检查项做法典型错误数据库初始化在目标服务器执行sql文件设置utf8mb4用root远程连不上数据库账号创建专用账号并授权直接用root且密码带特殊字符打包mvn clean package -DskipTests测试类报错Tomcat部署把war放webapps启动后等Server startup端口被占用访问前缀访问http://ip:8080/hotel忘了上下文路径我自己的习惯是拿到任何一个SSM毕业设计第一件事永远是删掉target目录重新打包第二件事才是读代码。打包成功代表环境可信环境可信之后所有翻车都会被缩小到业务逻辑的范畴。希望这篇笔记能帮你省掉一晚上的环境搭建时间也希望你在答辩时可以自信地说这个项目的每一层我都改过。希望帮到你。本文还有配套的精品资源点击获取
返回列表