
简介基于Java Web的人才招聘系统设计与实现文档是一份面向计算机相关专业毕业生的毕业设计范文/模板。内容围绕人才招聘管理信息系统展开完整覆盖系统开发背景、现状前景、技术介绍、系统设计概述与详细设计重点阐述了个人求职、企业招聘、管理员三大核心模块的功能划分与实现思路并给出了系统组成模块图、主要数据库表及首页等页面设计说明。压缩包内共1个doc文件大小约1.07MB属于纯文字版设计文档便于直接阅读、修改和参考。文档采用JSPTomcat技术平台搭配SQL Server 2000数据库包含JDK与JDBC介绍适合需要完成类似课题或学习Java Web项目开发流程的人群。已有483人浏览学习可作为毕业设计文档撰写、系统功能设计、技术选型与论文排版的重要参考。1. 人才招聘系统这个毕业设计拆开看其实就三件事如果你在 2024 年还要做一个 JSP Tomcat 的招聘网站第一反应大概是老古董。但真把这份文档翻开看你会发现它其实把招聘业务的骨架搭得很规矩个人求职、企业招聘、管理员后台三条线各走各的流程数据库用 6 张表就撑起了全部功能。相比现在动不动十几个微服务的招聘平台这种单体应用反而更适合拿来理解招聘系统到底在管哪些数据、谁在操作哪些数据。这篇博文会从数据模型、连接层、核心链路三个角度拆这套系统最后聊一下如果你要在新版 Tomcat 上把它跑起来哪些代码必须改、怎么改。适合正在做 Java Web 课设的在校生也适合接手过遗留 JSP 项目的工程师——后者能从中看到一套老系统最常见的病根。2. 系统架构与数据模型三端角色如何映射到六张表2.1 功能与权限拆分三类角色对应三条工作流这套系统在功能设计上并没有追求大而全而是严格围绕三种身份展开个人求职者、招聘企业、系统管理员。从文档的模块图可以看到每个角色登录后能做的事是互相隔离的这种按角色拆功能的方式在今天的前后端分离项目里依然是最常见的权限设计起点。个人求职端的工作流是注册 → 登录 → 填写/修改个人简历 → 发布求职信息 → 浏览企业招聘信息 → 发送邮件。企业端则是对称的注册 → 登录 → 维护企业基本信息 → 发布/删除招聘信息 → 浏览求职者简历 → 发送邮件。管理员端做的是平台侧的治理工作审核个人注册信息、审核企业注册信息、管理求职信息、管理招聘信息、维护友情链接。这里有个容易在课设答辩时被问到的问题为什么个人发布了求职信息之后还要再单独有一个个人简历字段文档里其实给出了答案——个人求职信息表tb_sjob存的是求职意向这种偏动态的数据比如期望岗位、期望薪资、有效期而用户信息表tb_student里的个人简历是偏静态的履历数据。这种拆分在业务上是合理的它让我想找什么工作和我是什么样的人解耦方便做定向匹配。2.2 数据库设计六张表如何撑起整套业务文档第四章给出了完整的 6 张表结构这里需要关注的不只是字段名而是字段的职责边界。下面把三组核心表拆开看。2.2.1 用户信息表tb_student与个人求职信息表tb_sjob用户信息表存的是账号级数据字段包括sname用户名即登录账号、password密码、name真实姓名、age、sex、birthday、school、specialty所学专业、knowledge最高学历、email、resume个人简历text 类型。求职信息表存的则是这一次想找什么样的工作字段为jobid自增主键、sname关联用户名、specialty专业、job意向职位、emolument期望薪资、ptime发布时间、atime截止时间、other其他说明。注意一个细节这两张表之间并没有用外键约束tb_sjob.sname关联tb_student.sname靠的是应用程序层来保证一致性。这在课设级别的项目里很常见——减少 DELETE/UPDATE 时的级联麻烦但副作用是如果用户被管理员删除他发布的求职信息会变成孤儿数据。实际开发中用user_id做外键并加ON DELETE CASCADE会更稳妥但这个设计放到当时的环境下可以理解。2.2.2 企业信息表tb_company与企业招聘信息表tb_cjob企业信息表用cname作为用户名登录凭证存了password、name公司全称、email、tel、manage从事行业、address、resume企业简历text 类型用于展示企业背景。招聘信息表tb_cjob的字段逻辑和求职信息表几乎对称jobid主键、cname、specialty所属行业、job招聘职位、emolument诚聘薪水、ptime有效时间、atime发布时间、other其他说明。这里比较别扭的是字段命名ptime在求职表里是注册时间在企业招聘表里却是有效时间atime在求职表里是截至时间在企业招聘表里又是发布时间。这种同名字段不同语义的情况在老系统里相当常见接手时一定要以表结构注释为准别想当然。如果要在现代工程里重构建议直接改成publish_time、expire_time这种一眼能看懂的名字。2.2.3 管理员表tb_admin与友情链接表tb_flink管理员表只有三个字段id、admin、password是纯账号表管理员本身没有业务资料。友情链接表tb_flink存id、name、address算是早期招聘网站的标配——通过互换链接获取流量入口。下面是完整的数据表汇总字段的整理顺序和文档一致补充了主键标识表名用途核心字段主键tb_student个人用户账号与简历sname, password, name, specialty, knowledge, email, resumesnametb_sjob个人发布的求职意向jobid, sname, specialty, job, emolument, ptime, atimejobidtb_company企业账号与基本资料cname, password, name, email, tel, manage, addresscnametb_cjob企业发布的招聘岗位jobid, cname, specialty, job, emolument, ptime, atimejobidtb_admin管理员账号id, admin, passwordidtb_flink友情链接id, name, addressid这套设计的巧妙之处在于用户表和业务表分离账号信息能不能登录和业务信息发布了什么各管各的即使求职者长时间不更新简历他的账号数据依然保留符合招聘平台老用户回访的业务特征。3. JDBC 连接层深挖从原始 Conn 类到连接池改造3.1 原始 Conn.java 的写法与问题文档末尾给出了一个Conn类的开头片段只有成员变量声明。在当年的课设里这个类的完整写法通常是这样的import java.sql.*; public class Conn { private static Connection con; private Statement stmt; public static Connection getConnection() { try { Class.forName(com.microsoft.jdbc.sqlserver.SQLServerDriver); con DriverManager.getConnection( jdbc:microsoft:sqlserver://localhost:1433;DatabaseNamezhaopin, sa, 123456); } catch (Exception e) { e.printStackTrace(); } return con; } }这段代码的逻辑很直白先用Class.forName加载 SQL Server 2000 的 JDBC 驱动然后通过DriverManager.getConnection建立 TCP 连接最后返回Connection对象供 DAO 层调用。参数说明localhost:1433是 SQL Server 的默认监听端口如果数据库装在远程服务器上这里要改成目标 IP比如192.168.1.100:1433。DatabaseNamezhaopin是数据库名要和 SQL Server 里实际建的库名一致否则连接会直接报无法打开数据库。sa是 SQL Server 的超级管理员账号实际项目中绝不应该用 sa应该建一个最小权限的专用账号只授予db_datareader和db_datawriter角色。这个类有两个在当时就值得商榷的问题。第一con是static成员多线程环境下多个请求会共享同一个Connection对象而 JDBC 的Connection不是线程安全的并发一高就会抛Connection is busy之类的异常。第二每次调用getConnection都新建物理连接没有复用在 JSP 页面里每查询一次就开关一次数据库连接压力稍大就会出现 Too many connections。3.2 连接池改造让老代码在 Tomcat 下活得更好如果这个系统要部署到 Tomcat 8 上直接用原始代码会有一个很尴尬的问题Tomcat 8 之后移除了对 JDBC 驱动自动注册的兼容层SQL Server 2000 的老驱动在 JDK 8 下也基本跑不起来。常见的做法是改用微软的 sqljdbc4 驱动并把连接管理改造成 JNDI 数据源。在META-INF/context.xml里配置 JNDI 数据源Context Resource namejdbc/zhaopin authContainer typejavax.sql.DataSource driverClassNamecom.microsoft.sqlserver.jdbc.SQLServerDriver urljdbc:sqlserver://localhost:1433;DatabaseNamezhaopin usernamezhaopin_app passwordyour_password maxActive20 maxIdle10 maxWait10000/ /Context然后在 Java 代码里通过 JNDI 获取连接import javax.naming.Context; import javax.naming.InitialContext; import javax.sql.DataSource; import java.sql.*; public class DBHelper { public static Connection getConnection() throws Exception { Context initCtx new InitialContext(); Context envCtx (Context) initCtx.lookup(java:comp/env); DataSource ds (DataSource) envCtx.lookup(jdbc/zhaopin); return ds.getConnection(); } }改造后的逻辑说明JNDI 数据源启动时由 Tomcat 容器创建连接池应用每次调用是从池里借连接用完通过close()归还。maxActive20控制最大并发连接数maxWait10000表示池满时最多等 10 秒。这套方案把连接生命周期从每次请求新建变成了池化复用对老系统来说是最小侵入的加固方式。有一个坑值得提改完数据源后原来写在 DAO 类里的Class.forName可以删掉但如果没删也不报错——只是多了一次无意义的驱动注册。真正会报错的是原来jdbc:microsoft:sqlserver://这种老 URL必须换成jdbc:sqlserver://否则新版驱动不识别协议。4. 核心链路代码落地登录、发布、浏览三大模块4.1 登录与会话管理校验逻辑放 Servlet不要放 JSP这套系统的登录入口在首页按身份分流到个人登录、企业登录、管理员登录。常见的课设写法是在 JSP 里直接嵌 Java 代码判断用户名密码但更清晰的做法是用一个 Servlet 统一处理。下面是一个个人用户登录的 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 password request.getParameter(password); String role request.getParameter(role); // 参数非空校验 if (username null || password null || role null) { response.sendRedirect(index.jsp?error1); return; } boolean valid false; String sql ; if (student.equals(role)) { sql SELECT COUNT(*) FROM tb_student WHERE sname? AND password?; } else if (company.equals(role)) { sql SELECT COUNT(*) FROM tb_company WHERE cname? AND password?; } try (Connection conn DBHelper.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, username); ps.setString(2, password); ResultSet rs ps.executeQuery(); if (rs.next() rs.getInt(1) 0) { valid true; } } catch (Exception e) { e.printStackTrace(); } if (valid) { HttpSession session request.getSession(); session.setAttribute(username, username); session.setAttribute(role, role); response.sendRedirect(main.jsp); } else { response.sendRedirect(index.jsp?error1); } } }这段代码有几个细节值得展开说明。第一个是防 SQL 注入原文里很多查询是直接用字符串拼 SQL 的比如SELECT * FROM tb_student WHERE sname name 这在课设答辩时属于必被追问的漏洞。上面改用PreparedStatement的?占位符参数通过setString传入数据库会把它当作纯字面量处理不再参与 SQL 解析这是最基础的注入防御。第二个是角色分流登录校验根据role参数选择不同的表student查tb_studentcompany查tb_company管理员表独立。这样的好处是三个登录入口可以共用一个 Servlet路由逻辑清晰坏处是如果后续新增角色if-else会越来越长。更好的做法是用策略模式按角色分派到不同的验证实现但对课设来说当前写法足够了。第三个是会话管理登录成功后把username和role存入HttpSession后续 JSP 页面可以通过session.getAttribute(role)判断当前用户类型控制页面元素的显示与隐藏。这里注意session 默认超时时间是 30 分钟如果希望调整可以在web.xml里配置session-config session-timeout60/session-timeout /session-config4.2 招聘信息发布与列表分页JSP JDBC 的最简实现企业登录后可以发布招聘信息。发布表单提交到 ServletServlet 做字段校验后插入tb_cjob表核心插入语句如下INSERT INTO tb_cjob (cname, specialty, job, emolument, ptime, atime, other) VALUES (?, ?, ?, ?, GETDATE(), DATEADD(month, 1, GETDATE()), ?);这条 SQL 里GETDATE()取当前时间作为发布时间DATEADD(month, 1, GETDATE())把招聘信息的有效期默认设置为一个月。这种在 SQL 里直接算时间的写法在 JSP 时代很常见逻辑简单直观而且避免了应用服务器和数据库服务器时钟不一致的问题。求职者浏览招聘信息时如果岗位数量多一定要做分页。文档里虽然没有给出分页实现的代码但基于这套表结构标准做法是用 JDBC 的TOP子句分页。SQL Server 2000 不支持LIMIT常见的分页 SQL 是这样SELECT TOP 10 * FROM tb_cjob WHERE jobid NOT IN ( SELECT TOP 10 jobid FROM tb_cjob ORDER BY jobid DESC ) ORDER BY jobid DESC;这段 SQL 的逻辑是先用子查询取出前 10 条记录的jobid然后用NOT IN排除它们再从剩下的记录里取前 10 条。配合传入的页码参数可以把第 3 页翻译成跳过前 20 条再取 10 条。在实际 JSP 页面里页码传递通常是这样的% int pageSize 10; int currentPage 1; String pageStr request.getParameter(currentPage); if (pageStr ! null !pageStr.isEmpty()) { currentPage Integer.parseInt(pageStr); } int start (currentPage - 1) * pageSize; %参数说明pageSize是每页显示的记录数currentPage是当前页码start是跳过的记录数。注意这个代码里没有处理pageStr是非数字字符的异常情况实际使用时应加try-catch或正则校验否则 URL 里传currentPageabc会让 JSP 直接抛NumberFormatException。4.3 浏览求职者简历与站内邮件跨表关联的查询练习企业端的核心操作是浏览求职者的简历。这个功能在数据模型上需要连表查询tb_cjob里存的是招聘岗位tb_student里存的是简历它们之间的桥梁是求职者投递过哪些岗位这一隐含关系。但由于系统里没有独立的投递记录表实际实现往往退化为企业浏览所有求职者列表点击某个求职者后查看他的resume字段。这个查询非常简单SELECT sname, name, age, sex, school, specialty, knowledge, email, resume FROM tb_student;但站在答辩角度这里更应该被讨论的是真正的招聘网站为什么会存在简历投递这个中间实体因为如果不记录谁在什么时间投递了哪个岗位招聘方就无法对投递行为做状态管理已查看、已通知面试、已录用。如果要把这套系统往工程化方向推进应该新增一张tb_apply表字段类型说明idint自增主键jobidint关联 tb_cjob 的岗位 IDsnamevarchar(20)投递简历的用户名apply_timedatetime投递时间statustinyint0-未查看 1-已查看 2-已通知面试 3-已录用邮件功能在文档中也有提及个人和企业登录后都可以发送邮件。这里用的邮件不是真的 SMTP 邮件而是站内信——简单做法是建一个tb_message表存发件人、收件人、标题、正文、发送时间、是否已读。站内信和邮件的本质区别在于邮件走 SMTP 协议需要邮件服务器站内信只是数据库里的几条记录实现成本低很多也是早期招聘网站的标配功能。5. 遗留系统的四个改造方向从课设到可部署的工程最后聊一下这套系统如果要真正部署上线最值得动手的四个改造点。按照投入产出比排序第一数据库从 SQL Server 2000 迁移到 SQL Server 2019 或直接换成 MySQL。SQL Server 2000 在 Windows Server 2022 上已经无法安装新版 SQL Server 的 JDBC 驱动也不再兼容旧的jdbc:microsoft:URL。如果只是课设演示建议直接转 MySQL 8.x把字段类型里的text改为text不变datetime改为datetime不变bit改为tinyint(1)改动量非常小。第二连接管理必须换掉原始 Conn 类。无论用 JNDI 连接池还是 HikariCP核心目标是消灭每次请求新建物理连接的模式。改造后顺手把password字段的存储从明文改成 MD5 加盐或 BCrypt老系统的用户表升级成本不高但对安全性的提升是决定性的。第三把 JSP 里的业务逻辑搬到 Servlet 或 Service 层。原始文档里的 JSP 页面是典型的页面即逻辑% %里既有数据库查询又有结果渲染。维护这种代码的痛苦接手过的工程师都懂。最稳妥的改造是引入最简单的 MVC 分层Servlet 收参数、调 Service、转发请求JSP 只负责通过 EL 表达式和 JSTL 标签渲染数据。第四URL 设计从父子目录式改成资源式。老版本常见login.jsp?typestudent这种写法改成/api/login?rolestudent之后前端页面和后端逻辑的边界会清晰很多。如果不想动大结构至少把登录、注册、发布信息这几个关键接口统一成POST /api/xxx的格式为将来迁移到 Spring Boot 留一条平滑路径。这个系统的价值不在技术栈新不新而在于它把招聘业务的完整流程用最小化的数据模型表达出来了——对于课设而言这种简洁但完整恰恰是评委最看重的评分点。本文还有配套的精品资源点击获取