
老读者都知道我个人对“校园”“管理系统”这类题目一直挺有感情。每年的毕业设计、课程设计里SpringBoot校园信息共享系统、二手交易平台、失物招领系统这类题目出现的频率极高。它不像电商秒杀系统那样追求极致的并发也不像大数据平台那样依赖复杂的分布式组件但它胜在业务场景足够真实、功能链路足够完整——用户体系、内容发布、分类检索、评论互动、管理后台这几乎把后端开发最常见的知识点全串起来了。这篇文章我会以“基于SpringBoot的校园信息共享系统”为切入点完整走一遍从需求拆解、数据库设计到后端接口实现、安全加固、部署上线的全过程。整个系列的核心思路是不堆砌华而不实的技术栈而是用SpringBoot最简单、最稳妥的姿势把校园信息共享系统真正落地。不管是正在做毕设的后端新手还是想快速上手一个完整Web项目的SpringBoot学习者这套内容都能直接用代码和思路基本可以做到“抄作业”级别。1. 项目定位与核心需求拆解1.1 校园信息共享系统到底解决什么问题先想清楚一件事校园信息共享系统不是为了“用SpringBoot”而做的系统它要解决的是校园内信息分散、获取成本高、时效性差这些真实痛点。比如学生想找二手教材、想发布失物招领、想获取讲座活动通知传统方式往往是微信群刷屏、公告栏贴纸信息容易淹没、难以检索。所以系统最核心的价值点有两个信息的集中发布和信息的高效检索。围绕这两点需求可以拆成三个层次用户侧注册登录、发布信息、浏览信息、收藏点赞、评论互动。信息侧信息分类二手闲置、失物招领、拼车组队、讲座活动等、关键词搜索、分页展示。管理侧管理员对信息的审核、下架、删除对用户的禁用、封禁对分类的维护。这个需求拆解的过程本身很重要。很多毕设项目失败不是编码能力不行而是需求模糊就动手结果做到一半发现表结构不合理、接口对不上返工成本极高。我的一贯建议是开工前先花一晚上把用户故事列清楚再推导数据表再定接口最后才是写代码。1.2 技术选型为什么是SpringBoot而不是Spring MVC或Spring Cloud校园类项目的真实运行环境通常是单机、低并发一台2核4G的云服务器绰绰有余。SpringBoot在这种场景下的优势非常明显自动化配置大大减少了样板代码半个小时就能搭出一个可运行的项目骨架。对比传统的SSM整合光Spring、SpringMVC、MyBatis的XML配置就能折腾一天。内嵌Tomcat容器部署时一个java -jar就搞定不需要单独安装配置外部服务器。生态兼容性好集成MyBatis-Plus、Redis、JWT这些工具非常顺畅。至于Spring Cloud我明确反对在毕设或单体业务项目中使用。微服务架构解决的问题是团队协作和独立扩展校园信息共享系统的业务复杂度远没到那一步。强行拆微服务只会给自己增加服务间调用、分布式事务、配置中心这些不必要的复杂度属于给自己挖坑。1.3 功能模块边界划分拿到需求之后第一步是把系统切成几个边界清晰的功能域这样做的好处是一方面方便并行开发另一方面避免后期改一个功能牵连整个项目。我通常这样划分用户模块注册、登录、个人信息维护、密码修改。内容模块信息发布、信息编辑、信息删除、信息审核。检索模块分类筛选、关键词搜索、分页列表。互动模块收藏、点赞、评论。管理模块管理员登录、内容管理、用户管理、数据统计。边界划分清楚后每个模块对应一组独立的Controller、Service、Mapper大家各管各的后期维护和扩展的难度都会小很多。这也是SpringBoot分包结构设计的核心思想。2. 系统总体架构与SpringBoot核心机制深挖2.1 单体分层架构为什么依然是最优解校园信息共享系统的架构设计我坚持使用经典的单体分层架构从上到下依次是Controller层接口层、Service层业务层、Mapper层数据访问层再加上统一封装的entity实体层、dto传输层、vo视图层。中间穿插统一的异常处理、参数校验和工具类。有的同学会纠结要不要引入DDD领域驱动设计或者用CQRS读写分离模式。我理解大家想学新东西的热情但请记住一个原则架构的复杂度应当与业务复杂度相匹配。对于信息共享系统MVC三层是经过无数项目验证过的稳妥方案它足够简单、足够清晰团队成员看得懂、接得住。DDD那套领域建模思路更适合业务规则极其复杂的中大型系统在毕设项目中强行套用评审老师大概率只会觉得你在炫技而非解决问题。2.2 SpringBoot自动装配原理它怎么把项目“转”起来的很多SpringBoot学习者对自动装配这件事停留在“会用SpringBootApplication”的层面但面试和实际调参时很容易露馅。这里我稍微深入讲一下。SpringBoot的启动入口上有三个核心注解合成了SpringBootApplicationSpringBootConfiguration本质上是个Configuration标记当前类是配置类。EnableAutoConfiguration自动装配的总开关它通过Import(AutoConfigurationImportSelector.class)加载META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件里声明的所有自动配置类。SpringBoot 2.7之前的版本这个文件叫spring.factories。ComponentScan默认扫描启动类所在包及其子包下的所有Component、Service、Controller等组件。自动配置类会在满足条件时生效判断依据是ConditionalOnClassclasspath下有对应依赖才生效、ConditionalOnMissingBean容器里没有指定Bean时才创建默认Bean、ConditionalOnProperty配置文件里指定属性才生效。这就是为什么引入spring-boot-starter-data-redis后配置好Redis连接信息就能直接用StringRedisTemplate不需要自己手动创建——SpringBoot在RedisAutoConfiguration里帮你做好了。理解了这套机制排查“为什么我配置没生效”这类问题时思路就清晰了。先看依赖是否引入再看配置项是否有对应前缀再看条件注解是否满足基本都能快速定位。2.3 持久层方案MyBatis-Plus为什么更适合这种项目数据访问层我的选择是MyBatis-Plus而不是原生MyBatis或者Spring Data JPA。理由有三点 第一MyBatis-Plus在MyBatis基础上提供了BaseMapper单表CRUD不需要手写SQL开发效率极高。 第二它的分页插件支持极简的分页查询配合IPage接口写起来很顺手。 第三MyBatis-Plus的代码生成器可以根据数据表自动生成entity、mapper、service、controller代码这个功能对赶工期的人来说简直是救命稻草。JPA虽然在国外用得很多自动建表能力也很方便但它的方法命名规范需要学习成本复杂查询时还是得写JPQL或者原生SQL而且和MyBatis系的团队协作确实有习惯差异。国内互联网公司的主流选择基本是MyBatis系列从就业角度考虑SpringBoot MyBatis-Plus的组合更值得熟悉。2.4 统一返回体与全局异常处理一个容易被忽略但极其影响开发体验的设计是统一接口返回格式。我习惯定义ResultT结构包含code、message、data三个字段。所有Controller的接口都返回这个结构前端拿到后统一判断code是否为200。同时需要定义全局异常处理器用RestControllerAdviceExceptionHandler捕获业务异常和系统异常。不这样做的话每写一个接口都要在catch块里做返回处理代码会特别冗余而且很容易漏掉某些异常分支。这套设计的价值在联调阶段体现得非常明显前端只需要处理一种Return结构不需要为了某个接口的“奇葩”返回单独写逻辑后端排查问题时通过code和message能快速定位是业务问题还是框架问题。3. 数据库设计与核心表结构详解3.1 六大核心表从用户故事推导表结构信息共享系统的数据表设计需要覆盖用户、内容、分类、互动、管理五大维度。我用自顶向下的思路梳理了以下核心表t_user用户表存储用户基本信息含用户名、密码、昵称、头像、手机号、状态、角色。角色字段用来区分普通用户和管理员。t_category分类表信息分类如“二手闲置”“失物招领”“拼车组队”“讲座活动”“求助互助”等字段包含分类名称、排序号、状态。t_post信息表这是系统最核心的表记录用户发布的信息内容字段包含标题、正文、图片、分类ID、发布者ID、标签、浏览量、点赞量、收藏量、状态。状态字段用于审核流程区分待审核、已发布、已下架、已删除。t_comment评论表信用评论信息包含评论内容、评论者ID、被评论信息ID、父评论ID用于楼中楼回复、发布时间。t_favorite收藏表记录用户收藏的信息字段包含用户ID、信息ID、收藏时间。联合唯一索引防止重复收藏。t_admin管理员表独立的管理员账号表虽然用户表可以用role字段区分但独立出来更安全也让权限模型更清晰。3.2 关键字段与索引设计数据表设计时我最看重的是索引和状态字段。以t_post表为例列表页最频繁的查询是“按分类查信息”和“按关键词搜索”所以category_id和title都需要建索引。浏览量、点赞量这类会随着用户操作频繁更新的统计字段单独放一张统计表比如t_post_stat会更好避免用户每次浏览都更新主表导致锁竞争。不过毕设阶段数据量小直接存在主表里也能接受。发布者ID字段强烈建议建索引。按用户查看“我发布的信息”是最常见的高频查询。如果将来数据量上来了可以通过发布者ID 发布时间的联合索引来加速分页查询。状态字段也值得一提。我习惯用tinyint用数字表示审核状态和删除状态比如0-待审核、1-已发布、2-已下架、3-已删除。这个逻辑删除字段非常关键——业务信息的删除应该是软删保留数据用于管理后台回溯和统计千万不要物理删除。MyBatis-Plus的TableLogic注解能帮你自动实现逻辑删除写查询时自动追加deleted0条件。3.3 数据字典与系统配置表如果项目的分类需要动态调整可以把分类信息独立成t_category表而不是写死在代码里这一设计能带来很大灵活性。比如管理员在后台新增一个分类“毕业季闲置大甩卖”前端菜单和发布页分类下拉框会自动更新完全不用改代码。另外我还习惯加一张t_system_config配置表存一些公告信息、网站开关、敏感词列表之类的动态配置项。这类表结构简单但是能让系统具备动态配置能力对后续维护非常重要。3.4 初始化数据与集成测试表建好后记得写一些合理的初始数据。分类表的初始数据因为后续所有功能都依赖它一定要有管理员账号也要在项目首次启动时初始化好否则项目跑起来后没有账号能登录管理后台就成了一个死局。数据库准备就绪后最好用Navicat或DataGrip的测试工具跑几轮简单的SQL验证数据表关系。我见过太多项目一启动就报Table xxx doesnt exist原因是建表前忘了在application.yml里配置正确的jdbc:mysql://连接串连错库了。这种低级错误非常浪费时间建议一开始就把连接信息核对清楚。4. 核心功能实现从登录态到信息发布4.1 基于JWT的用户登录与Token校验信息共享系统的登录认证我选的是JWT方案。方案选型的核心原因是它天然适合前后端分离且实现起来简单。具体逻辑如下用户登录成功后后端生成一个TokenToken中携带用户ID、用户名、角色等信息并设置过期时间。前端把Token存放到localStorage里后续请求在Authorization请求头中带上这个Token。后端通过拦截器解析Token拿到用户信息后放入当前线程上下文业务层需要获取当前用户ID时直接从上下文取。具体实现时我用了jjwt框架。生成Token和解析Token的代码逻辑封装成JwtUtil工具类这样拦截器和业务逻辑都可以复用同一个工具类。Token的过期时间我设置为2小时避免过期太长带来安全隐患、过期太短影响体验。如果希望更友好一些可以引入刷新机制。拦截器实现HandlerInterceptor接口在preHandle方法中校验Token通过则放行否则返回401状态码。注册Token校验拦截器到WebMvc配置时要注意登录接口、注册接口、公共信息浏览接口应该排除在拦截范围之外防止用户未登录完全不能访问系统。使用excludePathPatterns来实现这点即可。4.2 敏感数据加密与安全校验密码存储必须加密我使用的是BCryptPasswordEncoder。和MD5这类哈希算法不同BCrypt每次加密同一明文都会生成不同的密文内置盐值能有效抵御彩虹表攻击。SpringSecurity框架中的BCrypt实现可以直接拿来用不需要完整引入SpringSecurity体系。用户注册时密码明文经过编码器加密后存入数据库登录时用matches(password, hashedPassword)方法校验。这里有个Real经验不要在数据库里存明文密码即使是毕设也要养成这个好习惯。同时注册接口需要对用户名、密码、手机号等参数做校验比如邮箱格式、密码长度至少6位、用户名是否已存在等这些校验优先放在Service层使用Spring的Validated注解就能愉快地实现。4.3 信息发布功能控制器 业务层 数据层的标准协作信息发布是内容模块的核心功能。前端提交一个PostDTO请求Controller接收参数后调用Service层的publish方法。完整实现如下RestController RequestMapping(/api/post) public class PostController { Autowired private PostService postService; PostMapping(/publish) public ResultLong publish(RequestBody Validated PostDTO postDTO) { // 从当前登录上下文获取用户ID Long userId UserContext.getUserId(); Long postId postService.publish(postDTO, userId); return Result.success(postId); } }Service层负责业务逻辑先校验分类是否存在、标题是否为空再补充创建时间、更新时间和初始状态最后调用Mapper插入。整个流程中需要考虑的关键点有用户是否处于正常状态被封禁用户不能发布、分类是否可用、信息是否需要审核部分分类比如二手交易管理员可以设置先审后发。4.4 敏感词过滤与内容审核机制校园信息共享系统面向的学生群体内容安全是必须考虑的。我建议在发布环节做一道基础的内容过滤维护一个敏感词词库存在配置表或独立的敏感词表发布时遍历标题和正文命中敏感词后提示用户修改或者自动打上“待审核”标记由管理员人工确认。后者的模式叫做“先发后审”审核维度更强一些但需要管理员值班。前者的模式叫“先审后发”更安全但体验稍差。我建议两种结合命中敏感词的概率很高就先审后发未命中则直接发布。这套逻辑在Service层实现不算复杂但对项目的完整度和评审印象分提升非常大。管理员审核的接口位于管理模块。管理员调用“查询待审核列表”接口获取信息ID后在后台点击审核通过或驳回Service层更新状态字段。驳回时建议填一下驳回原因信息发布者能在“我的发布”中看到被驳回的信息及原因这是一个用户体验细节。4.5 分页查询与多条件搜索信息列表页需要支持分类筛选、关键词搜索、分页加载。用MyBatis-Plus实现起来非常简洁Override public IPagePostVO queryPostPage(int pageNum, int pageSize, Long categoryId, String keyword) { PagePost page new Page(pageNum, pageSize); LambdaQueryWrapperPost wrapper new LambdaQueryWrapper(); wrapper.eq(Post::getStatus, 1); // 只查已发布 if (categoryId ! null) { wrapper.eq(Post::getCategoryId, categoryId); } if (StringUtils.hasText(keyword)) { wrapper.and(w - w.like(Post::getTitle, keyword) .or().like(Post::getContent, keyword)); } wrapper.orderByDesc(Post::getCreateTime); // 分页查询 IPagePost postPage postMapper.selectPage(page, wrapper); // 组装VO补充用户昵称、分类名称 return convertToVO(postPage); }分页参数前端每页通常是10条或20条后端用Page对象接收返回的IPage里带有总记录数和总页数前端就可以实现分页器。搜索的关键词如果要对查询性能做优化可以考虑对title和content建立全文索引不过毕设阶段用MySQL的LIKE模糊查询也够用了。5. 互动模块评论与收藏的完整链路5.1 评论功能与楼中楼实现评论模块的交互场景有两种一种是平铺式的普通评论所有评论按时间排序另一种是分层的楼中楼用户可以回复某条评论。我实现的是第二种核心是表结构中的parent_id字段。平级评论的parent_id为0对某条评论的回复其parent_id设为被回复评论的ID。查询时先查出所有根评论parent_id0然后根据根评论ID查它的所有子评论。也可以一次性查出某条信息的所有评论在内存中组装成树形结构返回给前端。评论接口需要拦截未登录状态登录用户才能评论。评论内容同样要做敏感词过滤。同时要有幂等性考虑防止用户在弱网环境下重复点击导致重复评论。我通常会在前端做按钮防抖后端则通过校验评论内容时间窗口来辅助控制比如5秒内同IP同用户的评论频率限制简单实现一个滑动窗口计数器。5.2 收藏与点赞的幂等设计收藏是“收藏/取消收藏”双向操作。用户点击收藏时先判断该用户与信息之间是否存在收藏记录不存在 → 插入收藏记录信息表的favorite_count加1。已存在 → 删除收藏记录信息表的favorite_count减1。这个“查询-判断-操作”的流程在并发场景下会存在重复提交问题我通过给t_favorite表建立(user_id, post_id)联合唯一索引来兜底。插入时使用insertIgnore或者在Service层捕获DuplicateKeyException重复插入会自动失败不会导致数据错误。点赞的逻辑同理。有的系统把点赞表独立出来有的直接在信息表上累计毕设阶段直接在信息表加一个like_count字段用户点一次调一次更新接口即可。如果担心用户重复点赞可以在前端根据点赞状态做按钮切换后端更新时判断当前状态保证幂等。5.3 浏览量统计与防刷策略浏览量是信息热度的重要指标。最简单的设计是信息详情接口每次被调用时对view_count加1。但这里有个问题刷新页面也会调用详情接口会导致浏览量虚高。我采取的方案是同一用户对同一信息在10分钟内重复访问不增加浏览量。具体实现是维护一个Redis缓存key格式为view:postId:userId第一次访问写入缓存并设置过期时间后续访问先查缓存是否存在存在就直接返回不更新计数。Redis不存在时再增加数据库字段并写入缓存。这个防刷策略并不复杂但对数据质量提升特别明显。5.4 最近浏览记录与个性化推荐如果想让系统体验更进一步可以做一个“浏览历史”功能。用户每次打开信息详情时把该信息ID写入Redis的ZSetscore设为当前时间戳。查询时按score从大到小取最近浏览的N条就能得到用户的浏览足迹。这个功能很实用交互上类似于电商平台的“最近看过”。个性化推荐在毕设阶段用简单的“标签匹配”就够了。比如信息发布时打上分类和标签用户浏览记录关联的信息可以提取出偏好分类和标签然后按偏好优先级推荐该分类下发布时间最近的未浏览信息。不要碰协同过滤、Embedding这些重算法复杂度会失控。6. 管理后台与数据统计6.1 管理员权限模型与接口隔离管理员端和用户端在基础功能上有很多重叠比如都需要信息管理。但管理员拥有更高级的操作权限比如审核、下架、删除他人信息、禁言用户、管理分类等。在权限模型上我用JWT中的role字段区分用户角色。管理员登录后获取到的角色是ADMIN。通过自定义一个角色拦截器拦截/api/admin/**路径的所有请求要求Token中的角色必须是ADMIN否则返回403。这样职责分离清晰不会出现普通用户通过改接口参数拿到管理员数据的情况。6.2 审核流程与操作留痕管理员对信息的所有关键操作比如审核通过、强制下架、恢复都应该写入操作日志。我建了一张t_admin_operation_log表字段包含管理员ID、操作类型、操作对象ID、操作说明、操作时间。管理后台提供日志查询页面方便追溯。有人可能觉得这么个小系统做操作日志没必要但我认为这是专业素养的体现。一旦出问题操作日志能帮你快速定位“谁在什么时候做了什么”而不是靠猜。6.3 运营数据看板管理后台首页展示的数据看板包含几个核心指标今日新增用户数今日新增信息数累计信息总数待审核信息数分类信息分布近7天信息发布趋势这些数据用SQL聚合统计就能得到。近7天趋势查询时可以用GROUP BY DATE(create_time)但如果数据量特别大建议考虑在每天凌晨用定时任务生成统计快照存到统计表查询直接读快照避免实时聚合数据库压力。SpringBoot整合定时任务非常简单在启动类上添加EnableScheduling然后在统计Service里写一个带Scheduled(cron 0 0 2 * * ?)的方法每天凌晨2点执行统计任务。定时任务这块经常在面试中问到实际应用场景也很多这里正好作为项目亮点提一下。7. 高频报错与实战排查手册7.1 数据库连接与初始化问题报错Access denied for user rootlocalhost基本都是配置文件里MySQL密码写错了或者本机MySQL密码改过没有同步到项目配置。排查方式先用命令行连接数据库验证密码是否正确再检查application.yml的url、username、password三大件。报错Table schoolshare.t_post doesnt exist通常是数据库选错了或者建表脚本没有执行。排查方式到对应数据库执行show tables;确认表是否存在。我的经验是建表语句必须保存在项目里的sql目录下用Flyway做版本化管理最好不做的话至少确保建表脚本和项目代码一起提交。7.2 SpringBoot启动失败的常见原因启动时报APPLICATION FAILED TO START是最让人头疼的常见原因包括Failed to configure a DataSource没配置数据库连接或依赖冲突检查spring.datasource配置。Consider defining a bean of type xxxMapper in your configuration说明Mapper接口没有被Spring扫描到。检查启动类是否有MapperScan注解或Mapper接口上是否有Mapper注解。这个报错在未启动Mapper扫描时非常常见。Port 8080 was already in use端口被占用用netstat -ano | findstr 8080Windows或lsof -i:8080macOS/Linux查占用进程直接杀掉即可。7.3 接口返回404/500的排查思路404一般有两个原因一是路径写错了Controller里的RequestMapping和前端请求的URL对不上二是拦截器对路径做了错误的拦截处理。排查时可以打开SpringBoot的日志级别把logging.level.org.springframework.webDEBUG打开就能看到所有请求的映射匹配情况。500则表示服务器内部异常。在开发环境中把server.error.include-messagealways配置打开能直接看到具体的异常信息。生产环境不要开启避免泄露内部实现给用户。日志分析方面我习惯在Service层和Controller层加Logback日志输出把入参、出参、耗时记录下来排查问题时日志是还原现场的第一手资料。7.4 Token失效与用户态的坑JWT方案的经典坑是用户修改密码或账号被封禁后已签发的Token仍然有效直到过期。解决思路是在用户表和Token校验之间加一层校验逻辑拦截器解析Token拿到用户ID后查询用户状态如果状态为封禁或已删除立即返回401。这个额外查询虽然增加了一次DB访问但能保证安全性和权限隔离值得做。另一个坑是Token过期时间的设置。设置过短会导致用户频繁重新登录体验差设置过长则安全隐患大。我用2小时配套实现一个Redis黑名单或者刷新接口用户主动退出时把Token加入黑名单并设置与过期时间一致的TTL。7.5 分页查询出现的经典问题信息列表分页时最常见的报错是JSQLParserException原因是MyBatis-Plus分页插件没配置好。新版MyBatis-Plus用MybatisPlusInterceptor并注册PaginationInnerInterceptor老版是PaginationInterceptor。版本对不上、配置缺失都会导致分页SQL解析失败这里一定要按当前版本的官方文档配置。如果分页查询返回的总记录数是0但数据库明显有数据大概率是查询条件加了status1已发布而列表数据其实是待审核状态所以查不出来。排查类似问题时先去掉条件字段逐个验证很容易定位。8. 部署上线与容器化实践8.1 从Jar包到云服务器最省心的部署方式SpringBoot项目打包成可执行Jar包是部署最简单的方案。在pom.xml里配置好spring-boot-maven-plugin执行mvn clean package就能产出Jar包。使用java -jar school-share.jar启动项目进程会一直运行在后台直到杀掉。如果服务器上需要长期运行用系统服务方式托管更稳妥。Linux上可以写一个Systemd服务文件[Unit] DescriptionSchool Share Server Afternetwork.target [Service] Useradmin WorkingDirectory/home/admin/app ExecStart/usr/bin/java -jar school-share.jar --server.port8080 Restarton-failure RestartSec10 [Install] WantedBymulti-user.target配置好后执行systemctl enable school-share服务器重启后项目会自动运行。这种方式比sftp上传后手动nohup要专业得多适合真正上线使用的系统项目。8.2 数据库部署与备份策略学校的云服务器配置通常不高跑MySQL本身没问题。但数据库的部署有几个小细节要处理好时区问题连接串中加serverTimezoneAsia/Shanghai避免时间字段和本地差8小时。字符集问题数据库、表、连接串统一使用utf8mb4否则中文字符和Emoji会出现乱码。备份问题写一个crontab定时任务每天凌晨用mysqldump备份数据库保留近7天备份。我见过太多人项目写完了但数据没备份一次误删就前功尽弃。数据备份是系统的最后一道保险不能省。8.3 Nginx反向代理配置生产环境不会直接把8080端口暴露给用户。标准做法是Nginx监听80/443端口反向代理到本机的SpringBoot服务。Nginx配置示例server { listen 80; server_name yourdomain.com; location / { 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; } # 前端静态资源 location /static/ { alias /home/admin/app/static/; expires 7d; } }这套配置不仅解决了跨域问题前后端同域名还能隐藏后端实际端口。如果在Nginx后面加一层HTTPS证书安全等级会更高。8.4 Redis与缓存的部署注意事项如果系统用到了Redis做验证码、防刷、热点缓存务必在服务器上也部署Redis服务。安装后需要修改配置文件redis.conf设置bind 127.0.0.1或者云服务的安全组策略限制只允许本机访问并设置requirepass密码防止Redis被公网扫描后注入恶意数据。SpringBoot连接Redis只需配置spring.data.redis.host127.0.0.1 spring.data.redis.port6379 spring.data.redis.passwordyourpassword spring.data.redis.database0要注意SpringBoot 2.x和3.x的Redis配置前缀不同2.x是spring.redis.*3.x全系改为spring.data.redis.*版本不同踩坑点也不同。9. 从毕设到真实项目我的几点个人心得项目做到这里核心功能和部署链路都完整了。但这套系统真正的价值并不在于功能本身而在于你通过这个项目建立起来的一套工程化思维。我最大的体会是能跑通的项目很多能扛住问题追问的项目很少。毕设答辩或者面试时老师或面试官问的最多的往往是“为什么这样做”而不是“做了什么”。比如为什么用JWT而不是Session为什么选MyBatis-Plus而不是JPARedis在这里到底解决了什么问题如果一个表的数据量大了怎么优化——这些问题是需要你在开发的过程中真的思考过的而不是背几个面试题就能蒙混过关的。另一个感受是校园信息共享系统这种类型的项目非常适合做增量演进。第一阶段做单体Web应用第二阶段加Redis和消息队列第三阶段拆分成微服务。每一步都是在前一阶段基础上自然的演进每一次演进都能让你对系统设计有更深的理解。如果一上来就照着微服务的架构去设计反而很难讲清楚每一步的动机和价值。最后分享一个小技巧项目里尽量保留README.md记录开发环境版本、启动步骤、默认账号、部署方式。等你三个月后再来看这个项目会发现这些记录比任何代码注释都更有价值。而如果你是在做毕设把README写得清清楚楚评审老师也会觉得这个项目很完整、很规范。我始终认为校园信息共享系统是一个特别适合练手的项目它的业务足够真实、规模足够合理、技术栈足够主流。把这个项目从头到尾吃透你在后端开发这条路上就走稳了一大半。如果你在开发过程中也遇到了什么有意思的问题或者有更好的方案欢迎随时交流评论区见。