1. 项目概述与背景
这个摄影跟拍预约系统是一个典型的B/S架构毕业设计项目,采用前后端分离的开发模式。前端使用Vue.js框架构建用户界面,后端基于SpringBoot框架提供RESTful API服务。系统主要解决摄影师与客户之间的线上预约难题,实现了从浏览作品、预约下单到订单管理的全流程数字化。
我在实际开发中发现,这类系统有三个核心痛点:首先是时间冲突检测,需要精准处理摄影师的档期安排;其次是作品展示需要兼顾美观与性能;最后是支付环节的安全性与可靠性。这个项目通过合理的架构设计,较好地解决了这些问题。
2. 技术栈选型分析
2.1 后端技术栈
SpringBoot 2.7.x作为基础框架,主要基于以下考虑:
- 自动配置特性大幅减少了XML配置
- 内嵌Tomcat服务器简化部署流程
- Starter依赖管理让组件集成更便捷
- 与MyBatis-Plus的完美兼容性
数据库选用MySQL 8.0,主要优势在于:
- JSON字段支持便于存储作品集等半结构化数据
- 窗口函数简化了预约时间冲突的SQL查询
- 事务隔离级别可配置性强
2.2 前端技术栈
Vue 3.x + Element Plus的组合提供了:
- 响应式数据绑定简化状态管理
- 组件化开发提升代码复用率
- TypeScript支持增强类型安全
- 丰富的UI组件加速界面开发
特别值得一提的是使用了Vue Router的懒加载功能:
javascript复制{
path: '/portfolio',
component: () => import('../views/Portfolio.vue'),
meta: { requiresAuth: true }
}
这种动态导入方式显著提升了首屏加载速度。
3. 核心功能实现
3.1 预约时间冲突检测
后端采用重叠区间算法检测档期冲突:
java复制@Select("SELECT * FROM schedule WHERE photographer_id = #{photographerId} " +
"AND NOT (end_time <= #{startTime} OR start_time >= #{endTime})")
List<Schedule> findConflicts(@Param("photographerId") Long photographerId,
@Param("startTime") LocalDateTime startTime,
@Param("endTime") LocalDateTime endTime);
前端配合使用FullCalendar组件实现可视化时间选择:
javascript复制calendarOptions: {
selectOverlap: false,
selectConstraint: {
start: '08:00',
end: '20:00',
daysOfWeek: [1,2,3,4,5]
}
}
3.2 作品集展示优化
采用以下技术方案提升展示效果:
- 图片懒加载:Intersection Observer API
- 渐进式加载:先显示缩略图再加载原图
- CDN加速:七牛云对象存储
- WebP格式:比JPEG节省30%体积
3.3 支付系统集成
支付宝沙箱环境集成步骤:
- 配置AlipayClient bean
java复制@Bean
public AlipayClient alipayClient() {
return new DefaultAlipayClient(
"https://openapi.alipaydev.com/gateway.do",
APP_ID,
APP_PRIVATE_KEY,
"json",
"UTF-8",
ALIPAY_PUBLIC_KEY,
"RSA2");
}
- 实现支付回调验签
- 处理异步通知更新订单状态
4. 数据库设计要点
4.1 核心表结构
photographers表:
sql复制CREATE TABLE `photographers` (
`id` bigint NOT NULL AUTO_INCREMENT,
`user_id` bigint NOT NULL COMMENT '关联用户ID',
`specialty` varchar(50) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '摄影专长',
`hourly_rate` decimal(10,2) DEFAULT NULL COMMENT '时薪',
`introduction` text COLLATE utf8mb4_bin COMMENT '个人介绍',
`cover_url` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '封面图URL',
`rating` decimal(3,1) DEFAULT '5.0' COMMENT '评分',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_user` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
4.2 预约关系设计
采用冗余存储提升查询性能:
sql复制CREATE TABLE `appointments` (
`id` bigint NOT NULL AUTO_INCREMENT,
`order_no` varchar(32) COLLATE utf8mb4_bin NOT NULL COMMENT '订单编号',
`customer_id` bigint NOT NULL,
`photographer_id` bigint NOT NULL,
`start_time` datetime NOT NULL,
`end_time` datetime NOT NULL,
`location` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
`status` tinyint NOT NULL DEFAULT '0' COMMENT '0-待支付 1-已预约 2-已完成 3-已取消',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_photographer_time` (`photographer_id`,`start_time`),
KEY `idx_customer` (`customer_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
5. 部署实践
5.1 后端部署要点
- 使用SpringBoot Maven插件打包:
bash复制mvn clean package -DskipTests
- 生产环境推荐配置:
yaml复制server:
port: 8080
compression:
enabled: true
mime-types: text/html,text/xml,text/plain,application/json
spring:
datasource:
hikari:
maximum-pool-size: 20
connection-timeout: 30000
5.2 前端部署优化
- 生产环境构建命令:
bash复制npm run build -- --mode production
- Nginx配置示例:
nginx复制server {
listen 80;
server_name photo-booking.example.com;
gzip on;
gzip_types text/plain application/xml text/css application/javascript;
location / {
root /var/www/booking-frontend/dist;
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
}
}
6. 开发经验与避坑指南
6.1 跨域问题解决
开发环境配置:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowCredentials(true)
.maxAge(3600);
}
}
生产环境建议:
- 使用Nginx反向代理统一域名
- 配置精确的allowedOrigins白名单
6.2 文件上传优化
采用分块上传方案:
javascript复制const chunkSize = 2 * 1024 * 1024; // 2MB
const uploadChunk = async (file, chunkIndex) => {
const start = chunkIndex * 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('chunkIndex', chunkIndex);
formData.append('totalChunks', Math.ceil(file.size / chunkSize));
return axios.post('/api/upload', formData);
};
6.3 性能监控配置
SpringBoot Actuator集成:
xml复制<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
安全配置:
yaml复制management:
endpoints:
web:
exposure:
include: health,metrics,info
endpoint:
health:
show-details: always
7. 扩展功能建议
- 即时通讯集成:使用WebSocket实现客户与摄影师实时沟通
- 智能推荐:基于用户浏览历史推荐相似风格的摄影师
- 人脸识别登录:整合百度AI或阿里云人脸识别服务
- 电子合同签署:接入e签宝等第三方签署服务
- 数据分析看板:使用ECharts展示业务数据可视化
实际开发中发现,使用Lombok可以大幅减少样板代码:
java复制@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AppointmentDTO {
private Long id;
private String orderNo;
private LocalDateTime startTime;
private LocalDateTime endTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm")
private LocalDateTime createdAt;
}
对于前端状态管理,Vuex的模块化设计非常实用:
javascript复制const appointmentModule = {
namespaced: true,
state: () => ({
upcoming: [],
history: []
}),
mutations: {
SET_UPCOMING(state, appointments) {
state.upcoming = appointments
}
}
}
