☰
JSP+Servlet+JDBC学生请假管理系统:从工程导入到部署避坑指南
2026/10/10 6:27:15 网站建设 项目流程

简介:这是一份基于 jsp+servlet+jdbc 的学生请假信息管理系统课程设计,主要面向计算机相关专业大学生,用于毕业设计或课程设计参考。资源实现了学生、辅导员、宿管员三类角色的核心功能:学生可填写请假单、查看个人晚归记录与审核状态,辅导员可审核请假单、管理学生和班级信息,并可导出晚归记录;前端采用经典蓝色 UI 的 JSP 页面,后端以 Servlet+JDBC 完成数据处理,数据库脚本内置于压缩包中。压缩包共117个文件,包含78个 JSP 页面、5个 Java 源文件及对应 class 文件、2个 SQL 脚本、2个 CSS 样式文件,以及图片、配置文件和 jar 依赖包等,整体大小约2.25MB,结构清晰,导入 IDE 即可运行调试。目前已有2404人学习/下载,代码逻辑清晰,附带学生、辅导员、宿管员三组默认测试账号,适合初学者理解 JSP+Servlet+JDBC 三层交互,也可作为课程设计答辩与二次开发的基础。

1. 如果你拿到的是 jsp+servlet+jdbc 学生请假管理系统,先别急着改代码

如果你现在手头正压着一个 jsp+servlet+jdbc 学生请假信息管理系统课程设计,最要紧的不是研究什么高深框架,而是先让它在本地跑起来。这套系统覆盖了学生提交请假单、辅导员审核、导出晚归记录、宿管员维护基础信息这几条完整业务线,正好对应三个登录角色,答辩时既能讲业务又能演示功能,是那种“看着朴素但能撑住场面”的典型课设。它适合两类人:一是马上面临验收、需要一个能跑能演示的代码库的同学;二是没完整写过 Servlet 项目、想借一份真实工程理解分层和 JDBC 的初学者。下面我会按工程结构、数据库、Servlet、坑位、导出优化这几个顺序,把这份资源拆给你看。

2. 从 .classpath 到 pintuer.css:动手前先把 Eclipse 工程结构读透

2.1 .classpath 与 org.eclipse.wst.common.component:这两类元数据文件丢了项目就跑不起来

大多数课设包下载下来都是 Eclipse 工程。你会在根目录看到 .classpath、.project、.settings 这类隐藏文件,还有 org.eclipse.wst.common.component 这样的配置。如果你用 Eclipse 的 Import > Existing Projects into Workspace 导入时,发现项目没变成“地球图标”而是普通文件夹,问题基本出在 .project 丢失或失效。常见做法是手动补齐工程描述文件,或者直接用 New > Dynamic Web Project 重建一个空壳,再把源码导进来。

org.eclipse.wst.common.component 这个 XML 文件要特别留意,因为里面记录了 context-root(访问路径前缀)和部署组装方式,比如:

<?xml version="1.0" encoding="UTF-8"?> <project-modules ...> <wb-module deploy-name="LeaveSystem"> <wb-resource deploy-path="/" source-path="/WebContent" /> <property name="context-root" value="LeaveSystem"/> </wb-module> </project-modules>

context-root 改成你自己习惯的访问名,比如 leave,启动后访问地址就是 http://localhost:8080/leave/。很多同学把项目名改了之后发现 404,多半就是这里没同步,或者部署到 Tomcat 时项目名与 context-root 不一致。Eclipse 里还可以通过 Project Properties > Web Project Settings 修改 Context Root,改完会自动维护该文件。

.settings/org.eclipse.wst.jsdt.ui.superType.container 也是容易忽略的一个文件,它决定了 JS 代码补全和类型推断的容器,常见内容是 org.eclipse.wst.jsdt.launching.baseBrowserLibrary。它和运行无关,但如果整个 .settings 目录都丢了,Eclipse 对 JSP 里的 JS 报一堆红叉,非常烦人。

2.2 CodeUtil、PageBean、Excel、CodeServlet、CheckCode:一眼看出这套系统的五个关键类

打开 src 目录后,像 CodeUtil.class、PageBean.class、Excel.class、CodeServlet.class、CheckCode.class 这类类名,基本可以断定包的结构。如果是 .class 说明下载的是编译产物,需要有源码才能继续改。如果只有 class 文件没有源码,建议先找同名的 java 文件,实在没有的话就反编译——不过在课设阶段,我一般宁可自己重写一个同名类,也不去反编译,因为反编译出来的代码结构乱,答辩时根本说不清。

这些类的分工,从上往下数:

类名负责内容对应功能
CodeUtil验证码生成辅助逻辑(随机字符串、颜色、干扰线)登录页验证码图片
CodeServlet验证码图片输出,把答案写入 session登录页<img>的请求入口
CheckCode校验前端输入与 session 中验证码是否一致登录校验
PageBean分页数据模型晚归记录、学生列表的分页
Excel基于 POI 的导出封装辅导员导出晚归记录

看类名就能明确一件事:这套课设的验证码模块是完整的,分页也是独立封装的,不是把 SQL 拼在 JSP 里。写课设说明书时,你完全可以拿“PageBean 对查询结果做分页封装、Excel 负责数据导出”作为亮点描述。

2.3 pintuer.css 与 admin.css:前端资源路径别乱动

这套系统前端用的是 Pintuer 框架对应的样式文件,admin.css 是后台管理布局的补充样式。pintuer.css 是一套响应式框架,类似于把常用组件、栅格系统、弹层都打包好的 CSS+JS 前端库。课设里用它最大的好处是:不用自己写 CSS,页面看起来像“正经系统”。代价是 js 和 css 的引用必须用绝对或相对正确路径,否则页面花成一片。

建议拿到包后,先按下面步骤把前端资源关系理一遍:

  1. 看 WebContent 下是否有 css、js、fonts、image 目录,pintuer.css 是否在 css 目录内。
  2. 打开 login.jsp,看<link>标签的 href 是相对路径还是${pageContext.request.contextPath}拼接的绝对路径。
  3. 用浏览器直接访问登录页时,把地址栏路径与 css 的实际路径逐级对一遍。

常见问题是 JSP 放在子目录后,href="css/pintuer.css" 解析到了子目录,样式全丢。这个坑在第 5 章会展开讲。

2.4 拿到课设包后的半小时操作顺序

为了避免“不知道先干什么”的迷茫,我一般按下面顺序快速过一遍:先确认 MySQL 版本和密码,把 lib 下的 mysql-connector-java 找到;再用 Eclipse 导入工程,导入时如果项目没被识别,就补 .project 文件;然后打开项目属性,确认 Java Compiler 版本在 1.8 左右,Targeted Runtimes 里勾上本机 Tomcat;最后把 web.xml 或注解里 /login、/code 这些路径记录下来,后面排查 404 时直接对照。这套顺序能过滤掉八成环境问题。

3. 数据库设计:五张核心表与 JDBC 连接的完整写法

3.1 数据模型:用户、班级、请假单、晚归记录、课程怎么关联

先达成一个共识:这类课设的重点也是数据的归属。学生属于班级,班级挂课程,学生提交请假单,辅导员审核,宿管员记录晚归。默认登录账号 1/1、2/2、3/3 分别对应学生、辅导员、宿管员,说明 user 表里有一列 role(角色),初始数据就是这三行。

我一般会给出这样的建表 SQL,单人单机课设完全够用,你也可以直接导入:

CREATE DATABASE IF NOT EXISTS leave_db DEFAULT CHARACTER SET utf8mb4; USE leave_db; CREATE TABLE t_school_class ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT '班级ID', class_name VARCHAR(50) NOT NULL COMMENT '班级名称', grade_year INT COMMENT '年级' ) COMMENT '班级信息表'; CREATE TABLE t_course ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT '课程ID', course_name VARCHAR(50) NOT NULL COMMENT '课程名' ) COMMENT '课程表'; CREATE TABLE t_user ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID', username VARCHAR(20) NOT NULL COMMENT '登录名', password VARCHAR(50) NOT NULL COMMENT '密码', real_name VARCHAR(20) COMMENT '姓名', role INT NOT NULL COMMENT '角色:1学生 2辅导员 3宿管员', class_id INT COMMENT '学生所属班级' ) COMMENT '用户表'; CREATE TABLE t_leave_apply ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT '请假ID', stu_id INT NOT NULL COMMENT '学生用户ID', start_time DATETIME NOT NULL COMMENT '开始时间', end_time DATETIME NOT NULL COMMENT '结束时间', reason VARCHAR(255) COMMENT '请假事由', status INT DEFAULT 0 COMMENT '0待审 1通过 2驳回', audit_comment VARCHAR(255) COMMENT '审核意见', audit_time DATETIME COMMENT '审核时间', create_time DATETIME NOT NULL COMMENT '提交时间' ) COMMENT '请假申请表'; CREATE TABLE t_late_record ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT '记录ID', stu_id INT NOT NULL COMMENT '学生用户ID', late_time DATETIME NOT NULL COMMENT '晚归时间', recorder VARCHAR(20) COMMENT '记录人' ) COMMENT '晚归记录表';

几个容易理解错的地方说明一下:

  • 我用了 t_ 开头,是为了避免和 MySQL 关键字冲突,比如 course、class 单独使用有风险,加前缀更稳。
  • 班级、课程这两张表是最简单的字典表。如果课程和班级多对多,就建一张班级课程关联表,字段就两个:班级 ID、课程 ID。很多课设直接把 class_id 塞进课程表里,也行,答辩时能说清一对多关系就够。
  • 逻辑关联 > 物理外键。课设阶段不要在每张表上写 FOREIGN KEY,原因是以后要加数据、改数据,物理外键限制会导致增删改烦琐,而且答辩时经常被问到“为什么订单删不掉”——多半就是外键没处理干净。你用 JOIN 查询完全可以把逻辑关系讲明白。

3.2 JDBC 连接封装:DBUtil 类与 URL 参数的含义

servlet 项目最朴素的写法是一个 DBUtil 工具类。无论学号登录、请假的增删改查,还是导出晚归记录,都绕不开 Connection。下面是完整可用的版本:

package util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class DBUtil { private static final String URL = "jdbc:mysql://localhost:3306/leave_db" + "?useUnicode=true&characterEncoding=utf8" + "&useSSL=false&serverTimezone=Asia/Shanghai"; private static final String USER = "root"; private static final String PASSWORD = "123456"; static { try { Class.forName("com.mysql.cj.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } public static void close(ResultSet rs, Statement stmt, Connection conn) { if (rs != null) { try { rs.close(); } catch (SQLException e) { // 资源释放失败不影响主流程 } } if (stmt != null) { try { stmt.close(); } catch (SQLException e) { } } if (conn != null) { try { conn.close(); } catch (SQLException e) { } } } }

URL 里每个参数都有用途:useUnicode=true 和 characterEncoding=utf8 解决中文写入乱码,useSSL=false 避免 MySQL 8 连接时的 SSL 警告,serverTimezone 指定时区。如果本机数据库是 5.7,驱动类要改成 com.mysql.jdbc.Driver;如果是 8.0,则是 com.mysql.cj.jdbc.Driver,两者写反会在 Tomcat 启动时就报 ClassNotFoundException。密码改成你本地 MySQL 的密码,全项目就这一处需要动。

3.3 审核流程的状态机:从待审到通过/驳回的 SQL 边界

请假单的审核本质是一个状态流转:0 待审 → 1 通过,0 待审 → 2 驳回。辅导员在审核 JSP 里拿到请假单 ID 和审核意见后,后端一般这样更新:

String sql = "UPDATE t_leave_apply " + "SET status = ?, audit_comment = ?, audit_time = NOW() " + "WHERE id = ? AND status = 0"; try (Connection conn = DBUtil.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setInt(1, status); // 1 通过,2 驳回 ps.setString(2, comment); // 审核意见 ps.setInt(3, leaveId); // 请假单ID int rows = ps.executeUpdate(); if (rows == 0) { // 说明这张单已经审核过,页面提示 } }

注意我在 WHERE 里加了一个 AND status = 0,这是比较容易被忽略的小技巧:防止辅导员重复审核。两个页面同时打开一条待审单据,一个点通过,另一个人再点驳回,如果没这个条件,后执行的会把状态覆盖掉。rows == 0 就说明有人抢先改了,这时候页面提示“该请假单状态已变化,请刷新”。这是能在答辩时讲出来的业务细节。

如果项目里审核通过后还要给某个统计表加数据,两步操作就要放到事务里。JDBC 事务比较简单:

Connection conn = DBUtil.getConnection(); try { conn.setAutoCommit(false); // 1. 更新请假状态 // 2. 向统计表插入一条数据 conn.commit(); } catch (SQLException e) { conn.rollback(); throw e; } finally { conn.close(); }

事务的边界就看一件事:中间任何一步失败,业务数据是否仍然自洽。像审核加统计,必须一起成功;只更新一张表,那就老老实实单条 update,不要为了显得高级硬套事务。

4. Servlet 控制层:验证码、登录分发与分页的落地写法

4.1 CodeServlet 与 CheckCode:验证码不是摆设,要能连成完整链路

登录页输入的验证码看起来是小功能,实际上串起了三个类。CodeUtil 负责随机生成四位字符和干扰噪点,CodeServlet 把字符画成 PNG 输出,同时存到 session;CheckCode 在登录提交时把用户输入和 session 里的值做比较。

生成图片的核心代码大概长这样:

@WebServlet("/code") public class CodeServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { int width = 100, height = 35; BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics g = image.getGraphics(); g.setColor(Color.WHITE); g.fillRect(0, 0, width, height); String code = CodeUtil.randomCode(4); request.getSession().setAttribute("checkCode", code); // 逐字符绘制,并加简单干扰线 for (int i = 0; i < code.length(); i++) { g.setColor(new Color( (int) (Math.random() * 120) + 30, (int) (Math.random() * 120) + 30, (int) (Math.random() * 120) + 30)); g.drawString(String.valueOf(code.charAt(i)), 15 + i * 20, 25); } g.dispose(); response.setContentType("image/png"); ImageIO.write(image, "png", response.getOutputStream()); } }

需要补充两点。第一,验证码字符串和图片要同步生成,不要把生成代码写两遍,否则 session 里的值和图片不一致,导致明明看着是 abcd,输入 abcd 却说验证码错误。第二,登录 Servlet 里校验的 session 钥匙要和这里一致,比如都用 checkCode,而不是有的地方存 check_code。这两个问题让新手排查时能折腾一晚上,实际就是钥匙没对上。

4.2 登录分发:三个角色三种首页的跳转逻辑

登录账号 1/1、2/2、3/3 对应三个角色,后端只有拿到用户和角色才知道往哪儿跳。登录 Servlet 的流程我写成一版常规写法:

@WebServlet("/login") public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); String username = request.getParameter("username"); String inputPwd = request.getParameter("password"); String inputCode = request.getParameter("code"); String sessionCode = (String) request.getSession().getAttribute("checkCode"); if (sessionCode == null || !sessionCode.equalsIgnoreCase(inputCode)) { request.setAttribute("msg", "验证码错误"); request.getRequestDispatcher("/login.jsp").forward(request, response); return; } User user = userService.login(username, inputPwd); if (user == null) { request.setAttribute("msg", "用户名或密码错误"); request.getRequestDispatcher("/login.jsp").forward(request, response); return; } request.getSession().setAttribute("loginUser", user); String ctx = request.getContextPath(); if (user.getRole() == 1) { response.sendRedirect(ctx + "/student/index.jsp"); } else if (user.getRole() == 2) { response.sendRedirect(ctx + "/teacher/index.jsp"); } else { response.sendRedirect(ctx + "/admin/index.jsp"); } } }

这里有一个课设里反复出现的安全问题:大多数 JSP 页面没有做登录拦截,直接用地址栏输 /teacher/index.jsp 也能打开。正确做法是在 filter 包里写一个 LoginFilter:

@WebFilter("/student/*") public class StudentFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpSession session = request.getSession(false); User user = (User) (session == null ? null : session.getAttribute("loginUser")); if (user == null || user.getRole() != 1) { ((HttpServletResponse) resp).sendRedirect(request.getContextPath() + "/login.jsp"); return; } chain.doFilter(req, resp); } }

student、teacher、admin 三个路径各配一个过滤器,或者用一个拦截所有 jsp 的过滤器再按 role 放行。加了它,才敢在答辩演示时回答“我是怎么保证只有辅导员能审核的”。

4.3 PageBean:把 LIMIT 和 total 封装成可复用模型

列表页面用到的数据无非两类:当前页数据和总条数。PageBean 就是把这两样塞进同一个对象里,JSP 拿到后循环输出当前页,再显示“上一页/下一页”。数据层常见的查法是:

// 先查总数 String countSql = "SELECT COUNT(*) FROM t_late_record WHERE stu_id = ?"; int total = ...; // 执行 countSql 得到 total // 再查当前页数据 String listSql = "SELECT * FROM t_late_record WHERE stu_id = ? " + "ORDER BY late_time DESC LIMIT ?, ?"; List<LateRecord> list = ...; // 从 start 开始取 pageSize 条

PageBean 的起始偏移不能直接用前端传来的页码,必须服务端算一遍:

public int getStart() { if (pageNum < 1) { pageNum = 1; } return (pageNum - 1) * pageSize; }

防 SQL 注入的角度,LIMIT 后的问号同样用 PreparedStatement 的 setInt 绑定,不要直接拼字符串。分页参数 pageNum 从 request 拿到后最好强制转 int 并且设默认值 1,否则第一个访问进来的人不传 pageNum,Integer.parseInt(null) 直接 500。分页条在 JSP 里渲染时,还要注意“上一页”和“下一页”的链接别在边界页失效,第一页时禁用上一页,最后一页时禁用下一页,这个细节页面上要写。

5. 运行避坑:数据库导入、乱码、验证码与前端的常见故障排查

拿课设包跑不起来是常态,能一次跑通的反而少见。下面是我拆这类 JSP 课设时最常碰到的五类问题,按现象、原因、解决三步写给你。

5.1 现象:SQL 文件导入报 Unknown database

原因:包里的 SQL 文件通常以 USE leave_db; 开头,但你的 MySQL 里还没有 leave_db 这个库,所以 Navicat 或命令行执行到 USE 语句直接报错。 解决:先手动建库再导文件。在命令行或 Navicat 查询窗口执行:

CREATE DATABASE IF NOT EXISTS leave_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

然后右键该数据库执行 SQL 文件。如果 SQL 文件里已经写了 USE,第二次执行时就不会再报错。注意选择数据库后再导入,避免把表导进默认库。

5.2 现象:Tomcat 启动后访问项目 404

原因:最常见的是项目根本没被发布到 Tomcat Server。Eclipse 中虽然写了代码,但 Servers 视图里 Tomcat 上没有部署该项目。 解决:在 Servers 视图双击 Tomcat,打开 Server Locations,确保 Use Tomcat installation 已勾选,回到 Server 右键 Add and Remove,把项目 Add 进去。还要检查 org.eclipse.wst.common.component 里的 context-root,与访问地址 http://localhost:8080/xxx 保持完全一致。改完项目名后 404,九成是这个根路径没同步。

5.3 现象:页面、数据库、导出文件里的中文全是问号或乱码

原因:页面编码、请求编码、数据库连接编码三层不一致。JSP 页面设了 UTF-8,但 MySQL 库建库时是 utf8mb4 或 latin1,连接 URL 又没带 characterEncoding=utf8,中文必然乱。 解决:三层都固定成 UTF-8。JSP 页面顶部写<%@ page contentType="text/html;charset=UTF-8" %>;Servlet 在 doPost 入口调用 request.setCharacterEncoding("UTF-8");DBUtil 的 URL 加上 useUnicode=true&characterEncoding=utf8。如果已经乱掉的数据,重新插入或 UPDATE 回正确值,别一次改一半。

5.4 现象:登录页面验证码图片裂开或空白

原因:img 标签的 src 路径没有带 contextPath,像 src="code" 这类写法在项目部署名不是 ROOT 时必然 404;或者 web.xml 里的 servlet-mapping 和注解映射冲突,导致访问不到 CodeServlet。 解决:把验证码图片地址写成${pageContext.request.contextPath}/code(如果是注解 @WebServlet("/code"))。如果项目用 web.xml 配置,保持<url-pattern>/code</url-pattern>与 JSP 里的地址一致,不要同时用注解和 web.xml 重复映射同一路径——那是纯给自己添乱。

5.5 现象:样式和 JS 全部丢失,页面像纯文本

原因:登录页在根目录时 href="css/pintuer.css" 可能没问题,但进入 student/index.jsp 后,浏览器解析相对路径是基于当前目录,于是一层子目录就导致 css 路径错位。 解决:全部改用绝对路径,JSP 头部声明变量:

<% String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/"; %>

然后每个 css、js 链接都写成<%=basePath%>css/pintuer.css。或者在 EL 表达式里用${pageContext.request.contextPath}/css/pintuer.css拼,效果一样。这种问题 F12 看 Network 标签最直接,哪个 css 红了改哪个。

5.6 启动前十分钟自检清单

这几个坑排完,项目基本就能站在你面前了。第一次跑通后,把 MySQL 账号密码、context-root、导入路径这三样记下来。启动前再自查四件事:WEB-INF/lib 下有没有 mysql-connector jar;Servers 视图里项目是否已经 Add;登录页直接访问 login.jsp 是否白屏;filter 是否放行了 login.jsp 和验证码路径。这四项没问题,系统基本不会在演示当场翻车。

6. Excel 导出:把晚归记录导出做成答辩里的加分项

最后聊一个很多人忽略的优化点:导出晚归记录。项目里的 Excel 类基于 POI 封装,但默认导出往往会碰到两个问题:一是文件名中文乱码,二是数据量大时内存被撑爆。导出动作的本质是“把查询结果写成 Excel 文件流,通过 HttpServletResponse 输出给浏览器”,关键代码这样组织:

// 设置响应头,必须放在写数据之前 response.setContentType("application/vnd.ms-excel;charset=UTF-8"); String fileName = URLEncoder.encode("晚归记录.xls", "UTF-8") .replace("+", "%20"); response.setHeader("Content-Disposition", "attachment;filename=" + fileName); try (Workbook wb = new HSSFWorkbook(); OutputStream out = response.getOutputStream()) { Sheet sheet = wb.createSheet("晚归记录"); String[] header = {"学号", "姓名", "晚归时间", "记录人"}; Row headRow = sheet.createRow(0); for (int i = 0; i < header.length; i++) { headRow.createCell(i).setCellValue(header[i]); } // 循环查询出的 List,逐行写入数据 wb.write(out); } catch (IOException e) { log.error("导出失败", e); }

三点使用习惯,直接抄:HSSFWorkbook 对应 xls,课设数据量绝对够用;如果非要导 xlsx,改用 XSSFWorkbook,响应头对应改成 spreadsheetml.sheet,文件名后缀同步换。文件名必须 URLEncoder.encode,否则浏览器拿到中文文件名会乱码,replace("+", "%20") 是为了把空格还原。凡是产生流的地方都用 try-with-resources 或 finally 里关闭,Workbook 和 OutputStream 哪个不关,Tomcat 在 Windows 上就会一直锁文件,导致下一次导出报文件占用。

从那次以后,我拿到任何课设包,第一件事就是先打开 WEB-INF 下的 lib 确认驱动在不在,再把数据库导入、Tomcat 发布、登录、导出完整走一遍,最后才动业务代码。这套学生请假系统虽然不是我自己写的,但按这条路线把环境、登录、审核、导出全部核了一遍,踩坑顺序熟悉到闭着眼都能背。希望这个顺序,也帮你在答辩前少折腾几个晚上,希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询