资讯动态

基于Android的网络选课系统开发:从架构设计到联调答辩全指南

发布时间:2026/9/11 22:48:23 来源:尧图企业网站定制
简介面向毕业设计场景的Android网络选课系统完整源码项目覆盖学生选课、成绩查询、教师成绩录入、教务公告管理、超级管理员维护等多角色业务闭环适合计算机相关专业学生作为毕设参考或二次开发基础。压缩包整体约81.76MB包内文件总数2000其中以png界面资源、xml配置布局、java业务逻辑、jar依赖库为主同时包含jsp/html页面、SQL数据库脚本及多份工程说明文档目录结构清晰便于定位核心模块。已有169人学习下载资源除完整工程代码外还提供MySQL数据库SQL文件、可视化配置流程视频、项目结构说明文件、代码讲解视频以及配置完成后每次启动运行的操作演示视频可大幅降低环境搭建与源码理解门槛。通过跟随视频与文档读者能快速掌握Android端网络选课系统的前后台实现思路适合用其完成课程设计、毕业设计或作为移动端管理类项目的起步模板。1. 基于 Android 的网络选课系统到底在做什么如果你的毕业设计选了这个题目真正的难点不在 Android 界面上而在怎么让手机上的 App 和另一台电脑上的服务端稳定对话。选课系统比一般的记账 App 多了一层选课业务登录、名额校验、冲突检测、重复提交这四个问题几乎决定了你后面一半的编码量。很多学生拿到的毕业设计源码里代码能跑但一换电脑、一换手机就崩原因都是把服务端地址写死成了 localhost或者客户端直接连 MySQL。这篇文章按我辅导毕设时的常用顺序展开先定系统结构再写网络层最后给一份联调和答辩清单。2. 系统结构Android 端与服务器端怎么分工在动代码前先明确一件事基于 Android 的网络选课系统是 C/S 架构不是单机 App。Android 客户端只负责把用户操作转换成 HTTP 请求真正的选课规则、名额扣减、重复判断都要放在服务端。如果你拿到的源码里客户端直接用 JDBC 连 MySQL基本只能算演示代码答辩时老师问“数据库密码怎么保护”就接不上话。2.1 选课系统的三层角色与模块划分我把系统拆成三层学生端、管理端、服务端。学生端就是你的 Android App包含登录页、课程列表页、选课确认弹窗、我的课表页管理端可以做成简单的 Web 页面也可以先做一个命令行脚本核心职责是维护课程信息、学生信息和选课开关服务端统一对外提供 REST 接口并作为访问数据库的唯一入口。这样的分工在答辩时特别好解释。老师问“如果要把 Java 后端换成 Python 怎么办”你可以说只需要重写服务端接口Android 端接口定义保持不变。选课业务的规则也应该全部放在服务端配置同一门课是否允许重复选、是否允许退课、每学期学分上限是多少。客户端只负责展示服务端返回的状态码不要在界面上自己判断“还剩 5 个名额”否则换个手机登录时状态就错乱。2.2 数据库表的最小设计学生和课程是多对多关系所以至少需要三张表student、course、student_course。学生表不存课程 ID课程表不存学生 ID中间表只存关联关系和选课时间。这是我见过最容易写错的点很多人为了省事在 student 表里加一个 courseIds 字段用逗号分隔查询时只能遍历字符串完全没法做并发校验。CREATE TABLE student ( student_id VARCHAR(20) PRIMARY KEY, password VARCHAR(64) NOT NULL, name VARCHAR(30) NOT NULL, major VARCHAR(50) ); CREATE TABLE course ( course_id INT PRIMARY KEY AUTO_INCREMENT, course_name VARCHAR(60) NOT NULL, teacher VARCHAR(30), credit DECIMAL(3,1), capacity INT NOT NULL DEFAULT 60, selected_count INT NOT NULL DEFAULT 0, schedule VARCHAR(100) ); CREATE TABLE student_course ( id INT PRIMARY KEY AUTO_INCREMENT, student_id VARCHAR(20) NOT NULL, course_id INT NOT NULL, select_time DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_stu_course (student_id, course_id) );student_id 用 VARCHAR(20) 而不是自增整数因为学号不是纯数字而且登录时要按字符串匹配。course 表里的 selected_count 是冗余字段用来快速显示剩余名额真正判断是否超员不能只靠这个字段必须配合第 3 章的事务更新。student_course 上的 UNIQUE 约束是最后一道防线即使客户端连续点两次选课按钮同一个学生对同一门课也只能插入一条记录。2.3 用 SQLite 保存本地缓存还是直接连 MySQLAndroid 端千万不要直接连 MySQL。移动网络不稳定直接把数据库账号写在 App 里既不安全也会让后端业务逻辑没法复用。SQLite 在本项目里只做本地缓存比如保存“我的选课”列表让 App 在断网重连后还能显示最近一次结果。在 Android Studio 里创建 SQLiteOpenHelper 是常规做法public class CourseDbHelper extends SQLiteOpenHelper { public CourseDbHelper(Context context) { super(context, course_local.db, null, 1); } Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE TABLE my_course (course_id INTEGER PRIMARY KEY, name TEXT)); } Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL(DROP TABLE IF EXISTS my_course); onCreate(db); } }onUpgrade 里直接删表重建只适合本地缓存或开发阶段如果以后要发布必须写成逐版本迁移。SQLite 表结构一变旧数据就没了。另外每次使用 CourseDbHelper 后要记得关闭数据库很多人把它定义成全局单例Activity 退出后连接没释放长时间持有会导致性能问题。这里用 try-with-resources 或 finally 块关闭都可以。3. 用 Retrofit 把 Android 选课流程跑通3.1 网络层选型RetrofitOkHttp 对比原生 HTTPURLConnectionAndroid 发 HTTP 请求有三条路可走。原生 HttpURLConnection 不需要额外依赖但 JSON 序列化、统一错误处理、请求日志都要自己写选课接口一多就乱Volley 适合大量小图片请求用来做业务接口反而别扭Retrofit 通过接口注解描述请求配合 Gson 转换器可以直接把 JSON 响应转成 Java 对象这是我最常用的方式。对比项HttpURLConnectionVolleyRetrofit OkHttp学习成本低低中JSON 解析手动手动自动请求日志手动需插件OkHttp 拦截器协程/RxJava无无支持文件上传繁琐一般支持 Multipart选课系统建议少量接口可用不推荐推荐选课系统一般 5 到 10 个接口用 Retrofit 能让代码结构清晰很多。依赖只需要在 app/build.gradle 里加三行Sync 后就能用。如果你用 Kotlin还可以把接口方法声明成 suspend 函数避免回调嵌套。3.2 学生登录与课程列表的实现先定义接口把服务端地址单独拿出来方便之后从开发环境切到真机环境。public interface CourseApi { POST(student/login) CallLoginResult login(Body LoginRequest request); GET(course/list) CallListCourseBean getCourseList(); POST(student/select) CallOperateResult selectCourse(Body SelectRequest request); }对应的实体类字段名要和服务端返回的 JSON 保持一致不一致时用SerializedName显式指定。登录请求就是一个简单的对象public class LoginRequest { public String studentId; public String password; } public class LoginResult { public boolean success; public String token; public String message; }Retrofit 实例一般放在 Application 层避免每个 Activity 都重新创建OkHttpClient client new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)) .build(); Retrofit retrofit new Retrofit.Builder() .baseUrl(http://10.0.2.2:8080/) .client(client) .addConverterFactory(GsonConverterFactory.create()) .build(); CourseApi api retrofit.create(CourseApi.class);baseUrl 必须以/结尾否则 Retrofit 运行时会抛 IllegalArgumentException。登录按钮点击后通过 enqueue 发起异步请求不要再放到子线程去 execute防止阻塞主线程。api.login(new LoginRequest(studentId, password)).enqueue(new CallbackLoginResult() { Override public void onResponse(CallLoginResult call, ResponseLoginResult response) { if (response.isSuccessful() response.body() ! null) { LoginResult result response.body(); if (result.success) { // 保存 token 到 SharedPreferences然后跳转课程列表 } else { Toast.makeText(context, result.message, Toast.LENGTH_SHORT).show(); } } } Override public void onFailure(CallLoginResult call, Throwable t) { // 打印 t.getMessage()不要把异常吞掉 } });回调运行在主线程可以直接做 Toast 或跳转但不能在里面执行数据库操作。课程列表页拿到 List 后用 RecyclerView 展示即可接口返回的字段里要包含 selectedCount 和 capacity这样客户端可以在每张卡片上显示“已选人数 / 容量”。3.3 提交选课冲突检测放客户端还是服务端提交选课是核心接口也是最容易出问题的地方。很多人把名额判断写在 Android 端先查 selected_count 再提交。单机测试没问题但两个用户同时请求时各自读到剩余名额为 1就可能都提交成功最后数据库超收。服务端必须做原子性校验。常见做法是先把 student_id 和 course_id 插入中间表再更新 course 表的 selected_count用事务和条件更新把超员控制住Transactional public String selectCourse(String studentId, int courseId) { int count studentCourseMapper.insertIgnore(studentId, courseId); if (count 0) { return 重复选课; } int updated courseMapper.increaseSelectedCount(courseId); if (updated 0) { return 名额已满; } return 选课成功; }这里的 insertIgnore 依赖数据库的 UNIQUE 约束重复选课直接返回影响行数为 0。increaseSelectedCount 写成形如UPDATE course SET selected_count selected_count 1 WHERE course_id ? AND selected_count capacity这样即使两个请求同时到达数据库行锁也会让其中一个更新失败。Android 端只需要接收服务端返回的状态码和 message再决定弹 Toast 还是刷新列表。不要在客户端维护已选课程状态否则多端登录后界面会不一致。整个选课系统按照“客户端只发请求、服务端做决策”的思路实现后续加退课、加管理员功能都会轻松很多。4. Android 网络选课系统联调阶段必调的 5 个参数4.1 Android 模拟器访问开发机的地址怎么写在 Android Studio 模拟器里运行 App 时访问 localhost 或 127.0.0.1 会指向模拟器自己而不是电脑。模拟器专门有一个固定地址 10.0.2.2 映射到宿主机。服务端监听在电脑的 8080 端口时Retrofit 的 baseUrl 写成http://10.0.2.2:8080/才能连上。如果你使用的是 Genymotion对应地址是 10.0.3.2不要记混。这个参数最容易表现为“登录按钮点了没反应”日志里出现Failed to connect to /127.0.0.1:8080。遇到这种情况先用模拟器浏览器访问http://10.0.2.2:8080/探活再检查服务端进程是否启动。4.2 Android 9 以上默认禁止明文 HTTPtargetSdkVersion 高于 28 时Android 默认不允许 App 使用未加密的 HTTP 请求直接走http://会报CLEARTEXT communication not permitted。如果服务端没有配置 HTTPS最简单的解决办法是在 AndroidManifest.xml 的 application 节点加一行android:usesCleartextTraffictrue。更稳妥的方式是配置网络安全策略只放行开发用的 IP。在 res/xml/network_security_config.xml 里写network-security-config domain-config cleartextTrafficPermittedtrue domain includeSubdomainsfalse10.0.2.2/domain domain includeSubdomainsfalse192.168.1.10/domain /domain-config /network-security-config然后在 application 节点指定android:networkSecurityConfigxml/network_security_config。正式打包时把域名列表里的 IP 删掉只保留 https 配置。4.3 超时、重试与请求日志OkHttp 默认超时是 10 秒但在教室网络里服务端响应可能很慢。建议 connectTimeout 设成 5 秒readTimeout 设成 15 秒。重试次数不要盲目加大选课接口如果发生网络抖动而被自动重放就可能出现重复提交。虽然数据库有 UNIQUE 约束兜底但无谓的延迟会拖慢页面返回。参数推荐值调整依据connectTimeout5s内网开发环境建议短一点readTimeout15s课程列表接口数据量大时调大writeTimeout15s上传数据时调整OkHttp 重试false避免自动重放写请求HTTP Logging LevelBODY联调阶段查看响应上线改 BASICHttpLoggingInterceptor 的 Level.BODY 会打印完整的请求和响应 JSON联调时非常有用但上线前一定要改成 Level.BASIC否则学生密码这类信息也会被写进日志。4.4 服务端监听地址与防火墙服务端不要绑定 127.0.0.1要监听 0.0.0.0否则真机通过局域网 IP 访问不到。如果你用 Tomcat默认监听 8080还需要注意部署路径。Windows 防火墙或 Linux 的 ufw 要放行 8080 端口否则手机访问时表现为连接超时。检查命令是netstat -ano | findstr 8080Windows或ss -ltnp | grep 8080Linux。确认服务端监听在外网接口后再用手机浏览器访问http://笔记本局域网IP:8080/api/health。如果手机浏览器能打开说明网络通了问题在 App 配置。5. 基于 Android 的网络选课系统答辩验收技巧5.1 模拟多设备并发选课的检查方式选课系统最容易被问到的场景就是并发所以演示前要自己先演一遍。在 Android Studio 里启动两个模拟器用两个不同的学号登录同一个服务端打开同一门课同时点击选课。正常结果应该是一个成功、一个失败失败信息是“名额已满”或“重复选课”而不是两个都显示成功。操作时打开服务端日志观察两个请求的先后顺序和数据库影响行数。也可以在 MySQL 里直接查 student_course 表确认只有一条记录。如果你的服务端没有做事务保护这一条就足以暴露问题。另一种验证方式是用 Android Studio 的 Network Profiler 查看请求耗时看是否出现重试导致的时间异常。5.2 打包 APK 后连接真实服务器的完整检查单答辩现场通常用真机演示提前做好这几项检查# 手机开启 USB 调试连接电脑后执行端口转发 adb reverse tcp:8080 tcp:8080执行后手机访问http://127.0.0.1:8080/会被转发到电脑的 8080 端口这样 App 里的 baseUrl 不用改成局域网 IP 也能联调。这个方法在演示时最稳不受会议室 Wi-Fi 限制。如果不用 adb reverse就确保手机和电脑连同一个局域网服务端监听 0.0.0.0防火墙放行 8080并且把 baseUrl 改成http://电脑局域网IP:8080/。打包时注意签名问题的细节debug 包可以直接安装但换电脑后签名会变卸载重装才能更新。生成 release APK 只需要在 Android Studio 里 Build Generate Signed Bundle / APK创建一个 keystore之后每次打包用同一个文件。演示前先把服务端进程启动好用手机浏览器打开健康检查接口确认 200再打开 App 走一遍登录、选课、退课流程最后把录屏和数据库截图放进演示文档答辩时直接展示。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价