ARTICLE DETAIL

资讯详情

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

基于SpringBoot+Vue+MySQL的宠物健康顾问管理系统实战

基于SpringBoot+Vue+MySQL的宠物健康顾问管理系统实战 做宠物健康顾问系统这类管理项目最怕的就是技术栈太重、跑不起来、代码看不懂。最近整理了一套基于SpringBoot后端Vue前端MySQL数据库的宠物健康顾问信息管理系统源码开箱即用前后端分离结构清晰非常适合拿来当课程设计、毕业设计或者SpringBoot/Vue实战练手项目。这套系统不是那种只能看不能跑的演示项目而是把用户管理、宠物档案、健康记录、在线咨询这些核心功能都做了进去源码拿下来直接配好数据库就能启动前后端联调访问整个开发链路非常完整。下方我会把项目从技术选型到最后跑起来的完整过程拆开讲清楚包括后端分了哪些层、接口怎么设计、前端页面怎么对接、数据库表结构长什么样、怎么初始化、部署时容易踩哪些坑以及这套代码后续怎么扩展成更完整的商业项目。不管你是打算复刻来做毕设还是单纯想学一下SpringBoot和Vue怎么配合做前后端分离项目这篇文章都能给你省下大量试错时间。1. 项目概览与技术选型逻辑1.1 这套系统到底解决了什么问题宠物健康顾问系统这个名字乍一听有点抽象实际上它的核心定位是给宠物主和健康顾问之间搭一座信息桥梁。宠物主可以录入自己宠物的基础档案、接种疫苗记录、驱虫记录、体重变化、就诊历史甚至每天的健康状态备注健康顾问或者管理员角色可以查看这些档案针对性地给宠物主提供日常护理建议、饮食指导以及线上咨询答复。整个系统解决的是线下宠物健康信息散乱、顾问和宠物主之间沟通低效的问题——把纸质记录、聊天记录变成一处可查、可管、可追踪的线上数据源。从系统功能来看这是一套典型的信息管理系统模块划分围绕宠物全生命周期的健康管理展开。用户模块负责登录注册与角色权限宠物模块维护宠物基本信息与品种分类健康模块存储体检记录、疫苗接种、驱虫记录咨询模块支持宠物主在线提问、顾问回复再加上数据统计看板、公告管理、个人信息维护这些外围功能基本覆盖了一个中小型管理系统的全部常见需求。无论你是拿它当毕设、课程设计还是学习前后端分离开发这套系统都具备很好的参考价值。1.2 为什么是SpringBoot、Vue、MySQL这套经典组合这个技术组合在近几年的Java Web项目里几乎成了标配原因并不在于它有多热门而在于它的学习曲线和开发效率非常平衡。SpringBoot解决了传统SSM项目中大量繁杂的XML配置问题默认内置Tomcat一个main方法就能把服务跑起来Vue提供组件化和响应式数据绑定让前端页面的开发效率和可维护性远超传统JSPMySQL则是开源数据库里生态最完善、上手最轻松的选项配合Navicat或者命令行工具就能完成可视化管理和数据导入。选型时还有一个很重要的现实因素这套组合的招人需求和资料丰富程度都很高。无论去面试Java岗位还是全栈岗位SpringBoot是必问项Vue是加分项MySQL更是基本功。把这些技术串成完整项目跑一遍比只看零散的教程有价值得多。我在给别人推荐练手项目时通常也不会选特别冷门或新颖的技术栈能用最主流的技术把业务做清楚其实才是最符合实际工作需求的。从项目本身来看前后端分离架构也让团队协作变得更加自然前端专注页面交互后端专注接口和数据两边通过JSON进行通信。后面我会详细讲到项目结构、接口设计、数据表设计和部署流程每一步都会结合我在实操中积累的细节来展开。2. 项目结构与后端核心设计2.1 后端工程结构与分层设计拿到源码之后第一件事应该是先理解后端的工程结构。一个规范的SpringBoot项目目录结构通常遵循controller、service、mapper、entity这样的分层这套源码也不例外。pet-health-backend/ ├── src/main/java/ │ └── com/pethealth/ │ ├── controller/ # 控制层接收前端请求 │ ├── service/ # 业务逻辑层 │ ├── mapper/ # 数据库操作层MyBatis-Plus │ ├── entity/ # 数据库实体类 │ ├── dto/ # 请求参数封装 │ ├── vo/ # 返回结果封装 │ ├── config/ # 配置类跨域、拦截器等 │ ├── common/ # 通用返回结果、异常处理等 │ └── PetHealthApplication.java ├── src/main/resources/ │ ├── application.yml │ └── mapper/ # MyBatis-Plus SQL映射文件 └── pom.xml分层不只是为了好看而是为了让每一层职责单一。controller只负责接收参数和返回结果不写业务逻辑service承载核心业务比如新增宠物时同时校验用户权限、生成默认健康档案mapper只做数据持久化。这样后续要做代码审查、加功能、排查问题都能快速定位到文件不会在一个大Controller里翻几千行代码。很多新手拿到项目喜欢从Controller开始读这没错但同时建议先去service层看业务流向否则会有大量接口看过就忘。我习惯的做法是先跑一次系统、用Postman登录拿token然后跟着一个核心功能比如新增宠物档案从前端请求路径追到后端service方法这样整个调用链就串起来了。等你想二次开发时这套熟悉流程能帮你节省大量时间。2.2 核心接口设计与业务逻辑梳理后端接口的设计直接决定了前端好不好对接也决定了整个系统的可扩展性。这套系统的接口风格是标准的RESTful 统一返回格式比如用户模块有注册、登录、获取用户信息宠物模块有新增、编辑、删除、分页查询健康档案模块有新增体检记录、查询宠物历史健康记录咨询模块有发起咨询、顾问回复、查看咨询列表等接口。以登录接口为例它的典型调用流程是前端把用户名和密码POST到/api/user/login后端先做基础参数校验接着用MyBatis-Plus的QueryWrapper按用户名查询用户然后用工具类做密码的MD5或BCrypt加密比对。比对通过后生成JWT token返回给前端前端把它存在localStorage里之后每次带token请求受限接口后端通过拦截器解析token并判断角色权限。这里有一个非常关键的设计细节统一返回结果。后端没有在controller里直接返回一个裸的User对象或List而是统一用R对象包了一层格式大致长这样{ code: 200, msg: 操作成功, data: { token: eyJhbGciOiJIUzUxMiJ9... } }这么做的好处是前端可以统一拦截响应在axios响应拦截器里判断code字段拒绝登录过期、业务异常时弹统一的错误信息而不是每个接口单独写一遍判断逻辑。很多半路出家的项目没注意这个细节导致前端到处散落着res.data.code 200这类重复代码后续维护非常痛苦。另外要特别注意handler层对全局异常的处理。项目里通常会加一个RestControllerAdvice的全局异常处理器把业务异常、参数校验异常、未知异常统一封装成指定格式返回给前端。这样数据库报错、空指针这样的问题不会把整堆堆栈信息直接抛给用户线上排查起来也更安全。这个模式也是大厂开发中的通用做法值得仔细看。2.3 关键配置与常见版本坑后端跑起来之前必须检查application.yml里的配置。最核心的是数据源配置、端口配置、MyBatis-Plus配置和JWT相关配置。server: port: 8080 servlet: context-path: / spring: datasource: url: jdbc:mysql://localhost:3306/pet_health?useUnicodetruecharacterEncodingutf-8useSSLfalseserverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: id-type: auto关于serverTimezoneAsia/Shanghai和useSSLfalse这两个参数是从SpringBoot整合MySQL时最容易踩坑的地方。MySQL 8.0以上默认启用SSL如果不显式关闭启动连接时可能出现握手失败或SSL相关错误时区不设置Java 8的LocalDateTime存进MySQL时会出现时区偏移导致前后端展示的时间差8个小时。这两个属于不亲眼遇到根本不会在意但一遇到就要折腾半天的坑。版本问题更要留心。这套源码如果基于SpringBoot 2.x就不建议盲目升级到SpringBoot 3.x因为3.0之后强制要求JDK 17很多旧版依赖的API也变了硬升级会带来一堆莫名其妙的报错。我也见过有朋友拿到源码后把pom.xml换成最新的SpringBoot 3.1.0版本结果项目直接无法启动。正确的做法是先看项目原版的依赖版本如果能跑通就不要去改大版本如果必须用高版本就准备好额外的时间去适配。另外MyBatis-Plus分页插件需要手动在配置类里注册MybatisPlusInterceptor并添加PaginationInnerInterceptor很多分页功能失效的问题都出在漏配这个Bean上。老手可能觉得这是常识但新手在全新环境中很常见我会在后文的排查清单里再提到。3. Vue前端落地细节3.1 前端工程结构与路由设计前端部分用的是标准Vue项目结构整体技术栈以Vue 2为核心配合Element UI、Vue Router和Vuex构建工具为Webpack对应Vue CLI 4或5版本。依赖安装命令是npm install建议不要直接装最新版本而是用项目里package.json锁定的版本避免Element UI和Vue 3、Vite这些新生态混在一起出现兼容性灾难。pet-health-web/ ├── public/ │ └── index.html ├── src/ │ ├── api/ # 接口请求封装 │ ├── assets/ # 静态资源 │ ├── components/ # 公共组件文件上传、富文本等 │ ├── router/ # 路由配置 │ ├── store/ # Vuex状态管理 │ ├── views/ # 页面组件 │ ├── utils/ # 请求工具、token处理 │ ├── App.vue │ └── main.js └── package.json路由设计是前端骨架的关键。项目里通常把页面分成两个层级不需要登录校验的页面登录、注册和需要登录校验的业务页面首页、宠物档案、健康档案、咨询中心、个人中心等。实现这套区分最常见的方式是路由守卫在router.beforeEach里读取localStorage里是否存有token没有就重定向到登录页有token但访问的是登录页就重定向到首页。这套机制看着简单却是必须写好的安全底线前端路由只是交互层面的限制真正鉴权和越权控制还得依赖后端权限校验。很多学习Vue的同学容易忽略路由层级设计。不要把宠物列表、健康列表全部平铺在/views下面建议按模块分文件夹比如views/pet、views/health、views/consult、views/user组件放在components里统一管理。这套源码的目录划分就做得比较清楚拿来学习Vue Router的嵌套路由、动态路由以及组件复用都很合适。3.2 核心页面与交互逻辑说明打开系统之后第一个有感觉的页面通常就是登录页和注册页。这两个页面在Element UI基础上封装了一个表单组件包含基本的手机号或用户名输入、密码输入、登录和注册切换逻辑。表单校验用的是rules规则对象比如用户名不能为空、密码长度必须大于等于6位这些校验能做到在请求发出之前先把明显错误拦截下来。宠物档案列表页是系统的核心页面之一。这里的交互逻辑很有代表性页面一进来就调用getPetPage接口拿分页数据点新增按钮弹出一个DialogDialog里是宠物表单宠物名、品种、年龄、性别、体重、是否绝育等提交时调addPet接口成功后刷新列表。这里有一个值得学习的交互细节删除宠物前使用this.$confirm做二次确认避免用户误操作。很多初学项目忽略这类交互细节做得比较糙但从实际投入使用角度这类细节恰恰是体验感提升的关键。健康档案页面会用到大量的时间线和卡片展示。宠物健康记录在系统中不是一张单表无限堆数据而是以宠物为维度将疫苗接种、驱虫、体检、日常体征维护成多类记录。前端通过标签页或者时间线组件将不同类别的记录展示出来。这里值得提一下Vue组件的插槽用法——Element UI的表格卡片组件大量支持插槽自定义操作列、自定义状态显示都是通过插槽完成的。如果你不太理解Vue插槽到了这个页面就能非常直观地看到它的实战场景同样的表格组件每列的显示方式是可以通过具名插槽灵活控制的数据字段和展示UI被彻底解耦。3.3 接口请求封装与状态管理大型Vue项目必须做的事是把axios请求统一封装起来避免每个页面里直接写一堆axios.get加上重复的loading、错误处理代码。这套源码里utils/request.js就是干这件事的它的基本做法是创建axios实例设置baseURL为/api然后通过请求拦截器把存在localStorage里的token拼到请求头Authorization字段上再通过响应拦截器统一处理code码。import axios from axios const service axios.create({ baseURL: /api, timeout: 10000 }) service.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] token } return config }) service.interceptors.response.use( response { const res response.data if (res.code 401) { localStorage.removeItem(token) router.push(/login) return Promise.reject(new Error(登录已过期)) } if (res.code ! 200) { Message.error(res.msg || 系统错误) return Promise.reject(new Error(res.msg || 系统错误)) } return res }, error { Message.error(error.message) return Promise.reject(error) } )这段逻辑在项目里是一种标准答案几乎所有Vue后台管理系统都是这么做的。单独拿出来讲是因为很多初学者会在每个组件里重复写接口请求结果就是token失效后到处弹错误、接口报错后每页都要手动处理。把请求统一收敛到一个文件后你在任何新页面里只需要import { getPetList } from /api/pet就可以用了维护成本直接降一个级别。Vuex在项目里主要用来管理当前登录用户的信息。登录成功后把用户对象存入Vuex和localStorage页面刷新后再通过getUserInfo接口重新拉取用户信息。这里说一下我个人的建议用户名、头像这类展示型数据放Vuex方便但token持久化一定用localStorage因为Vuex的数据刷新就没了。有些项目把token也放进Vuex刷新后必须重新登录体验极差把这个点写进你日后自己的项目注意事项里。4. MySQL数据库设计4.1 核心表结构一用户与宠物档案数据库是这套系统的地基表设计不合理后期改起来成本极高。这套项目采用的是比较经典的多表设计核心表包括用户表、宠物表、健康档案表、体检记录表、疫苗记录表、咨询表等各自职责清晰、关系明确。用户表是最基础的一张表字段上至少要包含用户名、密码、昵称、头像、手机号、角色标识管理员/普通用户、状态是否禁用、创建时间、更新时间。需要注意密码字段不能存明文而是存加密后的密文。宠物表则记录宠物所属用户、宠物名、品种、性别、出生日期、体重、绝育状态、头像URL。宠物表通过user_id外键关联用户表这就保证了一个用户下可以拥有多只宠物符合实际业务场景。外键在MySQL里到底建不建很多项目分两派。这套项目我更建议以逻辑外键为主也就是在Java代码层面维护关联关系表结构层面不强制加外键约束。原因很简单加了物理外键删除宠物或用户时会被约束卡住还得先删关联数据很多业务场景并不希望这样更重要的是分库分表和后续数据迁移时物理外键会成为很大的阻碍。实际开发中见过大量表是保留user_id字段但不用物理外键的方式这属于行业默认做法。4.2 核心表结构二健康档案与体检记录健康档案表可以理解为一个动态的体检记录集合表它并不直接存健康状态这种宽泛概念而是把每一次具体的健康行为都记录成一行。体检记录表会存宠物ID、体检日期、体检医院、体重、体温、诊断结果、医嘱建议、下一次复查时间。疫苗记录表则存疫苗名称、接种日期、接种剂量、下次接种提醒时间。为什么要拆成多张表而不合并成一张健康记录表因为不同记录类型的字段差异太大了硬塞进一张表会造成大量空字段和解析困难查询和维护都是灾难。在设计这些记录表时有一个容易忽略但很关键的点业务上的冗余字段要留够。比如体检记录里存了宠物ID看似查宠物表就能拿到宠物名但在列表展示时每次都去关联查一次宠物会导致性能下降。更常见的做法是冗余一个pet_name字段在记录表里这样宠物改名字后历史记录展示的仍是当时体检时的名字这其实也是一种业务严谨性。数据分析时统计某只宠物一年内体重变化也只需要过滤宠物ID加日期区间就可以完成查询效率更高。4.3 索引、锁与数据一致性注意点数据库设计绕不开索引和数据一致性问题。这套项目的数据量不大索引策略不需要很激进但有几个字段一定要建索引用户表的username字段、宠物表的user_id字段、健康记录表的pet_id和record_date字段。这些字段是查询条件里的高频字段建了索引后的提升非常明显。新手最容易忽略的一个索引问题是在MySQL 8.0里一个普通的多列查询如果没走索引数据量一旦上千条就能感到明显卡顿。比如查询某个用户的所有宠物在某个日期之后的体检记录如果只在pet表上建了主键索引而体检记录表上没有pet_id record_date的联合索引这条SQL就会变成全表扫描。搭建这个项目后如果想做更复杂的数据统计建议用EXPLAIN看一遍常用SQL的执行计划看看有没有用上索引这是很好的MySQL排查习惯。关于MySQL锁的分类这在面试里是高频问题在项目里也值得对应理解。简单说锁从粒度上分为表锁和行锁从模式上分为共享锁和排他锁InnoDB引擎支持行级锁这也是为什么它适合高并发写操作。在这个宠物健康系统里同时有多位顾问去更新同一只宠物的健康档案时如果两个事务同时写入同一条记录就需要行锁来保证数据一致性。实际开发中我建议尽量不要在业务代码里手动加锁而是通过事务隔离级别和乐观锁比如在表里加version字段来解决MySQL的默认隔离级别Repeatable Read在这个系统完全够用。整理一下核心表的结构参考表名核心字段说明userid, username, password, nickname, avatar, phone, role用户登录与基本信息petid, user_id, pet_name, breed, gender, birthday, weight宠物档案health_recordid, pet_id, record_date, weight, temperature, diagnosis, advice健康档案/体检记录vaccine_recordid, pet_id, vaccine_name, injection_date, next_date疫苗记录consult_recordid, user_id, pet_id, question, answer, status, create_time线上咨询记录noticeid, title, content, create_time公告信息5. 从零到一跑起来5.1 环境准备JDK、Maven、Node、MySQL拿到源码想直接run起来环境这块就得先过关。后端需要JDK 8或11取决于pom.xml里的版本设置Maven 3.6以上MySQL 5.7或8.0前端需要Node.js 14到16之间的版本Vue CLI 4/5对Node 18以上会有兼容问题这是我踩过实实在在的坑。建议先打开命令行分别执行java -version、mvn -v、node -v、npm -v、mysql --version确认这些命令都正常返回再往下走。JDK安装没有太多悬念配好JAVA_HOME环境变量就行。Maven需要改一下本地仓库路径和镜像源国内建议在settings.xml里配置阿里云镜像否则首次拉取依赖会慢到你怀疑人生。Node.js安装更简单直接去官网下载LTS版本安装即可装完之后顺手把npm的registry切换成https://registry.npmmirror.com可以显著提升依赖安装速度。MySQL安装时要注意字符集选择utf8mb4不然后面在Windows命令行里插入中文数据会出现乱码。5.2 数据库初始化与账号配置项目里如果带了SQL脚本那就是最省心的情况通常是一个pet_health.sql文件。执行导入的方式很简单mysql -u root -p pet_health pet_health.sql或者直接在Navicat里右键运行SQL文件。导入的时候如果报错大概率是SQL文件里的字符集和当前数据库不一致或者MySQL版本太低导致某些语法不兼容。建议手工在MySQL里先创建好库再导表CREATE DATABASE pet_health DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;这里强烈建议使用utf8mb4而不是utf8因为utf8在MySQL里最多存3个字节一些特殊字符比如生僻字和部分符号会存不进去而utf8mb4完全兼容并且还支持emoji。虽然管理系统里不太会出现emoji但宠物名里偶尔会有特殊字符从源头把字符集设置对能避开很多脏数据问题。导入完SQL后检查一下t_user表里有没有内置管理员账号。这个很关键很多项目第一次登录用的就是预设的admin/admin123这样的账号密码。如果SQL里没有你需要自行注册一个账号然后手动在数据库里把角色改成管理员才能进入后台管理界面。我第一次跑一个开源项目时就遇到这种情况一开始没注意注册了一个普通用户结果很多管理接口报无权限排查了半天才意识到角色字段没改。5.3 后端启动与常见启动错误排查环境都准备好后先启动后端。用IDEA打开后端工程目录等Maven把依赖下载完成后在PetHealthApplication.java里运行main方法即可。如果你的IDEA没有自动导入Maven依赖可以右键pom.xml选择Add as Maven Project这是一个很隐蔽但很影响体验的坑。启动成功后会看到类似下面这样的日志Tomcat started on port(s): 8080 (http) with context path Started PetHealthApplication in 5.348 seconds (JVM running for 6.123)如果启动时端口被占用会直接报Port 8080 was already in use这时候要么关闭占用端口的进程要么在application.yml里换一个端口。用命令行查一下谁占用了8080netstat -ano | findstr 8080然后去任务管理器里找到对应PID的进程结束掉或者嫌麻烦直接把端口改成8081但注意改成8081后前端所有接口请求地址也要对应修改。通常我在本地调试时会直接固定使用8080端口避免后面前端代理还要改来改去。数据库连不上的错误也很常见报错信息一般是Access denied for user rootlocalhost或者Communications link failure。前者是账号或密码错了后者是MySQL没启动或者连接地址不对。MySQL在Windows上安装后默认不会自动启动服务需要在服务里找到MySQL服务并手动启动或者运行net start mysql命令。这个环节也是很多新手一走就卡壳的地方。5.4 前端安装依赖与启动联调后端跑起来后进入前端目录安装依赖cd pet-health-web npm install npm run serve如果npm install报了ERESOLVE unable to resolve dependency tree这种错误大概率是npm版本和项目依赖的版本冲突。最简单的解决办法是切换Node版本到14或16或者用npm install --legacy-peer-deps安装依赖。Vue CLI项目通常在node_modules安装完成后提示Compiled successfully in 2843ms就算成功浏览器访问http://localhost:8080就能看到登录页。这里需要注意前端默认的接口代理。vue.config.js里通常配置了proxy把/api的请求转发到后端的http://localhost:8080const { defineConfig } require(vue/cli-service) module.exports defineConfig({ devServer: { port: 3000, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } })启动成功访问http://localhost:3000后页面能打开但不一定代表前后端联调成功。建议打开浏览器开发者工具的Network面板刷新页面随便触发一个请求看看接口返回的状态码是不是200返回体里是否有正常数据。如果出现401、404或者跨域报错都说明代理配置或者后端路径有问题需要回到对应环节排查。我曾经帮别人联调过半天最后发现是前端代理配了/api但后端接口前缀根本没带/api两边路径对不上前端一直在404这种就属于典型的单独看都对连起来就不通的问题。5.5 打包部署与Vue打包放进SpringBoot方案开发环境跑通只是完成了第一步真正交付时还要思考部署方案。最常用的两种方式有两种。第一种是前后端完全分开部署前端执行npm run build生成dist目录放到Nginx或者其他静态服务器上后端打成jar包独立运行用Nginx把/api反向代理到后端端口比如location /api/ { proxy_pass http://127.0.0.1:8080; }第二种方式是很多人熟悉的Vue打包放进SpringBoot一体化部署把前端dist目录下的全部文件复制到后端src/main/resources/static目录下重新打包SpringBoot工程这样整个系统只需要跑一个jar包就能同时提供页面和接口。这种方案适合小型项目或个人项目省去了单独维护Nginx的麻烦但缺点是前端和后端耦合在一起后续需要分别修改时打包步骤会稍繁琐。一体化部署的注意点是路由模式。Vue Router默认用history模式打包后刷新页面容易遇到的404问题因为SpringBoot内部没有处理前端的history路由回退。要解决这个问题有两个可行路径一是把Vue Router模式改成hash模式URL里带个#刷新不会404二是在后端加一个转发控制器把非接口路径转发到index.html。个人项目为了省事直接用hash模式最稳这也是很多开源项目在可直接运行模式下采用的做法。生产环境部署时application.yml里的数据库连接、端口、JWT密钥等建议通过--spring.config.additional-location或者环境变量覆盖而不是直接写死在包里。这些都是让系统具备上线水平的细节虽然不影响本地跑通但如果你想拿这套源码去公司里展示落地能力这些点都非常加分。6. 常见问题与排查实录6.1 跨域问题报了CORS错误怎么办开发环境下只要配置了devServer代理一般不会遇到跨域问题。但一旦前端用npm run build之后直接双击index.html访问或者前后端部署在不同域名下CORS错误就来了。错误信息长得很典型常见的是Access to XMLHttpRequest at http://localhost:8080/api/... from origin http://localhost:3000 has been blocked by CORS policy。解决办法就是在后端加一个跨域配置类允许指定的前端来源访问。最简单的写法是Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .allowCredentials(true) .maxAge(3600); } }注意这里我用的allowedOriginPatterns而不是allowedOrigins。后者在高版本SpringBoot里配合allowCredentials(true)时会因为来源地址精确匹配而报错使用*通配模式更省心。如果项目里用了Spring Security跨域配置还需要在Security的过滤链上也放行预检请求否则前端发OPTIONS预检请求时会被Security拦下来这种问题表面上是跨域实际是安全配置冲突排查起来非常绕。6.2 MySQL连接失败的三类经典场景MySQL连接失败是我在这类项目里收到提问最多的一类问题。第一类是MySQL服务没启动Windows下安装MySQL后服务默认是停止状态报错见Communications link failure解决办法是启动服务并设为自动启动。第二类是用户权限问题报错是Access denied常见原因是root用户密码记错了或者没有允许远程连接本地连一般不会触发。这时可以试试在MySQL命令行里执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 你的新密码;这个命令不仅改了密码还把认证插件改成了mysql_native_password。MySQL 8.0默认的caching_sha2_password认证插件有些老版本的JDBC驱动和图形客户端不认就会连接报错。把认证插件改成老格式是最普适的解法。第三类是端口和字符集问题java.sql.SQLException: Unknown database pet_health基本就是没执行SQL脚本或者库名写错了。这类问题的排查思路很简单先用Navicat或命令行自己连一下MySQL看看能不能正常访问再用数据库配置里的账号密码去连看是否报错。这一步如果都没问题那问题就大概率不在数据库层面而在于SpringBoot的配置文件有没有生效。6.3 接口404与服务扫描路径问题前端页面能打开但每次接口请求都返回404这里有一个很隐蔽的坑——Controller的包扫描路径不对。SpringBoot启动类默认扫描的是SpringBootApplication所在包及其子包也就是说启动类放在com.pethealth下Controller也得放在com.pethealth.controller或者com.pethealth的子包里。如果把Controller放到com.xxx.controller这种不相关的包里SpringBoot启动时根本不会注册这个Bean接口自然404。碰到这种问题先检查控制台日志启动时一般会打印当前项目里所有已注册的接口路径比如Mapped {[/api/pet/list],methods[GET]}。如果日志里压根没有这个接口就说明Controller没被扫描到这时候把启动类往包结构上层移动是最省事的解法。如果日志里能打印接口但访问还是404那就得检查前端代理路径和后端context-path是否一致。SpringBoot的spring.mvc配置有时候会加上一个前缀路径前端如果没跟着改接口也会全部404。6.4 Node版本与依赖导致的启动失败npm run serve命令执行后控制台报各种语法错误或者TypeError: Cannot read properties of undefined十有八九是Node版本不兼容。现在想想身边超过一半的人在这套项目上卡壳都是因为前端环境版本太新。Vue CLI 5推荐Node 14到16Node 18之后Webpack的热更新和部分模块就会出问题。我用nvm这类版本管理工具在没有nvm的环境下切换很麻烦但为了这个项目专门装一个老版本Node也值得不会耽误多久。另外一个高频坑是npm install的时间过长或者中途报ELIFECYCLE错误。这种一般不是代码问题而是网络问题建议把npm源切到国内镜像后再装一次。有些老项目的依赖里有node-sass这东西在Node 16之后的版本上几乎必装失败如果遇到这种报错换成sassDart Sass可以原地解决。问题根源是node-sass是C插件每次装都要针对本机Node版本重新编译极其容易失败现在的项目基本已经淘汰它了。6.5 数据能存但查不出来字符集、时区与排序问题有朋友遇到过新增宠物后列表里中文是乱码但是数据库里看却是正常的这种多数是前端页面渲染字符集设置不对检查index.html里有charsetutf-8即可。反过来数据库乱码则大概率出在连接字符串上确保URL里带上characterEncodingutf-8。MySQL的utf8mb4和Java的UTF-8其实是一致的但中间环节如果没有统一就会出现看着对、存进去变样的问题。时区问题则集中体现在时间字段上。页面提交一个体检时间存进数据库后却少了8小时或者多了8小时第一反应应该是检查MySQL连接串里有没有serverTimezoneAsia/Shanghai同时检查Jackson的时区是否设置为GMT8。两边的时区都统一后时间显示基本就正常了。还有一个MySQL排序的坑如果列表排序结果不对很可能是排序字段选错或者字段类型是varchar导致排序时按字典序而不是数字序排比如体重字段如果是字符串10就会排在9前面。解决办法是把这类字段改成decimal或double类型或者排序时用CAST(weight AS DECIMAL)。7. 这套源码如何扩展成更完整的业务系统7.1 功能扩展方向一预约与提醒如果只是按源码原样跑通那它能满足课程设计/毕设的要求但离真正的线上宠物健康服务还有一段距离。我见过很多相关项目在它的基础上大约可以在三个方向做功能扩充。第一是预约医生和排班。宠物健康顾问的核心场景是宠物主有问题顾问给出建议目前咨询模块是留言式的可以进一步做成排班预约式顾问维护可预约时段宠物主选择一个时间段发起预约系统自动生成一条预约记录。这个功能看似多了一张预约表其实后端只需要新增一个预约Controller前端新增一个日历组件再加一个完整的业务状态流转待支付、待接诊、进行中、已完成。从技术上来说并不难但业务上它能让系统更像一个可用的在线问诊平台。第二是自动提醒功能。疫苗记录里有下次接种时间字段可以做一个定时任务每天扫描这些记录给临近日期的宠物主推送站内信或短信提醒。SpringBoot实现定时任务非常简单只需要在启动类上加EnableScheduling然后在service里写一个带Scheduled(cron 0 0 9 * * ?)的方法即可。每天上午9点跑一次检索未来三天需要接种疫苗的记录生成通知数据。这个扩展做出来很能体现健康管理的系统价值也是面试时非常好的加分细节。7.2 功能扩展方向二文件上传与数据可视化宠物档案和体检报告里往往需要上传诊断图片、化验单截图目前如果只支持URL填写使用体验会大打折扣。扩展文件上传功能时可以将本地存储作为最简实现在application.yml里配置一个上传目录通过MultipartFile接口接收文件保存后返回可访问的URL。等将来上了云服务器再替换成对象存储SDK业务代码不需要大改。这里我建议把所有上传接口统一定义为/api/file/upload前端封装一个FileUpload组件这样宠物档案、健康档案、公告模块都能复用。数据可视化则是把现有数据变成图表。宠物管理系统最值得统计的数据包括宠物总数、按品种分类的占比、每月新增宠物数量、各健康指标的异常比例。用Vue生态里的ECharts组件加上后端的统计接口就能快速实现一个数据看板。统计接口的做法一般是写一个DashboardController通过聚合查询返回各指标数据。比如查询每月新增宠物数SELECT DATE_FORMAT(create_time, %Y-%m) AS month, COUNT(*) AS count FROM pet GROUP BY month ORDER BY month这样前端拿到数据后直接喂给ECharts的柱状图或折线图即可。数据可视化几乎是所有管理系统的加分刚需如果项目里能展示一个像样的看板整个系统的完成度和专业性都会明显提升。7.3 工程化提升与代码规范补充最后再说一点工程化层面的建议这是我搭建类似系统时体会最深的部分。这套项目源码目前能直接运行但离规范的团队开发标准还有一段距离如果要作为正式项目迭代可以从这几个方面逐步提升。项目里可以补充统一响应体R类和全局异常处理器这两块属于最基础的部分很多系统源码会包含这部分但也有些简化版的项目里所有接口直接返回Map后端报错直接堆异常栈。如果你拿到的是简化版本建议无论如何都要加上统一响应体它能让你后面所有接口的改动都变得非常统一、非常省事。接口文档和日志也不能轻视。SpringBoot工程可以引入springdoc-openapi或者knife4j来生成Swagger接口文档这样前端对接时不用反复翻源码日志方面不要到处用System.out.println要使用SLF4J Logback在application.yml里配置Info级别和Error级别的日志文件输出。虽然这些不影响跑通但如果你日后要拿这套项目去面试或接项目工程化程度就是普通代码和规范代码的分水岭。单元测试也值得认真写。不要只写Service层的干净方法测试更重要是用SpringBootTest写几个核心接口的集成测试比如宠物新增、咨询回复的整个流程走一遍保证核心业务不崩。这个投入产出比很高能让你后续做任何功能扩展时都不用担心改挂了原有逻辑。8. 最后一点实际体会我在实际整理和运行这套项目过程中最大的感受是SpringBoot、Vue、MySQL这套组合本身就是最好的教案。把系统跑通不是终点你完全可以在此基础上把每条弯路、每个报错变成自己的经验积累。第一次跑通比预期多花了点时间但踩过那些坑之后再看其他任何前后端分离项目基本上第一眼就能定位到大概的部署结构、接口风格和数据流走向。如果你也正在拿这套源码做二次开发记住一个原则先跑通原版再改业务最后换技术。不要一开始就想换成最新版本、换UI框架、改数据库类型那等于给自己叠buff。顺着既定技术路线先跑通再加预约提醒、上传、图表看板这些扩展功能每一步都在原项目基础上落地慢慢就会形成自己的代码资产。到时候这套项目就不只是可运行的源码而是能代表你真实开发能力的一块敲门砖。
返回列表