
简介本资源为基于Android的人事管理系统毕业设计资料包面向计算机相关专业的本科毕业生及需要移动端开发练手的初学者。内容包含完整毕业论文与配套源码论文围绕Android平台下企业人事管理的移动化改造展开解决传统人工管理模式效率低、数据分散的问题覆盖系统开发工具、JAVA、MYSQL、Android编程与JSP等关键技术并依次梳理需求与可行性分析、数据库概要设计与实体模型、登录及主页、员工管理、部门管理、职位管理等模块的实现思路最后给出系统调试与功能测试过程可帮助读者对照选题背景、技术选型、数据库表结构到测试方法完整梳理一遍开发流程用于论文撰写参考或二次开发均较方便。压缩包共1个文件类型为doc包体约1.11MB篇幅紧凑便于通读。目前已有185人学习浏览适合作为Android方向毕业设计的参考样例。1. 考勤、请假、档案Android 人事管理系统真正难在哪人事管理系统常被当成几张表的增删改查套个后台模板就能交差。把运行环境换成 Android问题立刻变形员工在地铁里点请假、在厂区门口打卡、在信号很差的仓库里填调岗申请。脱离内网之后请求超时、定位漂移、重复提交、Token 过期会同时冒出来而这恰恰是评审最容易追问的地方。核心链路只有三条——员工档案查询、考勤打卡、请假审批。每条都要处理网络、权限、缓存和状态同步。往下按需求边界、工程骨架、核心模块、源码整理的顺序展开Android 端代码以 Java 配合 Android Studio 为主服务端只约定 HTTP 接口与 JSON 结构后端用 Spring Boot、SSM 还是别的框架都能对接。2. Android 人事管理系统的需求拆解与选型理由2.1 先划清四类角色和用例边界做移动端之前必须回答一个问题哪些功能值得放到手机上。把 PC 端后台的菜单原样搬到 Android最后会得到一个又长又难用的列表功能看着齐全实际没人点。我一般的做法是把用例按角色切开只把「离开工位才会发生」的操作留在移动端其余继续留在后台。角色移动端核心用例是否必须上手机普通员工打卡、请假申请、查工资条与考勤明细、改联系方式必须高频部门主管待办审批、团队考勤概览、驳回并填意见必须强时效HR 专员员工档案增改、入职离职办理、导出报表部分查询为主系统管理员角色授权、部门树维护、接口配置不建议后台更合适这张表决定了后面所有接口的粒度。员工端只暴露自己的数据主管端多一层「下属范围」的过滤条件HR 端才允许跨部门查询。权限边界放在服务端做Android 端只负责按角色渲染入口不要指望客户端能拦住越权请求。2.2 移动端为什么优先选原生 Android毕设和中小型企业内部应用我建议老老实实用原生 Android而不是一上来就跨平台框架。理由很实际打卡要拿定位和传感器、要读系统时间做校验、要在后台被杀死后恢复这些能力原生 API 最直接出了问题也容易定位。跨平台方案在写论文时讲不清「Android 特性体现在哪」答辩时反而被动。工程配置上有几个值要提前定死。minSdkVersion决定你能用哪些 API也决定兼容测试的范围targetSdkVersion影响权限行为和后台限制版本越高系统约束越严权限必须按需申请不要在启动页一次性弹完。清单文件里典型的声明如下。!-- AndroidManifest.xml -- uses-permission android:nameandroid.permission.INTERNET / uses-permission android:nameandroid.permission.ACCESS_NETWORK_STATE / !-- 打卡定位先要粗略再要精确按需申请 -- uses-permission android:nameandroid.permission.ACCESS_COARSE_LOCATION / uses-permission android:nameandroid.permission.ACCESS_FINE_LOCATION / !-- 上传头像、导出考勤凭证时读取相册/相机 -- uses-permission android:nameandroid.permission.CAMERA / uses-permission android:nameandroid.permission.READ_MEDIA_IMAGES / application android:name.App android:usesCleartextTrafficfalse android:networkSecurityConfigxml/network_security_config !-- 7.0 起跨应用传文件必须走 FileProvider头像上传就靠它 -- provider android:nameandroidx.core.content.FileProvider android:authorities${applicationId}.fileprovider android:exportedfalse android:grantUriPermissionstrue meta-data android:nameandroid.support.FILE_PROVIDER_PATHS android:resourcexml/file_paths / /provider /applicationusesCleartextTraffic设成 false 是硬要求正式环境全走 HTTPS。FileProvider那段看着多余但只要你做头像上传或导出 PDF 考勤单没有它就会在 Android 7.0 以上直接抛FileUriExposedException这也是很多移植过来的老项目一跑就崩的原因。2.3 服务端接口契约与数据库表的一一对应Android 端最怕接口反复改。我的习惯是先写接口表再写客户端代码字段名一旦确定就不动。下面这张表覆盖三条主链路实际开发时按它生成 Retrofit 接口即可。接口路径方法关键入参返回要点/api/auth/loginPOSTaccount、password、deviceIdtoken、过期时间、角色/api/employee/pageGETkeyword、deptId、page、size列表、总数/api/attendance/clockPOSTtype、longitude、latitude、clientTime服务端时间、打卡状态/api/leave/applyPOSTstartTime、endTime、reason、requestId审批单号/api/leave/approvePOSTleaveId、action、comment最新状态客户端架构上我不太推荐把逻辑全塞进 Activity。常见的稳妥组合是网络层用单例的 Retrofit 实例单例模式避免重复创建连接池数据层用 Repository 收口界面层订阅可观察的数据源。用 Java 写就是 LiveData 或 RxJava用 Kotlin 就是 Flow本质都是观察者模式。分层带来的直接好处是换 UI 不用动网络代码写论文时章节也自然分得开。2.4 离线缓存、权限与隐私这些非功能需求别留白考勤类应用绕不开断网。仓库、地下室、电梯间都可能没信号用户点了打卡却转圈失败体验直接崩。做法是本地建一张待提交表用 Room 存打卡记录和请求 ID网络恢复后按 ID 去重补传。服务端用requestId做幂等键重复提交只落一条。隐私部分有三个必须做到的点密码只在登录瞬间明文传输一次服务端加盐哈希存储客户端不落地Token 存 EncryptedSharedPreferences别写进普通 SharedPreferences日志里打印请求体时过滤掉身份证、手机号、薪资字段。权限申请要跟场景绑定用户点了「打卡」再申请定位比启动就弹窗的通过率高得多也更好写进论文的体验章节。3. 从 Android Studio 到第一条接口跑通3.1 安装、汉化与工程目录速览Android Studio 装完后第一件事是确认 Android SDK 下全了在 SDK Manager 里勾选对应 API 级别的 Platform、Build-Tools、Platform-Tools 和 Emulator。只装 IDE 不装 SDK新建工程时会卡在 Gradle 同步。英文界面不习惯的话在 Settings → Plugins 里搜中文语言包安装并重启菜单会切成中文但类名、Gradle 报错、Logcat 依然是英文排查问题还是得认英文关键词别把希望全押在汉化上。工程结构建议按职责分包而不是按类型堆在一起uiActivity/Fragment/Adapter、dataRepository、Room、本地缓存、netRetrofit 接口、拦截器、统一响应体、modelDTO、util时间、定位、加密。按类型分包到后期会出现一个包下几十个文件论文里也不好画模块图。3.2 Gradle 依赖与包分层依赖集中在模块级构建脚本里版本号用变量收口方便统一升级。下面这份是能跑通完整链路的最小集合。// app/build.gradle android { compileSdk 34 defaultConfig { applicationId com.example.hrms minSdk 24 // 覆盖绝大多数在用机型 targetSdk 34 // 决定权限与后台行为 versionCode 1 versionName 1.0 } buildFeatures { viewBinding true } // 干掉 findViewById compileOptions { sourceCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_17 } } dependencies { implementation androidx.appcompat:appcompat:1.6.1 implementation androidx.recyclerview:recyclerview:1.3.2 implementation com.squareup.retrofit2:retrofit:2.9.0 implementation com.squareup.retrofit2:converter-gson:2.9.0 implementation com.squareup.okhttp3:logging-interceptor:4.12.0 implementation androidx.room:room-runtime:2.6.1 annotationProcessor androidx.room:room-compiler:2.6.1 implementation androidx.security:security-crypto:1.1.0-alpha06 }minSdk定得越低兼容面越广但要多写版本分支targetSdk不要为了省事停在老版本系统会按旧行为兼容看着能跑实际在权限和后台任务上埋雷。viewBinding打开后布局里的控件通过生成的绑定类访问比findViewById少一大截空指针。3.3 Retrofit OkHttp 拦截器搞定登录态登录态统一在拦截器里加别在每个请求里手动塞 Token。同时拦截器还负责识别服务端返回的登录失效触发一次全局登出。// net/AuthInterceptor.java public class AuthInterceptor implements Interceptor { private final TokenStore tokenStore; // 内部用 EncryptedSharedPreferences public AuthInterceptor(TokenStore tokenStore) { this.tokenStore tokenStore; } Override public Response intercept(Chain chain) throws IOException { Request origin chain.request(); String token tokenStore.getToken(); Request request origin; if (token ! null !token.isEmpty()) { request origin.newBuilder() .header(Authorization, Bearer token) .header(X-Device-Id, tokenStore.getDeviceId()) // 打卡需要设备标识 .build(); } Response response chain.proceed(request); if (response.code() 401) { // 并发请求同时 401 时只登出一次 tokenStore.clear(); EventBus.getDefault().post(new SessionExpiredEvent()); } return response; } }Authorization用 Bearer 方案服务端解析头部即可X-Device-Id是打卡防代打的辅助字段绑定设备后才能和账号一一对应。401 的处理要注意并发三个请求同时返回 401如果每个都触发登出和跳转会出现连续弹三次登录页加个标记或事件总线去重就能避免。Retrofit 实例本身用单例持有OkHttpClient复用连接池频繁 new 会拖慢首屏。3.4 Android SDK 与真机联调的报错对照模拟器跑通不等于真机跑通尤其是从别的项目移植过来的工程。下面这张表是我踩过最多的几类。现象常见原因处理方式Gradle 同步失败、提示 plugin 版本不匹配Gradle Wrapper 与 AGP 版本错配对齐gradle-wrapper.properties与插件版本别手改单个应用装上后闪退日志报 ClassNotFoundmultidex 未开启或依赖冲突开 multidex用./gradlew app:dependencies查冲突请求一直失败但浏览器能打开接口明文 HTTP 被拦、或域名未配置全量改 HTTPS配置 network-security-config真机连不上电脑但模拟器正常用了localhost或10.0.2.2换成局域网 IP或做一层环境切换打卡定位永远返回 0.0运行时权限被拒或未开系统定位在回调里区分「权限拒绝」和「定位关闭」两种提示调试时把 Logcat 过滤成自己的包名再配 OkHttp 的HttpLoggingInterceptor只放到 debug 构建里release 关掉避免把请求体写进线上日志。4. 核心模块落地员工档案、考勤打卡、请假审批4.1 员工档案列表RecyclerView 分页与搜索防抖档案查询是使用频率最高的页面也是最容易做卡的地方。列表用 RecyclerView 分页加载搜索框输入不要每敲一个字就发请求加 300 毫秒防抖。// ui/employee/EmployeeListFragment.java节选 private void onKeywordChanged(String keyword) { searchHandler.removeCallbacksAndMessages(null); searchHandler.postDelayed(() - { currentPage 1; viewModel.loadEmployees(keyword, currentPage, 20); // 重新从第一页拉 }, 300); // 防抖窗口输入停顿后才真正请求 } private void bindLoadMore() { recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { Override public void onScrolled(NonNull RecyclerView rv, int dx, int dy) { LinearLayoutManager lm (LinearLayoutManager) rv.getLayoutManager(); if (lm null || isLoading || !hasMore) return; // 最后一条可见项接近列表末尾时触发下一页 if (lm.findLastVisibleItemPosition() adapter.getItemCount() - 3) { viewModel.loadEmployees(currentKeyword, currentPage, 20); } } }); }removeCallbacksAndMessages(null)清掉未执行的旧任务保证只有最后一次输入生效。分页触发点留 3 个 item 的余量用户滑到底部时数据已经回来了看不到空白等待。isLoading和hasMore两个标志位必须成对判断否则快速滑动会连发多页请求服务端出现重复数据。4.2 考勤打卡时间以服务端为准定位要留降级打卡有三个坑客户端时间可以被改、定位可能拿不到、网络可能断。处理思路是客户端只负责采集判定全部交给服务端。// data/AttendanceRepository.java节选 public void clock(int type, double lng, double lat) { String requestId UUID.randomUUID().toString(); // 幂等键重试不重复落库 ClockRequest req new ClockRequest(type, lng, lat, System.currentTimeMillis(), requestId); api.clock(req).enqueue(new CallbackApiResponseClockResult() { Override public void onResponse(CallApiResponseClockResult call, ResponseApiResponseClockResult resp) { ClockResult result resp.body() null ? null : resp.body().getData(); if (result ! null result.isSuccess()) { cache.remove(requestId); // 成功则清掉本地待补传记录 ui.showClockSuccess(result.getServerTime()); // 展示服务端下发的打卡时间 } else { cache.save(req); // 服务端判定失败同样入队列等人工处理 } } Override public void onFailure(CallApiResponseClockResult call, Throwable t) { cache.save(req); // 网络失败落本地连上网后按 requestId 补传 } }); }服务端收到clientTime只做参考判定上班迟到与否用服务器时间同时把服务端时间回传给客户端展示。这样即使用户改了手机时间记录也不会错。定位拿不到时不要直接拒绝打卡降级方案是允许提交并标记为「异常待核」由 HR 在后台复核比让员工在门口干等更合理。4.3 请假审批状态机与幂等提交请假单是有生命周期的用状态字段加枚举控制别用一堆布尔值拼。典型状态是待审批、审批中、已通过、已驳回、已撤销。每次流转都要校验当前状态是否允许该动作否则会出现已驳回的单子还能再通过。// service/LeaveStateMachine.java public LeaveStatus next(LeaveStatus current, ApproveAction action) { switch (current) { case PENDING: // 待审批只能通过或驳回 return action ApproveAction.APPROVE ? LeaveStatus.APPROVED : LeaveStatus.REJECTED; case APPROVED: case REJECTED: // 终态用户可撤销撤销后回到已撤销 return action ApproveAction.CANCEL ? LeaveStatus.CANCELED : current; default: throw new IllegalStateException(非法状态流转: current - action); } }提交申请时同样带一个客户端生成的requestId服务端建唯一索引网络重试只会命中同一条记录。审批接口要带乐观锁版本号或状态前置条件主管和 HR 同时点通过时只有第一个请求生效第二个返回「状态已变更」前端刷新列表即可。4.4 建表 SQL 与索引表结构不用花哨关键是字段类型和索引要合理。下面这几张覆盖主链路。-- 员工表 CREATE TABLE t_employee ( id BIGINT PRIMARY KEY AUTO_INCREMENT, emp_no VARCHAR(20) NOT NULL UNIQUE COMMENT 工号, name VARCHAR(32) NOT NULL, dept_id BIGINT NOT NULL, phone VARCHAR(20), password_hash VARCHAR(128) NOT NULL COMMENT 加盐哈希绝不存明文, status TINYINT DEFAULT 1 COMMENT 1在职 0离职, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX idx_emp_dept ON t_employee(dept_id); CREATE INDEX idx_emp_name ON t_employee(name); -- 考勤记录表 CREATE TABLE t_attendance ( id BIGINT PRIMARY KEY AUTO_INCREMENT, emp_id BIGINT NOT NULL, clock_type TINYINT NOT NULL COMMENT 1上班 2下班, clock_time DATETIME NOT NULL COMMENT 服务端时间, longitude DECIMAL(10,6), latitude DECIMAL(10,6), request_id VARCHAR(64) NOT NULL COMMENT 幂等键, status TINYINT DEFAULT 1 COMMENT 1正常 2异常待核, UNIQUE KEY uk_request (request_id), KEY idx_emp_time (emp_id, clock_time) );uk_request这个唯一索引是防重复打卡的关键比在业务代码里查一遍再插更可靠。idx_emp_time支撑「查某人某月考勤」这个最高频查询。员工姓名用普通索引就够LIKE %张%这种前置模糊匹配走不了索引数据量上到十万级要考虑全文索引或搜索引擎毕设规模下不用过度设计。5. 源码整理、兼容性排查与答辩演示的具体技巧5.1 源码目录分层与可交付清单评委翻源码的时间通常只有几分钟目录一眼看不懂就容易被扣印象分。把 Android 端和服务端放在同一个仓库的两个目录里根目录留一份 README 说明启动顺序、数据库脚本位置、默认账号。可交付物按这个清单核对Android 工程含local.properties模板不要提交本机 SDK 路径、服务端工程、schema.sql建表脚本、api.md接口文档、若干张运行截图、环境说明。最容易漏的是数据库初始化脚本别人拿到源码跑不起来多半卡在这一步。版本控制上有个细节值得注意gradle-wrapper.properties和build.gradle一定要一起提交只提交其中一个换台机器同步就失败。真机安装包在build/outputs/apk下重命名成带版本号和日期的形式演示当天不会拿错包。5.2 低端机与高版本 Android 的兼容排查兼容问题集中在两头低端机内存小、老系统 API 缺新系统权限严、后台限制多。低端机上图片列表容易 OOM把头像加载换成带缓存的图片库并限制尺寸列表项布局层级压到三层以内。Android 10 以后后台定位受限如果要做自动打卡必须明确告知用途并申请后台定位权限否则进程一退到后台就再也拿不到位置。Android 版本差异还有几处会直接影响功能通知渠道从 8.0 起必须建 channel不建就静默失败SharedPreferences在 9.0 之后改动不再跨进程可见12 以后清单里的exported属性必须显式声明启动就崩基本是这个原因。排查顺序建议是先在模拟器上按 API 级别切换复现再用真机确认最后看 Logcat 的完整堆栈不要只看最后一行。5.3 演示脚本三分钟让评审看到闭环演示不要从头点菜单按一条完整业务流走员工登录 → 打卡展示服务端返回时间→ 提交请假 → 切到主管账号审批 → 切回员工看状态变成已通过。这条链路把所有角色和状态流转都串起来了比挨个点页面有说服力。演练时准备两手兜底。一是断网演示本地队列关掉网络打卡界面提示已保存待同步恢复网络后记录自动补传成功这一下就把幂等和离线能力讲清楚了。二是准备好接口文档评审问到「数据从哪来」时直接翻到接口表对应行。数据准备上提前造好一个部门的十来个员工和一个月的考勤记录列表和统计图才有内容可看空列表的演示基本等于没演示。最后留一个可复现的细节彩蛋比如把手机时间改掉再打卡展示记录时间仍然是服务端时间这比口头强调「做了防篡改」有力得多。本文还有配套的精品资源点击获取