1. 项目背景与核心价值
作为一名同时具备Java后端和Vue前端开发经验的程序员,我最近完成了一个宠物管理系统的全栈项目。这个系统最初是为本地一家连锁宠物医院设计的,旨在解决他们手工登记宠物信息效率低下、客户档案混乱的问题。经过三个月的开发和迭代,系统已经稳定运行半年,日均处理300+次宠物信息更新操作。
现代宠物服务行业正面临数字化转型的关键时期。根据我接触的客户反馈,传统宠物店使用纸质档案或Excel表格管理存在四大痛点:信息易丢失、历史记录难追溯、服务响应慢、数据分析能力弱。而一个专业的宠物管理系统能够实现:
- 宠物档案电子化存储(包括品种、年龄、疫苗记录等核心数据)
- 服务预约与提醒自动化
- 多角色协同工作(店主、兽医、美容师等)
- 经营数据可视化分析
2. 技术架构设计解析
2.1 整体技术选型
系统采用经典的前后端分离架构:
code复制前端:Vue 3 + Element Plus + Axios
后端:Spring Boot 2.7 + MyBatis-Plus + MySQL 8.0
辅助工具:Redis缓存 + 阿里云OSS存储
选择这套技术栈主要基于以下考量:
- 开发效率:Vue+Element组合能快速构建管理后台界面,Spring Boot提供了完善的业务开发脚手架
- 性能平衡:MyBatis-Plus在简化DAO层代码的同时,仍保持灵活的SQL控制能力
- 扩展性:前后端分离架构便于后续App端或小程序端的接入
2.2 数据库设计要点
宠物系统的核心在于数据关系的设计。经过多次优化,最终确定的ER图包含12张主表,这里展示最关键的4张表结构:
| 表名 | 字段示例 | 设计说明 |
|---|---|---|
| pet_info | id, name, type_id, owner_id, birth_date, chip_number | 芯片号建立唯一索引 |
| pet_medical | id, pet_id, vaccine_records, allergy_info, last_checkup | 采用JSON存储动态医疗数据 |
| sys_user | id, username, role_id, clinic_id, avatar | 角色分离诊所管理员和普通员工 |
| service_order | id, pet_id, service_type, start_time, handler_id | 记录服务全过程 |
特别注意:宠物医疗记录采用JSON字段存储,这是为了适应不同宠物医院对医疗字段的个性化需求。虽然违反了第一范式,但实际查询时配合MySQL的JSON函数,仍能保证查询效率。
3. 核心功能实现细节
3.1 宠物档案管理模块
前端采用树形+表格混合布局:
vue复制<template>
<el-container>
<el-aside width="200px">
<el-tree :data="petTypeTree" @node-click="handleNodeClick"/>
</elaside>
<el-main>
<el-table :data="petList">
<el-table-column prop="name" label="宠物名"/>
<el-table-column label="主人">
<template #default="{row}">
{{ row.owner.name }} ({{ row.owner.phone }})
</template>
</el-table-column>
</el-table>
</el-main>
</el-container>
</template>
后端实现的关键点在于关联查询优化:
java复制// PetController.java
@GetMapping("/list")
public R list(PetQuery query) {
// 使用MyBatis-Plus的LambdaQueryWrapper构建查询
LambdaQueryWrapper<Pet> wrapper = Wrappers.lambdaQuery();
wrapper.eq(query.getTypeId() != null, Pet::getTypeId, query.getTypeId())
.like(StringUtils.isNotBlank(query.getName()), Pet::getName, query.getName())
.orderByDesc(Pet::getCreateTime);
// 使用自定义SQL实现关联查询
Page<PetVO> page = petService.selectPetWithOwner(new Page<>(query.getPage(), query.getSize()), wrapper);
return R.ok().data(page);
}
3.2 预约服务日历组件
采用FullCalendar进行二次开发:
javascript复制// 在vue组件中初始化日历
initCalendar() {
this.calendar = new Calendar(this.$refs.calendar, {
plugins: [dayGridPlugin, interactionPlugin],
initialView: 'dayGridMonth',
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek'
},
dateClick: this.handleDateClick,
eventClick: this.handleEventClick
});
this.loadAppointments();
}
后端接口需要注意并发控制:
java复制@Transactional
public boolean createAppointment(AppointmentDTO dto) {
// 检查时间冲突
Integer count = baseMapper.selectConflictCount(
dto.getClinicId(),
dto.getStaffId(),
dto.getStartTime(),
dto.getEndTime());
if (count > 0) {
throw new BusinessException("该时段已有预约");
}
// 创建预约记录
Appointment entity = new Appointment();
BeanUtils.copyProperties(dto, entity);
return save(entity);
}
4. 典型问题与解决方案
4.1 宠物图片上传优化
初期直接使用Base64编码存储导致接口响应缓慢,优化方案:
- 前端改用分片上传
- 后端集成阿里云OSS直传
- 数据库只存储OSS文件路径
关键代码:
java复制// OSS策略配置
@Bean
public OSS ossClient() {
return new OSSClientBuilder().build(
endpoint,
accessKeyId,
accessKeySecret);
}
// 生成签名URL
public String getUploadSignature(String dir) {
PolicyConditions policy = new PolicyConditions();
policy.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 10485760);
policy.addConditionItem(PolicyConditions.COND_KEY, PolicyConditions.STARTS_WITH, dir);
String postPolicy = ossClient.generatePostPolicy(expiration, policy);
return ossClient.calculatePostSignature(postPolicy);
}
4.2 疫苗提醒定时任务
使用Quartz实现动态提醒:
java复制public class VaccineReminderJob implements Job {
@Override
public void execute(JobExecutionContext context) {
List<PetVaccine> vaccines = vaccineMapper.selectNeedRemind();
vaccines.forEach(vaccine -> {
String content = String.format(
"%s的宠物%s需要接种%s疫苗了",
vaccine.getPet().getOwner().getName(),
vaccine.getPet().getName(),
vaccine.getVaccineType());
// 发送短信和站内信
messageService.sendSms(vaccine.getPet().getOwner().getPhone(), content);
messageService.sendNotice(vaccine.getPet().getOwner().getId(), content);
});
}
}
配置cron表达式实现灵活调度:
properties复制# application.properties
reminder.cron=0 0 9 * * ? # 每天上午9点执行
5. 部署与性能优化
5.1 生产环境部署方案
推荐使用Docker Compose编排服务:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: pet@1234
volumes:
- ./mysql/data:/var/lib/mysql
redis:
image: redis:6-alpine
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
- redis
frontend:
build: ./frontend
ports:
- "80:80"
5.2 性能监控配置
集成Spring Boot Actuator和Prometheus:
java复制// 安全配置中暴露监控端点
@Configuration
public class ActuatorConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/actuator/health").permitAll()
.antMatchers("/actuator/prometheus").hasRole("ADMIN")
.anyRequest().authenticated();
}
}
前端性能监控使用Sentry:
javascript复制// main.js
import * as Sentry from '@sentry/vue';
import { Integrations } from '@sentry/tracing';
Sentry.init({
dsn: 'your_dsn',
integrations: [new Integrations.BrowserTracing()],
tracesSampleRate: 0.2
});
6. 项目演进方向
在实际运营过程中,我们发现系统还可以在以下方面进行增强:
- 智能推荐引擎:基于宠物品种、年龄和既往病史,推荐合适的护理方案
- IoT设备集成:连接智能喂食器、摄像头等设备,实现远程宠物监护
- 区块链应用:将重要的医疗记录上链,确保数据不可篡改
一个让我印象深刻的优化案例:某宠物连锁机构接入系统后,客户预约效率提升了60%,通过数据分析发现周末下午3点是洗澡服务的高峰期,于是调整了人员排班,单店月营收增加了15%。这种实实在在的价值体现,正是我们开发者最大的成就感来源。