尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Spring Boot毕业设计实战:猪疾病信息查询系统从0到1完整开发

Spring Boot毕业设计实战:猪疾病信息查询系统从0到1完整开发 每年到这个时候总能看到一堆人在群里问“毕业设计怎么做”“Spring Boot项目从哪下手”。如果你看到这个标题点进来大概率也是在为毕设发愁或者手里正攥着一个不知道从哪开始的Spring Boot题目。我当初做猪疾病信息查询系统的时候差不多也是这个状态题目看着具体但真打开IDEA新建工程的那一刻脑子是完全空的。这个系统的核心价值其实不在“猪”上而在“信息查询”四个字。它本质上是一个典型的业务管理系统只不过业务实体从常见的学生、图书、商品换成了猪疾病信息。正因为换了实体反而让它在毕设答辩里显得有辨识度又能完整覆盖Spring Boot开发的核心链路从数据库设计、持久层框架、业务逻辑分层、RESTful接口到前端页面展示全部都能在一套源码里串起来。适合基础一般、想快速把项目跑通并搞清楚每一层在干什么的同学也适合需要在答辩时讲清楚“为什么这么设计”的人。下面我就按照我当初自己从零做这个项目的实际过程把思路、架构、核心代码、跑通步骤和踩过的坑一次性说清楚。1. 做这个系统的初衷和整体设计思路1.1 为什么选“猪疾病信息查询”这个方向毕业设计选题有个潜规则题目越具体反而越好做。因为具体意味着业务边界清楚你不需要天马行空地设计一堆用不上的功能。猪疾病信息查询系统就是这种“小而完整”的题目。它不再是千篇一律的图书管理、学生管理系统而是切入了养殖行业的实际场景表面上是给养殖户、兽医、畜牧专业学生查疾病用的实际上核心逻辑和任何一个“信息检索类”系统完全一致。从业务角度看猪疾病信息查询系统要解决的痛点很实在猪生病的症状往往容易混淆新手养殖户很难通过发热、咳嗽、腹泻这些表面症状判断是什么病更不知道该怎么对症处理。如果有一个平台把这些常见疾病的病因、症状、防治措施、用药建议都结构化存储再提供按症状和病名的快速检索养殖户就能在最短时间内找到参考方案。这个场景一讲出来答辩老师会立刻明白你做的是什么东西而不是听你绕半天说不清楚。从技术角度看这个题目覆盖的知识点非常标准。涉及用户管理登录注册、信息管理疾病信息增删改查、检索关键字模糊查询、分类筛选、数据展示列表分页、详情页。每个点都能在Spring Boot里找到对应的成熟解决方案不存在做不出来的技术难点。这也是我当时选它的重要原因既不会因为题目太简单让老师觉得没含金量也不会因为太难卡到做不出来。1.2 功能模块划分与用户角色系统前期先把角色和模块想清楚后面写代码会顺畅非常多。我当时把用户角色分成两类普通用户前台访客和管理员后台维护者。普通用户能做的事情包括注册登录、浏览疾病列表、按疾病名称或症状关键字搜索、查看某种疾病的详细防治方案、收藏常见的疾病以便快速查找。管理员额外拥有疾病信息的后台管理权限可以对疾病分类、病因、症状、预防措施、治疗用药进行全量增删改查还能维护前台展示的热门数据和分类信息。还有一个很容易被忽略但很加分的模块是数据统计。管理员登录后台后能看到每个疾病的浏览量、查询次数甚至可以按月份查看哪些疾病是当前高发期。我当时加了一个简单的查询记录表每次用户查看详情就插入一条记录然后在后台聚合展示Top10疾病排行和月度查询量趋势。这个功能代码量不大但答辩演示时很直观能明显体现出你对需求场景的理解深度。这些统计数据和疾病信息是分开存储的避免污染主表数据又能完整支撑查询业务。1.3 技术选型过程的踩坑与取舍选型这个环节很多人会犯一个错误看到什么新技术都想往里塞。我见过把Redis、RabbitMQ、Elasticsearch全部塞进一个图书管理系统的毕设结果是给自己挖坑答辩时连面试官问一句“Redis在这里解决了什么问题”都答不上来。猪疾病信息查询系统这种体量最合理的技术组合就是Spring Boot Spring Data JPA MySQL Thymeleaf最多加一个Layui或Bootstrap做页面美化。Spring Boot负责把整个Web应用的骨架搭起来Spring Data JPA负责数据库操作它比MyBatis少写大量XML映射文件对毕设来说更省时间MySQL存数据Thymeleaf做服务端渲染兼顾后端逻辑和前端页面。当然如果团队同学之前的主力是MyBatis也可以用MyBatis替换JPA这个没有绝对的对错。有一点我要反复强调毕设源码不是越复杂越好而是越清晰越好。评分老师真正看重的是你对每一行代码、每一个配置的理解程度。用JPA而不是MyBatis我在答辩时的解释是“JPA通过方法名自动生成SQL减少样板代码让精力集中在业务处理上”这个解释虽然简短但体现的是真实开发中的取舍能力。相比之下堆一堆用不上的中间件反而经不住追问。2. Spring Boot四层架构与源码目录规范2.1 四层架构到底指哪四层Spring Boot项目里经常有人提“四层架构”但很多人其实说不清楚是哪四层。我在这个系统里用的是比较经典的分层控制层Controller、业务层Service、数据访问层Repository/Dao和实体层Entity。严格来说实体层不属于“层次”但在实际项目中它是贯穿三层的数据载体所以通常和三层架构合并说成四层。控制层只做参数接收、调用业务层、返回结果这三件事。它不写任何业务逻辑也不直接操作数据库。业务层是系统的核心所有规则判断、数据校验、事务控制都在这一层完成。数据访问层负责和数据库对话在JPA里就是继承JpaRepository的接口Spring会自动帮我们实现常用增删改查。实体层对应数据库里的表结构用注解标明字段映射关系。我在项目里还额外加了一层VO和DTO的转换。严格来说这也算合理架构的一部分实体对象直接暴露给前端会泄露数据库表结构而且有些字段比如密码不该被返回。所以我设计了UserVO、DiseaseVO等类在控制层返回前把实体转为视图对象。这个细节在答辩时一提老师会明显觉得你的工程素养比普通学生高一层。2.2 源码目录到底怎么建目录规范这块我现在看很多毕设源码最头疼的就是包结构混乱。有些人把所有类都堆在com.example.demo下面一个包塞了几十个文件看着就头疼。我当时给猪疾病系统定的包结构如下你可以直接照着用com.example.pighealth ├── controller # 控制层接收请求放Controller类 ├── service # 业务层接口定义 ├── service.impl # 业务层实现类 ├── repository # 数据访问层JPA接口 ├── entity # 实体层数据库映射 ├── vo # 视图对象返回给前端的数据载体 ├── common # 公共类统一返回结果、异常处理、工具类 ├── config # 配置类拦截器、跨域配置等 └── PaymentApplication.java # 启动类这个目录本身就是四层架构的可视化表达。controller对外repository对内service夹在中间entity贯穿全程。有任何问题顺着包名就能定位到对应位置的代码。我在答辩时直接投影展示这个包结构图再配合说明每一层之间只能向下依赖不能向上调用老师基本不会再在这些基础问题上纠缠。2.3 为什么一定要按这个分层写很多新手会觉得分层麻烦一个简单的查询明明可以直接在Controller里写几行JPA调用为什么要绕一圈经过Service这个问题的本质是“代码维护性和可扩展性”。举一个我系统里真实遇到的情况。最开始写浏览记录统计时查询列表的功能已经写好了直接在Controller里操作了Repository。后来需求加了一个“查询时如果用户登录则同步收藏状态”这时候我发现必须在Controller里塞一堆额外判断代码越来越臃肿。如果当初就按照Controller调用ServiceService调用Repository的规范来写我只需要在Service层加一个方法在原有方法内部追加逻辑Controller那一行调用完全不用变。这就是分层最直接的好处软件的变化被隔离在一个独立的层里而不是散落在所有代码中。这句话如果你能在答辩时说出来比背十遍八股文都管用。3. 核心功能实现与关键代码解析3.1 实体建模疾病信息表的结构设计猪疾病信息系统的核心表是疾病信息表disease_info。这张表设计得好不好直接影响后续所有功能开发。我最终确定的结构包含这些核心字段疾病名称、疾病分类病毒性、细菌性、寄生虫性、营养代谢性等、发病季节春季、夏季、秋季、冬季、易感猪群仔猪、育肥猪、母猪等、主要症状、病因描述、预防措施、治疗方案、用药建议、图片路径、浏览量。每个字段都不是凭空捏造的而是我查了不少养殖资料后总结出来的。其中主要症状和疾病名称是两个检索权重最高的字段。用户搜“咳嗽”系统就要返回所有症状描述里包含“咳嗽”的疾病。这个需求直接影响了表结构设计我在症状字段上额外加了索引虽然数据量小的时候感知不明显但这是一个正确的设计习惯。另外图片路径字段要注意存相对路径而不是绝对路径避免服务器迁移时图片全部失效。实体类中用JPA注解来映射表也很关键示例代码如下Entity Table(name disease_info) public class DiseaseInfo { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; // 主键ID Column(nullable false, length 100, unique true) private String diseaseName; // 疾病名称 Column(length 50) private String category; // 疾病分类 Column(length 50) private String season; // 高发季节 Column(length 50) private String susceptibleGroup; // 易感猪群 Column(columnDefinition TEXT) private String symptom; // 主要症状 Column(columnDefinition TEXT) private String cause; // 病因描述 Column(columnDefinition TEXT) private String prevention; // 预防措施 Column(columnDefinition TEXT) private String treatment; // 治疗方案 Column(columnDefinition TEXT) private String drugAdvice; // 用药建议 private String imageUrl; // 配图路径 private Long viewCount 0L; // 浏览次数 Column(columnDefinition TIMESTAMP DEFAULT CURRENT_TIMESTAMP) private LocalDateTime createTime; // 创建时间 }这里有几个细节值得注意。第一症状、病因、治疗方案这些长文本字段用TEXT而不是VARCHAR因为VARCHAR默认长度只有255存一段完整的防治建议根本不够。第二diseaseName加了unique约束防止同名疾病重复录入。第三Column(columnDefinition TIMESTAMP DEFAULT CURRENT_TIMESTAMP)保证插入时自动填充时间。这些细节在代码评审阶段都是加分项。3.2 数据访问层Repository写法的核心技巧Spring Data JPA最强大的地方在于很多查询根本不用写SQL只要按照命名规范声明方法框架自动帮你实现。我系统里用得最多的两个查询是分页查询和模糊搜索。分页用Pageable参数模糊搜索用Containing关键字public interface DiseaseInfoRepository extends JpaRepositoryDiseaseInfo, Long { // 分页查询所有疾病信息 PageDiseaseInfo findAll(Pageable pageable); // 按名称模糊查询 PageDiseaseInfo findByDiseaseNameContaining(String diseaseName, Pageable pageable); // 按症状模糊查询 PageDiseaseInfo findBySymptomContaining(String symptom, Pageable pageable); // 按名称和症状同时模糊查询这是前端搜索框的主要入口 Query(SELECT d FROM DiseaseInfo d WHERE d.diseaseName LIKE %:keyword% OR d.symptom LIKE %:keyword% OR d.category LIKE %:keyword%) PageDiseaseInfo searchByKeyword(Param(keyword) String keyword, Pageable pageable); // 查询浏览量最高的前10条用于统计展示 ListDiseaseInfo findTop10ByOrderByViewCountDesc(); }这里我想重点说一下自定义Query注解的写法。JPA方法名查询虽然方便但“OR两个字段模糊匹配”这种场景方法名会变得很长可读性不理想这时候直接用Query写JPQL更简洁。很多人第一次接触会混淆JPQL和原生SQL其实JPQL操作的是实体对象和实体字段不是数据库表和字段。上面代码里LIKE %:keyword%就是JPQL写法它和SQL的LIKE语法很像但查询的目标是DiseaseInfo这个实体类。还有一个使用技巧所有列表接口都应该返回分页对象而不是全量List。经验不足的时候会觉得“先查出来再前端分页也行”数据量小确实看不出问题但这是一个非常糟糕的习惯。我系统里目前几千条数据全量查询和分页查询的差别可能不到几十毫秒但做任何管理系统都要为数据增长留足空间。使用Pageable参数时页数从0开始计算前端传递current1时要在后端减1这个边界处理bug也很经典我第一次调试时就卡在这个地方后面会专门讲。3.3 业务层核心检索逻辑与浏览量统计业务层是整个系统的灵魂所有规则都写在这一层。以疾病查询这个业务为例完整的业务逻辑应该是接收关键词、调Repository查询分页数据、同步处理用户收藏信息、记录查询行为。而关键词处理这块就有不少容易被忽略的细节。用户从搜索框输入的关键词可能带前后空格可能中英文混合可能搜的是“猪瘟”而库里存的是“猪瘟(经典型)”。所以我规定了业务层必须做标准化处理先trim去除首尾空格再统一转半角字符如果关键词为空则直接返回热门推荐不做全表扫描。这套逻辑放在Service而不是Controller是为了保证将来无论谁来调用前端页面、手机端、API接口都走同一个标准流程。浏览量统计也是一个业务层该管的逻辑。用户每次点击查看疾病详情viewCount加1同时插入一条浏览记录。这里要特别提醒事务控制的问题viewCount更新和查询记录插入必须保证同时成功或同时失败不能出现计数加了但记录没插上的情况。我系统里Transactional注解就加在这两个操作的封装方法上保证原子性。如果基础薄弱搞不清事务的传播机制就记住一条实用原则涉及两个及以上数据变更操作的方法一定要加Transactional防止数据不一致。3.4 控制层RESTful接口设计与统一返回控制层的代码风格直接决定前端联调是否顺畅。我给自己定了一条规矩所有接口返回结构必须统一。Java后端返回给前端的数据格式不统一是毕设项目最常见的“丑点”要么有的接口直接返回字符串有的返回对象有的又返回一个不知道什么结构的Map前端要写一堆兼容代码。我的做法是在common包里单独建一个统一返回类public class ResultT { private Integer code; // 状态码200成功500失败 private String message; // 提示信息 private T data; // 数据内容 public static T ResultT success(T data) { ResultT result new Result(); result.setCode(200); result.setMessage(操作成功); result.setData(data); return result; } public static T ResultT error(String message) { ResultT result new Result(); result.setCode(500); result.setMessage(message); return result; } }有了这个类之后控制层代码就会变得非常干净。比如查询详情的方法就是查数据、加浏览量、返回成功结果或者数据不存在直接抛业务异常由全局异常处理器兜底。这里还要补充一个全局异常处理器的概念如果一个数据不存在直接用try-catch处理会让代码到处都是异常捕获更好的做法是写一个RestControllerAdvice注解的全局类统一捕捉业务异常并转成Result返回。前端拿到的永远是code200加message提示而不是一堆乱七八糟的报错堆栈。控制层不写业务逻辑这条底线在这个系统里体现在Controller里只做参数校验和数据转换。比如用户传入的搜索关键词Controller只负责从RequestParam里取出来然后直接传给Service不会在这里做字符串处理。页面跳转路由和Ajax接口分开设计普通浏览用Thymeleaf返回页面所有数据的增删改查走RESTful接口。这样既保证了传统网页的SEO友好又保留了前后端分离的灵活性。3.5 前端展示层从列表页到详情页的完整链路我前端用的是Thymeleaf模板引擎配合Bootstrap做响应式布局页面数量不多但覆盖了一个完整业务的展示闭环。首页是疾病分类导航和热门疾病推荐列表页支持分页和条件筛选详情页展示完整的防治方案管理员后台是表格化的增删改查界面。Thymeleaf和JSP最大的区别在于JSP是在Java环境中动态渲染的而Thymeleaf更接近静态HTML可以直接用浏览器打开预览还能通过th:each、th:if这类属性在服务端渲染数据。列表页核心渲染代码就是一段th:each循环div classcol-md-4 mb-3 th:eachdisease : ${page.content} div classcard img th:src${disease.imageUrl} classcard-img-top alt疾病配图 div classcard-body h5 classcard-title th:text${disease.diseaseName}疾病名称/h5 p classcard-text th:text${#strings.abbreviate(disease.symptom, 50)}症状摘要/p a th:href{/disease/detail/{id}(id${disease.id})} classbtn btn-primary查看详情/a /div /div /div这里有个小技巧值得记一下。症状字段是TEXT类型可能几百字甚至上千字直接在卡片上全部展示会把页面撑得很长很难看。用#strings.abbreviate()方法可以截断字符串并自动添加省略号。前端控制摘要长度详情页再展示完整内容这是信息列表展示的通用做法。前端调后端接口用的是原生Ajax配合Thymeleaf页面中定义的数据接口路径。管理员的增删改查操作全部是异步请求提交给后端API然后刷新列表区域用户操作体验比传统表单同步提交顺畅很多。4. 实操过程从拿到源码到项目跑起来4.1 环境准备版本选错是第一个大坑跑Spring Boot项目需要的环境其实就四样JDK、Maven、MySQL、IDEA。我遇到过太多同学卡在启动阶段原因根本不是代码问题而是环境版本不匹配。JDK版本选择上Spring Boot 2.x系列推荐JDK 8或11这是兼容性最稳的组合。如果你非要用JDK 17建议直接把Spring Boot版本升级到3.x因为老版本Spring Boot和JDK 17的字节码不兼容运行时会报一堆莫名其妙的错误。我项目最初用的就是Spring Boot 2.7.5 JDK 8稳定跑了整个开发周期。这个组合是经过大规模生产验证的对毕设来说完全够用千万不要追求最新版本给自己添麻烦。你后面做任何Java毕设只要看到Spring Boot 2.x JDK 8的组合基本不会出环境问题。Maven的话不用刻意下载配置IDEA自带Maven插件只要本地装了JDKIDEA能自动识别内置Maven版本。不过国内网络环境下拉取依赖经常超时需要在Maven的settings.xml里配置阿里云镜像这个配置方法网上很多我这里只说一句配置镜像后记得重启IDEA不然不生效。MySQL版本选择上5.7和8.0都可以但驱动配置稍有区别。8.0的连接URL必须加上serverTimezoneAsia/Shanghai否则会报时区错误。5.7则不需要。我的项目用的是MySQL 8.0所以所有配置都按8.0来写。4.2 配置文件application.yml的核心参数Spring Boot的配置集中在application.yml中这个文件的正确性直接决定了项目能否连接数据库、能否正常启动。我的配置大致如下注释写得很详细server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/pig_health?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalse username: root password: 123456 jpa: hibernate: ddl-auto: update show-sql: true properties: hibernate: format_sql: true thymeleaf: prefix: classpath:/templates/ suffix: .html cache: false这里有几个参数必须重点说明。datasource.url里的useUnicodetrue和characterEncodingutf8是保证中文不乱码的关键配置少了任何一个数据库里存的中文都可能变成问号。JPA的ddl-auto配置了update意思是Hibernate会扫描实体类自动更新数据库表结构。开发阶段用update很省心新增字段不用手动改表但上线部署前最好改成validate或者none防止生产环境数据被意外修改。这个细节也经常被追问。show-sql配置为true可以在控制台看到每条SQL语句对于调试非常有用。我第一次联调时搜索接口查不出数据就是从控制台的SQL输出里发现实际执行的语句带了like条件而我没有传对参数名这种问题不看SQL很难定位。4.3 数据库初始化SQL脚本和自动建表我的系统数据库初始化用了双保险一份是纯SQL的初始化脚本一份是依赖JPA的自动建表。SQL脚本里建了用户表、疾病信息表、浏览记录表和收藏表还预置了十几条常见的猪疾病数据比如猪瘟、猪蓝耳病、猪圆环病毒病、猪链球菌病、猪气喘病等。初始数据的价值在于项目启动后打开页面就能看到展示效果不需要你再去手动录入数据也方便你测试分页和搜索会不会出问题。JPA自动建表方面当ddl-auto配置为update项目启动时会自动根据实体类创建缺失的表。两条路径的配合是最好的开发体验先跑SQL脚本初始化数据再启动项目让JPA补全新增的实体字段。注意如果SQL脚本和实体类字段不一致JPA update不会帮你删除已有字段只会新增缺失字段这个特性既是优点也是坑。如果你改错了字段名想删除旧字段只能自己手动到数据库执行ALTER TABLE语句。4.4 启动调试与验证流程环境全部配好之后启动项目会经历几个阶段Maven编译、Spring容器初始化、数据库连接建立、端口监听。首次启动因为有大量依赖需要下载耗时三五分钟很正常不要以为是卡死了。启动成功后的日志会有一行Spring Boot的标志性信息“Started PaymentApplication in x.xxx seconds”看到这行基本可以确认容器启动没问题。然后打开浏览器访问http://localhost:8080如果能看到首页说明前端资源加载正常。接着测试一个核心接口比如http://localhost:8080/disease/search?keyword发烧能够返回疾病列表就说明从控制器到数据访问层的链路全部打通了。具体的验证流程我建议按照这个顺序来先验证静态页面是否能访问再验证登录注册功能再测试带分页的列表查询最后测试搜索关键字。每验证一个功能就打个勾这样可以快速定位是哪一层出了问题。前端页面打不开大概率是Thymeleaf模板路径错了接口能通但数据查不出来大概率是SQL逻辑问题数据库返回乱码大概率是连接URL编码配置问题。先区分问题是哪一层的再着手解决效率高很多。5. 常见问题与排查技巧实录5.1 页面能打开但CSS样式全部失效这个问题在Thymeleaf项目里非常典型。页面内容显示出来了但所有按钮、卡片全部没有样式光秃秃的文本堆在页面上。我第一次遇到还以为是Bootstrap的CDN链接被墙了后来排查发现根本不是。原因是Thymeleaf的页面模板在解析资源路径时如果路径写的是相对路径/static/css/bootstrap.min.css实际会被解析成相对当前请求路径的URL导致目录层次对不上。正确写法是用Thymeleaf的{}语法来生成上下文相对路径例如/css/bootstrap.min.css这样Thymeleaf会自动在路径前面加上项目上下文。这个问题排查起来其实非常简单按F12打开开发者工具看CSS资源请求的状态码如果是404基本就是这个原因。别问我为什么知道说多了都是泪。5.2 分页数据一直和预期不符分页的坑主要是Pageable的页码起始值问题。JPA的页码从0开始而前端页面上用户看到的第一页是1。如果你从RequestParam获取current参数后直接传给PageRequest.of(current, size)页面上第二页请求的是current2后端实际查的是第三页数据永远差一页。正确做法是拿到page参数后先减1再传给PageRequest。这个逻辑很细但特别值得记住因为任何分页功能都逃不掉这个转换。我排查这个问题时一度以为自己SQL写错了后来单独写了一个测试接口打印Pageable参数才发现是起始页的问题。同时分页返回的总数totalPages如果前端要从0开始遍历页码也要记得加1再展示。5.3 查询数据库中文全部变成问号这个问题十个有九个是连接URL没加characterEncodingutf8导致的。MySQL在插入和读取中文时会依赖连接层的字符集设置而中文变成问号往往不是数据库本身的问题而是应用和数据库之间的连接没有声明正确字符集。解决办法很简单不过这里要补充一点MySQL 8.0的驱动连接参数要求更严格指定characterEncodingutf8之外还要确保数据库本身的字符集也是utf8mb4。可以通过SQL命令查看当前库的字符集如果不是utf8mb4就执行ALTER DATABASE pig_health CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;然后重启项目。注意表已经建好的情况下库字符集变更不会自动修改已有表的字符集需要针对每张表单独转换这个细节容易漏。5.4 端口被占用导致启动直接失败如果你开发过程中遇到过多次强行关闭IDEA的情况下次启动Spring Boot大概率会遇到端口被占用的问题。报错信息很明确Web server failed to start. Port 8080 was already in use. 原因是上一次运行的程序进程没有被完全杀掉IDEA的运行按钮变灰后后台的Java进程可能还在。处理办法分两步第一步在命令行执行netstat -ano | findstr 8080查看PID然后taskkill /F /PID 进程号强制杀掉。第二步是排查自己是不是有多个IDEA窗口同时打开了同一个项目这是最常见的原因。如果你希望换一个端口也可以直接在application.yml里把server.port改成8081大项目开发时多个服务同时跑是常态改端口是最省事的方案。5.5 表结构更新后JPA没有自动建新字段这个问题的坑点在于ddl-autoupdate的更新机制。当你在实体类新增一个字段并启动项目后Hibernate会尝试自动给对应表增加列但有三种情况不会成功一是JPA配置没有生效检查你是否误把ddl-auto写成了none二是实体类字段命使用了大写开头的规范但数据库列名映射因为命名策略对不上三是数据库表名和实体映射的Table(namexxx)不一致Hibernate识别不了对应关系。排查方法也很直接启动日志里搜hibernate关键字看它输出了什么SQL语句。如果一条DDL语句都没输出说明Hibernate根本没有识别到实体变化如果输出了字段增加语句但执行报错右键数据库控制面板刷新表结构再看。总的来说JPA自动建表适合开发阶段一旦进入后期联调和部署阶段还是老老实实维护SQL脚本更可靠。5.6 搜索功能查不到任何内容搜索查不到内容先看你的关键词到底传给后端没有。用浏览器开发者工具Network面板查看搜索请求的请求参数这是最快的判断方法。如果参数传了但查不到接着看控制台打印的SQL语句重点确认LIKE语句中的%包围是否正确。写Query(SELECT d FROM DiseaseInfo d WHERE d.diseaseName LIKE %:keyword%)这种情况下参数里再包含中文或特殊字符MySQL的LIKE不会做正则匹配应该没问题但有一个经典坑是关键词里带了空格或百分号。比如用户搜索“猪 瘟”关键词里带了空格最终执行的SQL就变成disease_name LIKE %猪 瘟%当然查不到。所以业务层对关键词做trim处理非常重要。另外还有一些很冷门的排查点如果用了缓存框架先清理缓存数据再试如果数据库里存的数据自带不可见字符复制网页内容时带上来的也会导致搜不到。数据无效字符导致的排查往往是兜底方向正常数据量下不容易遇到。6. 技术之外源码规范、项目扩展与答辩加分6.1 代码规范让你少改十遍bug我在写这个系统的过程中最深的一个体会是代码规范不是给别人看的是给自己省时间的。Java命名规范、注释规范、日志打印规范能直接减少排查bug的时间。比如我在Service层的每个核心方法上写了完整注释说明参数含义、返回值、异常情况。这个习惯让我在三天后重新翻代码时还能秒懂当时的逻辑。日志打印也一样我在用户登录、疾病新增、权限校验失败这些关键节点都加了一行日志出了问题打开日志文件就能定位而不是靠猜。很多同学写完代码从不打印日志出问题了就只能一行行读源码debug效率差距非常大。统一异常处理也是规范的一部分。全局异常处理器把用户操作类异常比如重复注册、密码错误和系统异常分开处理前者返回友好提示后者记录详细日志并返回统一错误信息。这样调试和用户反馈都清楚不会被一串英文报错直接糊脸。6.2 给这个系统的三个扩展方向做完核心功能后如果学有余力我建议在这个系统上做三个方向的扩展每一个都是成本不高但答辩很好讲的功能。第一个方向是数据统计可视化。系统已经有浏览量和查询记录可以进一步用ECharts展示疾病月度高发趋势、症状关键字词云、各类别疾病占比饼图。这项扩展的技术含量在于数据聚合查询JPA里写一条带GROUP BY的查询就能搞定但呈现效果直接拉升项目档次。第二个方向是疾病智能推荐。根据用户浏览记录在详情页下方推荐相似类别的疾病。这个功能用简单的标签匹配就能实现不用上机器学习但可以讲成“基于内容的协同过滤思路”从产品逻辑上让答辩老师觉得你有思考深度。第三个方向是消息通知。管理员新增疾病信息后给关注该分类的用户发送站内通知。用Spring Boot自带的事件监听机制就能完成代码量不大但能展示你对解耦设计的理解也方便引出Spring事件驱动模型的知识点算是辩论中的提分点。6.3 一份合格的毕设README要写什么最后我想认真聊一下README文档这是很多人忽略但其实很重要的东西。一份合格的毕设项目README至少包含项目简介、技术栈说明、核心功能列表、启动步骤、数据库初始化说明、项目结构说明、常见问题。这不是形式主义而是让接手你项目的人包括答辩老师用最短时间理解你的项目。我写README时有一个习惯把启动步骤写得像保姆级教程。从安装JDK开始到导入项目、修改数据库账号密码、执行SQL脚本、启动、访问每一步都写清楚。这样答辩现场如果老师想跑一下你的系统照着README就能完成不会因为你一笔带过而卡住。另外README里还可以加一个“设计思路”章节用几段文字说明你为什么选择这个架构、为什么用JPA、为什么分那些模块。这个章节对评分的帮助甚至超过代码本身因为它展示了你的思考过程。关于源码本身有一点必须提醒拿到任何参考源码后一定要自己从头到尾把关键路径读一遍然后动手改几个功能再跑通。这个过程不是浪费时间而是把参考源码变成自己能力的过程。答辩的时候老师随便问一个业务细节只有真正改过代码的人才能对答如流。我在实际开发中还有一个小习惯所有关键功能开发完成后都会把整个项目的目录结构截图放到一个备忘文档里然后标注每一层的核心类职责。这样最后写论文、做答辩PPT时素材都是现成的不用重新翻代码。做毕业设计最怕的不是技术难而是没有计划地瞎忙。先跑通一个最小闭环再一点点加功能每一步都能看到系统的成长这个过程本身就是最大的收获。
返回列表