1. 项目概述接手这个基于Android的电子书阅读系统时我的第一反应是这又是一个典型的Java全栈毕业设计项目后端SpringBoot负责业务逻辑前端Android负责展示交互再加一套完整的源码文档视频配套。但真正动手做完之后我发现这个项目比想象中有意思得多——它不只满足交差的需求整个技术栈选型、模块划分、数据库设计、接口对接每一环都有值得展开讲的地方。先说这个项目能做什么。它实现了一个移动端电子书阅读平台的核心闭环用户注册登录、书城展示、书籍分类检索、书籍详情查看、在线阅读器、书架收藏管理、阅读进度同步、个人中心等模块。如果你是正在准备毕业设计的计算机专业学生或者想用一套完整项目来练手、梳理Java后端Android前端协作流程的初级开发者这个项目都值得仔细过一遍。它能帮你把学校学过的SpringBoot、MyBatis、MySQL、Android四大件真正串成一条线。这个项目交付形态是源码加文档加运行视频加讲解视频也就是说不管你是打算自己二次开发、直接拿来答辩还是想照着视频一步步复现都有对应的参考路径。我这次是基于源码重新走了一遍完整流程从环境搭建、数据库初始化、后端启动、Android端编译联调到阅读器翻页、进度同步这类细功能的验证把整个系统的设计思路和踩坑点全部记录了下来。2. 整体设计与技术选型思路2.1 为什么是SpringBoot Android原生现在市面上做移动端电子书App无外乎几条技术路线纯原生Android、跨平台Flutter/React Native、或者套壳H5。这个项目选择Android原生 SpringBoot后端表面看是保守实际上是最稳妥的选择。从项目定位来看这是教学和毕设导向的项目不是商业级产品。原生Android配合Java语言和后端Java技术栈保持统一学习曲线低调试工具链成熟。Android Studio官方模拟器对原生项目支持最好Room或SQLite本地存储和网络请求库OkHttp、Retrofit的集成资料也多遇到问题搜一下就能找到解决方案。用Flutter的话虽然一套代码跑两端很吸引人但Dart语言、Widget树、状态管理这些概念对还没毕业的学生来说学习成本直接翻倍。SpringBoot这边就更不用说了。它解决了传统SSHStrutsSpringHibernate时代的配置地狱问题内嵌Tomcat打成Jar包就能跑配上MyBatis-Plus做数据操作CRUD写起来非常快。尤其适合这种业务不复杂、但涉及多张表关联查询的管理类系统。项目里书籍信息、用户信息、书架记录、阅读进度这几张表用MyBatis-Plus的Wrapper查询机制能省掉大量手写SQL的重复劳动。2.2 系统架构与核心模块划分这个系统整体上是标准的B/S C/S混合架构Android客户端是C端SpringBoot服务端是B端中间走RESTful API。没有引入过于复杂的微服务、消息队列、Redis缓存这些重型组件这是非常务实的决定。毕设项目最重要的是把核心业务逻辑讲清楚、把流程跑通过度设计反而会让答辩时说不明白。模块划分上系统拆成了两大块后端负责数据服务和业务规则主要模块包括用户模块注册、登录、Token鉴权、书籍模块书籍列表、分类、详情、书架模块加入书架、移除书架、书架列表、进度模块阅读进度上报、进度同步。Android端负责界面展示和用户交互主要模块包括启动页与引导页、登录注册页、书城首页推荐书籍、分类Tab、书籍详情页、阅读器页面、书架页面、个人中心页。这种模块划分的好处是前后端可以并行开发接口定义好之后后端不用等Android端Android端也不用等后端。项目文档里给出的API接口文档基本就是按照模块维度来组织的这在团队协作和答辩演示时都很有价值。2.3 技术栈选型的原因分析后端为什么选SpringBoot 2.x而不是3.x这是我在复现时特别留意的点。很多人在GitHub上拉完代码第一步就卡住就是因为JDK版本不对。这个项目如果用SpringBoot 2.7.x对应的JDK是8或11Maven配置也相对好处理。如果强行换成SpringBoot 3.xJDK最低要求17mybatis-spring-boot-starter、druid-spring-boot-starter这些老牌依赖可能还有兼容性问题。项目源码里锁定了版本就是为了保证开箱即用。Android端为什么用Java而不是Kotlin坦白说现在新项目用Kotlin是主流Google官方也推荐Kotlin。但毕设项目用Java依然有充分的理由大部分高校课程还是以Java为主学生的知识储备偏向Java用Java写Android遇到问题时网上的资料量和Stack Overflow的解决方案远比Kotlin多。至于评委老师他们对Java语法更熟悉答辩时解释代码也更容易被理解。从顺利通过答辩这个核心目标出发Java是性价比最高的选择。数据库选型为MySQL 5.7/8.0这个没什么好纠结的。MySQL是后端开发的事实标准客户端工具用Navicat或者DataGrip都能连。唯一需要注意的是字符集一定要统一成utf8mb4否则存一些特殊的标点符号或Emoji字符会出现乱码。项目文档的初始化SQL脚本里已经做了设置但我建议每张表都检查一下排序规则collation这能避免很多隐性问题。3. 后端SpringBoot核心实现拆解3.1 数据库设计与表结构解读这个系统一共涉及四张核心表我分别说一下设计和实际使用中的坑。用户表是最基础的。字段包括用户ID、用户名、密码、昵称、头像URL、注册时间等。密码存储一定要注意不能明文存。项目里用了MD5加密虽然现在看MD5不算安全但对于演示项目足够。如果你想更规范一点可以换BCryptSpring Security自带这个工具类改动成本也不大。书籍表是系统的心脏。字段包括书籍ID、书名、作者、封面图URL、简介、分类ID、文件URL指向PDF或TXT资源、字数、点击量等。这里有个很关键的设计点书籍文件不是直接存数据库而是存在服务器某个目录下数据库里只存文件路径。这个设计我非常赞同它遵循了大文件走文件系统小数据走数据库的基本原则。分类表结构简单就是分类ID和分类名称。书架表和阅读进度表稍微复杂一点。书架表是用户和书籍的多对多关系表核心字段是用户ID、书籍ID、加入时间联合唯一索引防止重复添加。阅读进度表记录了用户对某本书的阅读位置字段包括用户ID、书籍ID、章节ID或页码、进度百分比、最后阅读时间。这个表在阅读器续读功能里发挥作用也是答辩时可以重点讲的技术亮点之一。3.2 Controller-Service-Mapper三层代码实践代码结构是标准的Controller-Service-Mapper三层这也是SpringBoot项目最常见的分层方式。Controller层只做参数接收和结果封装不写业务逻辑Service层处理核心业务流程Mapper层通过MyBatis-Plus操作数据库。以书籍列表接口为例Controller里接收当前页码和每页大小Service层去调Mapper做分页查询返回统一格式的Result对象给前端。这个Result对象在项目里设计成包含状态码、消息、数据三个字段的结构前端可以根据状态码判断请求成功与否弹出对应的Toast提示。这里我想详细说一下项目里统一返回结果的设计这是很多学生容易忽略的细节。如果不做统一封装每个接口返回的数据格式都不一样前端解析起来非常痛苦。统一成Result结构之后Android端只需要写一个OkHttp的callback回调解析成功或失败分支代码复用率会大幅提升。分页查询这块MyBatis-Plus的分页插件要看配置版本低版本和高版本的写法有差异。项目中实际验证过dao层的Page对象、Service层传入new Page(pageNum, pageSize)这种方式在MyBatis-Plus 3.4.x版本下没有问题。需要注意的一点是分页查询时如果不配置分页插件Page参数不会生效SQL会查出全表数据这个坑很隐蔽排查方法是打印SQL日志。3.3 登录鉴权与Token机制这个项目没有引入Spring Security或者Shiro而是自己实现了一个简单的Token鉴权机制。登录成功后后端生成一个Token字符串返回给客户端客户端在后续请求时把Token放在Header里带上后端写一个拦截器Interceptor统一校验。自己在拦截器里做鉴权逻辑要处理清楚。项目里的实现是自定义一个AuthInterceptor实现HandlerInterceptor接口的preHandle方法从Header中取出Token用Redis或者内存Map对比是否存在且未过期。这个方法请求前都要查数据性能一般但胜在简单易懂也方便答辩时讲清楚无状态登录的原理。我建议把需要拦截的路径和不需要拦截的路径分开配置比如登录、注册、首页书籍列表接口可以不拦截书架、进度、个人中心接口必须拦截。项目里用注册拦截器时设置了excludePathPatterns来放行这些公开接口。在实际调试中我发现放行路径写错了会导致明明登录了却提示未认证排查时要先看拦截器配置。3.4 文件上传与静态资源映射电子书阅读系统永远避不开文件上传问题。后端要提供一个接口让管理员上传封面图和电子书文件。字母JAVA里最常见的方式是用MultipartFile接收文件然后写到服务器本地目录。这里有个看似简单但很影响体验的细节文件保存路径一定要和静态资源映射路径对应好。不配置WebMvcConfigurerAndroid端通过URL访问图片时会404。项目里实现了addResourceHandlers方法把本地保存目录映射到了/img/**和/file/**这两个虚拟路径下这样前端拼接URL时就不用关心服务器实际路径了。我在日志里看到过好几次路径拼接错误其实都是这里没配对。复现时还要注意文件上传大小默认限制是1MB电子书PDF动辄几十MB如果不在application.yml里配置spring.servlet.multipart.max-file-size上传大文件会直接报错。我第一次启动项目上传测试PDF时就被这个默认限制拦住了调整成100MB才正常。4. Android端核心功能与实现要点4.1 项目结构与页面导航框架Android端采用传统的XML布局 Activity/Fragment结构没有引入Jetpack Compose这是考虑到项目风格统一和兼容性。整体导航用的是底部导航栏BottomNavigationView加ViewPager2的组合方式底部四个Tab分别是书城、书架、分类、我的。底部导航加Fragment懒加载是Android项目中非常经典的做法。我在复现时发现ViewPager2的Fragment销毁和重建会带来一个问题每次切换Tab都会重新请求网络。为了避免频繁请求项目中用到了Fragment的setUserVisibleHint或者ViewPager2的registerOnPageChangeCallback来做懒加载。如果没有这层处理应用跑起来会感觉卡顿因为每个Tab都在抢网络资源。网络请求这块用的是OkHttp搭配Gson解析。项目里封装了一个HttpUtil工具类统一处理GET和POST请求返回数据通过Gson解析成对应的实体类。这个工具类没有引入Retrofit主要是为了简洁把网络层的依赖降到最低。如果你追求更好的代码结构换成Retrofit是完全可行的但要注意接口回调的线程切换问题。4.2 登录注册模块与SharedPreferences数据持久化登录注册这个模块用到的技术点虽然基础但它是理解整个App数据流的好入口。用户输入用户名密码后点击登录按钮Android端发起POST请求携带JSON格式的用户名密码后端校验成功后返回Token和用户信息。Android端拿到数据后把Token和用户信息存入SharedPreferences。之后所有的请求都从SharedPreferences里取Token放到Header里实现用户态保持。SharedPreferences存储是Android里最简单的持久化方案。它是一个XML文件通过键值对保存数据。对于登录状态这种轻量数据足够用不需要上数据库。But有一点要注意SharedPreferences里的多进程问题如果你用了多进程模式SharedPreferences会失效。这个项目是单进程应用不存在这个问题但在答辩时被问到可以提一句。自动登录功能是很多学生在项目里容易漏掉的。项目的处理思路是App启动时如果有缓存的Token就跳转首页没有就跳登录页。这个逻辑在启动页的onCreate里实现。我在测试时发现有个细节容易踩坑Token过期或被清掉后直接跳转登录页没问题但旧页面还停留在任务栈里按返回键会退到之前的界面。需要在跳转时加上Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK清理任务栈。4.3 书城列表与RecyclerView适配器书城首页是电子书App的门面列表展示的效果直接影响使用体验。项目使用RecyclerView来实现书籍列表配合CardView卡片列表和Glide图片加载库来完成界面效果。RecyclerView的适配器Adapter是理解Android数据绑定的钥匙。项目里为书籍列表实现了BookAdapter继承RecyclerView.Adapter在onBindViewHolder方法中为每一项的封面、书名、作者、简介赋值。数据源是List 通过setList方法从Activity传入Adapter更新后调用notifyDataSetChanged刷新列表。我在测试时发现一个Glide相关的细节加载网络图片时因为服务器返回的书籍封面尺寸不一有的特别大有的很小RecyclerView快速滑动时会明显卡顿。解决方法是Glide加载时强制指定图片尺寸然后用CenterCrop裁剪。这个优化效果立竿见影滑动流畅度提升非常明显。下拉刷新和上拉加载更多是书城列表的标配功能。项目用的是SmartRefreshLayout这个开源库配置起来比原生SwipeRefreshLayout更方便支持上拉加载、下拉刷新还自带动画效果。需要在网络请求中传入当前页码和页大小上拉时页码加一把新数据追加到列表尾部。这里容易出bug的是刷新数据时页码要重置为1否则第一条数据会重复出现。4.4 阅读器实现与进度同步逻辑阅读器是这个项目里最有分量的部分也是答辩时评委最可能追问的模块。项目的阅读器实现思路是从服务器拿到书籍文件的URLAndroid端下载文件后进行解析和渲染。如果书籍是TXT格式用流式读取的方式分段加载进内存。这个方案适合几MB到几十MB的TXT文件通过计算文件长度和每页显示字数可以把数据切分为多个页。阅读器界面上通过手势左右滑动实现翻页效果。具体实现分三步走。第一步计算每页可以显示多少个字符保存pdfChapter等阅读器配置这里要注意中文标点符号的显示宽度和屏幕上TextView的实际宽度。第二步用户滑到某一页时根据页码和每页字数计算开始字符位置和结束字符位置截取字符串显示到界面上。第三步页码变化时把最新的页码上报到后端后端更新阅读进度表。如果书籍是PDF格式项目用的是AndroidPdfViewer开源库。它基于PdfRenderer底层实现滑动流畅性不错。PDF阅读器的进度统计只能精确到页数不能精确到行。此时进度可能变化不大所以上报接口做了防抖处理即进度变化超过1%才真正请求后端。阅读进度同步是这个系统体现分布式思想的地方也是我觉得值得在答辩时说清楚的点。用户在手机A上读到第100页关闭App换到手机B登录同一账号打开这本书系统会根据后端保存的进度恢复阅读。这个功能涉及到查询进度接口和上报进度接口两个API的配合。为了不让人觉得是简单分页数据你要把进度同步从业务层面讲明白后端记录的是这本书的最终位置多端读取同一记录实现数据一致性。4.5 书架模块的增删查实现书架模块本质上是用户与书籍的关系维护。加入书架的按钮在书籍详情页点击后Android端调用POST接口把用户ID和书籍ID传给后端后端执行insert操作并做联合唯一索引冲突判断。如果用户已经在书架上返回已添加的提示。书架列表页面使用RecyclerView展示当前用户书架内的所有书籍。这个接口需要传递用户ID直接从SharedPreferences读取后端查询书架表关联书籍表返回完整书籍信息。移除书架的逻辑就是根据用户ID和书籍ID执行delete没什么特殊的。有一个交互上的细节值得提醒书架列表的item显示的是封面图和书名没有显示阅读进度条。但后端接口其实已经返回了进度字段。如果想增强用户体验可以在列表项上加上一个简易的水平进度条ProgressBar展示这本书读到百分之多少。这不影响后端只需前端把进度字段关联上去。扩展成本很低但演示效果会好很多。5. 常见问题排查与避坑实录5.1 环境与版本兼容性问题这个项目复现最核心的障碍永远是环境问题。我在不同电脑上跑过SpringBoot和Android项目每次遇到报错十有八九都是版本不匹配。最常见的是JDK版本不兼容。项目用的SpringBoot 2.x如果你本机装的是JDK 17甚至更高版本启动时会提示不支持发行版本或者某些反射方法找不到。最简单的解法是删除项目里的target目录然后通过IDE的Project Structure把SDK切到Java 8或11。如果你本机没有低版本JDK可以直接下载安装不需要卸载高版本通过IDE给这个项目单独指定JDK路径就行。Maven依赖下载失败是另一个高频问题。国内访问Maven中央仓库比较慢导致首次加载依赖时卡很久甚至超时。解决思路很简单修改Maven的settings.xml文件把镜像换成阿里云镜像仓库。配置方法是在mirrors节点中加一个mirrorurl指向https我的maven.aliyun.com/repository/public这能显著提升依赖下载速度。Android Studio这边也有坑。项目如果用的是老版本的Gradle和新的Android Studio版本可能不兼容。解决办法不是升级项目里的Gradle而是查看SDK Manager确保安装了项目build.gradle中指定的compileSdkVersion对应的SDK Platform。运行时如果报安装的Android SDK版本不匹配百分之九十是这个原因。5.2 运行时错误与接口联调问题接口联调是前后端分离项目最容易出问题的环节。第一个常见问题是IP地址没有配对。Android模拟器里访问本机后端服务不能用localhost或127.0.0.1必须用10.0.2.2。因为模拟器内部虚拟出一台独立的网络环境10.0.2.2是它映射到宿主机的特殊地址。我在测试时经常看到有人把接口地址写成localhost结果连接被拒绝这是新手最容易踩的坑之一。如果用的是真机调试则必须把地址改成电脑在局域网内的IP并保证手机和电脑连接同一个Wi-Fi。第二个常见问题是网络权限。Android 9API 28开始默认禁止明文HTTP流量。项目如果用的是http协议而不是https并且没有在AndroidManifest.xml里配置usesCleartextTraffictrue那么所有网络请求都会失败。具体表现是OkHttp回调收到IOException而后端日志里根本没有请求进来。配置后问题就能解决。如果你的项目targetSdkVersion比较高还可以用更精细化的networkSecurityConfig配置但作为毕设项目直接开全局明文比较简单。第三个问题是我在调试进度同步时遇到的后端时间字段传过来变成了字符串Gson解析时变成了Timestamp对象格式化后日期显示错乱。这个问题的根源是Jackson和Gson在序列化日期类型时格式不一致。建议在项目里约定统一的时间格式比如yyyy-MM-dd HH:mm:ss后端在DTO属性上加JsonFormat注解Android端用SimpleDateFormat解析。这样能让时间显示可控不会出现各种奇怪的偏移。5.3 数据库连接和中文乱码问题数据库连接出问题是另一个重灾区。项目启动时如果报Communications link failure首先检查MySQL服务有没有启动。Windows的Services窗口里可以看。环境变量里有没有配好MySQL的是其次。另一个常见的错误是Access denied for user用户名密码不对或者没有对应的远程访问权限。建议统一用root超级用户做本地演示但要说一句正式项目里不推荐这用法。中文乱码问题主要出现在两处。一处是后端向MySQL写入中文时由于数据库表的字符集不是utf8mb4变成了一串问号。另一处是Android端请求数据时CURD接口返回的中文乱码没有在服务器端设置编码。对于第一处问题最佳解法是删表重建直接把初始化SQL脚本改一遍建库语句把字符集定为utf8mb4。如果是已经建好的库可以用ALTER命令修改字符集。对于第二处问题要确保SpringBoot的配置文件里server.servlet.encoding.force和charset设置正确在application.yml里加上encoding相关配置。我在项目里实测下来最稳定的组合是数据库字符集utf8mb4Tomcat编码UTF-8Android端请求和解析全部用UTF-8这样中文显示非常稳定。5.4 其他值得说说的小问题模拟器启动时可能遇到内存不足的问题。Android Studio默认的AVD比较吃内存如果你电脑配置一般建议在AVD配置里把内存设成2GB同时在启动模拟器前关闭其他大型软件这样不容易卡死。阅读器加载大文件TXT时的ANRApplication Not Responding也非常值得提。如果一次性用readFile把几十MB的文件读入内存主线程会卡顿。我建议把文件读取放到子线程用AsyncTask或者线程池都行读取完成后再通过runOnUiThread切换回主线程更新UI。用户体验是反应灵敏不会卡顿不会弹出无响应的对话框。视频讲解里提到的Android后台管理端设计实际项目里通过一个简单的Web页面也能完成管理操作但完整的web管理后台并不在Android端体现而是在SpringBoot端直接用Postman测试。如果你想给答辩加分可以给项目写一个特别简单的基于Thymeleaf的网页管理后台功能只要实现新增书籍和删除书籍即可。工作量不大但展示了前后端分离之外的全栈能力。6. 关键代码逻辑解析与二次开发建议6.1 Token拦截器和后端核心代码解读先把项目中最关键的鉴权拦截器代码逻辑理一遍。这个拦截器需要实现HandlerInterceptor接口核心代码在preHandle方法中完成Token校验。Component public class AuthInterceptor implements HandlerInterceptor { Autowired private UserTokenMapper userTokenMapper; Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 放行OPTIONS请求 if (OPTIONS.equals(request.getMethod())) { return true; } String token request.getHeader(token); if (StringUtils.isEmpty(token)) { response.setStatus(401); return false; } // 判断token是否存在且未过期 UserToken userToken userTokenMapper.selectOne( new QueryWrapperUserToken().eq(token, token)); if (userToken null || userToken.getExpireTime().before(new Date())) { response.setStatus(401); return false; } return true; } }这段代码逻辑非常直观解释了为什么登录之后才能访问书架和进度这些接口。在WebConfig里注册拦截器时要注意排除掉登录和注册页面的路径否则会出现一个悖论你还没登录想访问登录接口反而被拦截器挡回来了。这里也想说一句关于Token存储的建议。我建议把这个拦截器配合一个比较长的随机字符串生成Token格式可以用UUID。这样每个用户的Token都是唯一的被拦截器解析时的碰撞概率也非常小。如果项目里加上Redis可以直接用Redis的key过期机制代替数据库存储会让Token过期这个逻辑更优雅。6.2 Android端网络请求的封装思路Android端所有网络请求走同一个入口是通过HttpUtil工具类实现的。它的核心代码思路如下基于OkHttp的异步请求把JSON字符串作为POST请求的body回调中再做JSON解析。public class HttpUtil { private static final String BASE_URL http://10.0.2.2:8080/api/; private static final MediaType JSON MediaType.parse(application/json; charsetutf-8); private static OkHttpClient client new OkHttpClient(); public static void post(String url, String json, Callback callback) { RequestBody body RequestBody.create(json, JSON); Request request new Request.Builder() .url(BASE_URL url) .header(token, getToken()) .post(body) .build(); client.newCall(request).enqueue(callback); } private static String getToken() { SharedPreferences sp MyApplication.getContext() .getSharedPreferences(user_info, Context.MODE_PRIVATE); return sp.getString(token, ); } }这种工具类的封装方式在毕设项目里已经够用了。但要注意BASE_URL里写的是10.0.2.2如果你用真机调试记得改成电脑的局域网IP。项目里要定义一个全局常量或者做一个Debug配置切换这样模拟器和真机切换时只改一处即可。6.3 书籍文件断点下载与阅读缓存电子书文件动辄几十MB如果不做断点下载和缓存用户每次打开书都要反复重新下载体验非常差也容易被评委追问这个高并发场景下如何优化。项目里虽然没有实现完整的断点续传但做了文件缓存的判断逻辑打开书籍时先检查本地缓存目录是否存在该书籍文件如果存在直接读取如果不存在先下载再打开。File bookFile new File(getExternalFilesDir(books), bookId .txt); if (!bookFile.exists()) { downloadBook(bookFile, bookUrl); } else { openBook(bookFile); }这是一种非常实用的缓存思路。我二次开发时建议把下载逻辑放到Service里执行这样即使用户退出阅读页面下载也不会中断。下载过程中用Notification显示进度条用户体验会更完整。断点续传可以用OkHttp的Range头实现逻辑不复杂但能给项目增色不少。6.4 基于项目的扩展方向这个项目按原样交付是一份标准的毕设作品但如果你在时间富余、想冲优秀论文的情况下有几个扩展方向性价比极高。方向一是增加智能推荐。目前书城的书籍列表是顺序展示的你可以通过后端埋点方式记录用户阅读历史然后用标签系统给用户打上分类偏好再基于协同过滤算法推荐书籍。实现上不需要造轮子用一个简单的余弦相似度计算公式就可以支撑小规模数据下的推荐效果。这项能力在答辩时拿出来比单纯增删改查能加不少分。方向二是引入搜索功能。目前系统里搜索书籍是通过后端模糊查询实现前端输入关键字搜书名或作者。建议扩展成支持搜索分类、简介和标签的全文搜索。数据库层面可以用LIKE结合倒排索引的思路实现简单但要说清楚适用于数据量小的场景。如果想用Elasticsearch数据量小反而显得杀鸡用牛刀答辩提问时可能不好解释。方向三是增加阅读统计和排行榜。后端记录每个用户每天的阅读时长按周生成排行榜在书城首页做个本周阅读之星的榜单。这个功能涉及定时任务Spring的Scheduled、聚合查询、Redis缓存等知识点纵向切入很深是很典型的小而美的功能扩展。方向四是实现多格式电子书支持。当前系统主要支持TXT和PDF可以扩展EPUB格式解析。EPUB是HTMLXML的压缩包使用Java的EPUB库可以比较方便地解析出章节内容和样式实现排版更美观的阅读器。这个功能在技术深度上足够写一篇突出的毕业设计论文。7. 项目复盘与实际操作体会东西都跑通之后我重新审视了这个项目的完整度。讲道理对于一个以教学和毕设为导向的项目来说它的覆盖面是相当全面的——既有后端常用的CRUD和Token鉴权也有Android端经典的RecyclerView列表、ViewPager2页面切换、阅读器解析实现还有最容易被忽视的跨端联调和版本兼容问题。我最推荐这个项目的部分是阅读模块。它不是一个花架子而是真的涉及到了文件解析、内存管理、UI 更新和网络请求的综合问题。你如果想研究 Android 开发里很常见的大文件读取会不会 OOM子线程更新 UI 的正确姿势这类问题这个模块就是很好的练兵场。理解透了你会发现很多 App 里的加载优化问题归根到底都是同一个模型。再聊一点代码习惯的问题。我在阅读源码时发现项目里有一部分的 Activity 直接持有 Service 的引用另一些又通过 Callback 模式解耦。它的实现存在不同风格混用的情况这在毕设项目里其实很常见因为代码是分阶段写出来的。如果你要二次开发建议把网络回调统一到一个层次比如 MVP 模式里的 Presenter 层不要让 Activity 里同时出现直接的网络请求和 Callback 嵌套不然维护起来会非常累。我个人的经验是拿到这种带源码的项目不要急着改功能先把完整的 Demo 跑通。跑通了你就有了一个可以放心对照的正确版本。之后做任何修改先把需求拆解成多个小的改动点一次只改一处改完立即编译测试。尤其是改数据库字段或接口参数时前后端必须同步改否则查 BUG 的时间比写代码的时间还长。最后分享一个小技巧。如果你准备拿这个项目答辩千万不要照着代码念。找一个你觉得最得意的模块比如阅读进度同步把完整的数据流讲出来用户滑动页码触发上报、后端更新数据库、换设备拉取进度、客户端恢复位置这整条链路里涉及的 Android 生命周期、网络请求、数据库事务、Token 鉴权一个模块能串起整个 Java 后端和 Android 端的技术点比拿着 PPT 念十页还管用。项目做完只是第一步能把过程说清楚、原理讲明白才算真正把它变成了自己的东西。