十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于SpringBoot+Vue的同人小说创作与在线阅读平台实现解析

基于SpringBoot+Vue的同人小说创作与在线阅读平台实现解析 最近两年同人小说创作的热度一直没降下来不管是LOFTER还是各种垂直阅读社区涌入的创作者和读者数量都非常可观。但真去做一个面向同人圈子的创作与分享平台和做一套普通的博客系统完全不是一回事——它涉及章节管理、阅读进度、作品审核、互动评论、用户激励等一整套闭环。这篇文章我以“javavue基于springboot的同人小说创作与在线阅读分享平台系统”为例完整拆解从需求分析、技术选型到前后端实现、部署上线的全过程把我在实际开发中踩过的坑、验证过好用的方案都放进来给准备做类似项目的同学一个能直接参考的路线。先说清楚这个项目能做什么它本质上是一个垂直领域的UGC内容平台核心用户有两类——写手和读者。写手需要便捷的创作工具比如分卷分章、草稿保存、定时发布读者需要沉浸式的阅读体验比如目录导航、上下章切换、阅读进度记忆。围绕这两个核心角色还要衍生出用户注册登录、作品分类检索、评论互动、收藏关注、后台管理等模块。技术实现上后端用Java和SpringBoot负责业务逻辑与数据接口前端用Vue负责界面交互两者通过RESTful API通信数据库用MySQL存储业务数据Redis处理热点数据和会话缓存。这套组合在Java技术栈的Web项目里属于最主流、生态最成熟的方案无论是自己练手还是做毕设、接外包都有大量资料可以参考遇到问题也容易找到解决方案。我自己在动手做这个项目时最先想的不是怎么写代码而是把业务边界彻底理清楚。因为同人小说平台和一般的内容管理系统有个很大的区别它的内容是强连载性质的一章一章往外放而且章节之间的顺序、卷册关系、草稿和正式发布的状态切换都非常频繁。如果把数据模型设计错了后面写代码会非常痛苦。所以我花了不少时间在设计表结构、划分子模块、确定前后端交互方式上。下面我就按照从整体到细节的顺序把整个实现过程完整过一遍。1. 项目整体设计与技术选型1.1 核心需求拆解同人创作平台到底要做什么在写第一行代码之前我习惯先用用户故事把系统功能梳理一遍。这个平台的用户角色很清楚游客、注册用户同时是读者和创作者、管理员。游客可以浏览作品和章节但不能评论、收藏或创作注册用户可以创建作品、管理章节、发表评论、收藏关注管理员则负责内容审核、用户管理和数据统计。从创作角度作者需要一个作品管理后台能创建多个作品每个作品下有多个分卷每个分卷下又有多个章节。章节有草稿和已发布两种状态作者可以编辑、删除、排序章节也可以设置作品封面、简介、标签和是否完结。从阅读角度读者打开一本作品后能看到目录列表点进某一章阅读可以调整字号和背景色可以记住上次读到的位置可以对章节进行评论、点赞、打赏早期可以不做打赏用积分替代可以把作品加入书架。从管理角度管理员需要能对注册用户进行封禁或解封对作品进行下架或恢复对评论进行删除同时能看到一些基础的数据看板比如新增用户数、新增作品数、日活跃阅读量。至于关键词搜索、标签筛选、作品排行榜这些属于提升体验的功能可以排在第二期做但表结构设计时最好预留字段。这种需求拆解方式能让我在物理设计阶段心里有谱。一个典型的同人小说平台核心数据实体至少有这些用户表、角色表、作品表、分卷表、章节表、评论表、收藏表、书架表、点赞表、关注表、审核日志表、浏览历史表。把这些表的字段和关系理顺了后面开发基本就是按部就班。1.2 技术栈选型逻辑为什么是SpringBoot Vue这套组合Java后端框架有很多选择SSH早过时了SSM虽然有大量老项目在用但配置繁琐。SpringBoot最大的价值在于“约定大于配置”内嵌Tomcat一键启动不需要额外装Web容器配合Spring生态的starter机制整合MyBatis、Redis、Security都极其方便。对于同人小说这种CRUD占主导、并发量有一定要求但并不夸张的业务场景SpringBoot的稳定性和开发效率非常贴合。前端框架Vue最突出的优势是上手温和、数据驱动视图配合Element UI或Element Plus组件库后台管理页面和用户端页面的开发速度能提升好几倍。相比React需要自己搭配路由和状态管理方案Vue生态的Vue Router和Vuex/Pinia都是官方维护心智负担低很多。特别是做这种展示型管理型混合的项目Vue的单文件组件方式让布局拆分、样式隔离都特别顺手。数据库层面MySQL 8.0是目前Java项目的主流选择事务支持好InnoDB引擎在高并发读写下表现稳定。持久层框架我用的是MyBatis Plus它在MyBatis基础上做了大量增强内置了通用的增删改查方法不用写XML就能完成80%的简单操作遇到复杂多表查询时再手写SQL灵活性和效率兼得。缓存用Redis主要存验证码、Token、热点作品信息和阅读排行榜。前端部署用Nginx托管打包后的静态文件后端打成一个可执行的Jar包运行在服务器上。前后端通过HTTP请求交互Nginx配置反向代理解决跨域问题。这套部署方案复杂度低、稳定性好适合中小型项目。1.3 项目工程结构分层设计让代码不粘稠工程结构我分为后端和前端两个独立目录。后端是标准的Maven多模块或单模块分包结构我个人建议直接单模块按功能分包避免过度设计。核心包结构如下com.fanfiction.platform ├── controller # REST API接口层 ├── service # 业务逻辑层 │ └── impl # 业务实现 ├── mapper # MyBatis Plus数据访问层 ├── entity # 数据库实体类 ├── dto # 数据传输对象 ├── vo # 视图对象 ├── config # 配置类Redis、Security、跨域等 ├── common # 通用工具、异常处理、返回结果封装 └── utils # JwtUtil、DateUtil等工具类这种分层方式的好处是职责单一Controller只管接收参数和返回结果Service专注业务逻辑Mapper只做数据访问。项目变大后想拆微服务也方便业务逻辑都在Service层不依赖Web层。前端Vue项目我用了Vue CLI创建目录结构如下src ├── api # 封装所有后端接口请求 ├── assets # 静态资源 ├── components # 公共组件分页、上传、富文本等 ├── router # 前端路由配置 ├── store # 状态管理 ├── views # 页面组件 │ ├── home # 首页 │ ├── novel # 作品列表、详情 │ ├── reader # 阅读器 │ ├── creation # 创作中心 │ ├── profile # 个人中心 │ └── admin # 后台管理 └── utils # 请求封装、工具函数前后端接口约定统一返回格式我的做法是封装一个Result对象包含code、message、data三个字段。code为200表示成功其他为失败或异常。这样前端拦截器统一判断code值即可不需要每个接口单独处理异常分支。2. 数据库设计与核心模块实现2.1 表结构设计同人平台的数据基石数据库设计是这个项目的重中之重直接决定后续开发的顺畅程度。我先把核心表的字段列一下并说明几个容易踩坑的设计点。用户表设计时需要注意除了基本的用户名、密码、邮箱手机号还需要status字段用于封禁操作。密码不能明文存储我这里用BCrypt加密这是Spring Security内置的加密算法安全性足够。头像、简介、注册时间这些常规字段不多说。有个细节值得提醒用户名和邮箱要做唯一索引否则并发注册时会出现脏数据。作品表是信息量最大的表字段包括作品标题、简介、封面图URL、作者ID、作品状态连载中、已完结、被封禁、分类ID、标签字符串、总字数、收藏数、点赞数、点击量、创建时间、更新时间。其中总字数是通过章节字数累加得到的可以在发布或编辑章节时同步更新而不是查询时实时计算否则数据量大了会拖慢列表页。标签我用逗号拼接字符串存储虽然不算严格规范化但实际查询时可以配合like匹配简单够用。章节表有几个容易出错的地方chapter_no用于排序order字段是MySQL关键字不要用order做字段名章节内容用mediumtext类型避免小说内容太长导致text字段存不下is_free字段用于控制付费章节如果将来要接入付费阅读目前可以默认全部免费。章节表和作品表、分卷表都建立外键索引查询时按chapter_no排序返回。评论表要同时考虑记录评论内容和状态status用于软删除作者删除评论后不是物理删除而是把status改成0方便管理员后台追溯审核。评论支持楼中楼回复的话需要parent_id字段表设计时虽然二期才做但我一开始就预留了。收藏表和书架表可以合并成一张表记录用户ID、作品ID、创建时间唯一索引加在用户ID和作品ID组合上。这里我专门画一个表格把核心表的用途和要点列出来表名核心用途关键字段设计说明t_user存储注册用户信息用户名唯一索引密码BCrypt加密status限制登录t_role用户角色项目中用role字段区分user/admin也可以拆角色表t_novel作品主表author_id索引status索引hot_score用于排行榜t_volume分卷表novel_id关联作品volume_name和排序t_chapter章节表novel_id和volume_id索引content用mediumtext新增word_count字段t_comment章节评论novel_id/chapter_id/user_id索引parent_id支持回复status软删t_favorite书架/收藏user_id和novel_id联合唯一索引t_like_record点赞记录target_type区分点赞作品或章节user_id和target_id联合唯一索引2.2 用户认证与权限控制JWT Spring Security用户认证这块我采用JWTJSON Web Token方案配合Spring Security做接口级别的权限控制。为什么不直接用Session因为前后端分离项目Session有跨域和分布式扩展方面的问题而且移动端将来要对接的话Token方式更灵活。登录流程是这样的用户提交用户名密码后端校验通过后生成一个TokenToken里包含用户ID、用户名、角色信息设置过期时间一般7天返回给前端。前端把Token存在localStorage每次请求时通过axios拦截器在请求头加上Authorization: Bearer xxx。后端Spring Security配置中定义哪些接口需要认证、哪些放行。比如作品列表、章节阅读这些公开接口放行创作中心、评论发布等接口要求认证。Spring Security配置类中我自定义了一个JwtAuthenticationFilter继承OncePerRequestFilter在每次请求时解析Token并将用户信息放入SecurityContext。如果Token过期或非法直接抛出异常并返回401状态码。这里有个细节一定要注意密码加密方式用PasswordEncoderFactories.createDelegatingPasswordEncoder()这样老项目升级密码加密方式时不会导致已存密码全部失效。权限控制上我的做法比较简单用户表里直接有role字段字符串类型一个是ROLE_USER一个是ROLE_ADMIN。Controller方法上用PreAuthorize(hasRole(ADMIN))来限制管理员接口。后台上传作品审核、用户封禁、评论删除这些操作都会校验该注解。这种方式对中小项目够用且直观不用去设计复杂的RBAC权限表。2.3 作品发布与创作中心草稿、分卷、章节三级管理创作中心是这类平台最核心的功能。作者进入创作中心后第一眼看到的是自己名下所有作品点击某个作品进入作品详情页可以编辑封面、简介、分类、标签也可以管理分卷和章节。先说分卷管理。一本长篇小说动辄几十万字分卷是必需的。前端用一个列表展示所有分卷卷名可编辑卷内章节用拖拽排序后端提供新增卷和删除卷的接口。删除卷时要注意需要先判断卷下是否有章节有章节则提示作者先删除或移动章节不能在数据库层面直接级联删除否则作者误操作会丢失大量稿件。这个逻辑虽然简单但如果没有考虑周全处理用户反馈时会很难受。创作编辑页是作者使用频率最高的页面。我采用的方案是Markdown编辑器配合实时字数统计用vue-markdown-editor这个开源组件支持上传图片、代码块、表格等常用语法。章节内容存的是Markdown原始文本阅读器端再通过marked或marked-highlight等库渲染成HTML展示。之所以不直接存富文本HTML是因为Markdown文本更轻量、易迁移而且后续如果要导出TXT或EPUB处理Markdown比处理HTML简单得多。草稿功能我用了一个字段chapter.status区分0表示草稿1表示已发布。作者点击“保存草稿”时只更新内容不修改状态点击“发布”时才正式上架。发布时可以填写发布时间支持定时发布功能。定时发布的后端实现很简单在WebSocket或者定时任务中每分钟扫描一次待发布章节如果当前时间大于等于发布时间就把状态改成已发布。这种轮询方式虽然不优雅但实现简单错误率低。章节排序涉及一个操作技巧前端把拖动后的章节ID列表按顺序传给后端后端逐个更新chapter_no字段。这个接口需要放在Service层加事务避免中途出错导致部分章节顺序改变而部分没有改变。在我的实现里我把整个排序操作封装在一个事务方法里先关掉唯一约束检查如果chapter_no有唯一索引再批量更新。2.4 阅读器模块与阅读进度一次高质量的阅读体验阅读页是同人平台的门面体验好不好读者说了算。我做阅读器时有几个具体指标目录加载要快翻页要流畅阅读进度要能保存字体和背景要能调。目录接口我用了Redis做缓存key是novel:chapterList:{novelId}value是章节ID、标题、序号的JSON数组。作者新增、删除、修改章节时删除对应的缓存key强制下次查询时回源数据库。这样高并发场景下目录接口不会把压力压到MySQL上。阅读正文接口返回的是Markdown转HTML后的内容同时返回当前章节的ID、标题、上一章ID、下一章ID。上一章和下一章的ID通过SQL查询当前章节序号前后两条记录获取比前端根据列表下标猜更可靠。阅读进度记录这里有个关键决策我选择在每次加载章节内容时把阅读进度异步上报到后端存入t_read_history表记录用户ID、作品ID、章节ID、阅读时间。下次用户打开同一作品时后端返回上次阅读章节ID和进度百分比。为什么不前端存localStorage虽然localStorage更轻量但用户换设备后进度就丢了一个成熟的平台肯定要云端保存。异步上报使用消息队列太重我直接用一个异步线程池处理请求先返回后台慢慢写库不阻塞阅读接口。阅读器外观上我给了三种背景色白色、米黄、夜间黑和四种字号档位通过CSS变量实现实时切换。翻页方式支持左右滑动和点击翻页。这部分前端工作量不小但都是纯交互细节只要数据结构设计得好实现起来不会出问题。这里我想强调章节内容渲染后的CSS样式一定不能依赖全局样式要包裹在一个固定类名如.chapter-content下避免和后台管理、个人中心等页面的样式互相污染。我就是在这个问题上吃过亏全局样式导致后台管理页面部分组件样式错乱排查了很久才发现是阅读页的CSS没有加作用域。2.5 互动模块与搜索排行让读者留下来评论、收藏、点赞、关注这四类互动能让平台从“人找书”变成“人聚人”。评论是核心互动方式设计上保留了回复功能。评论列表默认按时间倒序查询时关联用户头像和昵称。删除评论区分作者删除和管理员删除作者只能删自己作品下的评论管理员可以删任何评论。收藏功能就是前面表设计里的t_favorite表用户点击收藏后前端立即更新按钮状态后端异步更新作品收藏数字段。为了防刷我做了限制同一用户对同一作品只能收藏一次数据库联合唯一索引兜底。点赞功能类似不过我在点赞基础上引入了点赞数排行榜用于首页展示热门作品。搜索功能我没用Elasticsearch对中小项目来说过度设计。直接用MySQL的like查询配合组合索引select * from t_novel where title like concat(%, keyword, %) or tags like concat(%, keyword, %)。数据量到几十万条时like查询会有点慢但考虑到大多数同人平台的体量这个方案完全够用。后续如果数据量真上来了再引入Elasticsearch做全文检索也来得及。排行榜我基于hot_score字段这个字段通过定时任务每天凌晨计算一次综合收藏数、点赞数、点击量、更新时间加权得出避免频繁更新导致数据库压力过大。3. 前端Vue实现与前后端联调实战3.1 Vue工程搭建与路由设计这部分先讲工程搭建。Vue项目我用vue/cli创建选择Vue 2.7版本。虽然Vue 3已经是主流但Element UI、vue-markdown-editor等组件对Vue 2的兼容性更稳定网上资料也最多。如果你不依赖老组件直接用Vue 3 Vite也是不错的选择构建速度会快很多。我这里为了稳定少踩坑选了Vue 2.7 Element UI Axios这个组合。路由设计上我分为两部分普通用户路由和管理后台路由。普通用户路由包括首页、作品列表页、作品详情页、阅读器页面、创作中心、个人中心、登录注册页管理后台路由统一挂在/admin路径下子路由有用户管理、作品管理、评论管理、数据看板。管理后台和用户前台共用一个布局外壳左侧侧边栏右侧内容区。比较关键的一个路由设计是阅读器页面的路径/reader/:novelId/:chapterId通过动态路由参数控制上一篇和下一篇的切换。为什么用两个动态参数因为阅读器需要知道当前在哪本书的第几章而不只是章节ID。进入阅读器时先从URL取novelId和chapterId调接口获取章节内容上一章/下一章按钮通过替换router params实现而不是使用router.push重新渲染整个页面这样页面不会闪烁体验更流畅。axios请求封装是重要一环。我在utils/request.js中创建axios实例设置baseURL和超时时间请求拦截器统一添加Token响应拦截器统一处理code不为200的情况。401状态直接跳转登录页403显示无权限提示。每个页面只需调用封装的api方法不用关心Token管理和错误处理代码简洁且不容易出错。3.2 作品展示页与阅读器视觉和交互的平衡作品详情页是决定读者是否入坑的关键页面。我按照常见阅读平台的习惯设计顶部是封面大图、书名、作者、分类、标签、简介和收藏/开始阅读按钮下面是分卷章节列表。这种布局比较常规但信息利用率高。封面图用El-upload组件上传到服务器后端用本地存储策略上传到项目配置的目录下。生产环境如果要上云可以换阿里云OSS或MinIO接口逻辑不需要大改只改存储实现。章节列表我用el-collapse手风琴折叠面板展示分卷结构展开某个分卷后显示该卷下所有章节标题。当前阅读章节高亮显示已读章节标题旁边打个对勾标记。这个标记需要一个已读章节ID集合前端从阅读历史接口获取。阅读器页面是整个项目中交互最讲究的页面。顶部是状态栏显示作品名、章节名、字号调节、背景色切换中间是正文内容底部是上一章、评论、下一章三个按钮。用CSS控制阅读区域宽度字号和行高通过CSS变量动态切换。这里有个很影响体验的细节进入阅读器时页面要自动滚动到上次阅读位置。实现方式是在阅读记录里存一个scrollPercent字段0到100之间的数值章节内容加载完成后通过window.scrollTo(0, document.body.scrollHeight * scrollPercent / 100)定位。需要等图片、样式全部加载完再定位所以放在this.$nextTick和window.onload里双保险。有时候用路由缓存keep-alive可以让阅读器回退时不重新加载但要注意缓存了章节列表会导致章节更新不生效我用include属性只缓存指定组件名并且监听路由变化时做数据刷新。3.3 创作中心与富文本编辑作者体验就是产品口碑创作中心我用了比较克制但信息完整的设计。左侧是作品列表展示每个作品的封面、书名、状态、字数、更新时间和编辑按钮右侧是选中作品的详情面板。点击进入某个作品后进入作品管理页面分为基本信息、分卷章节、评论管理三个tab。基本信息tab里就是作品封面上传、标题、分类、标签、简介的表单。分卷章节tab是创作中心的重头戏我用了一个双栏布局左侧分卷列表右侧章节列表。点击分卷右侧显示该卷下的章节。章节列表每一行显示章节序号、标题、字数、状态、最后更新时间以及编辑、发布/撤回、删除操作。编辑操作跳转到独立编辑页而不是弹窗。因为写小说是一个长时间专注的过程弹窗一不小心就误触关闭丢掉草稿独立页面更安全。编辑页的核心是Markdown编辑器。我用vue-markdown-editor配置了工具栏项加粗、斜体、标题、引用、代码块、图片上传、预览、全屏。图片上传调后端接口返回URL后自动插入编辑器。编辑器下方是章节标题、字数统计和两个按钮保存草稿和发布。字数统计实时计算content字段去空格后的字符数这个数字同步更新到服务器端字段用于作品总字数累计。这里我必须提醒一个易错点Markdown文本里如果包含特殊字符比如反引号、美元符号在向后端传递时要防止被解析或截断。axios默认的application/json传输方式没有这个问题但如果你用表单提交一定要对content做encodeURIComponent处理。我自己在测试时遇到过章节内容里带了一个反引号导致前端JSON解析出错排查了半天最后发现是某个编辑器组件在处理字符串时处理不当。后来我在提交前用JSON.stringify统一序列化问题就再没出现过。3.4 前后端联调与API对接实践前端开发时后端接口可能还没全部完成这时可以使用Mock方案用mockjs拦截axios请求返回模拟数据。但我在真实项目中不太推荐过度依赖Mock因为Mock数据和真实数据结构不一致时联调阶段的问题反而更多。我推荐前后端并行开发时先定好接口文档Swagger或Apifox前端按文档写mock数据后端按文档实现接口最终联调时再修正细节。联调时最容易出问题的是参数格式。我的接口规范是POST请求用JSON格式传递GET请求参数在URL上时间类型统一用字符串传递格式yyyy-MM-dd HH:mm:ss分页参数统一用pageNum和pageSize。这些约定在项目开始前就要写进接口文档里否则每个人按自己的习惯传参联调阶段会乱成一锅粥。登录Token的管理也值得说。我在store里维护userInfo和token两个状态登录成功后存入localStorage。axios请求拦截器从localStorage读Token不需要每次从vuex拿。响应拦截器遇到401时清除本地登录状态并跳转/login?redirect当前地址登录成功后可以跳回原页面。这个ecosystem看起来简单但在实际项目中很能提升体验。Swagger集成很简单后端引入springfox或springdoc配置一下路径和分组启动后访问/swagger-ui/index.html就能看到所有接口的定义、参数、返回值在线调试也非常方便。整个联调过程我强烈建议用Apifox或Postman管理接口集合将常见参数存为环境变量能省下大量时间。4. 部署上线与常见问题排查4.1 本地环境搭建从零跑通前后端如果你想在本机把这个项目跑起来需要先准备好这些环境工具JDK 1.8或11推荐1.8因为兼容性最好Maven 3.6MySQL 5.7或8.0Redis 5.0Node.js 14Vue 2项目Node版本不要太高16或18都可以npm或yarn包管理器后端启动流程先在MySQL中创建数据库执行根目录下的init.sql初始化表结构和基础数据。然后修改application.yml中的数据库连接信息、Redis连接信息确保本机Redis已启动。接着在项目根目录执行mvn spring-boot:run或者用IDEA直接运行主类。启动成功后访问http://localhost:8080/swagger-ui/index.html能看到接口文档就说明后端没问题。前端启动流程在vue目录下执行npm install安装依赖安装时间取决于网络情况。然后修改src/utils/request.js中的baseURL为http://localhost:8080/api再执行npm run serve访问http://localhost:8081。如果端口冲突在vue.config.js里新增devServer配置修改端口。前后端联调时需要在后端取消防跨域限制。我直接在SpringBoot的配置类里写一个CorsFilter允许所有来源访问本地调试的URL。这里有个细节允许的请求头要包含Authorization允许的请求方法要包含PUT和DELETE否则部分请求会失败。4.2 服务器部署Jar包 Nginx一步到位服务器部署我选择的方案是后端打Jar包用systemd或Docker管理前端打静态文件用Nginx托管Nginx反向代理后端接口。这种组合的好处是部署简单、占资源少、稳定性高适合中小项目。后端打包执行mvn clean package -DskipTests在target目录生成xxx.jar。上传到服务器后创建一个systemd服务文件管理生命周期包含启动命令和重启策略。这个设计即使服务器重启后端进程也能自动拉起。前端打包执行npm run build生成dist目录。把dist目录下所有文件上传到Nginx的html目录修改Nginx配置server { listen 80; server_name your_domain.com; location / { root /var/www/html; index index.html; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }try_files配置非常重要因为Vue路由是history模式刷新页面时如果路径不是实际文件Nginx会404加上这个配置后会回退到index.html由前端路由兜底。如果不加你会遇到“刷新页面就404”的经典问题。后端Jar包启动时端口不要用8080我习惯改成8090避免和本机其他Java程序冲突。在application.yml里改server.port。另外生产环境的数据库密码、Redis密码建议用环境变量的方式注入不要明文写在配置里。4.3 高并发场景下的性能优化实践同人小说平台如果做起来了流量可能集中在晚上和周末。我在这类项目上做过的性能优化从基础到进阶有以下几个方向数据库层面合理建立索引是第一优先级。我在t_novel表上建了三个常用索引status索引查公开作品、create_time索引按时间排序、hot_score索引排行榜查询。t_chapter表上建了novel_id chapter_no的联合索引保证章节列表查询走索引。评论表上建了chapter_id索引分页查询时按主键ID分页比直接limit offset高效得多。Redis缓存是第二优先级。除了章节列表缓存我还缓存了作品基本信息key为novel:info:{id}因为作品详情页需要频繁查询并展示作品信息。更新作品时删除对应缓存。对于排行榜直接缓存整个热门榜单JSON每10分钟刷新一次避免每次请求都去数据库算排行榜。浏览器端的性能优化也不能忽视。封面图用懒加载章节列表用虚拟滚动如果章节数超过200章节普通渲染会有明显卡顿图片压缩后上传前端canvas压缩后转Blob再提交。代码层面开启Gzip压缩Nginx配置gzip on前端打包时使用terser压缩能明显减少传输体积。4.4 常见问题与排查技巧速查表我在开发和调试过程中整理了这么一张问题排查表遇到类似问题可以直接对照解决常见现象可能原因排查与解决方案前端请求接口报404后端接口路径或请求方法不匹配进入Swagger对比实际接口路径和前端调用路径检查Controller上有没有CrossOrigin登录后接口仍然返回401Token没有正确传到后端检查axios请求拦截器是否正确设置Authorization头检查Token是否过期前端页面刷新后404Nginx没有配置try_files检查Nginx配置中location / 块是否包含try_files $uri $uri/ /index.html图片上传后加载不出来图片路径拼接错误后端返回相对路径前端在展示时拼接服务器地址章节内容加载慢可能是Markdown渲染耗时长检查渲染过程是否同步阻塞页面改用异步渲染或延迟渲染MyBatis Plus更新数据不生效实体类中某些字段为null时被忽略使用UpdateWrapper配合set方法明确指定要更新的字段定时任务不执行忘了加EnableScheduling注解在启动类上加上该注解检查任务方法是否有Component修饰阅读进度丢失异步上报失败或字段未存检查t_read_history表字段是否与实体类一致上报接口是否有异常吞掉前端打包后样式乱套某个组件的样式没有加scoped排查全局样式覆盖用浏览器开发者工具定位被覆盖的选择器4.5 上线后的运维关注点项目上线后有几件事建议第一时间做配置日志级别为WARN以上减少磁盘占用每日凌晨备份数据库监控JVM内存使用情况配置OOM自动重启Nginx开启访问日志切割防止日志文件无限增长。如果有条件接入一个简单的监控告警平台比如在系统登录数超过阈值或接口错误率上升时发邮件通知。运营层面同人平台的内容安全需要特别上心。除了管理员人工审核建议在作品发布和章节发布接口上增加基础敏感词过滤避免违规内容流入公开区。虽然这会影响一些发布效率但正规化的平台这是必经之路。后台还要提供快速下架能力和用户举报入口审核一定要及时。我个人在实际操作中的体会是这类平台项目只要数据模型设计到位技术实现本身并不复杂。最花时间的往往不是写代码而是反复打磨阅读体验和交互流程。比如阅读进度恢复的准确性、Markdown渲染的细节样式、目录列表在几百个章节时的滚动性能这些看似不起眼的点恰恰决定了用户愿不愿意每天打开你的平台。整个系统从零到一做完你会发现自己在SpringBoot的接口设计、Vue的组件通信、MySQL的索引优化这几个方面都有了非常扎实的实战积累。如果后续想继续扩展可以往WebSocket实时评论、移动端适配、推荐算法这几个方向走每一条路都足够再写好几篇文章。
返回列表