1. 项目概述与背景
作为一名从业多年的全栈开发者,最近刚完成了一个基于SpringBoot的摄影工作室网站项目。这个项目源于传统摄影行业向数字化转型的实际需求,旨在为摄影工作室打造一个集作品展示、在线预约、支付结算于一体的综合性平台。
在项目启动前,我们调研了市面上30多家摄影工作室,发现近80%仍在使用传统的线下预约方式,导致客户流失率高、管理效率低下。这个系统正是为了解决这些痛点而设计的,主要包含以下核心功能模块:
- 前台用户系统:作品展示、摄影师介绍、在线预约、支付功能
- 后台管理系统:订单管理、作品管理、用户管理、数据统计
- API服务层:为移动端应用预留接口
技术选型方面,我们采用了目前主流的SpringBoot+Vue.js前后端分离架构。这种架构的优势在于:
- 前后端可以并行开发,提高开发效率
- Vue.js的组件化开发模式便于维护和扩展
- SpringBoot的自动配置特性简化了后端开发复杂度
2. 系统架构设计
2.1 技术栈选型解析
后端技术栈:
- SpringBoot 2.7.5:作为基础框架,提供依赖注入和自动配置
- MyBatis-Plus 3.5.2:简化数据库操作,内置常用CRUD方法
- Redis 6.2:用于缓存热门作品数据和会话管理
- MySQL 8.0:主数据库,存储核心业务数据
- Swagger 3.0:API文档自动生成工具
前端技术栈:
- Vue.js 3.2:前端主框架
- Element Plus:UI组件库
- Axios:HTTP请求库
- Vue Router:前端路由管理
- Pinia:状态管理库
提示:选择MyBatis-Plus而非JPA的主要考虑是团队更熟悉MyBatis体系,且项目中有较多复杂SQL查询需求。
2.2 系统架构图
系统采用典型的三层架构:
code复制表示层(Vue.js) ↔ 业务逻辑层(SpringBoot) ↔ 数据访问层(MySQL)
↕
缓存层(Redis)
这种分层设计的优势在于:
- 各层职责明确,便于维护
- 可以针对单层进行性能优化
- 缓存层的引入减轻了数据库压力
3. 核心功能实现
3.1 作品展示模块
作品展示是系统的核心功能之一,我们实现了:
- 多维度分类(风格、场景、摄影师)
- 瀑布流布局
- 收藏点赞功能
- 高级搜索(标签、拍摄时间等)
后端关键代码示例:
java复制@GetMapping("/works")
public Result<List<WorkVO>> getWorks(
@RequestParam(required = false) String style,
@RequestParam(required = false) String scene,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "12") Integer size) {
LambdaQueryWrapper<Work> wrapper = new LambdaQueryWrapper<>();
if (StringUtils.isNotBlank(style)) {
wrapper.eq(Work::getStyle, style);
}
if (StringUtils.isNotBlank(scene)) {
wrapper.eq(Work::getScene, scene);
}
Page<Work> workPage = workService.page(new Page<>(page, size), wrapper);
return Result.success(workPage.getRecords().stream()
.map(this::convertToVO).collect(Collectors.toList()));
}
前端采用了虚拟滚动技术优化大量图片加载性能,核心思路是:
- 只渲染可视区域内的图片
- 监听滚动事件动态加载新数据
- 使用Intersection Observer API实现懒加载
3.2 在线预约系统
预约功能的技术难点在于处理时间冲突,我们的解决方案是:
- 数据库设计时采用时间段存储:
sql复制CREATE TABLE `reservation` (
`id` bigint NOT NULL AUTO_INCREMENT,
`photographer_id` bigint NOT NULL,
`user_id` bigint NOT NULL,
`start_time` datetime NOT NULL,
`end_time` datetime NOT NULL,
`status` tinyint DEFAULT '0' COMMENT '0-待确认 1-已确认 2-已取消',
PRIMARY KEY (`id`),
KEY `idx_photographer_time` (`photographer_id`,`start_time`,`end_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
- 预约时检查时间冲突的SQL:
sql复制SELECT COUNT(*) FROM reservation
WHERE photographer_id = ?
AND ((start_time <= ? AND end_time >= ?)
OR (start_time <= ? AND end_time >= ?)
OR (start_time >= ? AND end_time <= ?))
- 使用分布式锁防止超卖:
java复制public boolean makeReservation(Long photographerId, LocalDateTime start, LocalDateTime end) {
String lockKey = "reserve:" + photographerId + ":" + start.toString();
try {
// 尝试获取锁
Boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS);
if (Boolean.TRUE.equals(locked)) {
// 检查时间冲突
if (checkTimeConflict(photographerId, start, end)) {
return false;
}
// 创建预约记录
return createReservation(photographerId, start, end);
}
return false;
} finally {
redisTemplate.delete(lockKey);
}
}
4. 性能优化实践
4.1 缓存策略设计
针对高并发的作品浏览场景,我们设计了多级缓存:
- 热点数据缓存:使用Redis缓存点击量前100的作品
- 本地缓存:使用Caffeine缓存用户最近浏览记录
- CDN加速:静态资源部署在CDN上
缓存更新策略采用"先更新数据库,再删除缓存"的方式,避免缓存一致性问题。
4.2 数据库优化
-
索引优化:
- 为所有外键字段添加索引
- 为常用查询条件组合创建联合索引
- 使用EXPLAIN分析慢查询
-
分表策略:
- 预约记录按月分表
- 用户操作日志按周分表
-
SQL优化:
- 避免SELECT *
- 使用JOIN替代子查询
- 批量操作代替循环单条操作
5. 安全防护措施
5.1 认证与授权
采用JWT+Spring Security实现安全控制:
- 登录成功生成JWT token
- 前端存储token在localStorage
- 后端通过过滤器验证token
- 基于注解的方法级权限控制
关键配置示例:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.addFilter(new JwtAuthorizationFilter(authenticationManager()));
}
}
5.2 数据安全
-
敏感数据加密:
- 密码使用BCrypt加密
- 用户手机号等PII信息加密存储
-
SQL注入防护:
- 使用预编译语句
- 禁止拼接SQL
- MyBatis使用#{}而非${}
-
XSS防护:
- 前端使用DOMPurify过滤输入
- 后端对输出内容进行转义
6. 部署与监控
6.1 容器化部署
使用Docker+Docker Compose实现一键部署:
yaml复制version: '3'
services:
app:
image: openjdk:11-jre
ports:
- "8080:8080"
volumes:
- ./app.jar:/app.jar
command: java -jar /app.jar
depends_on:
- redis
- mysql
redis:
image: redis:6.2
ports:
- "6379:6379"
volumes:
- redis_data:/data
mysql:
image: mysql:8.0
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: root
volumes:
- mysql_data:/var/lib/mysql
volumes:
redis_data:
mysql_data:
6.2 监控方案
- Spring Boot Actuator:暴露健康检查端点
- Prometheus + Grafana:监控系统指标
- ELK:日志收集与分析
- Sentry:错误追踪
7. 开发经验总结
在实际开发过程中,我们积累了一些宝贵经验:
- 接口设计要遵循RESTful规范,保持一致性
- 使用Swagger维护API文档,便于前后端协作
- 重要业务操作要添加操作日志
- 数据库迁移使用Flyway管理
- 使用TestContainers进行集成测试
一个典型的开发工作流应该是:
- 编写接口文档
- 前后端并行开发
- 联调测试
- 代码审查
- 自动化部署
对于想要开发类似系统的开发者,我的建议是:
- 前期做好需求分析和系统设计
- 选择熟悉且适合项目规模的技术栈
- 重视代码质量和测试覆盖率
- 合理使用设计模式,避免过度设计
- 持续集成和自动化测试能节省大量时间