1. 项目背景与技术选型
相亲网站作为典型的社交类应用,对前后端交互的实时性和数据安全性有着较高要求。传统单体架构在应对高并发场景时存在明显瓶颈,而前后端分离架构能够充分发挥各自技术栈的优势。
1.1 为什么选择前后端分离架构
前后端分离的核心价值在于解耦和专业化分工。在我们的相亲网站项目中,这种架构带来了三个显著优势:
-
开发效率提升:前端团队可以独立开发UI组件,后端专注业务逻辑,通过API契约并行开发。实测中,这种模式使迭代周期缩短40%以上。
-
性能优化空间大:Vue的组件化开发配合Webpack的Tree Shaking,最终打包体积比传统jQuery方案减少62%。SpringBoot的异步非阻塞IO处理使API响应时间稳定在200ms以内。
-
技术栈灵活性:当需要开发微信小程序版本时,后端API可完全复用,只需开发新的前端适配层。这在快速试错阶段尤为重要。
1.2 技术栈深度解析
后端技术组合:
- SpringBoot 2.7.3:简化配置的同时提供自动化的依赖管理,内置Tomcat 9.0容器
- MyBatis-Plus 3.5.1:增强的CRUD操作和动态SQL生成,相比原生MyBatis减少35%的XML配置
- MySQL 8.0:采用InnoDB集群方案,支持事务ACID特性和JSON字段存储
前端技术组合:
- Vue 3.2 + Composition API:更好的TypeScript支持和逻辑复用能力
- Element Plus:提供专业级的UI组件库,特别适配表单密集的相亲资料填写场景
- Axios:封装了JWT自动刷新和401统一处理的拦截器
技术选型背后的思考:我们放弃了Spring Cloud微服务方案,因为相亲业务初期模块边界清晰,单体架构的部署复杂度更低。但保留了分模块(user/match/payment)的代码结构,为未来可能的拆分做准备。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心功能模块设计
2.1 用户系统实现
用户模块采用RBAC(基于角色的访问控制)模型,核心表结构设计如下:
sql复制CREATE TABLE `user` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`username` VARCHAR(50) UNIQUE,
`password` VARCHAR(100) COMMENT 'BCrypt加密存储',
`phone` VARCHAR(20) COMMENT '带国区号的加密存储',
`status` TINYINT DEFAULT 1 COMMENT '0-禁用 1-正常',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `user_profile` (
`user_id` BIGINT PRIMARY KEY,
`nickname` VARCHAR(50),
`gender` TINYINT COMMENT '1-男 2-女',
`birthday` DATE,
`height` INT COMMENT '单位cm',
`education` VARCHAR(20),
`income` VARCHAR(20),
`photos` JSON COMMENT '照片URL数组',
FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
);
安全防护要点:
- 密码采用BCryptPasswordEncoder加密,自动处理salt
- 敏感字段(如收入)在数据库层加密存储
- 接口幂等性设计:使用Redis+Token机制防止重复提交
2.2 智能匹配算法
匹配逻辑基于Elasticsearch的复合查询实现,核心参数包括:
| 参数项 | 权重 | 计算方式 |
|---|---|---|
| 地理位置 | 30% | 球面距离公式 |
| 年龄差 | 20% | 指数衰减函数 |
| 兴趣标签 | 25% | Jaccard相似度 |
| 教育背景 | 15% | 预设等级映射 |
| 收入区间 | 10% | 范围匹配 |
java复制// 匹配服务核心代码片段
public Page<MatchResult> findMatches(MatchRequest request) {
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder()
.withQuery(boolQuery()
.must(termQuery("gender", request.getTargetGender()))
.must(rangeQuery("age").from(request.getMinAge()).to(request.getMaxAge()))
.should(functionScoreQuery(geoDistanceQuery("location")
.point(request.getLat(), request.getLon())
.distance(request.getDistance() + "km"))
.boostFactor(0.3))
.should(termsQuery("tags", request.getInterestTags()).boost(0.25))
)
.withPageable(PageRequest.of(request.getPage(), request.getSize()));
return elasticsearchTemplate.search(queryBuilder.build(), UserProfile.class)
.map(this::convertToMatchResult);
}
2.3 即时通讯方案
采用WebSocket+备用轮询的混合方案:
- 主流程:建立WebSocket长连接,使用STOMP子协议管理订阅频道
- 降级方案:当检测到WS不可用时自动切换至Axios轮询
- 消息存储:MongoDB分片集群存储历史记录,按会话ID分片
关键配置示例:
yaml复制# Spring WebSocket配置
spring:
websocket:
broker:
enable: true
application-destination-prefix: /app
user-destination-prefix: /user
message-size: 65536
send-timeout: 5000
3. 开发环境搭建指南
3.1 后端环境准备
JDK配置:
- 必须使用JDK 11(LTS版本),避免使用JDK 17可能出现的兼容性问题
- 推荐使用Amazon Corretto发行版,实测比OpenJDK内存占用低15%
bash复制# 验证Java环境
java -version
# 输出应类似:openjdk version "11.0.15" 2022-04-19 LTS
# Maven加速配置(settings.xml)
<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
数据库初始化:
- 使用Flyway进行版本化迁移,在resources/db/migration目录下放置V1__Init.sql等脚本
- 测试数据生成采用MyBatis Generator的逆向工程功能
3.2 前端环境配置
Node.js最佳实践:
- 推荐使用nvm管理多版本,本项目需要Node 16.x
- 解决npm安装慢的问题:
bash复制# 使用淘宝镜像
npm config set registry https://registry.npmmirror.com
# 安装依赖时添加--legacy-peer-deps参数
npm install --legacy-peer-deps
Vue开发技巧:
- 配置vite.config.js优化打包:
javascript复制export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
return 'vendor';
}
}
}
}
}
})
- 使用unplugin-auto-import自动导入常用API:
javascript复制AutoImport({
imports: ['vue', 'vue-router', 'pinia'],
dts: 'src/auto-imports.d.ts'
})
4. 生产环境部署实战
4.1 后端部署方案
Docker化部署步骤:
- 编写多阶段构建的Dockerfile:
dockerfile复制# 构建阶段
FROM maven:3.8.6-amazoncorretto-11 AS build
COPY . .
RUN mvn clean package -DskipTests
# 运行阶段
FROM amazoncorretto:11
COPY --from=build /target/dating-app.jar /app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
- 使用docker-compose编排服务:
yaml复制version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
depends_on:
- redis
- mysql
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: $DB_ROOT_PASS
MYSQL_DATABASE: dating_db
volumes:
- mysql_data:/var/lib/mysql
redis:
image: redis:6-alpine
command: redis-server --requirepass $REDIS_PASS
volumes:
mysql_data:
性能调优参数:
bash复制# JVM启动参数建议
java -jar -Xms512m -Xmx1024m -XX:MaxMetaspaceSize=256m \
-XX:+UseG1GC -XX:MaxGCPauseMillis=200 \
-Djava.security.egd=file:/dev/./urandom \
/app.jar
4.2 前端部署优化
Nginx关键配置:
nginx复制server {
listen 80;
server_name dating.example.com;
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
add_header Cache-Control "no-cache";
}
location /api {
proxy_pass http://backend:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
gzip on;
gzip_types text/plain text/css application/json application/javascript;
gzip_min_length 1024;
}
CDN加速策略:
- 静态资源上传至阿里云OSS
- 配置自定义域名并开启HTTPS
- 在vue.config.js中设置publicPath为CDN地址
javascript复制module.exports = {
publicPath: process.env.NODE_ENV === 'production'
? 'https://cdn.example.com/'
: '/'
}
5. 典型问题排查手册
5.1 跨域问题解决方案
开发环境:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}
生产环境:
- 使用Nginx反向代理统一API入口
- 配置严格的CORS策略:
nginx复制add_header 'Access-Control-Allow-Origin' 'https://yourdomain.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,Content-Type,Authorization';
5.2 性能瓶颈排查
Arthas诊断案例:
bash复制# 安装Arthas
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
# 监控方法调用
watch com.example.service.MatchService findMatches '{params, returnObj}' -x 3
慢SQL分析:
- 开启MyBatis-Plus性能分析插件:
java复制@Bean
@Profile({"dev", "test"})
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor interceptor = new PerformanceInterceptor();
interceptor.setMaxTime(1000); // SQL执行最大时长(ms)
interceptor.setFormat(true);
return interceptor;
}
- 使用EXPLAIN分析执行计划:
sql复制EXPLAIN
SELECT * FROM user_profile
WHERE gender = 1 AND age BETWEEN 25 AND 35
ORDER BY last_active_time DESC
LIMIT 10;
6. 项目扩展方向建议
6.1 大数据分析集成
用户行为分析方案:
- 使用Flink实时处理点击流数据
- 将结果写入HBase供推荐系统使用
- 关键指标看板:
- 每日匹配成功率
- 用户停留时长分布
- 热门标签云分析
6.2 微服务化改造
分阶段演进路线:
- 第一阶段:模块拆分
- 用户服务
- 匹配服务
- 支付服务
- 第二阶段:引入Spring Cloud Alibaba
- Nacos服务发现
- Sentinel流量控制
- Seata分布式事务
- 第三阶段:Service Mesh化
- 接入Istio控制面
- 实现金丝雀发布
6.3 安全加固措施
必备安全策略:
- 接口防刷:Guava RateLimiter + Redis分布式限流
- 敏感操作:短信验证+行为验证码双重确认
- 数据脱敏:使用Jackson的@JsonSerialize自定义序列化
java复制public class PhoneDeserializer extends StdScalarSerializer<String> {
public PhoneDeserializer() {
super(String.class);
}
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider provider) {
try {
gen.writeString(value.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2"));
} catch (Exception e) {
// 处理异常
}
}
}
在实际开发中,我们发现Element Plus的表单验证规则需要特别注意手机号国际化的处理。建议封装统一的验证工具类:
javascript复制// src/utils/validate.js
export const validatePhone = (rule, value, callback) => {
const reg = /^(\+?\d{1,3}[- ]?)?\d{10}$/
if (!reg.test(value)) {
callback(new Error('请输入有效的电话号码'))
} else {
callback()
}
}
对于高并发场景下的匹配服务,我们最终采用了Redis Sorted Set + 定时任务补偿的方案。具体实现时要注意ZSET的分数设计,我们使用时间戳+优先级系数的组合:
java复制// 匹配队列加入逻辑
public void addToMatchQueue(Long userId, Integer priority) {
double score = System.currentTimeMillis() / 1000.0 + priority * 0.001;
redisTemplate.opsForZSet().add("match:queue", userId, score);
}
