Spring Boot 3技术栈做网文系统,现在算得上是Java后端入门阶段非常合适的实战选题。这份“springboot3网文系统---附源码06107”我完整跑通了一遍,从环境准备到功能实现再到二次扩展都摸了一圈,下面把我实际操作中的理解和踩坑记录整理出来,给正在做课程设计、毕业设计,或者想系统学习Spring Boot 3 + Spring Security 6这套技术组合的同学一个参考。
网文系统说白了就是网络文学阅读平台的后端管理系统,核心业务围绕“小说—章节—用户—阅读”这条主线展开,前台管阅读,后台管内容,整个业务链路非常清晰,很适合用来串联Spring Boot 3框架里那些核心知识点。而这份源码的价值在于,它不是一个只写了几个CRUD接口的demo,而是把Spring Boot 3、Spring Security 6、JWT认证、MyBatis Plus持久层、分层架构等真实项目常用技术一并集成进去了,每一块都值得花时间吃透。
1. 项目概述与技术选型思路
1.1 网文系统的核心业务到底是什么
拿到这个项目标题,第一反应是“网文系统”到底包含哪些功能。我实际把源码拉下来跑通之后,业务模块基本可以分成前台和后台两条线。
前台面向普通读者,核心功能是用户注册登录、首页内容展示、小说分类浏览、关键词搜索、小说详情查看、章节目录、章节内容阅读、收藏、评论等。这里有个容易被忽略的细节,别看“阅读章节”这个功能简单,背后涉及章节排序、阅读记录、内容分页等多个环节,是前台开发的重点。
后台面向小说编辑和管理员,核心功能是小说分类管理、小说信息维护(书名、作者、简介、封面、连载状态)、章节录入与编辑、用户管理、评论审核、阅读数据统计等,属于典型的内容管理场景。
整个系统的数据模型设计也非常典型,小说表、章节表、用户表、评论表、收藏表、阅读记录表这几张核心表就能把主流程串联起来。章节表通过小说ID关联小说表,评论表关联小说或章节,收藏表和阅读记录表关联用户和小说,表结构不复杂但关系清晰,非常适合用来理解“数据表设计是如何支撑业务逻辑的”。
1.2 为什么用Spring Boot 3而不是继续用2.x
现在很多学校课程设计和网上的开源项目还在用Spring Boot 2.x,这份源码直接用Spring Boot 3,是它比较有价值的一个点。Spring Boot 3相比2.x不仅仅是版本号变化,底层有几次不能忽视的调整。
最直观的变化是Java版本基线。Spring Boot 3要求Java 17及以上,这意味着本地开发环境需要装JDK 17,IDE也要做相应配置,以前用JDK 8跑Spring Boot 2.x的习惯得改一改。Java 17引入的record、switch表达式增强等新特性,在实际编码中也能带来一些便利。
另一个重大变化是javax包名迁移到jakarta。这算得上是Spring Boot 3迁移中最容易出问题的点,导入依赖时如果不小心用到旧的javax.annotation、javax.servlet等包,编译阶段直接报错找不到类。实际测试中,第三方库如果还没适配jakarta命名空间,在Spring Boot 3里也跑不起来。
除此之外还有Spring Security 6的配置方式变化,方法级安全注解从原WebSecurityConfigurerAdapter改为基于SecurityFilterChain的Bean注册,配置风格更偏向Lambda表达式。这套变化在源码的认证授权模块中体现得非常明显,学习价值很高。
1.3 项目整体模块划分与源码结构解读
源码的包结构走的是标准的Maven单工程多包分层思路,没有拆成微服务,对于这个体量的项目来说非常务实。我实际把工程导入IDEA之后,整体结构大致如下:
- config包:放各类配置类,包括Web配置、Spring Security配置、跨域配置、MyBatis Plus配置等,是整个项目的“基础设施层”。
- controller包:接收前端请求,按业务模块拆分为多个Controller类,只负责参数接收、调用Service、结果返回,不写具体业务逻辑。
- service包:业务逻辑层,接口加实现类的形式,核心业务判断放在这一层。
- mapper包:数据持久层,基于MyBatis Plus的BaseMapper接口,大部分单表操作直接继承就能用。
- entity包:数据库表对应的实体类,使用Lombok简化getter/setter。
- dto包 / vo包:数据传输对象和视图对象,用于前后端数据交互,避免直接暴露实体类结构。
- common包 / util包:通用返回结果封装、异常处理、JWT工具类、字符串处理等公共组件。
- resources目录:配置文件、SQL脚本、可能用到的静态资源或模版文件。
这种分层方式没有花哨的设计,但每层职责分得很清楚,从Controller到Service再到Mapper是一条非常直接的调用链。对于正在学Spring Boot的同学来说,这种传统分层结构反而更容易理解,因为每一层的任务都很固定,不像微服务那样需要考虑服务拆分、远程调用、分布式事务等问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心细节拆解与源码重点解析
2.1 Spring Boot 3 + MyBatis Plus的整合细节
项目持久层框架选择的是MyBatis Plus,不是Spring Data JPA,也不是原生MyBatis。这个选型很贴近国内Java开发者的实际工作场景,MyBatis Plus在MyBatis基础上封装了通用CRUD、分页插件、条件构造器,大幅度减少单表操作的样板代码。
整合过程中有个细节值得留意:Spring Boot 3对应的MyBatis Plus版本需要选用支持jakarta命名空间的新版本。早期版本是在javax命名空间下面运行的,直接拿旧版本移植到Spring Boot 3会报错。实际操作中建议使用3.5.5以上的版本,并且引入mybatis-plus-boot-starter依赖时要注意版本号不要过低。
分页功能的实现是MyBatis Plus非常常用的能力。配置分页插件时,新版API和旧版略微不同,需要在配置类中手动注入PaginationInnerInterceptor:
java复制@Configuration
@MapperScan("com.example.wenxian.mapper")
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
配置完成之后,Service层通过Page对象传参调用Mapper方法即可实现物理分页。这里有一个很容易被新手忽略的点:Spring Boot 3里@MapperScan注解的包路径一定要和实际Mapper接口所在包保持一致,否则启动时会报找不到Bean的错误。我调试源码时有一回就是因为包名复制错了,导致项目直接启动失败。
2.2 Spring Security 6 + JWT认证方案的类型变化
网文系统的用户认证与授权是源码的精华部分。Spring Boot 3内置的安全框架是Spring Security 6,配置方式和早期版本相比有比较明显的调整。
在Spring Security 6中,WebSecurityConfigurerAdapter已经被标记为废弃,取而代之的是基于SecurityFilterChain的Bean配置方式。这份源码走的正是新式配置,核心思路是创建一组过滤器链,告诉Spring Security哪些路径允许匿名访问、哪些路径需要认证、使用什么方式处理登录请求。
一个简化的配置骨架如下:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/user/login", "/api/user/register", "/api/book/list").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
注意到几个关键点:一是关闭csrf,因为基于JWT的无状态接口本身不依赖Session机制,开启CSRF防护反而没有实际意义;二是关闭Session,设置SessionCreationPolicy.STATELESS,让每一次请求都独立携带JWT做认证;三是放行部分公开接口,比如登录、注册、图书列表,其余接口都需要登录后才能访问。
JWT认证过滤器是整个认证链路的核心,它的作用非常简单粗暴:从请求头的Authorization字段提取Bearer Token,解析成功后把用户信息封装进SecurityContext中,后续接口通过@AuthenticationPrincipal或SecurityContextHolder就能拿到当前登录用户。
调试这一段时需要注意,Spring Security 6对请求匹配规则的写法有变化,旧版的antMatchers被淘汰,换成requestMatchers方法。如果从网上复制旧版代码到Spring Boot 3项目里,编译会直接报错。
2.3 小说章节表结构设计与阅读记录的业务处理
网文系统一个重要的业务场景是章节阅读,涉及的数据表设计和业务逻辑可以用“体积不大但结构严谨”来形容。
小说章节表最关键的设计是排序字段,章节必须按照发布顺序展示给读者。很多新手做章节表时只存章节名称和内容,没有排序字段,导致章节顺序错乱。正确定义是在章节表中设置chapterOrder或sort字段,查询时使用order by chapterOrder asc来保证顺序。
章节内容属于典型的TEXT大字段,如果标题、简介、正文全塞在同一张表里,列表页查章节目录时也会把大字段查询出来,性能会白白浪费。优化方式是章节表把基础信息(所属小说、章节标题、排序、字数、发布时间)和正文内容拆分成不同字段,列表页只要基础信息,阅读页再查正文。有些系统甚至会拆成章节信息表和章节内容表两张表,这是网文系统性能优化中很实用的思路。
阅读记录表的设计同样值得研究。它的核心作用是让读者再次进入小说时能快速定位到上次阅读位置,业务上需要以用户ID和小说ID作为联合维度记录最新章节ID和最后阅读时间。这里常见做法是建唯一索引(userId, bookId),不存在记录就插入,存在就更新,避免重复数据。
源码中阅读记录模块的Service实现很适合作为MyBatis Plus条件构造器CRUD的练习素材,用LambdaQueryWrapper就能写得很简洁:
java复制// 新增或更新阅读记录
WenReadRecord existing = readRecordMapper.selectOne(
new LambdaQueryWrapper<WenReadRecord>()
.eq(WenReadRecord::getUserId, userId)
.eq(WenReadRecord::getBookId, bookId)
);
if (existing == null) {
// 新增
} else {
// 更新章节ID和阅读时间
}
2.4 JWT双Token刷新机制设计与源码实现
继续往下看认证模块,我发现这套网文系统JWT实现时参考的是双Token方案——Access Token负责短时访问,Refresh Token负责过期续期。
Access Token有效期设置较短,大约2小时,用户访问接口时随身携带,服务端验签通过后放行。Refresh Token有效期略长一点,一般在7到14天,专门提供给前端在Access Token过期后去换取新Token。
方案设计上这么拆有明确的原因:Access Token有效期太长会有安全隐患,一旦泄露,攻击者能持续访问;有效期太短又会让用户频繁重新登录,体验很差。双Token方案在安全和体验之间找到了一个平衡。
Refresh Token在下发到前端时同样走JWT生成流程,但数据结构上可能增加一个tokenType字段标识访问Token还是刷新Token,服务端校验时对Token类型做区分,防止用Access Token去刷新新Token。这个细节在自定义登录逻辑和Token生成代码里有所体现。
JWT相关的工具类和过滤器在整份源码中属于核心位置,我建议优先阅读这几个类:
java复制// JWT工具类生成Token的典型方法
public String generateToken(Long userId, String username) {
return Jwts.builder()
.setSubject(username)
.claim("userId", userId)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 86400000L))
.signWith(secretKey)
.compact();
}
代码里如果看到为每个用户分配随机盐值生成Token的方式,那就是为后续Token主动失效和做审计预留的方案,属于加分项设计。
3. 实操过程与核心功能实现
3.1 本地环境准备与项目启动流程
把源码下载到本地之后,第一步要做的事情是检查环境。Spring Boot 3对这个项目的开发环境有硬性要求,这套源码我运行时使用的是本机JDK 17,Maven 3.8以上版本,IDE用的IDEA。这三样不达标,后面的步骤会不断踩环境坑。
数据库方面项目默认使用的是MySQL 5.7或8.x都可以,需要提前把一个名为数据库名的空数据库准备好,再通过Navicat等工具导入项目SQL脚本。SQL脚本一般在源码的sql目录或根目录下,文件名类似wenxian.sql、init.sql,导完脚本就能看到全部核心表结构和部分初始化数据。
接下来改配置文件,application.yml或application.properties中,需要重点确认这几项配置:
yaml复制server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/wenxian_system?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: 你自己数据库的密码
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
如果你的MySQL是8.x版本,注意driver-class-name一定是com.mysql.cj.jdbc.Driver,老版本驱动名称在Spring Boot 3下会提示异常。还有url里最好加上serverTimezone=Asia/Shanghai,否则数据库时区差异会导致时间字段显示不正确。
配置完成后用IDEA右侧Maven面板执行clean和install,编译通过后启动项目。控制台出现Tomcat started on port(s): 8080代表服务启动成功。如果想验证接口是否正常,浏览器访问http://localhost:8080或调用登录接口测试一下就行了。
3.2 登录注册与JWT认证流程的完整解析
登录注册是网文系统中最有技术含量的链路,我建议读源码时重点分析这条流程。注册流程重点看密码如何加密存储,源码中大概率使用的是BCryptPasswordEncoder。Spring Security官方推荐这个加密方式,每次加密同一个密码会得到不同hash,内置加了随机盐,可以防御彩虹表攻击。
用户名重复校验、邮箱/手机号格式校验属于注册接口的常规逻辑,在Service层实现。前端传参密码,后端加密后入库,绝不直接存明文,把数据库表打开看到的应该是BCrypt加密串。
登录流程涉及一个常见的设计点:验证密码时使用passwordEncoder.matches(rawPassword, encodedPassword)方法,而不是把数据库中的密文解密后比较。BCrypt是不可逆的,只能通过输入原始密码再生成hash结果做比对,这是很多写用户模块的开发者容易误解的地方。
认证成功后的核心逻辑简单说:服务端生成JWT Token,将用户基础信息放入Token的Claims中,最终返回给前端。前端之后每次请求,在Authorization请求头携带Bearer Token,JwtAuthenticationFilter会自动解析出用户身份并放入SecurityContext。
网文系统在获得用户身份后,还会通过ThreadLocal或SecurityContextHolder拿到当前登录用户的userId,用于判断收藏、评论、阅读记录等归属关系。这是一条完整的认证链条,跟着源码走一遍会对Spring Security + JWT方案有比较立体的理解。
3.3 小说发布、章节管理的后台设计要点
网文系统的后台管理模块,本质上是“可运营”的内容管理后台。小说管理围绕一本书做全生命周期管理,从新建作品开始,维护小说名称、作者笔名、分类、简介、封面图、连载状态(连载中/已完结)、点击量、收藏量等字段。之后进入章节管理,编辑章节标题和内容,设置章节顺序,发布后前台可见。
后台设计有一个贯穿始终的原则:数据完整性。编辑删改章节时要联动更新小说表的总字数、最新章节ID或更新时间,保证前台展示的书架列表与真实章节数据保持一致。用事务注解@Transactional保证这些操作要么全部成功,要么全部回滚,是源码中最常见的业务约束。
源码中后台Controller的方法命名和Service分工,也适合作为标准三层架构的练习材料。比如后台书籍管理接口的常规路径是/admin/book/add、/admin/book/edit、/admin/book/delete,前台接口则走/api/book/page地址。区分后台接口与前台接口在权限控制上很有必要,后台接口要求管理员角色访问,前台接口只要求登录或直接公开,通过Spring Security的请求路径匹配就能轻松实现。
3.4 前台阅读体验相关功能实现解析
前台阅读体验功能的核心模块包括小说列表、小说搜索、分类筛选、小说详情、章节阅读、收藏与阅读记录。从源码角度看,这些功能的实现难度集中在数据组装和查询效率上,而不是单个接口的CRUD。
小说列表页最需要关注的逻辑是条件组合查询。用户可能按分类浏览,也可能按书名或作者名搜索,还可能按点击量或更新时间排序,三者组合在一起,QueryWrapper或LambdaQueryWrapper就派上用场了:
java复制LambdaQueryWrapper<WenBook> wrapper = new LambdaQueryWrapper<>();
if (StringUtils.isNotBlank(keyword)) {
wrapper.like(WenBook::getBookName, keyword)
.or().like(WenBook::getAuthor, keyword);
}
if (categoryId != null) {
wrapper.eq(WenBook::getCategoryId, categoryId);
}
wrapper.orderByDesc(WenBook::getUpdateTime);
小说详情页会展示书籍基本信息、最新章节标题、总点击量、总收藏量等信息。源码中如果把详情页和章节列表拆成两个接口分开查询,是比较合理的设计,因为详情页的核心是一本小说的基本信息,章节列表则是整本小说所有章节的目录树结构,数据量不同,查询目标也不同。
章节内容阅读接口还需要加上阅读人数增加、阅读记录写入、访问量统计等操作。阅读记录和访问量统计通常可以异步处理,用@Async注解或异步消息队列技术,避免用户点开阅读时同步等待写库,影响响应速度。源码如果没有做异步,这部分也可看作一个可优化的点。
4. 常见问题与排查技巧实录
4.1 编译启动过程中最常见的报错与解决
我按源码操作时,遇到过几个报错,相信很多下载了这套网文系统的同学也会踩到相同的坑,整理成表格方便直接对照。
| 报错现象 | 根本原因 | 解决办法 |
|---|---|---|
| java: 程序包javax.servlet不存在 | Spring Boot 3的命名空间迁移 | 确认所有依赖中不包含javax开头的旧包,替换为jakarta命名空间 |
| ClassNotFoundException: jakarta.xml.bind... | 缺少JAXB相关依赖,JDK17环境问题 | 引入jakarta.xml.bind-api或调整JDK版本 |
| Failed to configure a DataSource | 数据库连接配置未生效 | 检查application.yml中url、用户名、密码,确认数据库已启动 |
| Spring Security 6报错antMatchers方法找不到 | 旧版API移除 | 改为requestMatchers或authorizeHttpRequests |
| Port 8080 was already in use | 端口被占用 | 修改server.port或关闭占用端口的进程 |
| Invalid bound statement (not found) | Mapper接口没有正确扫描或XML映射缺失 | 检查@MapperScan路径和Mapper XML的namespace是否对应 |
其中一个重点是,如果Mapper使用XML文件方式写SQL,检查resources目录下XML放置位置是否与application.yml配置的mapper-locations路径一致。MyBatis Plus中常见的约定是把XML放在resources/mapper目录,然后在配置文件中指定:
yaml复制mybatis-plus:
mapper-locations: classpath*:/mapper/**/*.xml
这样写的好处是Spring Boot 3打包时能把XML文件一起打进去,不会出现运行环境找不到SQL的情况。
4.2 数据库表设计与字段命名经验总结
网文系统源码中表名和字段名基本采用下划线风格,比如book_name、author_name、chapter_order、create_time。MyBatis Plus默认开启驼峰映射,所以Java实体类中对应属性写成bookName、authorName、chapterOrder、createTime即可,两者能自动完成转换。
如果遇到字段命名不一致,还有@TableField注解可以指定对应关系。例如实体类属性是isDelete,数据库字段是is_delete,用@TableField("is_delete")注解就能精确对应。
另外,数据库设计时几个通用字段建议所有业务表都加上:create_time创建时间、update_time更新时间、deleted逻辑删除标记。MyBatis Plus对逻辑删除有内置支持,配置@TableLogic注解后,执行delete方法会自动变成update set deleted=1,查询时会自动带上deleted=0条件。这在网文系统的用户数据、评论数据管理上非常有用,删除用户并不是真的把记录抹掉,而是逻辑上的不可见,方便后续审计和运营恢复。
4.3 二次开发与功能扩展的几个方向
拿到这份源码,能做的扩展方向其实很多,难易程度也不同。如果只是想拿它当课程设计或求职项目,建议做以下两个方向的扩展,投入产出比最高。
第一个方向是加缓存,这是最直观的性能优化点。小说列表和小说详情这类高频读取的低变化数据,非常适合使用Redis做缓存。用Spring Boot 3整合Redis,先查缓存再查数据库,缓存不存在回源数据库并写回缓存,代码改动量不大,但能显著提升接口响应速度,而且面试时能作为性能优化案例展开。
第二个方向是评论模块的扩展。如果源码本身带了简单的评论功能,可以在评论列表中增加点赞、回复、楼层展示、评论审核等能力。这些功能会牵扯出点赞表、回复表、评论审核字段等设计,天然能展示数据库设计和业务抽象能力,扩展起来也很有意思。
对想做系统复杂度再提升的同学,可以考虑把作者和管理员角色拆开,增加作者投稿审核流程,让读者可以为小说打赏、购买章节、开通VIP,这会引入支付模拟流程和商业化阅读模式设计,复杂度上升,但对标真实网文平台的能力也更接近。
4.4 阅读源码的路线与方法
源码可以下载,但“会跑”和“看懂”之间至少差着一个系统学习的距离。我推荐的阅读路线是分层推进:整体浏览到细节研究,先跑通系统,后画结构,再逐层深入。第一步,运行系统,从前台页面和后台页面把功能走一遍,建立业务直观感。第二步,画出全局结构图,从数据库表到Controller,梳理出整个系统模块关系。第三步,聚焦重点模块源码,按用户认证、小说管理、章节管理的顺序逐层阅读。第四步是动手改源码,换配置换功能甚至换技术选型,比如把Spring Security配置方式重写一遍,把JWT工具类换成另一种写法,都是很好的练习。
5. 进阶思考与工程化经验补充
5.1 从网文系统源码能学习到的工程化思想
很多同学看源码只盯着代码语法和框架API,很容易忽略隐藏在背后的工程化思想。这份网文系统源码级别还称不上大厂级项目,但它体现出的几个工程化习惯已经足够入门级开发去参考了。
第一是全局统一返回结果。源码中大概率定义了一个统一的结果封装类,业务接口统一通过它返回code、message、data三个字段。这样做的好处是前端对接时不需要每个接口单独处理数据结构,出错时也能统一区分业务异常和系统异常。这个习惯虽然简单,但在课程设计或自研项目中经常被忽略,实际工程中它几乎是标配。
第二是全局异常处理。Spring Boot通过@RestControllerAdvice能统一处理系统中未捕获的异常,返回友好错误信息,而不是把堆栈信息直接抛给前端。源码如果实现了全局异常处理器,这个类值得作为重点阅读。
第三是配置与代码分离。数据库连接、Token秘钥、缓存配置等运维相关的参数都放在配置文件中,通过@ConfigurationProperties或@Value注解注入,而不是硬编码在业务代码中。这样项目部署到不同环境时只需要修改配置文件,不用重新编译代码。
5.2 Spring Boot 3新特性在项目中的体现
网文系统源码既然选择了Spring Boot 3,编码时很可能会用到一部分Java 17和Spring Boot 3的新特性。相比Spring Boot 2.x,这套项目在几个方向上有明显体现。
一个是record类型的使用。Java 17中record可以代替传统POJO类,在DTO和VO上非常合适,一行代码搞定构造、equals、toString等方法。Controller层接收参数的类,如果源码中使用了record,它接收参数的方式看起来会比传统的getter/setter类简洁不少。
另一个是方法级安全。Spring Security 6支持使用@PreAuthorize注解在方法级别做权限校验,例如后台管理接口标注@PreAuthorize("hasRole('ADMIN')"),这样即使URL被猜中,角色权限不足也会被拦截。相比SecurityFilterChain统一匹配URL权限,方法级注解能让权限控制和业务逻辑放在一起,更直观也更好维护。
架构设计上无状态的RESTful API风格也是Spring Boot 3项目的标配。源码中接口路径设计尽量使用/api前缀,用HTTP动词(GET、POST、PUT、DELETE)表达操作语义,配合JWT无状态认证,整体架构风格统一,为将来前端分离部署、移动端接入打下基础。
5.3 部署上线环节的经验分享
本地跑通源码之后,如果有条件,强烈建议走一遍上线部署流程。这一步在课堂作业中容易被省略,但工作中是必备技能。我实操下来的经验是:先将打包方式设置为jar,然后执行mvn clean package,在target目录下生成jar包,最后用java -jar命令启动。因为项目启动依赖外部MySQL数据库,上线时要把数据库脚本同步到云服务器,并修改配置文件的数据库地址。
线上环境配置和生产环境不同,密码、秘钥等敏感信息不要直接写在配置文件中,推荐使用环境变量或外部配置中心。对于网文系统这类中小项目,Spring Boot内嵌Tomcat单机部署已经足够,用systemd或supervisor守护进程就能保证基本的可靠运行。
部署过程中容易忽略的,是数据库时区和字符集设置。网文系统核心内容全部是中文,如果数据库默认字符集不是utf8mb4,插入章节正文会出现中文乱码,封面图之类的URL也可能因为特殊字符保存失败。创建数据库时明确设置字符集为utf8mb4,能规避这一整类问题。
6. 写在后面:源码学习的实际体会
花时间把这份Spring Boot 3网文系统完整跑通之后,我最大的感受是这个项目很适合作为从“会写接口”到“能写系统”的过渡练习。数据表设计、用户认证、角色权限、CRUD封装、异常处理、配置集成都覆盖到了,同时因为业务场景是网文阅读,功能链路比较完整,不像网上的纯登录Demo那样学不到全貌。
给想拿这份源码练手的同学一个建议:不要只满足于把项目启动起来看效果,尽量动手改一两处功能。比如把每章的正文改为支持Markdown渲染,或者在前台增加按点击量排序的“热门榜单”,这些改动虽然不大,但会让你从“看代码的人”变成“改代码的人”,对框架知识的掌握会发生质的变化。我自己第一次动手改源码时,光是排查一个跨域配置问题就花了半个晚上,但正是这种踩坑过程,才真正把Spring Security的过滤器链机制记进脑子里了。
