尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
SpringBoot+Vue+MyBatis构建宠物爱心组织管理系统全栈实战
做宠物爱心组织管理系统的初衷其实源于一个很现实的场景大量民间救助站和志愿者团队日常工作还停留在Excel加微信群哪只猫打了疫苗、谁提交了领养申请、仓库里还剩多少袋猫粮全靠人肉记忆。这个SpringBootVueMyBatisMySQL搭建的宠物爱心组织管理系统完整源码项目就是把这些散落在表格和聊天记录里的信息变成一套能真正跑起来的业务系统。它适合两类人一类是准备给本地救助站做信息化项目的开发者另一类是刚学完前后端分离、想找一个带完整业务闭环的项目练手的人。这套系统覆盖了志愿者管理、宠物档案、领养审批、善款物资、活动报名、资讯发布和统计看板不是那种只为了应付毕业设计的玩具代码而是把权限、事务、软删除、数据统计这些企业级系统的常见诉求都做了进去值得照着拆一遍。1. 项目框架与需求拆解1.1 宠物爱心组织的管理痛点宠物救助站这类组织看起来业务简单实际管起来非常琐碎。我接触过的几个救助站最痛的不是收容宠物而是信息的反复登记和核对。志愿者花半天时间给新来的流浪猫建档结果一个月后另一批志愿者来值班根本不知道这只猫做过几次驱虫、有没有绝育、对什么食物过敏。领养环节更麻烦申请人的回访记录、宠物状态变更、协议签署情况全都靠聊天记录时间一长根本没法追溯。这套系统的价值就是把角色、宠物、申请、物资、资金、活动六条主线的数据串起来。志愿者在后台录入一只宠物自动生成唯一的宠物编号领养人提交申请后管理员可以根据体检记录、疫苗记录、回访情况决定是否通过捐赠物资入库后库存扣减、出库登记、领用记录都要对得上账。和Excel相比系统最大的收益不是代替人记录而是用数据流转约束业务流程谁改了什么、什么时候改的、改之前是什么状态都留得下来。1.2 为什么叫企业级“企业级”这个词经常被滥用但也有它的实际含义。放到这个项目里主要体现在几个非功能性设计上第一是权限管控。系统不能让所有人都能改宠物状态、审批领养申请。需要区分超级管理员、值班志愿者、普通访客每种角色能看到什么、能操作什么必须有明确边界。第二是数据一致性。领养申请审批通过后宠物状态要同步改为“已领养”如果两步操作不在同一个事务里很容易出现申请通过了、宠物却还是“待领养”的脏数据。第三是审计追溯。删除记录不能物理删除要支持软删除和操作留痕。第四是接口规范。前后端分离之后所有数据交互都以JSON形式走RESTful接口前端拿到的数据格式必须稳定。这个源码并不是那种大而全的中台系统但把以上四点都做了落地。对于一家规模不大的宠物爱心组织来说这套系统足够支撑日常运营对于学习者来说正好能理解企业级项目在工程结构、异常处理、权限模型上的常见做法。2. 技术选型为什么是SpringBoot加Vue加MyBatis加MySQL2.1 后端框架选择后端选择SpringBoot基本不存在争议。它是当前Java后端最主流的快速开发框架内嵌Tomcat简化了Spring配置配合Spring Security或JWT可以很轻松地实现认证授权。项目里用的是SpringBoot 2.x版本这个选择值得说明。Spring Boot 3.x虽然已经推出但要求JDK 17以上并且MyBatis的兼容版本、javax到jakarta的包名迁移都会带来额外适配工作。如果目标是快速稳定运行2.x依然是相对稳妥的选择。实际搭建时要注意版本搭配不要盲目追新。我见过有人直接用Spring Boot 3.1配MyBatis旧版启动时就报ClassNotFoundException: javax.servlet.*这个错误就是包名迁移导致的。后面第6章会把这类问题单独整理出来。2.2 前端Vue 2还是Vue 3前端选型上系统采用Vue框架源码里通常以Vue 2为主这符合大量存量项目的现状。Vue 2生态成熟、教程多Element UI组件库直接可用对一些尚未完全掌握Composition API的开发者更友好。如果你是新手建议先基于Vue 2把项目跑起来熟悉生命周期、路由、Vuex之后再迁移到Vue 3心理负担会小很多。Vue环境的搭建有几个容易卡住的地方Node.js版本不要太老也不要太新建议用LTS版本npm install时如果网络不稳定可以配置国内镜像源vue.config.js里的devServer代理一定要配置否则开发环境请求后端接口会遇到跨域问题。前端和后端本身是两个独立进程联调阶段靠Vue Cli的代理转发请求打包上线后靠Nginx或SpringBoot静态资源目录解决。2.3 ORM与数据库MyBatis加MySQLMyBatis在这个项目里的定位是“半自动ORM”。它不像MyBatis-Plus那样自动生成大部分SQL而是把SQL写在哪、怎么写完全交给开发者。对于宠物组织管理系统这种业务逻辑不复杂、但统计查询较多的项目MyBatis的灵活性非常有价值。比如统计月度捐赠总额、按宠物状态分组统计数量这些SQL不按约定自动生成手写SQL反而更容易控制执行计划。MySQL方面选用8.x版本字符集统一utf8mb4存储引擎用InnoDB。为什么不用5.7?8.0在窗口函数、JSON支持、字符集排序规则上都有改进而且官方对5.7的维护已经停止。不过要注意MySQL 8默认的caching_sha2_password认证插件和旧版连接驱动不兼容使用5.x版本驱动连接时容易报Unable to load authentication plugin caching_sha2_password需要换mysql-connector-java 8.0以上版本或者调整认证插件。2.4 后端工程结构设计一个清晰的工程结构比任何文档都重要。后端源码通常按这样的职责分层com.pet.organization ├── common // 通用返回结果、异常处理、工具类 ├── config // 配置类、拦截器、WebMvc配置 ├── controller // 接口层接收请求、返回结果 ├── service // 业务层处理业务逻辑、事务 ├── mapper // 数据访问层MyBatis的Mapper接口 ├── entity // 数据库实体 ├── dto // 数据传输对象参数校验、返回封装 └── utils // 通用工具如JWT工具前端则按功能模块拆分目录src ├── api // 按模块封装的接口请求 ├── assets // 静态资源 ├── components // 公共组件 ├── router // 路由配置 ├── store // Vuex状态管理 ├── utils // 请求封装、鉴权工具 ├── views // 页面 └── App.vue这种结构的核心好处是每个人的代码放哪里是确定的。新增一个“活动报名”功能后端只需要加controller、service、mapper三层前端加一个api文件和一个views页面不需要改动其他模块的代码。后面接手的人能快速定位问题这是企业级项目最基本的工程素养。3. 核心功能模块实现细节3.1 登录认证与权限控制系统采用JWT做无状态登录认证。用户登录成功后后端生成一个包含用户ID、用户名、角色信息的token前端存储到localStorage每次请求通过Authorization请求头携带。后端设置一个HandlerInterceptor对非白名单接口做token校验。关键实现要点是这样的public class JwtInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { if (request.getMethod().equals(OPTIONS)) { return true; } String token request.getHeader(Authorization); if (token null || !token.startsWith(Bearer )) { throw new BusinessException(401, 未登录或token已过期); } // 解析token校验签名从Redis或数据库加载用户权限 Claims claims JwtUtil.parseToken(token.replace(Bearer , )); request.setAttribute(userId, claims.get(userId)); return true; } }权限控制建议采用RABC模型即用户关联角色角色关联菜单和权限标识。后端在需要权限的接口上加注解比如RequirePermission(pet:audit)切面里判断当前用户是否拥有对应权限标识。前端再配合路由守卫根据用户角色过滤菜单和页面按钮。这样就算前端把隐藏按钮调出来后端接口依然有校验兜底不会出现越权操作。3.2 志愿者与会员档案管理志愿者管理模块沉淀组织最基础的人力信息。字段一般包括姓名、联系方式、职责救助/运输/照料/宣传、可服务时间、紧急联系人、服务次数统计等。管理端支持志愿者入驻审核新志愿者注册后状态为“待审核”管理员审核通过才分配账号权限。审核这块有一个值得注意的业务逻辑志愿者状态变更时对应的账号状态也要同步变更否则会出现人已经从组织退出、账号还能登录的情况。这里必须在同一个事务里更新user表的status和volunteer表的status不能分开提交。我的经验是这类跨表状态同步问题很容易被忽略等到运营两周后才发现离职志愿者的账号还能访问后台排查成本很高。3.3 宠物档案与状态流转宠物档案是本系统最核心的基础数据。每只宠物录入时生成编号关联品种、性别、年龄、毛色、是否绝育、疫苗记录、驱虫记录、所在基地、健康状态、入所时间等字段。更关键的是状态机设计宠物状态至少包括待领养、已申请、已领养、寄养中、医疗中、已离世。状态流转不能随意跳转比如“已领养”不能直接回到“待领养”必须通过撤销领养申请或退回操作实现。最适合的方式是在代码里定义状态流转规则Map而不是到处写if-else避免出现随意修改状态导致的业务混乱。宠物档案通常还涉及图片上传。项目里常见做法是将图片存储到本地磁盘或OSS数据库中存URL。注意图片上传接口一定要限制文件类型和大小不能直接信任前端传的字符串要校验后缀和文件头防止上传恶意文件。3.4 领养申请流程领养模块体现的是审批流思想。申请流程为领养人在小程序或Web端选择宠物填写申请表包含居住情况、养宠经验、经济来源、是否同意回访。后端生成申请记录状态为“待审核”同时将宠物状态置为“已申请”防止多人同时申请同一只宠物。管理员查看申请资料可以执行“通过”或“拒绝”。通过后自动将宠物状态改为“已领养”生成领养协议记录并安排第一次回访日期。这个流程里最需要留意的是并发问题。两个领养人同时点击“申请领养同一只宠物”如果没有做状态控制就会生成两条待审核申请。解决思路是在更新宠物状态的SQL里加状态条件UPDATE pet SET status 已申请 WHERE id #{petId} AND status 待领养如果更新行数为0说明宠物已经被申请直接拒绝第二次请求。3.5 善款、物资与库存管理捐赠管理分为资金和物资两类不能混在一起算。资金流水记录捐赠人、金额、支付方式、捐赠时间、款项用途定向或非定向并支持导出月报表。物资捐赠则要进入库存台账包含物资名称、分类猫粮/狗粮/药品/用品、数量、单位、入库时间、有效期。物资出库时库存扣减操作要考虑“超卖”问题也就是出库数量不能超过现有库存。和领养并发处理类似UPDATE时加库存条件判断同时扣减操作和出库记录写入必须在同一个事务内。3.6 活动与资讯发布活动模块支持线下领养日、义卖、宣讲、募捐等活动的创建和报名。活动信息包含时间、地点、报名截止时间、名额上限、活动状态。志愿者报名后管理员可以确认参与名单活动结束后能登记活动反馈和实际参与人数。资讯公告模块则用于发布领养故事、救助指南、寻主启事等内容。这个模块看起来简单但要注意富文本内容的存储和安全过滤。前端提交的HTML不能直接入库展示要经过内容转义或白名单过滤避免XSS注入。最简单稳妥的方案是使用Markdown编辑器前端渲染时再做过滤处理。3.7 数据看板与统计最后是管理层最关心的数据看板。首页通常用ECharts呈现几个关键指标总宠物数、各状态宠物占比、本月新增领养数、志愿者人数、月度捐赠趋势、库存预警。统计SQL是MyBatis手写SQL的用武之地。比如统计最近6个月捐赠总额SELECT DATE_FORMAT(create_time, %Y-%m) AS month, COALESCE(SUM(amount), 0) AS total_amount FROM donation_record WHERE create_time DATE_SUB(CURDATE(), INTERVAL 6 MONTH) AND pay_status 1 GROUP BY DATE_FORMAT(create_time, %Y-%m) ORDER BY month;注意GROUP BY之前一定要确认ONLY_FULL_GROUP_BY模式的影响。MySQL 5.7之后默认开启ONLY_FULL_GROUP_BYSELECT的字段要么在GROUP BY里要么在聚合函数里写不规范就会直接报错。这类SQL建议提前在Navicat里跑通再放进Mapper文件里面。4. 数据库设计表结构、索引与事务4.1 核心表关系拆解数据库是这个项目的地基。核心表大概有这十张表名说明关键字段sys_user系统用户/登录账号username、password、status、typevolunteer志愿者档案user_id、name、phone、audit_statuspet宠物档案pet_no、name、status、health_status、shelter_idadoption_application领养申请pet_id、applicant_name、audit_statusdonation_record资金捐赠donor_name、amount、pay_method、pay_statusmaterial_stock物资库存material_name、category、stock、unitmaterial_in_out物资出入库记录material_id、type、quantity、operatoractivity活动表title、start_time、sign_up_deadline、statusactivity_signup活动报名表activity_id、volunteer_id、statusarticle资讯文章title、content、author、statussys_role角色表role_name、role_codesys_menu菜单权限表parent_id、name、permission_code表与表之间的关系注意几个点sys_user和volunteer是1对1关联外键用user_id而不是id直连避免两张表主键语义冲突。pet和adoption_application是1对多关系一只宠物可以有多次申请历史但要保证同一时间只能有一条有效申请。activity和activity_signup也是1对多报名表加唯一约束(activity_id, volunteer_id)避免同一个志愿者重复报名。4.2 核心表DDL示例下面给出三张核心表的参考DDL。实际源码里的字段会更多但下面这些结构足够表达核心设计思路CREATE TABLE pet ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT 主键, pet_no VARCHAR(32) NOT NULL COMMENT 宠物编号, name VARCHAR(50) DEFAULT NULL COMMENT 宠物昵称, category TINYINT NOT NULL COMMENT 物种 1猫 2狗, breed VARCHAR(50) DEFAULT NULL COMMENT 品种, gender TINYINT DEFAULT NULL COMMENT 性别 1公 2母, health_status TINYINT DEFAULT 1 COMMENT 健康状态 1健康 2治疗中 3康复, status TINYINT NOT NULL DEFAULT 1 COMMENT 状态 1待领养 2已申请 3已领养 4寄养 5已离世, is_deleted TINYINT NOT NULL DEFAULT 0 COMMENT 软删除 0正常 1删除, shelter_id BIGINT DEFAULT NULL COMMENT 所属基地, adopt_date DATE DEFAULT NULL COMMENT 领养日期, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_pet_no (pet_no), KEY idx_status (status), KEY idx_category (category) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT宠物档案表;CREATE TABLE adoption_application ( id BIGINT NOT NULL AUTO_INCREMENT, application_no VARCHAR(32) NOT NULL, pet_id BIGINT NOT NULL, applicant_name VARCHAR(50) NOT NULL, applicant_phone VARCHAR(20) NOT NULL, has_experience TINYINT DEFAULT 0 COMMENT 有无养宠经验, home_condition VARCHAR(255) DEFAULT NULL COMMENT 居住情况, audit_status TINYINT NOT NULL DEFAULT 1 COMMENT 1待审核 2通过 3拒绝, audit_remark VARCHAR(255) DEFAULT NULL COMMENT 审核意见, audit_time DATETIME DEFAULT NULL, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_application_no (application_no), KEY idx_pet_id (pet_id), KEY idx_audit_status (audit_status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT领养申请表;注意一个细节凡是后续要软删除的表一定要保留is_deleted字段并且所有业务查询都要带上is_deleted 0条件。很多人在查询时漏掉这个条件导致数据明明删了还出现在列表里或者刚删除的记录仍然能被修改。MyBatis里写SQL时最好把删除条件钉死在每条select语句里而不是通过拦截器黑魔法统一处理避免不同Mapper行为不一致。4.3 索引设计的原则这个系统体量不会特别大单表数据可能涨到几十万条索引设计不需要特别复杂但几个原则必须守住第一唯一索引保证业务编号唯一。比如pet_no、application_no、username全部建唯一索引比在代码里判断是否存在再插入要可靠得多数据库层面的约束才是最终防线。第二外键查询字段都要建索引。adoption_application的pet_id、activity_signup的activity_id、material_in_out的material_id这些字段在列表查询、关联查询中高频出现不建索引走全表扫描数据量上去后接口响应时间会迅速恶化。第三状态字段可以建索引但不要建太多组合索引。status字段区分度不高单独建索引不一定能优化查询更有效的方式是用创建时间倒序。比如“最近一个月提交的待审核申请”可以建(audit_status, create_time)组合索引。4.4 事务边界与乐观锁事务设计上几个关键业务必须加上Transactional领养审批通过时更新申请状态 更新宠物状态。物资入库时插入入库记录 更新库存表。活动报名时插入报名记录 更新活动已报名人数。特别注意活动报名的并发问题。如果活动设置了名额上限不能用先查count再判断是否小于上限的方式因为并发请求可能同时查到count等于上限减1然后都执行插入。更稳妥的方式是直接UPDATE活动表同时把计数和名额判断放进WHERE条件UPDATE activity SET signup_count signup_count 1 WHERE id #{activityId} AND signup_count max_count;如果影响行数为0说明名额已满事务回滚并提示用户。这是典型的乐观锁思路比Java代码里的synchronized更可靠因为实际部署往往是多实例synchronized只能锁住单台机器。5. 项目搭建、运行与部署实操5.1 环境准备与版本匹配我按“能跑起来”的标准列一下推荐的本地环境组件推荐版本说明JDK1.8 或 11配Spring Boot 2.x不要用JDK 17直接跑Spring Boot 2Maven3.6建议用IDEA自带或本地安装Node.js14/16 LTSVue 2项目建议Node 14-16Node 18在某些场景会提示OpenSSL错误MySQL8.0字符集utf8mb4IDEIDEA / VSCode后端IDEA前端VSCode均可如果你是WindowsMySQL安装有几个坑先提醒一下安装8.0建议直接下载ZIP包解压配置或者用官方Installer要记住root密码和端口安装完成后如果本地缺少VC运行库服务可能启动失败。初始化数据时直接在Navicat或命令行执行项目里的init.sql脚本一次性建库建表并插入基础数据。5.2 后端启动步骤与配置说明拿到源码后后端工程先改配置再启动。核心配置文件是src/main/resources/application.ymlserver: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/pet_org?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltrue username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.pet.organization.entity configuration: map-underscore-to-camel-case: true这里最关键的是serverTimezone如果不加MySQL 8和JDBC驱动之间会报时区错误。allowPublicKeyRetrievaltrue也是MySQL 8连接时常见的坑不加可能会报Public Key Retrieval is not allowed。启动前先执行mvn clean install下载依赖然后用mvn spring-boot:run或IDEA直接跑Application类。如果端口被占用可以在配置里换端口也可以命令行找到占用进程干掉。5.3 前端安装与开发调试前端拿到源码后先进目录执行npm install npm run serve正常情况会自动打开localhost:8081这样的端口。开发环境下前端需要用代理解决跨域在vue.config.js里配置module.exports { devServer: { port: 8081, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }这样前端请求/api/user/login就会自动转发到后端8080端口不会出现跨域报错。如果你发现登录接口200了但数据不对多半是代理路径没有匹配上先看Network请求的实际URL。5.4 Vue打包产物放进SpringBoot这个操作是很多入门开发者问得最多的点。Vue开发完执行npm run build会生成一个dist目录。后端开发阶段不一定要把它塞进SpringBoot部署服务器时再合并更合理。合并步骤将dist目录下的所有文件复制到后端工程的src/main/resources/static目录。重新打包后端mvn clean package -DskipTests。运行生成的jar包访问http://ip:8080前端页面和后端接口就都在同一个端口了。这里有三个坑必须说明。第一Vue的router如果使用history模式刷新页面会404因为SpringBoot静态资源没有对应的路径映射需要配置资源映射或把路由模式改成hash模式。项目源码里如果用的是history路由建议在开发阶段就确认刷新是否正常。第二清理旧静态资源每次重新build后static目录下可能有残留文件建议先删除static目录再复制。第三SpringBoot默认静态资源路径优先级是classpath:/static/不要把dist放错位置。5.5 服务器部署与进程守护生产环境部署最简单的方案是单机jar包直接跑nohup java -jar pet-org-system.jar --spring.profiles.activeprod app.log 21 nohup方式不提供自动重启和进程守护更规范的做法是使用systemd配置服务[Unit] DescriptionPet Org System Afternetwork.target [Service] Userwww WorkingDirectory/opt/pet-org ExecStart/usr/bin/java -jar /opt/pet-org/pet-org-system.jar Restartalways RestartSec10 [Install] WantedBymulti-user.target如果静态资源量比较大或者未来要配HTTPS、做负载均衡可以在前面加一层Nginx把/api请求代理到8080其余路径直接serve静态文件。但前期只是内部使用一个jar包加systemd已经绰绰有余。6. 常见问题与排查技巧实录6.1 启动与环境问题现象原因解决办法SpringBoot启动后自动退出端口被占用或数据库连接失败看启动日志先解决端口冲突和数据库配置启动报ClassNotFoundException: javax.servlet.*Spring Boot 3配了旧版MyBatis换Spring Boot 2.x或升级MyBatis相关依赖前端npm install报ERR_OSSL_EVP_UNSUPPORTEDNode版本过高导致OpenSSL问题换Node 14/16或在启动脚本里加NODE_OPTIONS--openssl-legacy-providerMySQL连接失败Server returns invalid timezone时区没有配置JDBC URL加serverTimezoneAsia/Shanghai6.2 数据库与MyBatis问题问题一Mapper里的SQL报字段找不到。SQL报Unknown column通常是实体字段和数据库字段映射不上。如果配置了map-underscore-to-camel-case: true实体字段要写成createTime对应数据库create_time。如果命名不一致要么改实体要么在SQL里写别名。问题二如何打印MyBatis执行的SQL。排查慢查询时需要看到实际执行的SQL和参数。在application.yml里配置mybatis: configuration: log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl同时把对应Mapper的日志级别调成debuglogging: level: com.pet.organization.mapper: debug问题三二级缓存导致数据不刷新。项目里如果开启了MyBatis二级缓存表数据变更后查询结果可能还是旧的。排查方法是先确认CacheNamespace是不是在Mapper上然后区分场景热点数据、变更频繁的数据不要开二级缓存统计数据更不建议缓存。MyBatis二级缓存默认是粗粒度的容易出现SQL查询缓存了相关联的插入更新却没有清缓存的情况。最稳妥的方案是减少不必要的缓存把缓存控制交给Redis。6.3 前端联调与部署问题问题一登录接口正常但后续请求401。排查一下前端请求拦截器是否正确携带token。很多项目把token存localStorage但请求拦截器里读取的key拼写不一致或者请求头名称和后端拦截器校验的不一样。统一一个auth工具类管理token的存取避免散落各处。问题二Vue打包部署后白屏。先看浏览器控制台。如果静态资源路径是绝对路径/js/app.js但项目部署在子路径下资源就找不到。解决方法是修改vue.config.js里的publicPath为./再重新build。另外白屏也可能是路由模式导致刷新404前面已经提到要结合路由方式和资源映射一起检查。问题三跨域问题。很多人分不清开发环境和生产环境的跨域。开发环境用devServer代理生产环境如果前后端不在同一域名下后端要配置CorsFilter并且注意allowedOrigins不要用*和allowCredentials同时开启浏览器会直接拒绝这种组合。更推荐的做法是生产环境直接用同端口部署彻底绕开跨域。6.4 业务逻辑问题比较典型的业务bug是领养申请重复提交。如果前端没有按钮禁用后端也没有唯一性校验同一个人可以给同一只宠物提交多次申请。解决办法有两种后端在adoption_application表加上(pet_id, applicant_phone, audit_status)的唯一索引限定同一宠物同一个申请人只能有一条待审核记录或者在后端接口里先查有效申请是否存在。两种一起做更好数据库兜底代码给友好提示。另一个常见问题是删除基地或者宠物时关联数据没处理。系统里如果要删除某只宠物但它还有领养申请记录直接物理删除会导致历史数据缺失。正确的做法是先检查关联数据如果有申请记录要么不允许删除要么改为软删除并且把申请记录也一并软删除保证界面列表和历史查询都不出现“死链”。6.5 几条非常有用的排查命令作为运维习惯我实际排查问题时会快速用这几条命令定位# 看端口占用 ss -lntp | grep 8080 # 看Java进程 ps -ef | grep java # 实时看日志 tail -f app.log # 接口是否通 curl -X POST http://localhost:8080/api/user/login -H Content-Type: application/json -d {username:admin,password:123456}遇到接口报错先curl一把能区分是后端问题还是前端问题。如果curl正常那就是前端参数或代理问题如果curl返回5xx再去看应用日志和SQL日志。这个排查顺序能省下大量时间。项目整体拆完之后我自己最大的体会是这种业务系统真正难的不是某个技术点而是状态流转和数据一致性。宠物状态、领养申请状态、志愿者审核状态、物资库存每条线都有自己的状态机状态之间还有联动。写代码之前把状态机画清楚比急着建表、写接口重要得多。我建议拿到源码后不要先跑起来就完事而是花半小时看数据库表和service层的事务注解把几条核心链路走一遍比如从录入宠物到领养成功、从物资入库到出库登记你会对整个系统的设计意图理解得更透彻。如果后续你自己要扩展功能比如增加回访记录模块或者对接微信公众号这套前后端分离的结构也不会拖后腿。
RELATED

相关推荐

SharePoint Online文档库还原实战:回收站、版本历史与文件恢复全解析

SharePoint Online文档库还原实战:回收站、版本历史与文件恢复全解析

做SharePoint Online运维这些年,被问得最多的就是文档库的还原功能——“文件不小心删了能找回来吗”“整个文档库不见了还有救吗”“版本被覆盖了能不能倒回去”。我上周刚处理过一起真实事故:客户财务部共用的合同库整个消失,4万多份PDF全部…

📅 2026/10/8 10:11:15
大厂Offer通关攻略:从投递到谈薪的硬核复盘

大厂Offer通关攻略:从投递到谈薪的硬核复盘

去年秋天,西安的雨下个不停。我坐在实验室电脑前,第无数次刷新招聘官网的投递状态页——“流程终止”四个字刺眼地亮在那里。那是我投出的第11份简历,目标岗位是后端开发。老实说,那一刻我挺慌的:西电的牌子不差&#…

📅 2026/10/8 10:11:15
AI应用从演示到上线:跨越工程化鸿沟的落地实践

AI应用从演示到上线:跨越工程化鸿沟的落地实践

1. 从一句吐槽说起:演示与上线之间的鸿沟 “AI演示过了,上线照样卡半年”——这句话我第一次听到是在一个技术群里,有人发了张截图,某团队用大模型做了个智能客服的Demo,演示当天效果惊艳,老板当场拍板“下…

📅 2026/10/8 10:11:15
MORE NEWS

更多资讯

📰

基于BERT的IMDB情感分析:从微调到部署的完整实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

龙虾服务实战:从对话到执行,AI如何真正动手干活

1. 从“能聊天”到“能干活”:龙虾服务到底在解决什么问题大多数人第一次接触AI助手,体验都差不多:问它一个问题,它给你一段回答,看起来挺聪明,但关掉对话框之后,该干的活还是得自己干。写周报要…

📰

MiniMax M3.1-Flash-Preview实测:首字响应280ms与动态慢思考的编程体验

最近MCode上冷不丁冒出来一个MiniMax M3.1-Flash-Preview,我盯着"首字响应低至280ms"看了半天,又看到"动态慢思考"这个新词,第一反应是:这又是什么营销话术?但翻了下定价和参数,又跟了…

📰

OpenClaw自托管AI助手:Gateway路由与Agent部署实战指南

1. 为什么“自托管 AI 助手”突然成了刚需1.1 从“租用智能”到“拥有智能”的转折点过去两年,绝大多数人用 AI 的方式其实很单一:打开某个网页,输入问题,等回复,关掉。整个过程里,你的对话记录、你的文件、…

📰

轻量级AI信息流自动化系统设计与实践

1. 项目概述:这不是一份新闻简报,而是一套可复用的AI信息流自动化系统 “AI 日报(2026年9月29日)”——看到这个标题,第一反应可能是:又一份AI生成的热点汇总?但作为连续三年搭建、维护、迭代过…

📰

从纯Chat到终端Agent:Claude Code与Hermes Agent如何重塑编码工作流

一个很典型的现象:现在讨论 Coding Agent,话题基本都集中在 Claude Code、Codex、Gemini CLI 这类命令行工具上,反而很少有人再吹"用 ChatGPT 网页聊着天把代码写完"了。我自己从去年开始把大量开发工作迁到终端 Agent,…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬