1. 项目背景与需求分析
作为一名养宠人士,我深知宠物主人在出差或旅行时面临的困扰。去年我出差一周,不得不将猫咪寄养在宠物店,结果接回家后它整整三天不吃不喝,让我心疼不已。正是这次经历促使我开发了这套同城上门喂遛宠物系统。
传统宠物寄养存在几个痛点:
- 环境陌生导致宠物应激反应
- 集中寄养容易交叉感染
- 费用高昂(日均100-200元)
- 无法实时了解宠物状况
我们的系统通过线上平台连接宠物主人和服务提供者,提供以下核心价值:
- 宠物可留在家中,减少环境变化带来的压力
- 一对一服务降低疾病传播风险
- 价格比传统寄养低30%-50%
- 服务过程可拍照打卡,主人随时查看
2. 技术架构设计
2.1 整体架构方案
采用前后端分离架构,这是经过多次迭代验证的最优方案。早期版本尝试过JSP+Servlet的传统模式,但面临三个问题:
- 前端页面渲染性能差
- 前后端开发耦合度高
- 移动端适配困难
最终架构如下:
code复制前端:Vue3 + Element Plus + Axios
后端:SpringBoot 2.7 + MyBatis-Plus 3.5
数据库:MySQL 8.0
中间件:Redis 6.2
地图服务:高德地图API
2.2 关键技术选型
Vue3选择理由:
- Composition API更适合复杂业务逻辑
- 更好的TypeScript支持
- 体积比Vue2小40%
- 实测渲染速度快1.5倍
SpringBoot优势:
- 自动配置省去大量XML配置
- 内嵌Tomcat简化部署
- Starter依赖一键集成常用组件
- 与MyBatis无缝整合
提示:MyBatis-Plus比原生MyBatis开发效率提升60%以上,特别适合快速迭代项目
3. 核心功能实现
3.1 基于地理位置的智能匹配
这是系统的核心技术难点,我们采用三级匹配策略:
- 初级筛选(数据库实现):
sql复制SELECT * FROM service_provider
WHERE
ST_Distance_Sphere(
point(#{lng}, #{lat}),
point(longitude, latitude)
) < #{radius}
- 精准排序(Java实现):
java复制List<ProviderVO> sortByDistance(List<Provider> providers, double userLng, double userLat) {
return providers.stream()
.map(p -> {
double distance = GeoUtils.calculateDistance(
userLng, userLat,
p.getLongitude(), p.getLatitude());
p.setDistance(distance);
return p;
})
.sorted(Comparator.comparingDouble(Provider::getDistance))
.collect(Collectors.toList());
}
- 推荐优化(Redis缓存):
- 使用ZSET存储服务者评分
- 每周定时任务更新排行榜
- 优先展示评分前20%的服务者
3.2 订单状态机设计
订单状态流转是业务核心,我们采用状态模式实现:
java复制public interface OrderState {
void handle(OrderContext context);
}
// 具体状态实现
public class PendingState implements OrderState {
@Override
public void handle(OrderContext context) {
// 待接单状态逻辑
if (context.getEvent() == OrderEvent.ACCEPT) {
context.setState(new OngoingState());
// 发送通知等操作
}
}
}
// 状态上下文
public class OrderContext {
private OrderState state;
public void process() {
state.handle(this);
}
}
状态转换图:
code复制待接单 --接单--> 进行中
进行中 --完成--> 已完成
进行中 --取消--> 已取消
4. 安全与性能优化
4.1 JWT认证方案
采用双Token机制提升安全性:
- AccessToken(有效期2小时)
- RefreshToken(有效期7天)
关键实现代码:
java复制public String generateToken(UserDetails user) {
Map<String, Object> claims = new HashMap<>();
claims.put("userId", user.getId());
claims.put("role", user.getRole());
return Jwts.builder()
.setClaims(claims)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 3600000))
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
4.2 Redis缓存策略
采用多级缓存方案:
- 一级缓存:本地Caffeine(超时5分钟)
- 二级缓存:Redis集群(超时30分钟)
- 数据库:最终数据源
缓存穿透解决方案:
java复制public PetInfo getPetInfo(Long id) {
// 1. 查本地缓存
PetInfo info = localCache.get(id);
if (info != null) return info;
// 2. 查Redis
String key = "pet:" + id;
info = redisTemplate.opsForValue().get(key);
if (info != null) {
localCache.put(id, info);
return info;
}
// 3. 查数据库
info = petMapper.selectById(id);
if (info == null) {
// 防穿透:缓存空值5分钟
redisTemplate.opsForValue().set(key, null, 5, TimeUnit.MINUTES);
} else {
redisTemplate.opsForValue().set(key, info, 30, TimeUnit.MINUTES);
localCache.put(id, info);
}
return info;
}
5. 数据库设计与优化
5.1 核心表结构
用户表优化方案:
- 将大字段(如avatar_url)拆分到单独表
- 建立复合索引:(user_account, user_type)
- 使用雪花算法生成user_id
sql复制CREATE TABLE `user` (
`user_id` bigint NOT NULL COMMENT '雪花ID',
`user_account` varchar(32) NOT NULL,
`user_pwd` varchar(64) NOT NULL,
`user_type` tinyint NOT NULL DEFAULT '1',
`nickname` varchar(20) DEFAULT NULL,
`register_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`user_id`),
UNIQUE KEY `idx_account_type` (`user_account`,`user_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
5.2 查询性能优化
订单分页查询优化:
java复制public Page<OrderVO> queryOrders(Long userId, int page, int size) {
Page<Order> pageInfo = new Page<>(page, size);
orderMapper.selectPage(pageInfo,
new LambdaQueryWrapper<Order>()
.eq(Order::getPetOwnerId, userId)
.orderByDesc(Order::getCreateTime));
// 转换VO时批量查询关联数据
List<Long> providerIds = pageInfo.getRecords().stream()
.map(Order::getServiceProviderId)
.filter(Objects::nonNull)
.collect(Collectors.toList());
Map<Long, User> providerMap = userService.batchGetUsers(providerIds)
.stream()
.collect(Collectors.toMap(User::getUserId, u -> u));
return pageInfo.convert(order -> {
OrderVO vo = new OrderVO();
BeanUtils.copyProperties(order, vo);
vo.setProvider(providerMap.get(order.getServiceProviderId()));
return vo;
});
}
6. 部署与运维实践
6.1 容器化部署方案
采用Docker Compose编排服务:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- ./mysql/data:/var/lib/mysql
- ./mysql/conf:/etc/mysql/conf.d
redis:
image: redis:6.2
ports:
- "6379:6379"
volumes:
- ./redis/data:/data
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
- redis
frontend:
build: ./frontend
ports:
- "80:80"
6.2 性能监控配置
使用Spring Boot Actuator + Prometheus + Grafana:
- 添加依赖:
xml复制<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
- 配置application.yml:
yaml复制management:
endpoints:
web:
exposure:
include: health,metrics,prometheus
metrics:
tags:
application: pet-service
7. 常见问题解决方案
7.1 跨域问题处理
前端开发中最常遇到的问题,解决方案:
后端配置:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.maxAge(3600);
}
}
前端axios配置:
javascript复制const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
timeout: 10000,
withCredentials: true
})
7.2 文件上传大小限制
SpringBoot默认限制1MB文件上传,需要调整:
yaml复制spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 20MB
前端分片上传示例:
javascript复制async function chunkUpload(file) {
const chunkSize = 2 * 1024 * 1024 // 2MB
const chunks = Math.ceil(file.size / chunkSize)
for (let i = 0; i < chunks; i++) {
const start = i * chunkSize
const end = Math.min(file.size, start + chunkSize)
const chunk = file.slice(start, end)
const formData = new FormData()
formData.append('file', chunk)
formData.append('chunkNumber', i)
formData.append('totalChunks', chunks)
await uploadChunk(formData)
}
}
8. 项目扩展方向
在实际运营过程中,我们发现几个有价值的扩展点:
- 宠物健康档案:
- 记录体重、饮食、排便等数据
- 生成健康趋势图表
- 异常情况预警
- 智能硬件对接:
- 智能喂食器远程控制
- 宠物摄像头实时监控
- 智能项圈定位追踪
- 服务者培训体系:
- 在线培训课程
- 资格认证考试
- 分级服务体系
这个项目从最初版本到现在已经迭代了12次,最大的体会是:技术方案要随着业务发展不断进化。比如最初使用简单的主从复制MySQL,当用户量突破10万后不得不改为分库分表。建议开发者在架构设计时预留20%的扩展空间。