简介:面向Java Web课程设计或毕业设计人群,这套龙腾公司员工信息管理系统采用SSM+JSP+MySQL技术栈,完整覆盖员工、部门、职位、薪资、培训、考勤六大业务模块,可处理信息校验、上下班打卡、薪资条增删改查等日常人事场景。项目包含前后端源码、SQL数据库脚本与说明文档,环境基于JDK1.8、Tomcat7、Maven3.3,适合按部就班部署学习或直接二次改造。压缩包共891个文件、约10.47MB,其中104个Java类为核心业务逻辑,49个JSP页面与219个JS文件构成前端交互,119个CSS负责样式布局,大量PNG/JPG/GIF图片素材支撑界面展示,XML与SQL文件则是配置和数据结构的落点。目前已有63人浏览学习,虽然文件体量不算大,但六大模块齐全,从建表脚本到部署清单一应俱全。配套说明文档和LW能辅助理解设计思路与实现流程,特别适合需要快速上手同类管理系统的毕业生参考。
1. 一个毕业设计选题,凭什么值钱
如果你正在筛选 java 毕业设计题目,看到“龙腾公司员工信息管理系统(ssm+jsp+mysql)”这类标题,第一反应可能是“又一个 CRUD 管理系统,太普通了”。但恰恰是这种“普通”,才是市面上通过率最高、代码最好改、答辩最好讲的选题。它覆盖了 Java Web 开发最标准的一条链路:SSM 三件套做后端、JSP 做页面、MySQL 存数据,再加上“员工信息管理”这个几乎是所有企业都需要的业务场景。无论你是想做毕设,还是想拿一套完整源码去二次开发,这套组合都足够撑起一份能入库、能答辩、能演示的项目。
这篇文章就围绕“员工信息管理系统”这个具体方向,把这套 SSM + JSP + MySQL 方案拆开讲:它由哪些模块组成、数据库怎么设计、核心代码怎么写、部署要踩哪些坑、以及拿到源码后怎么改成自己的题目。目标是让手里没项目的人照着一路做下来能跑通,让手里有项目的人知道边界在哪、哪里容易翻车。
2. 为什么是 ssm+jsp+mysql:选型逻辑与系统边界
2.1 SSM 三件套在系统里分别干什么
SSM 指的是 Spring、SpringMVC、MyBatis 三者的组合,在“龙腾公司员工信息管理系统”这类项目中,三者的分工非常清晰。Spring 负责管理对象:service 层的业务对象、事务管理器、数据源都在 Spring 容器里装配,Controller 和 Service 之间的依赖注入全靠它。SpringMVC 负责前后端交互:浏览器发来的请求由 DispatcherServlet 分发到具体 Controller 方法,Controller 返回的视图名再由视图解析器拼成 JSP 页面路径。MyBatis 负责 SQL 层:把 EmployeeMapper 接口里的方法映射到 XML 文件里的 SQL 语句,查询结果自动封装成 Employee 实体对象。
对应到具体功能点:员工列表查询走的是 SpringMVC 接收参数 + MyBatis 动态 SQL 拼接条件;新增员工走的是 Spring 的事务管理,一旦插入员工基本信息后写入部门或账号数据失败,整条事务回滚,不会留下半个员工;登录校验走的是 Spring 的拦截器,Session 里没有登录标记就直接打回登录页。这个组合不是性能最优的,也不是代码最简洁的,但它把“分层”做得明明白白,答辩时老师问“请求是怎么从 JSP 页面走到数据库的”,你可以沿着 JSP → Controller → Service → Mapper → MySQL 一条线讲清楚,这是纯 JSP + Servlet 项目做不到的。
2.2 JSP + MySQL 为什么到现在还是毕设主力
JSP 在今天的企业开发里确实用得少了,但毕设和课设里它依然是绝对主力,原因有两点。一是它天然贴合教学大纲:Java Web 课程基本都按 JSP + Servlet 教,SSM 只是在这基础上引入框架,学生上手成本低,代码量也比前后端分离项目少一个量级。二是演示效果好:不需要额外启动前端工程,Tomcat 跑起来,浏览器直接访问 JSP 页面,数据实时回显,打分老师一眼能看到页面变化和数据库变化,不用解释“这里调用了 API,数据在 Network 面板里”。
MySQL 在这个项目里的定位是纯粹、好查。员工表、部门表、用户表能装下全部业务数据。MySQL 5.7 和 8.0 都行,但建议用 5.7,原因是网上能搜到的 SSM 项目绝大部分是在 5.7 上开发的,8.0 的驱动需要改为com.mysql.cj.jdbc.Driver,且要额外设置时区参数,这些细节对新手来说很容易卡住。整个系统不涉及复杂查询,无非是单表查询、多表联查、模糊搜索、分页,MySQL 的索引和 SQL 写法完全够用,不需要引入 Redis 做缓存,也不需要用 Elasticsearch 做搜索,那些反而会让项目失真。
2.3 系统模块清单和数据流
一个标准员工信息管理系统,按权限可以切成三个角色:管理员、HR、普通员工。管理员管理用户账号和部门,HR 做员工信息的增删改查和统计,普通员工只能看自己的信息。再往下拆,核心模块有六个:登录注册模块、员工信息管理模块、部门管理模块、考勤管理模块、薪资管理模块、统计报表模块。其中统计报表一般是按部门统计员工数量,用 ECharts 画柱状图或饼图,属于加分项,不是必需项。
数据流从页面开始。JSP 页面的表单提交到 Controller,Controller 调 Service 接口,Service 实现类里通过 MyBatis Mapper 访问 MySQL,数据再逐层返回,渲染到 JSP 的 JSTL 标签里。开发者需要编写的代码集中在 Controller、Service、Mapper 接口、Mapper XML、JSP 页面这五层。理解这个数据流还有个好处:错误排查时可以按层定位——页面不显示数据先看 JSP 标签是否取到了 request 里的变量,接口报 500 先看 Mapper XML 里的 SQL 是否写错,数据没写入先看事务配置是否生效。
3. 数据库设计与初始化:建库脚本和 5 张核心表
3.1 数据字典:每张表建来干什么
“员工信息管理系统”的数据库设计不需要花哨,但要覆盖业务闭环。下面是一个我常用的建表脚本,五张表:t_user存登录账号,t_employee存员工基本信息,t_dept存部门,t_attendance存考勤,t_salary存薪资记录。部门表和员工表是一对多,员工表和薪资表、考勤表都是一对多。
-- 创建数据库,指定字符集,避免中文乱码 CREATE DATABASE IF NOT EXISTS db_employee DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE db_employee; -- 用户表:负责登录认证,密码使用 MD5,存密文 CREATE TABLE t_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL, role VARCHAR(20) DEFAULT 'EMPLOYEE', emp_id INT, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 部门表:部门名称唯一,负责人存员工表 id,便于连表查询 CREATE TABLE t_dept ( id INT PRIMARY KEY AUTO_INCREMENT, dept_name VARCHAR(100) NOT NULL UNIQUE, manager_id INT, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 员工表:核心表,字段按企业人事档案常见项设计 CREATE TABLE t_employee ( id INT PRIMARY KEY AUTO_INCREMENT, emp_no VARCHAR(20) NOT NULL UNIQUE COMMENT '工号', name VARCHAR(50) NOT NULL, gender VARCHAR(10), birth_date DATE, phone VARCHAR(20), email VARCHAR(100), dept_id INT COMMENT '关联 t_dept.id', position VARCHAR(50), entry_date DATE, status VARCHAR(20) DEFAULT '在职', create_time DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_dept (dept_id), CONSTRAINT fk_emp_dept FOREIGN KEY (dept_id) REFERENCES t_dept(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 考勤表:记录每日打卡情况,按员工 + 日期去重 CREATE TABLE t_attendance ( id INT PRIMARY KEY AUTO_INCREMENT, emp_id INT, work_date DATE, status VARCHAR(20) COMMENT '正常/迟到/早退/缺勤', create_time DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_emp_date (emp_id, work_date), CONSTRAINT fk_att_emp FOREIGN KEY (emp_id) REFERENCES t_employee(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 薪资表:按月记录员工薪资流水 CREATE TABLE t_salary ( id INT PRIMARY KEY AUTO_INCREMENT, emp_id INT, month VARCHAR(7) COMMENT '月份 yyyy-MM', basic_salary DECIMAL(10,2), bonus DECIMAL(10,2) DEFAULT 0, deductions DECIMAL(10,2) DEFAULT 0, total_salary DECIMAL(10,2), create_time DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_emp_month (emp_id, month), CONSTRAINT fk_sal_emp FOREIGN KEY (emp_id) REFERENCES t_employee(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;脚本建好后的关键点说明:utf8mb4字符集是必须的,如果用utf8,遇到生僻字或特殊符号页面会显示问号,这是毕设里最常见的乱码原因。所有时间字段统一用DATETIME,不混用TIMESTAMP,避免 2038 年问题和时区差异。外键约束建议保留,InnoDB 引擎下外键能保证插入考勤、薪资时不会写入不存在的员工 id,这一点在答辩时可以说“数据库层做了完整性约束,应用层再做了逻辑校验”。
3.2 初始数据的坑:别让演示页面空空如也
建完表之后必须插入一批测试数据,否则登录进去后页面一片空白,第一印象就垮了。密码建议直接用 MD5 加密后的固定值,比如123456的 MD5 是e10adc3949ba59abbe56e057f20f883e,在数据脚本里写死,避免登录模块还没写好时无法测试。
-- 初始管理员账号,密码 123456 的 MD5 密文 INSERT INTO t_user (username, password, role) VALUES ('admin', 'e10adc3949ba59abbe56e057f20f883e', 'ADMIN'); -- 插入两个部门和多位员工,覆盖多部门统计场景 INSERT INTO t_dept (dept_name, manager_id) VALUES ('技术部', 1), ('人事部', 2); INSERT INTO t_employee (emp_no, name, gender, birth_date, phone, dept_id, position, entry_date) VALUES ('E001', '张伟', '男', '1995-03-12', '13800138001', 1, 'Java工程师', '2021-06-01'), ('E002', '李娜', '女', '1998-07-24', '13800138002', 2, 'HR专员', '2022-03-15'), ('E003', '王强', '男', '1992-11-02', '13800138003', 1, '前端工程师', '2020-09-01');插入完成后,可以用一条连表查询验证数据,例如统计每个部门的人数。这条查询语句也可以直接沿用到统计模块的列表页展示:
SELECT d.dept_name AS 部门名称, COUNT(e.id) AS 员工人数 FROM t_dept d LEFT JOIN t_employee e ON d.id = e.dept_id GROUP BY d.id;3.3 数据库连接配置:jdbc.properties 的时区与驱动
SSM 项目的数据源配置写在jdbc.properties里,Spring 容器加载它再创建 Druid 连接池。以下配置同时兼容 MySQL 5.7 和 8.0,前提是驱动 jar 包版本和连接串一致。
jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/db_employee?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai jdbc.username=root jdbc.password=123456配置里的三个参数是血泪经验:useSSL=false去掉 SSL 握手告警,serverTimezone=Asia/Shanghai指定时区,characterEncoding=utf8保证中文写入。如果你用的 MySQL 8.0,驱动必须是com.mysql.cj.jdbc.Driver,com.mysql.jdbc.Driver会直接报ClassNotFoundException;如果你用的 MySQL 5.7,可以把两个驱动都试一下,不同版本的 mysql-connector-java 对驱动类名的要求不同。
4. 核心功能实现:从登录校验到员工信息 CRUD
4.1 登录和拦截器:防止未登录直接访问页面
登录模块是整个后端的第一道门,实现分成两步:登录验证和拦截器。登录验证写一个LoginController,接收用户名和密码,密码用MD5工具类加密后和数据库里的密文比对,成功后把用户信息放进 Session;拦截器实现HandlerInterceptor,在preHandle里判断 Session 中是否存有用户对象。
// 登录 Controller:核心逻辑就三步,查用户、验密文、存 Session @Controller public class LoginController { @Autowired private UserService userService; @RequestMapping("/login") public String login(String username, String password, HttpSession session, Model model) { // 1. 调用业务层查询用户 User user = userService.findByUsername(username); // 2. 比对 MD5 密文,避免明文传输和存储 if (user != null && user.getPassword().equals(MD5Util.md5(password))) { session.setAttribute("loginUser", user); // 角色不同跳不同主页:管理员进去看全部菜单,员工进去只看个人信息 if ("ADMIN".equals(user.getRole())) { return "redirect:/employee/list"; } return "redirect:/employee/myInfo"; } // 3. 失败返回登录页并携带提示 model.addAttribute("msg", "用户名或密码错误"); return "login"; } }这段代码的逻辑说明:MD5Util.md5()是封装好的工具方法,内部用MessageDigest生成 32 位密文;user.getPassword().equals(...)拿的是数据库中存好的密文,二者一致才放行。拦截器配置在 SpringMVC XML 中,最容易被忽略的是放行路径——登录接口、静态资源(JS/CSS/图片)必须放行,否则登录页面自己都加载不出来。
<!-- 拦截器配置:登录接口和静态资源放行,其余全部拦截 --> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <mvc:exclude-mapping path="/login"/> <mvc:exclude-mapping path="/css/**"/> <mvc:exclude-mapping path="/js/**"/> <mvc:exclude-mapping path="/images/**"/> <bean class="com.longteng.interceptor.LoginInterceptor"/> </mvc:interceptor> </mvc:interceptors>这里有个高频翻车点:如果不放行静态资源,JSP 页面能打开但样式全丢,浏览器控制台报 404。排查顺序是:先看拦截器 exclude-mapping,再看 web.xml 里 SpringMVC 前端控制器的 servlet-mapping 是否写成了*.do或/,这两种写法对静态资源的处理路径完全不同。
4.2 员工列表和条件查询:MyBatis 动态 SQL 的经典用法
员工管理模块的核心是一个带条件查询的分页列表。搜索条件通常是姓名、部门、状态,分页用 PageHelper 插件。Controller 接收pageNum、pageSize和条件参数,Service 层用 PageHelper 开启分页,Mapper XML 里用<where>和<if>动态拼 SQL。
<!-- EmployeeMapper.xml:条件查询 + 连表查部门名 --> <select id="selectByCondition" resultType="com.longteng.entity.EmployeeVO"> SELECT e.*, d.dept_name AS deptName FROM t_employee e LEFT JOIN t_dept d ON e.dept_id = d.id <where> <if test="name != null and name != ''"> AND e.name LIKE CONCAT('%', #{name}, '%') </if> <if test="deptId != null and deptId != 0"> AND e.dept_id = #{deptId} </if> <if test="status != null and status != ''"> AND e.status = #{status} </if> </where> ORDER BY e.emp_no ASC </select>动态 SQL 的好处是三个搜索条件可以自由组合:只填姓名就只按姓名查,全部留空就查全表。LIKE CONCAT('%', #{name}, '%')这样写比直接写'%${name}%'安全,${}会有 SQL 注入风险,#{}是预编译占位符,新手容易在这里被答辩老师追问。另外注意resultType是EmployeeVO而不是Employee,因为多查了一个deptName字段,实体类里没有这个属性时 MyBatis 会报映射异常,所以要么扩展一个 VO 类,要么在实体里加一个deptName字段。
4.3 新增和编辑员工:表单校验与事务回滚
新增员工和编辑员工共用一个 JSP 表单页面,Controller 里通过empId是否为空判断是新增还是更新。这里我一般会把新增员工和分配账号放在一个事务里——员工录入了,但账号创建失败,职工数据也要失效,用 Spring 的@Transactional注解兜底。
// EmployeeService 实现类:新增员工 + 创建登录账号,一个事务搞定 @Service public class EmployeeServiceImpl implements EmployeeService { @Autowired private EmployeeMapper employeeMapper; @Autowired private UserMapper userMapper; @Override @Transactional(rollbackFor = Exception.class) public void addEmployee(Employee emp, String username) { // 1. 插入员工基本信息,回填自增主键 employeeMapper.insert(emp); // 2. 为员工创建登录账号,工号作为初始密码,密文入库 User user = new User(); user.setUsername(username); user.setPassword(MD5Util.md5(emp.getEmpNo())); user.setRole("EMPLOYEE"); user.setEmpId(emp.getId()); userMapper.insert(user); } }@Transactional(rollbackFor = Exception.class)里那个参数很重要:默认情况下 Spring 只对 RuntimeException 回滚,如果你在业务方法里抛的是自定义 Exception,不加rollbackFor事务不会回滚,数据会只写一半。这个是面试也常问的点,毕设里加上了,答辩时能多说两句。表单里的非空校验,建议在后端 Controller 里用参数判断或者 Hibernate Validator 注解,前端 JS 校验只能拦操作失误,拦不了直接 POST 请求。
4.4 JSP 页面渲染与删除操作的后遗症
JSP 列表页用 JSTL 的<c:forEach>循环渲染员工数据,表格操作栏放“编辑”“删除”按钮。删除操作我建议写成表单 POST 提交而不是<a href>链接,原因是删除是修改数据的操作,用 GET 方式可以被浏览器缓存和预加载,容易误删。
<%-- employeeList.jsp:核心表格循环 --%> <c:forEach items="${pageInfo.list}" var="emp"> <tr> <td>${emp.empNo}</td> <td>${emp.name}</td> <td>${emp.gender}</td> <td>${emp.deptName}</td> <td>${emp.position}</td> <td> <fmt:formatDate value="${emp.entryDate}" pattern="yyyy-MM-dd"/> </td> <td> <!-- 修改走 GET 带 id 跳转编辑页 --> <a href="${pageContext.request.contextPath}/employee/toEdit?id=${emp.id}">编辑</a> <!-- 删除走 POST 提交,避免浏览器预加载误删 --> <form action="${pageContext.request.contextPath}/employee/delete" method="post" style="display:inline;"> <input type="hidden" name="id" value="${emp.id}"/> <button type="submit" onclick="return confirm('确定删除该员工吗?')">删除</button> </form> </td> </tr> </c:forEach>这段代码的隐含知识点是表单 action 里的pageContext.request.contextPath,它动态获取项目上下文路径。新手经常写死/demo/employee/delete,一旦项目部署名改了,所有请求全部 404。JSP 里所有链接、表单 action、JS 里的请求地址都建议带上ctx变量——在页面顶部用一个<c:set var="ctx" value="${pageContext.request.contextPath}"/>统一接管,这是 JSP 项目避免路径翻车最基本的手段。
5. ssm+jsp+mysql 的避坑清单:从环境到部署的 5 条踩坑记录
5.1 报错java.sql.SQLException: Unknown system variable 'query_cache_size'
这是 MySQL 8.0 和旧版驱动不兼容的经典报错。项目的pom.xml或 lib 目录里如果放的是mysql-connector-java 5.x驱动,但数据库装的是 MySQL 8.0,驱动连接时探测query_cache_size变量失败,直接抛异常。
解决路径是确认两端版本再改:要么把驱动换成mysql-connector-java 8.0.x并把driverClassName改成com.mysql.cj.jdbc.Driver,要么把数据库换回 MySQL 5.7。如果只是为了跑通毕设,换数据库不现实,多数情况下是换驱动。
5.2 数据中文乱码:页面问号,数据库也是问号
页面新增员工后,数据库中保存的中文变成???。这是三处配置不一致导致的——项目过滤器没设编码、JSP 页面contentType没写、数据库表字符集不是 utf8mb4。
解决时按顺序处理:web.xml 里加 Spring 的CharacterEncodingFilter,forceEncoding 设为 true;JSP 头部确认pageEncoding="UTF-8";数据库表字符集和连接串里的characterEncoding保持一致。很多项目只加了前三者,忘了数据库连接串,结果数据库没问题但页面回显乱码,再加characterEncoding=utf8就好。
5.3 修改员工失败或删除主键冲突:外键约束在拦路
删除部门时如果该部门下还有员工,InnoDB 外键约束会拒绝删除,报Cannot delete or update a parent row。很多人的直接反应是“把外键删了”,这不对。正确做法是业务层先处理子表数据:删除部门前先检查t_employee.dept_id下有没有人,有人的话提示“请先移除该部门下的员工”,或者把员工部门改成待分配。这个处理逻辑写在 Service 里,代码量不大,但体现了对数据完整性的理解,答辩是加分项。
5.4 JSP 页面加载不出样式和图片:拦截器把所有请求拦了
登录页能调出接口,但 CSS 全丢,浏览器控制台全是 404。原因是前面提到的拦截器配置没有放行/css/**、/js/**、/images/**,所有静态资源都被preHandle打回了登录页。
另一个隐藏原因是在web.xml里把 DispatcherServlet 的 url-pattern 配成了/,这会把静态资源的请求也交给 SpringMVC 处理。解决办法是引入<mvc:default-servlet-handler/>,让容器默认 Servlet 处理静态资源,再把静态资源对应目录挂上mvc:resources映射。两个配置同时存在时要注意顺序,default-servlet-handler要在拦截器配置之前声明。
5.5 明明写对了 SQL,但查询出来的 list 是空的
控制台打印 SQL 语句能查到数据,但页面列表是空白,而且不报错。最常见的原因有两个:一是 MyBatis 的结果映射出了问题,实体类的deptId和数据库的dept_id没对应上,用resultMap映射或在 SQL 里起别名解决;二是 JSP 的 EL 表达式取错了 key,Controller 里往 model 放的是pageInfo,JSP 里写成了${page.list}。
排查顺序:先在 Service 实现里打印 list size,确认数据到了业务层;再在 Controller return 前打印 model 的 key;最后检查 JSP 里的${}取值。多数情况问题在命名不一致,而不是 SQL 写错。
6. 从“能跑”到“能答辩”:验收清单、演示顺序与二次开发方向
拿到或者写完这套系统之后,别急着打包交差,先按下面这份验收清单自查一遍。功能层面:能不能用不同角色登录、员工增删改查是否正常、列表搜索条件是否能组合查询、修改员工后刷新列表数据是否正确、删除时有确认提示。代码层面:项目打包之后能不能以 war 包形式部署到另一个电脑的 Tomcat,数据库脚本是否独立于项目,换一台新电脑能否在一小时内跑起来。文档层面:说明文档里是否画了用例图、E-R 图、系统架构图,这几张图是答辩时的“一页纸讲解”,比几百行源码更让老师直观理解你的系统。
答辩演示顺序我建议按“登录 → 员工列表 → 条件搜索 → 新增员工 → 修改员工 → 删除员工 → 统计报表”来走。原因很简单:登录是入口,列表是主功能,搜索体现 SQL 能力,增删改查体现业务闭环,统计报表体现亮点。每操作一步,用一句话说你对应在哪个文件里做了什么,比如“这里点新增,Controller 接收参数,Service 里调用了 employeeMapper.insert,并且用事务保证了员工和账号同时创建”,这种表达比默背代码更显得真正掌握。
最后一个二级方向的建议:如果你的项目需要和同班同学区分开,不要大改功能,而是加一个你讲得清楚的小特性。我见过翻车最少的方向是在统计模块加条件报表——按部门、按时间段查入职人数,用 ECharts 画柱状图和饼图,代码量在两三百行内,但对系统的完整性提升非常明显。另一个可选方向是导出 Excel,用 POI 把员工列表导出,核心代码在 50 行内,却能把“数据处理”这个点坐实。靠给一个列表页换个模板或者改个颜色来假装工作量,答辩时老师多问两句就露馅了。
我自己的习惯是拿到任何一套 SSM 源码,先不打开 IDE,而是先花二十分钟把数据库脚本和配置文件读一遍,搞清楚它连什么库、表结构是什么、账号密码是什么,确认这些再启动项目。直接Run on Server报错了再回来查配置的做法,是浪费最多时间的路径。这套流程走完,再回头加功能和改页面,心里会踏实得多。希望帮到你。
本文还有配套的精品资源,点击获取