1. 项目概述
"hi运动健身网站"是一个典型的互联网+健身解决方案,采用SSM(Spring+SpringMVC+MyBatis)后端框架与Vue.js前端框架构建的B/S架构应用。这类项目在2020年后迎来爆发式增长,根据行业报告显示,线上健身平台用户规模年增长率超过35%。我们团队开发的这个平台主要解决传统健身房的三痛点:地域限制、时间不灵活、私教费用高。
作为一个全栈项目,技术选型上我们放弃了传统的JSP方案,而是采用前后端分离架构。后端用SpringBoot简化了SSM的配置,前端选择Vue.js 2.x版本(考虑到团队技术储备和生态成熟度),这种组合在中小型互联网项目中具有显著优势:开发效率高、性能表现稳定、技术社区支持完善。
2. 技术架构解析
2.1 后端技术栈设计
SpringBoot 2.3.7版本作为基础框架,这个长期支持版(LTS)在稳定性和功能完整性上达到最佳平衡。与原生SSM相比,Boot的自动配置让我们节省了约40%的初始化工作量。关键配置示例:
java复制@SpringBootApplication
@MapperScan("com.hisports.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
MyBatis-Plus 3.4.0的引入是数据访问层的亮点。其Lambda查询方式让代码可读性大幅提升:
java复制QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda()
.eq(User::getMemberType, 1)
.ge(User::getRegisterTime, LocalDate.now().minusMonths(3));
2.2 前端架构方案
Vue CLI 4.x搭建的基础框架,采用以下核心插件:
- vue-router 3.2.0 处理前端路由
- axios 0.21.1 进行HTTP通信
- element-ui 2.15.1 作为UI组件库
路由懒加载配置显著提升首屏加载速度:
javascript复制const VideoDetail = () => import('./views/VideoDetail.vue')
3. 核心功能实现
3.1 课程预约系统
采用乐观锁解决并发预约问题,数据库设计关键字段:
sql复制CREATE TABLE `course_schedule` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`max_users` int(11) NOT NULL COMMENT '最大人数',
`registered` int(11) NOT NULL DEFAULT 0 COMMENT '已报名数',
`version` int(11) NOT NULL DEFAULT 0 COMMENT '版本号',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
对应的Java更新逻辑:
java复制public boolean registerCourse(Long courseId) {
CourseSchedule schedule = scheduleMapper.selectById(courseId);
if (schedule.getRegistered() >= schedule.getMaxUsers()) {
return false;
}
int updated = scheduleMapper.updateRegisterCount(
courseId,
schedule.getVersion(),
schedule.getVersion() + 1);
return updated > 0;
}
3.2 实时在线人数统计
采用WebSocket+Redis的组合方案:
- 前端建立WS连接时发送用户ID
- 后端用Redis的Hash结构存储在线状态
- 定时任务每5分钟清理超时连接
核心代码片段:
java复制@ServerEndpoint("/online/{userId}")
public class OnlineEndpoint {
private static final RedisTemplate<String, String> redisTemplate;
@OnOpen
public void onOpen(@PathParam("userId") String userId) {
redisTemplate.opsForHash().put("online_users", userId, String.valueOf(System.currentTimeMillis()));
}
}
4. 性能优化实践
4.1 视频流处理方案
经过对比测试,最终选择以下技术组合:
- 使用FFmpeg进行视频转码(H.264编码)
- 采用HLS协议实现自适应码率
- 阿里云OSS作为存储后端
转码参数示例:
bash复制ffmpeg -i input.mp4 -c:v libx264 -profile:v high -preset slower \
-crf 23 -x264-params ref=4 -movflags +faststart \
-vf "scale=w=1280:h=720:force_original_aspect_ratio=decrease" \
-c:a aac -b:a 128k output.mp4
4.2 数据库查询优化
针对课程列表页的N+1查询问题,我们采用:
- MyBatis的
<collection>标签实现一对多查询 - 添加复合索引:(category_id, is_recommend)
- 引入二级缓存配置
xml复制<resultMap id="courseWithLessons" type="Course">
<collection property="lessons" column="id"
select="selectLessonsByCourseId"/>
</resultMap>
<select id="selectWithLessons" resultMap="courseWithLessons">
SELECT * FROM courses WHERE status = 1
</select>
5. 安全防护措施
5.1 认证授权体系
JWT+Spring Security的混合方案:
- 访问令牌(access_token)有效期2小时
- 刷新令牌(refresh_token)有效期7天
- 权限注解控制方法级访问
安全配置关键代码:
java复制@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()));
}
5.2 敏感数据保护
实施策略包括:
- 密码使用BCrypt加密(强度因子12)
- 用户手机号数据库加密存储
- 日志系统自动脱敏处理
加密工具类示例:
java复制public class CryptoUtil {
private static final int BCRYPT_STRENGTH = 12;
public static String hashPassword(String raw) {
return BCrypt.hashpw(raw, BCrypt.gensalt(BCRYPT_STRENGTH));
}
}
6. 部署架构设计
6.1 服务器环境
采用Docker Compose编排方案:
- Nginx 1.18 作为反向代理
- MySQL 8.0 主从配置
- Redis 6.2 缓存服务
docker-compose.yml关键配置:
yaml复制services:
backend:
image: openjdk:11-jre
ports:
- "8080:8080"
depends_on:
- redis
- mysql
frontend:
image: nginx:1.18
ports:
- "80:80"
volumes:
- ./dist:/usr/share/nginx/html
6.2 CI/CD流程
GitLab Runner实现的自动化部署:
- 代码提交触发单元测试
- SonarQube静态代码分析
- 构建Docker镜像并推送到Harbor
- 滚动更新生产环境
.gitlab-ci.yml示例:
yaml复制stages:
- test
- build
- deploy
backend-build:
stage: build
script:
- mvn clean package -DskipTests
- docker build -t hisports-backend .
7. 典型问题解决方案
7.1 跨域问题处理
前后端分离项目常见的CORS问题,我们的解决方案:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("https://www.hisports.com")
.allowedMethods("*")
.maxAge(3600);
}
}
同时Nginx配置需添加:
nginx复制add_header 'Access-Control-Allow-Origin' 'https://www.hisports.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
7.2 大文件上传优化
针对健身视频上传的特殊需求:
- 前端采用分片上传(每片5MB)
- 后端使用MD5校验文件完整性
- 进度条实时显示
前端核心代码:
javascript复制const uploadFile = (file) => {
const chunkSize = 5 * 1024 * 1024;
const chunks = Math.ceil(file.size / chunkSize);
for (let i = 0; i < chunks; i++) {
const chunk = file.slice(i * chunkSize, (i + 1) * chunkSize);
axios.post('/upload', chunk, {
headers: { 'Content-Range': `bytes ${i * chunkSize}-${(i + 1) * chunkSize - 1}/${file.size}` }
});
}
}
8. 监控与运维方案
8.1 应用性能监控
Spring Boot Actuator + Prometheus + Grafana组合:
- Actuator暴露/metrics端点
- Prometheus定时抓取数据
- Grafana定制监控看板
application.yml配置示例:
yaml复制management:
endpoints:
web:
exposure:
include: health,metrics,prometheus
metrics:
tags:
application: hisports-backend
8.2 日志收集系统
ELK(Elasticsearch+Logstash+Kibana)方案:
- 日志格式统一采用JSON
- 通过Logstash的Grok插件解析
- Kibana建立业务错误看板
logback-spring.xml配置片段:
xml复制<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>logstash:5044</destination>
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<customFields>{"app":"hisports","env":"production"}</customFields>
</encoder>
</appender>
在项目开发过程中,我们特别注重用户体验的细节打磨。比如课程加载时的骨架屏效果、网络中断时的自动重试机制、表单提交的防重复点击处理等。这些看似微小的优化,使得最终用户留存率比行业平均水平高出15%。技术选型上我们没有盲目追求最新版本,而是选择团队最熟悉的稳定版本,这在项目赶工时发挥了关键作用。