
简介围绕Android平台的人事管理系统毕业设计资料包适合计算机相关专业学生、移动应用开发者及准备提交毕业设计项目的同学参考。该论文以JAVA、MYSQL、Android、JSP技术为支撑针对传统人事管理效率低、信息更新滞后等问题设计并实现了一套覆盖员工信息管理、部门结构设置、职位调整及休假管理等核心业务的管理系统。文中详细说明了开发工具与运行环境给出了需求分析、可行性分析、数据库概要设计及实体模型并通过业务活动图直观展示了系统工作流程功能实现部分依次介绍了登录模块、主页、员工管理、部门管理、职位管理等模块的设计思路后端还包含系统调试与多维度功能测试的完整过程如登录验证、员工数据校验等确保系统稳定可用。压缩包内为1个doc格式的论文文档大小1.11MB内容兼具理论框架与实现细节既可作为毕业设计说明书撰写模板也可作为同类Android管理系统开发时的参考原型。该资源已有187人学习下载对于需要快速完成人事管理系统毕业设计或论文写作的同学能提供清晰的结构借鉴和落地思路。1. 这份Android人事管理系统资源论文源码值不值得拆如果你正在找Android方向的毕业设计项目十有八九会碰到“人事管理系统”这个题材。它不花哨、需求清晰、模块边界好划分用来展示增删改查、网络请求、数据库设计这些基本功非常合适。但网上这类资源的通病是论文归论文源码归源码两边对不上跑起来更是另一回事。这份“基于Android的人事管理系统”是论文源码一起打包的功能覆盖员工、部门、职位、休假、工资五个模块技术栈是Android客户端 Java服务端 MySQL数据库属于典型的C/S结构移动端管理系统。适合谁准备做Android毕设的学生、想快速搭一套人事管理Demo的初级开发者以及需要一份完整设计文档支撑开题或答辩的人。这篇笔记我会从技术选型、数据库设计、核心代码路径到踩坑记录拆一遍帮你判断它值不值得下以及下了之后怎么最快跑起来。2. 技术选型与架构为什么必须带服务端客户端和服务端各自管什么2.1 C/S架构的取舍移动端原生App比B/S更适合这类场景论文里有一段关于研究现状的分析传统的人事管理系统大多是基于B/S结构浏览器/服务器用户在PC上通过浏览器访问。B/S的好处是部署方便、不需要安装客户端但对智能手机支持不完整而且页面渲染和交互受限于HTML和JavaScript。现在很多企业系统转向移动端采用C/S结构客户端/服务器Android App作为客户端服务端提供数据接口。这个选型逻辑放在毕业设计里是站得住脚的。人事管理这种场景核心诉求是“随时打开手机就能查员工信息、批休假申请”B/S模式下手机浏览器体验确实一般C/S模式能更好地控制UI和交互。当然C/S的代价也很直观需要在每台手机上安装APK开发成本比Web高。但在毕业设计的范畴里这个代价反而成了优点——因为工作量更饱满论文有内容可写源码有代码可展示。常见的技术组合是Android端负责界面和交互服务端用Java Web技术Servlet/JSP Tomcat作为容器MySQL做数据持久化客户端通过HTTP协议访问服务端的Servlet接口。这份资源对应的架构可以简化成一条链路Android App(Activity/Fragment) ↓ HTTP POST/GET (JSON) Tomcat Servlet(Java) ↓ JDBC MySQL数据库如果之前没接触过这种前后端分离的Android项目建议先把这个链路印在脑子里。后面所有模块调试本质上都是在这条链路上查问题App端有没有把参数传对、Servlet有没有接到、SQL有没有写错、数据库有没有对应表。2.2 开发工具链拆解Android Studio、MyEclipse、Tomcat、MySQL各自扮演什么角色论文第2章用了不少篇幅介绍开发工具包括MyEclipse、Tomcat、Android Studio。这套工具链放在今天可以精简一下但不影响对资源本身的理解。Android Studio负责Android客户端的开发、打包APK。它的作用是写界面XML布局、写点击事件、发HTTP请求、解析JSON渲染到列表里。MyEclipse / Eclipse / IDEA负责服务端Java代码的编写和发布。这里要注意服务端代码通常是标准的Java Web项目打成WAR包放到Tomcat里跑所以IDE选择不是关键。TomcatWeb应用服务器跑Servlet接收Android端发来的HTTP请求转发给DAO层做数据库操作最后把结果以JSON形式返回。MySQL存所有业务数据包括管理员账号、员工信息、部门、职位、休假申请等。论文用的是MySQL 5.x版本对应的JDBC驱动类名是com.mysql.jdbc.Driver。如果用MySQL 8.x驱动类名要换这个坑后面专门说。这里额外提醒一下很多新手拿到源码后喜欢先在Android Studio里一顿操作发现跑不起来就急了。正确的打开顺序是先装好MySQL并导入数据库脚本再启动Tomcat部署服务端最后才打开Android Studio跑App。客户端只是一个壳它自己没法造数据。2.3 客户端与服务端的数据交互HTTP请求、Servlet处理和JSON封装模块间的通信是这种项目中“黑匣子”感最强的地方直接看代码最实在。下面以登录请求为例写一个典型的Android端HTTP调用// LoginActivity.java 登录按钮点击后触发 private void login() { String username etUsername.getText().toString().trim(); String password etPassword.getText().toString().trim(); if (username.isEmpty() || password.isEmpty()) { Toast.makeText(this, 用户名和密码不能为空, Toast.LENGTH_SHORT).show(); return; } // Android模拟器访问宿主机用10.0.2.2真机调试需替换成电脑的局域网IP String url http://10.0.2.2:8080/hr_system/login; new Thread(() - { try { URL httpUrl new URL(url); HttpURLConnection conn (HttpURLConnection) httpUrl.openConnection(); conn.setRequestMethod(POST); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); conn.setDoOutput(true); // 拼接表单参数 String body username URLEncoder.encode(username, UTF-8) password URLEncoder.encode(password, UTF-8); OutputStream os conn.getOutputStream(); os.write(body.getBytes(UTF-8)); os.close(); if (conn.getResponseCode() 200) { InputStream is conn.getInputStream(); String result readStream(is); JSONObject json new JSONObject(result); if (json.getInt(code) 0) { runOnUiThread(() - { Toast.makeText(this, 登录成功, Toast.LENGTH_SHORT).show(); startActivity(new Intent(this, MainActivity.class)); }); } else { runOnUiThread(() - Toast.makeText(this, json.getString(msg), Toast.LENGTH_SHORT).show()); } } } catch (Exception e) { e.printStackTrace(); runOnUiThread(() - Toast.makeText(this, 网络请求失败, Toast.LENGTH_SHORT).show()); } }).start(); }这段代码里有几个关键参数值得注意10.0.2.2是Android模拟器访问宿主机的固定地址不是写错了8080是Tomcat的默认端口/hr_system/login是服务端部署上下文和Servlet映射路径。URLEncoder.encode负责把中文参数转成URL安全格式比如用户名如果是中文不编码会直接乱码。connectTimeout和readTimeout都设成5000毫秒避免网络异常时界面卡死。整个请求放在子线程里是必须的Android不允许在主线程做网络操作否则会抛NetworkOnMainThreadException。对应服务端的Servlet看起来是这样// LoginServlet.java 服务端登录接口 WebServlet(/login) public class LoginServlet extends HttpServlet { private static final long serialVersionUID 1L; Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); String username request.getParameter(username); String password request.getParameter(password); response.setContentType(application/json;charsetUTF-8); PrintWriter out response.getWriter(); // 调用DAO层查询管理员表 AdminDao dao new AdminDao(); Admin admin dao.findByUsernameAndPassword(username, password); if (admin ! null) { // 登录成功写入Session request.getSession().setAttribute(admin, admin); out.print({\code\:0,\msg\:\登录成功\}); } else { out.print({\code\:1,\msg\:\用户名或密码错误\}); } out.flush(); out.close(); } }Service端接收客户端传来的username和password两个请求参数调用AdminDao去数据库里查查到就把管理员对象放进Session返回code:0查不到就返回code:1。客户端根据code字段决定跳转主界面还是弹出错误提示。这种“0成功/1失败”的code约定很简单但很实用整个项目里所有模块的接口都是这个套路。3. 需求分析与数据库设计五张核心表、角色权限与审批状态流转3.1 系统角色与用例分析管理员单角色五个业务域这篇论文里的系统只有一个角色——人事管理员。不需要区分普通员工和管理员因为系统的定位是“给人事部门用的管理工具”不是员工自助平台。这一点和很多功能更全的人事系统不太一样但不影响它作为毕业设计的完整性。从论文的需求分析来看系统的核心业务可以归纳为五个模块模块核心操作论文对应章节员工管理增、删、改、查员工信息5.3部门管理部门增加、删除、修改、查询5.4职位管理职位信息维护5.5休假管理休假申请审批同意/驳回5.1-5.2登录与主页关联工资管理薪资信息查询系统功能结构图登录用例相对简单管理员输入账号密码验证通过进入主界面验证失败返回登录页。业务用例里管理员可以查询员工详细信息、按部门查询、按岗位查询、处理薪资变动、管理部门的增删。整体是“单角色 多模块CRUD 一个审批流”的结构对于展示基本功来说刚刚好——既不会因为过于复杂写不完也不会因为太简单没技术含量。3.2 数据库实体设计与建表SQL员工表挂在部门和职位之下论文4.3节专门做了数据库设计包括概要设计和实体模型。从实体关系上看员工表是核心它同时关联部门表和职位表休假表又关联员工表形成一条“部门-员工-休假”的引用链。管理员表独立存放账号密码工资信息则可以挂在员工表里。主流的设计方案会把表拆成这样-- 管理员表存放登录账号 CREATE TABLE t_admin ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT 管理员ID, username VARCHAR(50) NOT NULL UNIQUE COMMENT 登录账号, password VARCHAR(100) NOT NULL COMMENT 登录密码 ) COMMENT 管理员表; -- 部门表 CREATE TABLE t_department ( dept_id INT PRIMARY KEY AUTO_INCREMENT COMMENT 部门ID, dept_name VARCHAR(50) NOT NULL COMMENT 部门名称, dept_manager VARCHAR(50) COMMENT 部门负责人, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间 ) COMMENT 部门表; -- 职位表 CREATE TABLE t_position ( pos_id INT PRIMARY KEY AUTO_INCREMENT COMMENT 职位ID, pos_name VARCHAR(50) NOT NULL COMMENT 职位名称, pos_level VARCHAR(20) COMMENT 职位级别, salary_base DECIMAL(10,2) COMMENT 基本工资 ) COMMENT 职位表; -- 员工表核心业务实体关联部门和职位 CREATE TABLE t_employee ( emp_id INT PRIMARY KEY AUTO_INCREMENT COMMENT 员工ID, emp_no VARCHAR(20) NOT NULL UNIQUE COMMENT 工号, emp_name VARCHAR(50) NOT NULL COMMENT 姓名, gender CHAR(2) COMMENT 性别, phone VARCHAR(20) COMMENT 手机号, email VARCHAR(100) COMMENT 邮箱, dept_id INT COMMENT 所属部门ID, pos_id INT COMMENT 职位ID, hire_date DATE COMMENT 入职日期, status TINYINT DEFAULT 1 COMMENT 在职状态 1在职 0离职, FOREIGN KEY (dept_id) REFERENCES t_department(dept_id), FOREIGN KEY (pos_id) REFERENCES t_position(pos_id) ) COMMENT 员工表; -- 休假申请表审批状态是核心字段 CREATE TABLE t_leave ( leave_id INT PRIMARY KEY AUTO_INCREMENT COMMENT 休假申请ID, emp_id INT NOT NULL COMMENT 员工ID, leave_type VARCHAR(20) COMMENT 休假类型年假/事假/病假, start_date DATE COMMENT 开始日期, end_date DATE COMMENT 结束日期, reason VARCHAR(255) COMMENT 请假原因, status TINYINT DEFAULT 0 COMMENT 0待审批 1同意 2驳回, apply_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 申请时间, FOREIGN KEY (emp_id) REFERENCES t_employee(emp_id) ) COMMENT 休假申请表;这五张表的关系可以这样理解t_employee里的dept_id和pos_id是两个外键分别指向部门表和职位表查询员工列表时通过JOIN把部门名称和职位名称带出来。t_leave的status字段是一个状态机默认0表示待审批管理员操作后改成1或2。这个字段在实现“审批与驳回”功能时是关键后面第4章的代码会用到。写这段建表SQL时有几个细节要注意。第一所有表名加了t_前缀避免和MySQL系统表冲突第二字符集建议统一用utf8mb4不然中文姓名、部门名称可能乱码第三DECIMAL(10,2)用来存工资比FLOAT精确不会出现0.10.20.30000000000000004这种浮点误差第四外键约束在建表时直接声明保证数据完整性。如果拿到的源码里表名不完全一样没关系核心字段基本就是这些。3.3 业务活动图变体登录验证、主界面与模块跳转的完整链路论文4.2节画了业务活动图从文字描述看系统的业务流转是启动App进入登录页 → 输入账号密码 → 验证失败返回登录页验证成功进入主界面 → 主界面显示五个功能入口员工、部门、职位、休假、工资 → 点选某个模块进入对应页面 → 执行增删改查或审批操作 → 操作完成后刷新列表或返回上一层。这个流转逻辑对应到Android端就是登录成功后启动MainActivity主界面用RecyclerView或GridView展示功能菜单每个菜单项对应一个Activity。员工管理页打开后页面顶部是搜索框和“添加员工”按钮中间是员工列表点击列表项可以进入详情或编辑页面长按可以删除。休假管理页则牵涉到审批操作列表里显示待审批的申请点“同意”或“驳回”时更新数据库里的status字段。如果要自己复现这套流程我一般会建议在Android端做一个BaseActivity把公共的标题栏、加载对话框、网络请求工具类抽出来避免每个模块都重复写一遍HTTP请求代码。源码里不一定做了这个抽象但复现的时候按这个思路改会更省力。4. 功能模块实现登录校验、员工CRUD、部门职位管理、休假审批的核心代码路径4.1 员工管理模块列表加载、条件查询与增删改的接口约定员工管理是整个系统的重头戏论文5.3节讲得最详细。它的核心是列表展示和增删改查典型实现是EmployeeListActivity里放一个RecyclerView进入页面时调服务端查询接口拿到JSON数组解析成员工对象列表再通过Adapter渲染到界面上。服务端查询接口按部门过滤、按姓名模糊查询是常见需求对应SQL里的WHERE子句动态拼接// EmployeeDao.java 员工查询核心方法 public ListEmployee findEmployees(String keyword, int deptId) { ListEmployee list new ArrayList(); // 基础SQL StringBuilder sql new StringBuilder(); sql.append(SELECT e.*, d.dept_name, p.pos_name ); sql.append(FROM t_employee e ); sql.append(LEFT JOIN t_department d ON e.dept_id d.dept_id ); sql.append(LEFT JOIN t_position p ON e.pos_id p.pos_id ); sql.append(WHERE 11 ); ListObject params new ArrayList(); // 按关键字模糊匹配姓名或工号 if (keyword ! null !keyword.trim().isEmpty()) { sql.append(AND (e.emp_name LIKE ? OR e.emp_no LIKE ?) ); params.add(% keyword %); params.add(% keyword %); } // 按部门精确过滤 if (deptId 0) { sql.append(AND e.dept_id ? ); params.add(deptId); } sql.append(ORDER BY e.emp_id DESC); try (PreparedStatement ps conn.prepareStatement(sql.toString())) { for (int i 0; i params.size(); i) { ps.setObject(i 1, params.get(i)); } ResultSet rs ps.executeQuery(); while (rs.next()) { Employee emp new Employee(); emp.setEmpId(rs.getInt(emp_id)); emp.setEmpNo(rs.getString(emp_no)); emp.setEmpName(rs.getString(emp_name)); emp.setDeptName(rs.getString(dept_name)); emp.setPosName(rs.getString(pos_name)); emp.setHireDate(rs.getString(hire_date)); list.add(emp); } } catch (SQLException e) { e.printStackTrace(); } return list; }这段代码体现了两个关键点第一用LEFT JOIN把员工表的部门ID和职位ID换成可读的名称前端展示的时候就不用再二次请求了第二用WHERE 11配合动态拼接条件这是Java Web项目里最常见的查询写法避免了“第一个条件要不要加AND”的判断逻辑。需要注意的是PreparedStatement的占位符从1开始计数参数填充顺着SQL顺序走别跳漏了。如果查询慢优先检查t_employee表上的emp_no有没有加索引——数据量小的时候无所谓但这是一个好习惯。4.2 部门与职位管理下拉联动的数据来源与级联刷新部门管理和职位管理的实现比员工管理简单本质上是对两张独立表的CRUD。但在实际代码里有一个容易踩坑的点添加或编辑员工时界面上的“所属部门”和“职位”往往用Spinner下拉框来选择而这两个下拉框的数据要动态加载自服务端接口。常见的实现路径是进入员工编辑页时同时请求部门列表和职位列表接口用返回的JSON填充两个Spinner。用户选择了某个部门后如果有“职位随部门联动”的需求还需要根据部门ID重新请求职位列表。这份资源的论文里没有提到联动逻辑但做毕设的话加上“根据部门筛选职位”是一个很加分的小功能。服务端返回部门列表的接口实现一般长这样// DepartmentServlet.java 部门下拉列表接口 WebServlet(/department/listAll) public class DepartmentListServlet extends HttpServlet { Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { DepartmentDao dao new DepartmentDao(); ListDepartment list dao.findAll(); response.setContentType(application/json;charsetUTF-8); PrintWriter out response.getWriter(); // 手动拼JSON数组字段保持与前端约定一致 StringBuilder sb new StringBuilder([); for (int i 0; i list.size(); i) { Department d list.get(i); if (i 0) sb.append(,); sb.append({\deptId\:).append(d.getDeptId()) .append(,\deptName\:\).append(d.getDeptName()).append(\}); } sb.append(]); out.print(sb.toString()); out.flush(); out.close(); } }这里我刻意没用JSON库而是手动拼字符串是为了展示JSON结构的本质它就是一个有格式约定的字符串。实际项目里用Gson或Fastjson会简洁很多但读懂手拼JSON有助于理解接口数据的来龙去脉。前端拿到数组后遍历解析把deptName填进SpinnerdeptId作为选中项的value添加员工时把这个ID作为参数传给服务端服务端再存进t_employee.dept_id字段。整条链路的参数流转是界面上的选中项 → 对应ID → HTTP请求参数 → DAO的SQL占位符。4.3 休假管理模块审批状态机与列表刷新的实现细节休假管理是这套系统里唯一带“状态流转”的模块也是答辩时最容易被问到的部分。核心逻辑围绕t_leave.status字段展开员工提交申请时status默认为0管理员看到申请后点击“同意”status改为1点击“驳回”status改为2。这个状态机虽然简单但涉及一个容易被忽略的问题权限控制。在单管理员角色的设定下权限控制就是“只有登录后的管理员才能操作审批”。实现方式很直接审批接口在Servlet里先判断Session中是否有admin属性没有就直接返回401或code:1。虽然技术上不够精细但作为毕业设计能在答辩时说出“通过Session控制接口访问权限”这句话比只说“每个接口都能调”要加分不少。审批的核心更新逻辑// LeaveApproveServlet.java 休假审批处理 WebServlet(/leave/approve) public class LeaveApproveServlet extends HttpServlet { Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); response.setContentType(application/json;charsetUTF-8); PrintWriter out response.getWriter(); // 简单校验登录状态 Object admin request.getSession().getAttribute(admin); if (admin null) { out.print({\code\:2,\msg\:\未登录或会话已过期\}); return; } int leaveId Integer.parseInt(request.getParameter(leaveId)); int status Integer.parseInt(request.getParameter(status)); String reply request.getParameter(reply); LeaveDao dao new LeaveDao(); boolean ok dao.updateStatus(leaveId, status, reply); if (ok) { out.print({\code\:0,\msg\:\操作成功\}); } else { out.print({\code\:1,\msg\:\操作失败\}); } out.flush(); out.close(); } }对应的DAO更新方法和前端刷新逻辑就不展开了但有一个前端细节值得提点击“同意”或“驳回”之后如果列表没有刷新界面上的状态还是“待审批”会给人一种没点上的错觉。正确做法是在接口返回成功后重新调用列表加载方法或者在Adapter里做局部状态更新。我一般倾向直接重新请求列表数据量小代码简单不会出现局部更新漏掉排序问题的尴尬。5. 避坑指南模拟器连库、JDBC驱动、HTTP明文与端口冲突的排错记录5.1 模拟器连不上服务端localhost用不得10.0.2.2才是宿主机现象App在模拟器里打开输入正确的账号密码点击登录Toast弹出“网络请求失败”但服务端Tomcat日志里没有任何请求记录。原因模拟器是一个独立的虚拟机它自己的localhost指向模拟器本身不是你的电脑。代码里写了http://localhost:8080模拟器访问的是自己肚子里的8080端口自然什么都连不上。解决把代码里的地址改成http://10.0.2.2:8080这是Android模拟器为宿主机预留的固定地址。如果你用的是真机调试需要把10.0.2.2换成电脑在局域网里的IP并且保证手机和电脑连的是同一个WiFi。这个IP可以在电脑上通过ipconfigWindows或ifconfigmacOS/Linux查到。从那以后我每拿到一套Android源码第一件事就是全局搜索localhost和10.0.2.2把网络地址统一改对再跑。5.2 MySQL 8.x版本驱动类名变化ClassNotFoundException的典型翻车现象Tomcat启动后访问登录接口报错控制台出现ClassNotFoundException: com.mysql.jdbc.Driver。原因源码里用的是com.mysql.jdbc.Driver这个驱动在MySQL 5.x时代是标准配置。但MySQL Connector/J 6.0之后驱动类改名成com.mysql.cj.jdbc.Driver旧的类名不再保留。如果你本机装的是MySQL 8.x又按照论文里的老写法配驱动必然报错。解决打开服务端项目的数据库连接工具类找到Class.forName(...)这一行把驱动类名改成com.mysql.cj.jdbc.Driver同时把mysql-connector的jar包换成8.x版本。另外连接串建议补上时区参数jdbc:mysql://localhost:3306/hr_system?useSSLfalseserverTimezoneAsia/Shanghai不然会报The server time zone value Öйú±ê׼ʱ¼ä is unrecognized这类乱码时区错误。5.3 Android 9及以上默认禁止HTTP明文流量明明代码没毛病请求就是发不出去现象在Android 9API 28及以上的设备或模拟器上运行App所有HTTP请求都失败Logcat里能看到CLEARTEXT communication to xxx not permitted by network security policy。原因从Android 9开始系统默认禁止应用使用明文HTTP流量。你的服务端地址是http://10.0.2.2:8080不是HTTPS所以被系统拦了。很多毕业设计源码是好几年前写的当时没有这个限制跑在新设备上就会这么翻车。解决在AndroidManifest.xml的application标签里加一行android:usesCleartextTraffictrue允许应用使用明文流量。如果是正式项目更好的方案是配置network security config只对特定域名开放HTTP但毕设场景直接加这个属性最快。加完之后记得Clean Project再重新Run有时候改完Manifest不重新构建不会生效。5.4 Tomcat端口8080被占用你改了配置但Android端地址没跟上现象Tomcat启动时报Port 8080 required by Tomcat X.X Server at localhost is already in use或者能启动但页面一直转圈加载不出来。原因本机有其他程序占用了8080端口。常见“凶手”包括另一个Tomcat实例、IDEA内置的HTTP服务、某些开发工具的调试端口。有人习惯把Tomcat的端口改成8081或其他值但如果只改了服务端配置忘了同步修改Android端代码里的URL就会出现“服务端明明能访问App里永远连不上”的诡异情况。解决在Tomcat的conf/server.xml里找到Connector port8080改成空闲端口比如8088。同时全局搜索Android工程里的8080把URL同步改成新端口。改完Tomcat配置要重启才生效。一个需要养成的习惯是端口不是默认值的时候第一反应去App代码里搜一遍连接串别只盯着Tomcat看。5.5 数据库连接池缺失与并发压力毕业设计可以忍但答辩要说得出现象多个模块同时操作数据库时偶尔出现连接超时Tomcat控制台报Connection is not available, request timed out。原因源码里大概率是每次操作都新建Connection用完就关没有连接池管理。低并发下够用一旦频繁切换页面、快速点击按钮数据库连接建立的开销会被放大。解决如果不改代码那就在答辩前准备好说辞说明“当前Demo采用直连方式生产环境会引入连接池”。如果想把系统做得更完整可以把直连接改成Druid或HikariCP连接池配置放在druid.properties文件里初始化时读取一次后续所有DAO从池里取连接。这个改动大概半小时能完成但对系统的稳定性和答辩观感提升非常明显。6. 从“跑通”到“答辩”验证清单、源码阅读顺序与三个加分改造6.1 一套可复现的功能验证清单源码跑通之后不要急着截图写报告先用一套固定顺序把功能过一遍。我的习惯是按业务流转来测而不是按模块跳着测因为这样能模拟真实使用路径测试项操作步骤预期结果错误登录输入不存在的账号或错误密码Toast提示“用户名或密码错误”停留在登录页正确登录输入管理员账号密码跳转主界面Session生效员工添加进入员工管理填写完整信息并保存列表出现新员工数据库t_employee多一条记录员工搜索输入员工姓名或工号关键字列表只显示匹配记录员工删除长按或点击删除按钮记录消失数据库同步删除休假审批进入休假管理同意或驳回一条申请状态从“待审批”变为“同意/驳回”未登录访问退出App后直接尝试访问功能页跳转回登录页或提示需要登录这份清单覆盖了登录校验、CRUD、状态流转、权限控制四层核心逻辑也是答辩时演示的标准顺序。实测过程中把每个步骤截图保存最后整理进论文的测试章节或附录。6.2 源码阅读顺序从包结构入手五分钟建立代码地图拿到源码第一件事不是打开某个Activity狂看而是先看包结构。典型的分层是bean实体类、dao数据库访问层、servlet接口层、activityAndroid界面层。按这个顺序读每一层都建立在上一层的基础上不会迷路。读代码时的关注点有三个一是bean类里的字段和数据库表的字段一一对应关系二是dao层里SQL与业务逻辑的映射三是activity里网络请求的URL路径和Servlet的映射是否一致。如果发现URL完全不同说明你拿到的源码和服务端版本不匹配优先检查baseUrl是不是在某个常量类里统一定义——很多项目会把URL前缀抽出来只改一处即可全局生效。6.3 三个实用性改造让系统更像一个“产品”而不是“作业”第一个改造是加登录状态持久化。用SharedPreferences记住“是否登录”和“管理员账号”下次启动App时跳过登录页直接进主界面同时在服务端Session过期后自动踢回登录页。第二个改造是给员工列表加一个按部门筛选的Tab或下拉框用第3章的动态SQL就能实现界面上的体验提升明显。第三个改造是休假申请加一个“催办”按钮或备注字段让系统不只有单一审批流这在论文的功能展望部分也能作为未来工作来写。从搭环境到跑通全流程再到现在能对着清单一条条过功能这个过程其实就是把“论文里的设计”变成“能跑的代码”的完整路径。做这类毕业设计资源复盘最忌拿到就npm install或gradle build然后等着奇迹发生。我后来的习惯是先花十分钟看数据库脚本、再花十分钟看包结构、再决定要不要动手启环境——任何一套能跑起来的Android毕设项目数据库和服务端永远是入口。希望这篇拆解能帮你在拿到资源后少走弯路顺利跑起来。本文还有配套的精品资源点击获取