ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

JSP+Servlet+JDBC实战:大学生兼职家教网项目全解析与部署指南

JSP+Servlet+JDBC实战:大学生兼职家教网项目全解析与部署指南 简介这是一份基于JSP技术的大学生兼职家教网站项目源码包面向初学Java Web的开发者或需要完成课程设计的学生定位于展示从零搭建信息发布、查询、申请与后台管理平台的完整流程。压缩包共包含79个文件体积仅4.24MB主要由19个JSP页面、22个class编译文件、3个Java源文件、4个jar库、gif/jpg图像素材以及js/css等前端素材组成可快速导入IDE进行二次学习与部署。项目完整覆盖JSP基本语法、Servlet控制器、MVC分层、JDBC数据库操作、AJAX异步交互及Session会话保持等关键知识点并提供登录注册、家教信息管理等常见业务模块有助于理解前后端数据流转与数据库表设计。目前已有140人学习下载适合用于毕业设计参考或Web开发初级项目实战按包内目录即可梳理页面、类与资源文件的对应关系便于对照调试。总体而言这份源码包结构紧凑适合快速上手并深入体会Java Web项目的完整开发链路。1. 从信息登记表到管理后台JSP-324 大学生兼职家教网能解决什么一到寒暑假高校附近的家教需求就成倍增长。JSP-324 大学生兼职家教网这类项目最初就是为了解决这种场景出现的某社团负责人手里的纸质登记表没几天就攒成一沓想找初三数学一对一的家长、能带小学英语的大二学生、谈好的课时费和上课地点全挤在同一张表上改一处就乱三处。它把家教信息的发布、查询、申请和状态管理搬进了浏览器学生注册后发布可授课科目家长发布需求双方在系统里完成匹配并一路流转到成交。整个项目按 JSP Servlet JDBC MySQL 的技术栈组织服务端用 JSP 动态输出页面用 Servlet 接收前端请求并把业务结果转发回视图数据库操作走 JDBC 标准接口。涉及的模块包括用户注册登录、家教信息发布与多条件查询、预约申请、接单与完成状态管理。相比现在流行的前后端分离架构这套玩法重一些、渲染在服务端完成但正因为这样它把 Java Web 开发最核心的链路完整展现了一遍。适合谁刚学完 JSP 和 Servlet 语法、想用完整项目把知识点串起来的人在做课程设计选题、需要一套能跑通全流程参考代码的人以及想快速了解 MVC 分层在实际项目里怎么落地的开发者。下面按从环境到运行、从功能到坑位的顺序把它拆开讲。2. 工程技术栈与部署环境MVC 三层分工与本地跑通的前提2.1 为什么是 JSP Servlet JDBC选型逻辑与适用边界先回答一个很多人会问的问题都什么年代了为什么还要做一个 JSP 项目这个问题的答案藏在项目的业务形态里。大学生兼职家教网的核心操作是信息流的增删改查——发布一条家教信息、浏览列表、提交申请、更新接单状态。它的页面数量不大、交互不复杂、并发量也不高用 JSP 在服务端直接渲染页面反而比前后端分离少一层接口约定部署方式也简单打一个 WAR 包丢进容器就能跑。从学习角度看JSP 项目迫使你在同一套代码里同时处理视图、控制、数据三个层次理解请求在浏览器与服务器之间怎么走。这个项目的分层方式很典型JSP 页面只负责展示和收集参数Servlet 负责把请求转给业务逻辑并决定跳转到哪个页面DAO 类负责数据库读写中间的 service 包放业务规则。视图层拿到的所有数据都来自控制器塞进 request 或 session 的属性不直接访问数据库。适用边界也要说清楚。如果业务再复杂一点比如加了实时聊天、复杂权限矩阵JSP 这套就会因为页面与 Java 代码耦合而变得难维护。它的优势区间是中小型信息管理类应用。将来做毕业设计或者接小型外包项目这个技术组合依然够用这也是我建议把项目跑通的原因——它的每个模块都能迁移到其他管理系统中去。2.2 环境准备清单JDK、Tomcat、MySQL 的版本匹配在导入项目之前先把环境对齐。这个项目基于 JSP/Servlet 传统架构对版本的要求不算苛刻但版本差太多会出很隐蔽的问题。建议按下面这张表准备组件建议版本说明JDK8 或 118 最稳11 也能跑注意 IDE 编译级别要与之一致Tomcat8.5 / 9.x支持 Servlet 3.1/4.0匹配常见 JSP 版本MySQL5.7 或 8.05.7 配 connector 5.1.x8.0 必须换 8.x 驱动IDE任意支持 Java Web 的 IDE导入时选择 Dynamic Web Project 结构准备完成后先在命令行确认基础环境正常java -version mysql --version看到版本号输出后再确认 Tomcat 的 CATALINA_HOME 环境变量或者 IDE 里的 Server Runtime 配置。这里有一个常见坑IDE 里配置的 Tomcat 和命令行启动的 Tomcat 不是同一个实例。如果你在 IDE 外手工把项目丢进 webapps 启动过一次项目的编译产物可能残留在 work 目录里后面在 IDE 里启动会加载到过期内容。所以我一般会让 IDE 管理一个独立的 Tomcat 运行时避免混用。2.3 数据库初始化三张核心表与角色设计家教平台的数据量不大但表之间的关系值得认真设计。项目里最基本的有三张表用户表、家教信息表、申请记录表。用下面的 SQL 初始化数据库CREATE DATABASE IF NOT EXISTS tutor_db DEFAULT CHARACTER SET utf8mb4; CREATE TABLE sys_user ( user_id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, real_name VARCHAR(30), phone VARCHAR(20), role TINYINT DEFAULT 0 COMMENT 0-学生 1-家长, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE job_info ( job_id INT PRIMARY KEY AUTO_INCREMENT, publisher_id INT NOT NULL, title VARCHAR(100) NOT NULL, subject VARCHAR(30) COMMENT 科目, grade VARCHAR(20) COMMENT 年级, teach_type TINYINT DEFAULT 0 COMMENT 0-线上 1-线下, price DECIMAL(6,2) COMMENT 课时费, address VARCHAR(200), detail TEXT, status TINYINT DEFAULT 0 COMMENT 0-待接单 1-已接单 2-已完成 3-已关闭, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE apply_record ( apply_id INT PRIMARY KEY AUTO_INCREMENT, job_id INT NOT NULL, apply_user_id INT NOT NULL, message VARCHAR(200), status TINYINT DEFAULT 0 COMMENT 0-待处理 1-已同意 2-已拒绝, create_time DATETIME DEFAULT CURRENT_TIMESTAMP );注意几个设计意图。第一role 用整数而不是字符串避免数据库里出现学生家长studentparent等多种写法导致查询条件对不上。第二status 采用从 0 开始的数字枚举每个值在代码里用常量或注释明确对应关系后面做状态流转时只需要比较数值不用解析字符串。第三字符字段都用 utf8mb4 而不是 utf8否则 emoji 或生僻姓名写入时会报 Incorrect string value 错误。这三张表是项目跑起来的最小集合实际项目可能还会加管理员表但核心链路依赖的就是它们。2.4 导入项目后的目录阅读顺序拿到项目压缩包后解压导入 IDE先不要急着点运行花十分钟把目录结构读一遍。典型目录长这样src/ ├── com/tutor/controller/ # Servlet 控制器 ├── com/tutor/service/ # 业务逻辑层 ├── com/tutor/dao/ # JDBC 数据访问层 ├── com/tutor/entity/ # 实体类对应数据表 └── com/tutor/util/ # 工具类DBUtil、MD5Util 等 WebContent/ ├── index.jsp # 入口页/首页 ├── page/ │ ├── login.jsp │ ├── register.jsp │ ├── release.jsp # 发布家教信息 │ └── list.jsp # 家教信息列表 └── WEB-INF/ ├── web.xml # Servlet 映射与过滤器注册 └── lib/ # mysql 驱动等 JAR 包我推荐的阅读顺序是先看 WEB-INF/web.xml它告诉你请求路径与 Servlet 的对应关系是整个应用的路由表再看 util/DBUtil.java了解数据库连接怎么建立和关闭然后挑一个完整链路看比如从 list.jsp 往下追到对应 Servlet 再到 DAO。顺着 controller → service → dao 的顺序追代码比从首页 F5 开始点速度快得多原因是视图层 JSP 语法对新手干扰大而控制层和数据层更接近纯 Java逻辑更清楚。提示这个项目解压后如果打算用 Git 管理记得把 .settings、build、target 这类 IDE 与编译产物目录加进 .gitignore否则仓库会被无意义文件撑大队友拉下来还容易因为本地配置不同产生一堆冲突。3. 家教信息发布与管理从表单到数据库的闭环实现3.1 发布表单JSP 页面的字段设计与参数对应关系家教信息发布页面是项目的核心入口。它的职责只有一个把用户在浏览器里填写的表单数据收集起来交给后端 Servlet 处理。先看页面片段form action${pageContext.request.contextPath}/job methodpost input typehidden nameaction valuerelease/ label标题/label input typetext nametitle required maxlength100/ label科目/label select namesubject option value数学数学/option option value英语英语/option option value物理物理/option /select label年级/label input typetext namegrade placeholder如初三/ label课时费元/小时/label input typenumber nameprice min0 step0.01/ label授课方式/label input typeradio nameteachType value0 checked/线上 input typeradio nameteachType value1/线下 label详细描述/label textarea namedetail rows5/textarea button typesubmit发布/button /form表单里每个控件的 name 属性就是后端 Servlet 用 getParameter 取参数时的键名前后端必须严格一致这是最常见也最难排查的 bug 来源之一。action 用 ${pageContext.request.contextPath}/job 而不是写死路径是因为项目部署时上下文路径可能变化写死会导致 404。隐藏字段 actionrelease 是让同一个 Servlet 处理多种操作时的分发标记——发布、修改、删除都走 /job 这个 URL靠 action 区分。3.2 实体类与 DAO 层PreparedStatement 的参数化写法后端的第一个落点是实体类和 DAO。实体类 JobInfo 的字段与 job_info 表一一对应这里不再贴全部 getter/setter重点看 DAO 的插入方法public int insert(JobInfo job) throws SQLException { String sql INSERT INTO job_info (publisher_id, title, subject, grade, teach_type, price, detail) VALUES (?, ?, ?, ?, ?, ?, ?); try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setInt(1, job.getPublisherId()); ps.setString(2, job.getTitle()); ps.setString(3, job.getSubject()); ps.setString(4, job.getGrade()); ps.setInt(5, job.getTeachType()); ps.setBigDecimal(6, job.getPrice()); ps.setString(7, job.getDetail()); return ps.executeUpdate(); } }这里用 PreparedStatement 而不是 Statement是 JDBC 编程里一条不能破的规矩。第一参数通过 ? 占位符传递数据库驱动会把它们当作纯数据而不是 SQL 片段从源头堵住 SQL 注入第二PreparedStatement 有预编译缓存同一条 SQL 执行多次时性能更好。代码里的 try-with-resources 是 Java 7 引入的写法Connection、PreparedStatement 实现了 AutoCloseable会在 try 块结束后自动关闭不必再手写 finally 里的一堆 close()。参数类型需要注意price 在 MySQL 里是 DECIMAL(6,2)在 Java 侧对应 BigDecimal用 setBigDecimal 传入而不是 setDouble否则小数精度可能出问题teach_type 是 TINYINT对应 setInt。如果某个 DAO 方法里看到 setString 传整数那多半会触发隐式转换MySQL 能接收但存在隐患。3.3 Servlet 控制器接收参数、设置编码、决定跳转Servlet 是 MVC 里的 C 层负责把请求参数整理成实体类调用 service/DAO最后决定返回哪个视图。看核心处理逻辑protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); String action request.getParameter(action); if (release.equals(action)) { JobInfo job new JobInfo(); job.setPublisherId((Integer) request.getSession() .getAttribute(userId)); job.setTitle(request.getParameter(title)); job.setSubject(request.getParameter(subject)); job.setGrade(request.getParameter(grade)); job.setTeachType(Integer.parseInt(request.getParameter(teachType))); job.setPrice(new BigDecimal(request.getParameter(price))); boolean ok jobService.addJob(job); if (ok) { response.sendRedirect(request.getContextPath() /job?actionlist); } else { request.setAttribute(error, 发布失败); request.getRequestDispatcher(/page/release.jsp) .forward(request, response); } } }第一行 setCharacterEncoding(UTF-8) 必须放在读取任何参数之前因为 POST 请求体的解码在第一次 getParameter 时已完成之后再设置就无效了。userId 从 session 取而不是信任前端传值这是防止越权的关键设计——发布者身份必须由服务端会话决定。成功后用 sendRedirect 走一次新的 GET 请求到列表页符合POST 后重定向的习惯避免刷新页面时重复提交失败则用 forward 回到发布页并携带 error 信息此时浏览器地址栏不变用户可以马上修改重试。注意sendRedirect 会丢 request 里的属性所以错误提示必须换成 session 或者在重定向 URL 后面带参数而 forward 保留 request 作用域适合表单校验失败回显的场景。两者别混用。3.4 列表查询与分页条件组合和 LIMIT 偏移量家教信息列表需要支持按科目、年级和授课方式筛选同时做分页。查询 SQL 是动态拼装的但拼的是条件骨架值仍然用占位符StringBuilder sql new StringBuilder( SELECT * FROM job_info WHERE status 0 ); if (subject ! null !subject.isEmpty()) { sql.append(AND subject ? ); } if (grade ! null !grade.isEmpty()) { sql.append(AND grade LIKE ? ); } sql.append(ORDER BY create_time DESC LIMIT ?, ?);对应参数设置要注意顺序先设置前面条件里的 subject、grade最后再设置 LIMIT 的两个参数。LIMIT 第一个参数是偏移量 offset第二个是每页条数 pageSize计算公式是 offset (pageNum - 1) * pageSize。比如每页 10 条第三页的 offset 就是 20。很多人在这个计算上翻车把 pageNum 直接当 offset 传进去结果第二页开始数据错位。分页还要向前端返回总页数一般先 COUNT(*) 查总记录数再除以 pageSize 向上取整。这个 COUNT 查询和列表查询条件必须完全一致否则会出现列表显示 3 页但分页条只有 2 页的尴尬。我一般会把条件拼装抽成一个公共方法两个查询共用从根上避免条件不一致。4. 登录认证与申请流程Session 管理与状态机的实现4.1 登录成功后的会话设计服务端存什么、过期时间设多少登录是整个应用的身份基础。用户提交用户名和密码后Servlet 用用户名查库、比对密码成功后把用户标识存进 Session而不是把整个用户对象随便乱放。推荐的做法是只存 userId、realName、role 三个字段够用且减少 session 体积。代码示意public User login(String username, String password) { // 先按用户名查用户再比对密码 User user userDao.findByUsername(username); if (user ! null user.getPassword().equals(MD5Util.md5(password))) { return user; } return null; }登录成功后控制器里这样存会话HttpSession session request.getSession(); session.setAttribute(userId, user.getUserId()); session.setAttribute(realName, user.getRealName()); session.setAttribute(role, user.getRole()); session.setMaxInactiveInterval(30 * 60);setMaxInactiveInterval(30 * 60) 把会话闲置超时设为 30 分钟单位是秒超过这个时间用户再操作就要重新登录。这个值需要根据使用场景调整——家教平台的用户不会一直盯着页面20~30 分钟是合理区间设太短会被频繁踢下线设太长又有会话被劫持的风险。这里还要理解 Session 和 Cookie 的关系Session 数据在服务端浏览器端只保存一个 JSESSIONID 的 CookieCookie 失效或清除后服务端就找不到对应的用户数据。所以 Session 里存状态Cookie 只是拿钥匙钥匙丢了状态就找不回来。4.2 登录过滤器统一拦截未登录请求与静态资源放行页面一多如果每个 Servlet 都手动判断 session 是否有效代码会非常啰嗦而且容易漏。项目里正确的做法是写一个 Filter在 web.xml 里注册为 /*对所有请求先做身份检查。核心逻辑public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; HttpServletResponse response (HttpServletResponse) resp; HttpSession session request.getSession(false); String uri request.getRequestURI(); if (uri.endsWith(.css) || uri.endsWith(.js) || uri.endsWith(.png) || uri.contains(/page/login.jsp)) { chain.doFilter(req, resp); return; } if (session ! null session.getAttribute(userId) ! null) { chain.doFilter(req, resp); } else { response.sendRedirect(request.getContextPath() /page/login.jsp); } }注意两点。第一request.getSession(false) 传 false 表示不新建 Session——如果用户本来没有会话这里会返回 null而不是自动创建一个空的避免每个未登录请求都白白产生 Session 对象。第二静态资源和登录页本身必须放行否则会出现登录页加载不出 CSS、jQuery 全被拦的问题。放行规则用 URI 后缀判断比较直观也可以用前缀匹配如 /static/、/assets/。如果项目里用了验证码图片同样要放进放行清单。4.3 申请接单的状态流转四个状态的权限边界家教信息发布之后核心业务就是申请与接单。一个家教订单在系统里经历的状态序列如下状态值状态名触发动作谁可以操作0待接单发布成功学生申请1已接单家长同意申请家长2已完成双方确认学生/家长3已关闭发布者撤销发布者状态机的实现并不复杂关键在于每个状态变更操作开始时都要校验当前状态和操作者身份。以家长同意申请为例Servlet 里需要先查出 job 的 publisher_id跟 session 里的 userId 比较不一致直接拒绝再检查 job.status 必须是 0否则提示该家教信息已接单。这两步校验缺一不可只校验状态不校验身份就会出现 A 用户能操作 B 用户信息的越权漏洞。对应的一条更新 SQL 涉及两张表UPDATE apply_record SET status 1 WHERE apply_id ? AND status 0; UPDATE job_info SET status 1 WHERE job_id ? AND status 0;这两条 UPDATE 都带有 status 0 的条件既是状态校验也起到乐观锁的作用如果记录已经被别人改过执行影响行数为 0程序就能感知到并发冲突并提示用户而不是盲目覆盖。4.4 密码存储MD5 加盐与防拖库思路用户表里的 password 字段不能存明文这是 Java Web 项目的底线。项目里一般会用 MD5 做摘要但裸 MD5 对彩虹表几乎没抵抗力所以必须加盐。思路是生成一个随机盐值拼到密码后面再算摘要盐值随用户记录一起存储。实现通常收敛在一个工具类里public static String md5WithSalt(String rawPassword, String salt) { String input rawPassword salt; return md5(input); }注册时生成盐值String salt UUID.randomUUID().toString().substring(0, 8); 登录时从库里取出该用户的盐值重新拼接计算再比对。这样即使数据库泄露攻击者拿到的也是加盐摘要想反推原文需要为每个用户单独跑字典成本高很多。MD5 在这个项目阶段够用如果做生产系统建议直接换 BCrypt算法自带随机盐而且计算慢更抗暴力破解。5. 部署与运行避坑最常见五个异常及排查路径这个项目从导入到跑通最容易踩的坑集中在五组问题里。每条按现象、原因、解决三个步骤写照着排查能省下大量时间。5.1 Tomcat 启动失败8080 端口被占用现象启动 Tomcat 时控制台报 Port 8080 required by Tomcat v9.0 Server at localhost is already in use服务起不来或者起来后访问不到页面。原因本机有其他程序占用了 8080。最常见的是之前手工启动的 Tomcat 实例没关干净或者其他开发工具的调试端口恰好落在 8080。解决先查占用进程Windows 用 netstat -ano | findstr 8080看到 PID 后在任务管理器里结束对应进程或者直接改端口在 conf/server.xml 里把 Connector 的 port 改成 8081同时注意项目里所有 contextPath 相关路径不受影响因为改的是服务器监听端口而不是上下文路径。改完端口别忘了 IDE 里的 server 配置也要同步更新。5.2 启动即 ClassNotFoundExceptionMySQL 驱动缺失或版本不匹配现象访问任意需要操作数据库的页面抛 java.lang.ClassNotFoundException: com.mysql.jdbc.Driver或者启动时就报驱动类加载失败。原因mysql-connector-java 的 JAR 没有放进 WEB-INF/lib。很多人把驱动 JAR 加到了 IDE 的 Classpath 里但部署时 IDE 没有把它打包进 WEB-INF/libTomcat 运行时自然找不到。驱动版本不匹配导致的启动翻车十次里有八次是这类原因。解决把 mysql-connector-java-x.x.x.jar 直接复制到 WebContent/WEB-INF/lib 目录下然后右键项目刷新确认构建路径里能看到它。另外注意驱动类名变了MySQL 8.x 驱动是 com.mysql.cj.jdbc.Driver老代码里写 com.mysql.jdbc.Driver 会报错需要同步改掉。5.3 数据库中文乱码连接 URL 和页面编码不一致现象从数据库查出来的中文显示为问号或者往库里写中文后读出来是乱码。原因问题往往不是单点而是链路里多个环节的编码不一致。常见组合是连接 URL 少了 characterEncoding 参数而数据库、表、JSP 页面各自用了不同编码。解决在 JDBC URL 上显式声明编码URL 形如 jdbc:mysql://localhost:3306/tutor_db?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/Shanghai。同时把建库语句的 DEFAULT CHARACTER SET utf8mb4 手动执行一次确认表也是 utf8mb4。JSP 页面顶部加上 % page contentTypetext/html;charsetUTF-8 pageEncodingUTF-8 %三处对齐后乱码基本绝迹。注意MySQL 8.x 不加 serverTimezone 会直接报时区错误这个参数不是可选项连接 URL 里必须带上。5.4 修改 JSP 后页面不更新Tomcat 工作目录缓存旧编译结果现象改了 JSP 里的标题或样式刷新浏览器还是旧页面清浏览器缓存也没用。原因JSP 第一次被访问时 Tomcat 会把它编译成 Servlet class 存到 work 目录之后每次请求默认先检查 JSP 文件是否有改动。但在 IDE 的增量部署场景下有时候文件时间戳没有变化或者修改发生在 IDE 外部Tomcat 没感知到更新一直用缓存里的旧 class。解决先停掉 Tomcat找到 Tomcat 安装目录下的 work/Catalina 目录或者 IDE 里配置的 catalina.base 对应 work 目录整体删除再重新启动也可以在 IDE 的 Server 面板里右键 Clean。从那以后我只要改了 JSP 或 web.xml都会顺手 Clean 一次再启动二十秒的事但能省掉改了没反应的半小时排查。5.5 登录页样式全丢过滤器把 CSS/JS 误伤现象进入 login.jsp 页面HTML 结构正常但所有样式和脚本都没生效F12 看到 .css 请求返回 302 跳转到了登录页。原因过滤器注册为 /* 对所有请求做登录校验静态资源路径也被拦截未登录状态下 CSS/JS 请求被重定向走页面自然裸奔。解决在过滤器里放行静态资源前面 4.2 的代码已经写了按后缀放行的方式更规范的做法是把静态资源统一放在 /static、/assets 目录下过滤器按路径前缀放行。还要注意一个隐藏点放行条件里如果用了 contains(/page/login.jsp)那么登录页里的 CSS 是放行了但 CSS 本身请求的 URL 是 /css/style.css必须同时有后缀判断否则依然拿不到。6. 上线前的最后两步SQL 审计与操作日志6.1 全面检查 SQL 拼装点在项目收尾演示之前我会全局搜索所有 DAO 类里是否还有 Statement 或字符串拼接 SQL 的地方。搜索特征是 String sql SELECT ... 变量只要出现一律改成 PreparedStatement 的参数化写法。判断标准很简单任何来自 request.getParameter 的值都不允许直接拼进 SQL。用 IDE 的全局搜索把范围限定在 dao 包和 service 包逐条过一遍这个动作花不了十分钟但能堵住最危险的注入口。6.2 给关键操作补一行日志发布信息、申请接单、修改状态这三类操作是业务里最容易出纠纷的地方。我会在 Servlet 处理完成后加一行日志输出记录操作人、操作对象和结果。用最朴素的 java.util.logging 或者 Log4j 都行关键是日志里要有 userId、jobId 和操作类型格式类似 release|user12|job78|success。这样演示或者测试时一旦出问题可以直接从日志里还原操作链路不需要再去数据库里猜是谁改的数据。最后说一个自己的习惯每次部署前我都会拿两个浏览器账号把完整流程走一遍——学生账号注册、发布家教信息、退出家长账号登录、搜索到目标信息、提交申请切回学生账号同意申请状态从待接单变成已接单。这个流程能跑通项目就达到了可验收的状态。JSESSIONID 跨浏览器互不影响这点正好是 Session 机制可靠性的实际验证。希望这组拆解能帮你在导入这个项目时少走几步弯路顺利把它跑起来。本文还有配套的精品资源点击获取
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表