1. 项目背景与核心需求
宠物驯养行业近年来呈现爆发式增长,根据2023年宠物行业白皮书数据显示,中国城镇宠物(犬猫)消费市场规模达到2490亿元,其中宠物训练服务占比约8.3%。但市场上专业的线上驯养服务平台仍存在以下痛点:
- 信息不对称:传统线下训练机构服务价格不透明,用户难以横向对比
- 地域限制:优质驯养师资源集中在一线城市,二三线城市用户获取困难
- 缺乏系统性:现有平台多侧重宠物用品销售,驯养知识呈现碎片化
本项目采用Spring Boot+Vue全栈技术架构,旨在构建一个集课程预约、在线咨询、训练日志管理于一体的专业平台。核心解决三个业务场景:
- 驯养师可展示资质案例,管理课程排期
- 宠物主能根据LBS定位筛选附近服务
- 双方通过站内IM系统实时沟通训练进展
技术选型思考:Spring Boot的快速开发特性适合业务多变的初创项目,Vue的组件化开发能高效实现复杂交互界面,两者通过RESTful API解耦,便于后期扩展移动端。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构设计
2.1 后端Spring Boot实现方案
采用经典三层架构,关键包结构如下:
code复制com.pet.training
├── config # 安全/JPA等配置
├── controller # 暴露API接口
├── service # 业务逻辑层
├── repository # 数据持久层
├── entity # 数据库实体
└── util # 工具类
数据库设计遵循第三范式,核心表包括:
trainer(驯养师信息表)course(训练课程表)order(预约订单表)training_log(训练日志表)
使用JPA+Hibernate实现ORM映射,典型实体类配置示例:
java复制@Entity
@Table(name = "course")
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "trainer_id")
private Trainer trainer;
@Enumerated(EnumType.STRING)
private CourseLevel level;
@Column(precision=10, scale=2)
private BigDecimal price;
// getters/setters...
}
2.2 前端Vue实现方案
采用Vue 3组合式API开发,项目结构:
code复制src/
├── api/ # 接口封装
├── assets/ # 静态资源
├── components/ # 公共组件
├── router/ # 路由配置
├── stores/ # Pinia状态管理
├── views/ # 页面组件
└── utils/ # 工具函数
典型页面组件开发模式:
vue复制<script setup>
import { ref } from 'vue'
import { useGeoStore } from '@/stores/geo'
const geoStore = useGeoStore()
const trainers = ref([])
const loadNearbyTrainers = async () => {
const { lng, lat } = geoStore.currentPosition
trainers.value = await api.getTrainers({ lng, lat })
}
</script>
<template>
<div class="map-container">
<TrainerCard
v-for="t in trainers"
:key="t.id"
:trainer="t"
/>
</div>
</template>
3. 核心功能实现细节
3.1 预约系统实现
采用状态机模式管理订单生命周期:
mermaid复制stateDiagram
[*] --> PENDING
PENDING --> CONFIRMED: 驯养师确认
PENDING --> CANCELLED: 用户取消
CONFIRMED --> COMPLETED: 完成训练
CONFIRMED --> CANCELLED: 协商取消
对应Spring Boot中的状态转换逻辑:
java复制@Transactional
public Order confirmOrder(Long orderId) {
Order order = orderRepo.findById(orderId)
.orElseThrow(EntityNotFoundException::new);
if (order.getStatus() != OrderStatus.PENDING) {
throw new IllegalStateException("只有待确认订单可操作");
}
order.setStatus(OrderStatus.CONFIRMED);
order.setConfirmTime(LocalDateTime.now());
return orderRepo.save(order);
}
3.2 即时通讯模块
基于WebSocket实现实时对话,关键设计点:
- 使用STOMP子协议处理消息路由
- 消息表设计添加
is_read标记位 - 前端采用消息队列防抖策略
后端配置示例:
java复制@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/queue");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat")
.setAllowedOriginPatterns("*")
.withSockJS();
}
}
前端连接处理:
javascript复制const socket = new SockJS('/chat-endpoint')
const stompClient = Stomp.over(socket)
stompClient.connect({}, () => {
stompClient.subscribe('/user/queue/messages', (message) => {
store.addMessage(JSON.parse(message.body))
})
})
4. 性能优化实践
4.1 数据库查询优化
- N+1查询问题解决:
java复制// 错误做法:会触发多次查询
List<Course> courses = courseRepo.findAll();
courses.forEach(c -> System.out.println(c.getTrainer().getName()));
// 正确方案:使用JOIN FETCH
@Query("SELECT c FROM Course c JOIN FETCH c.trainer")
List<Course> findAllWithTrainer();
- 添加复合索引:
sql复制ALTER TABLE training_log
ADD INDEX idx_trainer_date (trainer_id, training_date);
4.2 前端性能提升
- 图片懒加载实现:
vue复制<template>
<img
v-for="img in images"
:data-src="img.url"
class="lazyload"
>
</template>
<script>
import { useIntersectionObserver } from '@vueuse/core'
onMounted(() => {
const images = document.querySelectorAll('.lazyload')
images.forEach(img => {
useIntersectionObserver(img, ([{ isIntersecting }]) => {
if (isIntersecting) {
img.src = img.dataset.src
}
})
})
})
</script>
- API请求防抖处理:
javascript复制import { debounce } from 'lodash-es'
const searchTrainers = debounce(async (keywords) => {
const res = await api.search({ keywords })
trainers.value = res.data
}, 300)
5. 安全防护措施
5.1 认证与授权
采用JWT+Spring Security方案,关键配置:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/trainer/**").hasRole("TRAINER")
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
return http.build();
}
}
5.2 敏感数据保护
- 密码加密存储:
java复制@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// 使用示例
User user = new User();
user.setPassword(passwordEncoder.encode(rawPassword));
- 日志脱敏处理:
java复制@Aspect
@Component
public class LogMaskAspect {
@Around("execution(* com.pet.training.controller..*(..))")
public Object maskSensitiveData(ProceedingJoinPoint pjp) throws Throwable {
Object[] args = pjp.getArgs();
// 对参数进行脱敏处理
return pjp.proceed(args);
}
}
6. 部署与监控
6.1 Docker化部署
后端Dockerfile示例:
dockerfile复制FROM openjdk:17-jdk-alpine
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
使用docker-compose编排:
yaml复制version: '3'
services:
app:
build: .
ports:
- "8080:8080"
depends_on:
- db
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: pet@123
MYSQL_DATABASE: pet_training
6.2 Prometheus监控
Spring Boot Actuator配置:
yaml复制management:
endpoints:
web:
exposure:
include: health,metrics,prometheus
metrics:
tags:
application: pet-training
对应的Grafana监控面板应包含:
- JVM内存使用率
- 数据库连接池状态
- HTTP请求成功率
- 系统CPU/内存负载
7. 典型问题解决方案
7.1 文件上传限制
Spring Boot默认文件上传限制为1MB,需要调整配置:
yaml复制spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
前端需做双重验证:
vue复制<script setup>
const beforeUpload = (file) => {
const isLt10M = file.size / 1024 / 1024 < 10
if (!isLt10M) {
ElMessage.error('文件大小不能超过10MB!')
return false
}
return true
}
</script>
7.2 跨域问题处理
全局CORS配置:
java复制@Bean
WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("https://yourdomain.com")
.allowedMethods("*")
.maxAge(3600);
}
};
}
开发环境可添加临时配置:
java复制@Profile("dev")
@Configuration
public class DevCorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("*")
.allowedOrigins("*");
}
}
8. 项目演进方向
- 智能化扩展:
- 集成CV算法实现宠物行为分析
- 训练方案个性化推荐引擎
- 生态化建设:
- 对接宠物医院HIS系统
- 开发驯养师端APP
- 技术架构升级:
- 引入Kafka处理高并发预约
- 用Elasticsearch实现智能搜索
实际开发中我们发现,驯养师资质验证模块需要特别加强。我们最终采用了第三方认证服务+人工复核的双重机制,通过定时任务每天同步最新资质信息到本地数据库,同时在用户端展示明显的认证标识。这个设计比初期方案减少了70%的投诉量。
