23 KiB
23 KiB
🚀 结伴客开发指南
📋 项目概述
结伴客是一个创新的社交旅行平台,融合了结伴旅行和动物认领功能。本开发指南为开发者提供完整的开发环境搭建、代码规范、最佳实践等指导,帮助团队高效协作开发。
🎯 开发目标
代码质量目标
- 可维护性:代码结构清晰,易于理解和修改
- 可扩展性:支持功能快速迭代和模块化扩展
- 性能优化:响应时间 < 200ms,并发支持 1000+
- 安全性:数据安全,防止常见安全漏洞
团队协作目标
- 统一规范:代码风格、命名规范、提交规范统一
- 文档完善:API文档、技术文档实时更新
- 测试覆盖:单元测试覆盖率 > 80%
- 持续集成:自动化构建、测试、部署
🛠️ 开发环境搭建
系统要求
前端开发环境
- Node.js: 16.0+ (推荐使用 18.x LTS)
- 包管理器: npm 8.0+ 或 yarn 1.22+ 或 pnpm 7.0+
- 微信开发者工具: 最新稳定版 (1.06.x)
- IDE: VS Code (推荐) / WebStorm
- Git: 2.30+
- 浏览器: Chrome 100+ (开发调试)
后端开发环境
- Node.js: 16.0+ (主要后端)
- JDK: Java 17 (微服务版本,推荐使用 OpenJDK)
- Maven: 3.6+ (Java项目构建)
- IDE: IntelliJ IDEA (推荐) / Eclipse / VS Code
- 数据库: MySQL 8.0+
- 缓存: Redis 6.0+
- 消息队列: RabbitMQ 3.8+ (可选)
- 容器化: Docker 20.10+ 和 Docker Compose 1.29+
快速环境安装
macOS 环境安装
# 使用 Homebrew 安装开发工具
# 1. 安装 Homebrew (如果未安装)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# 2. 安装 Node.js 和 npm
brew install node
# 3. 安装 Java 17
brew install openjdk@17
echo 'export PATH="/opt/homebrew/opt/openjdk@17/bin:$PATH"' >> ~/.zshrc
# 4. 安装 Maven
brew install maven
# 5. 安装 Docker
brew install docker docker-compose
# 6. 安装数据库
brew install mysql redis
# 7. 安装开发工具
brew install git wget curl
# 8. 验证安装
node --version # 应显示 v16.x 或更高
java --version # 应显示 Java 17
mvn --version # 应显示 Maven 3.6+
docker --version # 应显示 Docker 20.10+
Windows 环境安装
- Node.js: 从 官网 下载安装
- JDK 17: 从 Adoptium 下载安装
- Maven: 从 官网 下载配置
- Docker Desktop: 从 官网 下载安装
- 微信开发者工具: 从 官网 下载安装
Ubuntu/Debian 环境安装
# 更新包管理器
sudo apt update
# 安装 Node.js
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs
# 安装 Java 17
sudo apt install openjdk-17-jdk
# 安装 Maven
sudo apt install maven
# 安装 Docker
sudo apt install docker.io docker-compose
# 安装 MySQL
sudo apt install mysql-server
# 安装 Redis
sudo apt install redis-server
环境验证
# 验证 Node.js 和 npm
node --version
npm --version
# 验证 Java 和 Maven
java -version
mvn -version
# 验证 Docker
docker --version
docker-compose --version
# 验证数据库连接
mysql --version
redis-cli --version
🏗️ 项目架构
整体架构
graph TB
A[微信小程序前端] --> B[API网关]
C[管理后台前端] --> B
D[官网前端] --> B
B --> E[认证服务]
B --> F[用户服务]
B --> G[旅行服务]
B --> H[动物服务]
B --> I[订单服务]
B --> J[商家服务]
E --> K[MySQL数据库]
F --> K
G --> K
H --> K
I --> K
J --> K
E --> L[Redis缓存]
F --> L
G --> L
H --> L
subgraph "服务注册与发现"
M[Eureka Server]
end
E --> M
F --> M
G --> M
H --> M
I --> M
J --> M
目录结构
jiebanke/
├── frontend/ # 前端项目
│ ├── miniprogram/ # 微信小程序
│ ├── admin-web/ # 管理后台
│ └── website/ # 官方网站
├── backend-java/ # Java后端服务
│ ├── eureka-server/ # 服务注册中心
│ ├── gateway-service/ # API网关
│ ├── auth-service/ # 认证服务
│ ├── user-service/ # 用户服务
│ ├── travel-service/ # 旅行服务
│ ├── animal-service/ # 动物服务
│ ├── order-service/ # 订单服务
│ ├── merchant-service/ # 商家服务
│ └── common/ # 公共模块
├── docs/ # 项目文档
├── scripts/ # 部署脚本
└── docker-compose.yml # Docker编排文件
📝 开发规范
1. 代码规范
前端代码规范
JavaScript/TypeScript 规范
// ✅ 推荐写法
const getUserInfo = async (userId) => {
try {
const response = await api.get(`/users/${userId}`);
return response.data;
} catch (error) {
console.error('获取用户信息失败:', error);
throw error;
}
};
// ❌ 不推荐写法
function getUserInfo(userId) {
return new Promise((resolve, reject) => {
api.get('/users/' + userId).then(res => {
resolve(res.data);
}).catch(err => {
reject(err);
});
});
}
Vue 组件规范
<template>
<div class="user-profile">
<div class="user-avatar">
<image :src="userInfo.avatar" mode="aspectFill" />
</div>
<div class="user-info">
<text class="username">{{ userInfo.nickname }}</text>
<text class="user-desc">{{ userInfo.description }}</text>
</div>
</div>
</template>
<script>
export default {
name: 'UserProfile',
props: {
userInfo: {
type: Object,
required: true,
default: () => ({})
}
},
data() {
return {
// 组件内部状态
};
},
computed: {
// 计算属性
},
methods: {
// 组件方法
}
};
</script>
<style scoped>
.user-profile {
display: flex;
align-items: center;
padding: 20rpx;
}
.user-avatar {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
overflow: hidden;
margin-right: 20rpx;
}
.user-info {
flex: 1;
}
.username {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.user-desc {
font-size: 28rpx;
color: #666;
margin-top: 10rpx;
}
</style>
后端代码规范
Java 命名规范
// ✅ 推荐写法
public class UserService {
private static final int MAX_RETRY_COUNT = 3;
private final UserMapper userMapper;
/**
* 根据用户ID获取用户信息
*
* @param userId 用户ID
* @return 用户信息
* @throws BusinessException 当用户不存在时抛出
*/
public UserDTO getUserById(Long userId) {
if (userId == null || userId <= 0) {
throw new IllegalArgumentException("用户ID不能为空或小于等于0");
}
User user = userMapper.selectById(userId);
if (user == null) {
throw new BusinessException(ErrorCode.USER_NOT_FOUND, "用户不存在");
}
return UserConverter.toDTO(user);
}
}
// ❌ 不推荐写法
public class userservice {
public Object getuser(Object id) {
return userMapper.selectById((Long)id);
}
}
Spring Boot 控制器规范
@RestController
@RequestMapping("/api/v1/users")
@Validated
@Slf4j
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/{id}")
@Operation(summary = "获取用户信息", description = "根据用户ID获取用户详细信息")
public ApiResponse<UserDTO> getUserById(
@PathVariable @Min(1) Long id) {
log.info("获取用户信息, userId: {}", id);
try {
UserDTO user = userService.getUserById(id);
return ApiResponse.success(user);
} catch (BusinessException e) {
log.warn("获取用户信息失败, userId: {}, error: {}", id, e.getMessage());
return ApiResponse.error(e.getCode(), e.getMessage());
} catch (Exception e) {
log.error("获取用户信息系统错误, userId: {}", id, e);
return ApiResponse.error(ErrorCode.SYSTEM_ERROR, "系统错误");
}
}
}
2. 数据库规范
表设计规范
-- ✅ 推荐的表结构设计
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID',
openid VARCHAR(100) UNIQUE NOT NULL COMMENT '微信openid',
nickname VARCHAR(50) NOT NULL COMMENT '用户昵称',
avatar VARCHAR(255) COMMENT '头像URL',
gender ENUM('male', 'female', 'unknown') DEFAULT 'unknown' COMMENT '性别',
phone VARCHAR(20) UNIQUE COMMENT '手机号码',
status ENUM('active', 'inactive', 'banned') DEFAULT 'active' COMMENT '用户状态',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
INDEX idx_openid (openid),
INDEX idx_phone (phone),
INDEX idx_status (status),
INDEX idx_created_at (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户基础信息表';
SQL 查询规范
-- ✅ 推荐的查询写法
SELECT
u.id,
u.nickname,
u.avatar,
u.created_at
FROM users u
WHERE u.status = 'active'
AND u.created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY)
ORDER BY u.created_at DESC
LIMIT 20;
-- ❌ 不推荐的查询写法
select * from users where status='active' order by created_at desc;
3. API 接口规范
RESTful API 设计
// ✅ 推荐的API设计
GET /api/v1/users // 获取用户列表
GET /api/v1/users/{id} // 获取单个用户
POST /api/v1/users // 创建用户
PUT /api/v1/users/{id} // 更新用户
DELETE /api/v1/users/{id} // 删除用户
GET /api/v1/users/{id}/travels // 获取用户的旅行计划
POST /api/v1/travels // 创建旅行计划
// ❌ 不推荐的API设计
GET /api/getUserList
POST /api/createUser
GET /api/user_travels?userId=123
统一响应格式
{
"code": 200,
"message": "success",
"data": {
"id": 1,
"nickname": "张三",
"avatar": "https://example.com/avatar.jpg"
},
"timestamp": "2025-01-15T10:30:00Z"
}
错误响应格式
{
"code": 400,
"message": "参数错误",
"data": null,
"errors": [
{
"field": "phone",
"message": "手机号格式不正确"
}
],
"timestamp": "2025-01-15T10:30:00Z"
}
4. Git 工作流规范
分支管理
# 主要分支
main # 生产环境分支
develop # 开发环境分支
release/* # 发布分支
hotfix/* # 热修复分支
# 功能分支
feature/user-management # 用户管理功能
feature/travel-booking # 旅行预订功能
feature/animal-adoption # 动物认领功能
# 修复分支
bugfix/login-issue # 登录问题修复
bugfix/payment-error # 支付错误修复
提交信息规范
# 提交信息格式
<type>(<scope>): <subject>
<body>
<footer>
# 示例
feat(user): 添加用户注册功能
- 实现微信授权登录
- 添加用户信息完善页面
- 集成短信验证码功能
Closes #123
# 类型说明
feat: 新功能
fix: 修复bug
docs: 文档更新
style: 代码格式调整
refactor: 代码重构
test: 测试相关
chore: 构建工具或辅助工具的变动
🧪 测试规范
1. 前端测试
单元测试 (Jest)
// utils/formatDate.test.js
import { formatDate } from './formatDate';
describe('formatDate', () => {
test('应该正确格式化日期', () => {
const date = new Date('2025-01-15T10:30:00Z');
const result = formatDate(date, 'YYYY-MM-DD');
expect(result).toBe('2025-01-15');
});
test('应该处理无效日期', () => {
const result = formatDate(null, 'YYYY-MM-DD');
expect(result).toBe('');
});
});
组件测试 (Vue Test Utils)
// components/UserProfile.test.js
import { mount } from '@vue/test-utils';
import UserProfile from './UserProfile.vue';
describe('UserProfile', () => {
test('应该正确显示用户信息', () => {
const userInfo = {
nickname: '张三',
avatar: 'https://example.com/avatar.jpg'
};
const wrapper = mount(UserProfile, {
props: { userInfo }
});
expect(wrapper.find('.username').text()).toBe('张三');
expect(wrapper.find('image').attributes('src')).toBe('https://example.com/avatar.jpg');
});
});
2. 后端测试
单元测试 (JUnit 5)
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserMapper userMapper;
@InjectMocks
private UserService userService;
@Test
@DisplayName("根据ID获取用户信息 - 成功")
void getUserById_Success() {
// Given
Long userId = 1L;
User mockUser = User.builder()
.id(userId)
.nickname("张三")
.status(UserStatus.ACTIVE)
.build();
when(userMapper.selectById(userId)).thenReturn(mockUser);
// When
UserDTO result = userService.getUserById(userId);
// Then
assertThat(result).isNotNull();
assertThat(result.getId()).isEqualTo(userId);
assertThat(result.getNickname()).isEqualTo("张三");
verify(userMapper).selectById(userId);
}
@Test
@DisplayName("根据ID获取用户信息 - 用户不存在")
void getUserById_UserNotFound() {
// Given
Long userId = 999L;
when(userMapper.selectById(userId)).thenReturn(null);
// When & Then
assertThatThrownBy(() -> userService.getUserById(userId))
.isInstanceOf(BusinessException.class)
.hasMessage("用户不存在");
}
}
集成测试 (Spring Boot Test)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Transactional
class UserControllerIntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
@Autowired
private UserMapper userMapper;
@Test
@DisplayName("获取用户信息接口测试")
void getUserById_Integration() {
// Given - 准备测试数据
User user = User.builder()
.openid("test_openid")
.nickname("测试用户")
.status(UserStatus.ACTIVE)
.build();
userMapper.insert(user);
// When - 调用接口
ResponseEntity<ApiResponse<UserDTO>> response = restTemplate.exchange(
"/api/v1/users/" + user.getId(),
HttpMethod.GET,
null,
new ParameterizedTypeReference<ApiResponse<UserDTO>>() {}
);
// Then - 验证结果
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).isNotNull();
assertThat(response.getBody().getCode()).isEqualTo(200);
assertThat(response.getBody().getData().getNickname()).isEqualTo("测试用户");
}
}
🚀 开发流程
1. 功能开发流程
步骤1: 需求分析
- 阅读产品需求文档
- 理解业务逻辑和用户场景
- 确认技术实现方案
- 评估开发工作量
步骤2: 技术设计
- 设计数据库表结构
- 设计API接口
- 设计前端页面结构
- 确定技术选型
步骤3: 开发实现
# 1. 创建功能分支
git checkout develop
git pull origin develop
git checkout -b feature/user-profile
# 2. 后端开发
# - 创建实体类和DTO
# - 实现数据访问层
# - 实现业务逻辑层
# - 实现控制器层
# - 编写单元测试
# 3. 前端开发
# - 创建页面组件
# - 实现业务逻辑
# - 调用后端API
# - 编写组件测试
# 4. 联调测试
# - 启动后端服务
# - 启动前端应用
# - 测试完整功能流程
# 5. 提交代码
git add .
git commit -m "feat(user): 实现用户个人资料功能"
git push origin feature/user-profile
步骤4: 代码审查
- 创建Pull Request
- 同事进行代码审查
- 修复审查意见
- 合并到develop分支
步骤5: 测试验证
- 部署到测试环境
- 执行功能测试
- 执行回归测试
- 修复发现的问题
2. 本地开发环境启动
后端服务启动
# 1. 启动基础服务
docker-compose up -d mysql redis rabbitmq
# 2. 启动微服务 (按顺序启动)
cd backend-java
# 启动服务注册中心
cd eureka-server
mvn spring-boot:run &
# 等待Eureka启动完成,然后启动其他服务
cd ../gateway-service
mvn spring-boot:run &
cd ../auth-service
mvn spring-boot:run &
cd ../user-service
mvn spring-boot:run &
# 或者使用脚本一键启动
./start-services.sh
前端应用启动
# 1. 启动微信小程序
cd frontend/miniprogram
npm install
npm run dev
# 2. 启动管理后台
cd ../admin-web
npm install
npm run serve
# 3. 启动官方网站
cd ../website
npm install
npm run dev
3. 调试技巧
后端调试
// 使用日志进行调试
@Slf4j
@Service
public class UserService {
public UserDTO getUserById(Long userId) {
log.debug("开始获取用户信息, userId: {}", userId);
User user = userMapper.selectById(userId);
log.debug("查询到用户信息: {}", user);
if (user == null) {
log.warn("用户不存在, userId: {}", userId);
throw new BusinessException(ErrorCode.USER_NOT_FOUND);
}
UserDTO result = UserConverter.toDTO(user);
log.debug("转换后的用户信息: {}", result);
return result;
}
}
前端调试
// 使用console进行调试
const getUserInfo = async (userId) => {
console.log('开始获取用户信息, userId:', userId);
try {
const response = await api.get(`/users/${userId}`);
console.log('获取用户信息成功:', response.data);
return response.data;
} catch (error) {
console.error('获取用户信息失败:', error);
throw error;
}
};
// 使用微信开发者工具调试
wx.request({
url: 'https://api.jiebanke.com/users/1',
success: (res) => {
console.log('请求成功:', res);
},
fail: (err) => {
console.error('请求失败:', err);
}
});
📦 构建与部署
1. 本地构建
前端构建
# 微信小程序构建
cd frontend/miniprogram
npm run build
# 管理后台构建
cd ../admin-web
npm run build
# 官方网站构建
cd ../website
npm run build
后端构建
# Maven构建
cd backend-java
mvn clean package -DskipTests
# Docker构建
./build-services.sh
2. 容器化部署
# 构建Docker镜像
docker-compose build
# 启动所有服务
docker-compose up -d
# 查看服务状态
docker-compose ps
# 查看服务日志
docker-compose logs -f user-service
🔧 开发工具配置
1. VS Code 配置
推荐插件
{
"recommendations": [
"ms-vscode.vscode-typescript-next",
"vue.volar",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"ms-vscode.vscode-json",
"redhat.java",
"vscjava.vscode-spring-boot-dashboard",
"ms-python.python"
]
}
工作区设置
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.workingDirectories": [
"frontend/miniprogram",
"frontend/admin-web",
"frontend/website"
],
"java.configuration.workspaces": [
"backend-java"
]
}
2. IntelliJ IDEA 配置
代码格式化
- 导入项目代码风格配置
- 启用自动格式化
- 配置Import优化
插件推荐
- Lombok
- MyBatis Log Plugin
- RestfulTool
- Maven Helper
- Git Commit Template
📚 学习资源
官方文档
推荐书籍
- 《JavaScript高级程序设计》
- 《Vue.js设计与实现》
- 《Spring Boot实战》
- 《Java并发编程实战》
在线课程
🤝 团队协作
1. 代码审查清单
前端代码审查
- 代码格式是否符合规范
- 组件是否可复用
- 是否有内存泄漏风险
- 错误处理是否完善
- 用户体验是否良好
后端代码审查
- 业务逻辑是否正确
- 异常处理是否完善
- 数据库操作是否高效
- 安全性是否考虑
- 日志记录是否完整
2. 沟通协作
日常沟通
- 每日站会:同步开发进度和问题
- 技术分享:定期分享技术心得
- 代码审查:互相学习和改进
文档维护
- 及时更新API文档
- 记录重要的技术决策
- 维护常见问题解答
🆘 常见问题
1. 环境问题
Q: Node.js 版本不兼容怎么办? A: 使用 nvm 管理 Node.js 版本
# 安装 nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
# 安装并使用指定版本
nvm install 18
nvm use 18
Q: Java 版本冲突怎么办? A: 使用 JAVA_HOME 环境变量指定版本
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
export PATH=$JAVA_HOME/bin:$PATH
2. 开发问题
Q: 微信小程序真机调试问题? A: 检查以下几点:
- 确认服务器域名已配置
- 检查HTTPS证书是否有效
- 确认API接口返回格式正确
Q: 后端服务启动失败? A: 常见原因和解决方案:
- 端口被占用:
lsof -i :8080查看占用进程 - 数据库连接失败:检查数据库配置和网络
- 依赖冲突:清理Maven缓存重新构建
3. 部署问题
Q: Docker 容器启动失败? A: 查看容器日志定位问题
docker logs container_name
docker-compose logs service_name
Q: 数据库迁移问题? A: 使用Flyway进行版本化管理
-- V1__Create_users_table.sql
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
nickname VARCHAR(50) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
📞 技术支持
联系方式
- 技术负责人: tech-lead@jiebanke.com
- 开发团队: dev@jiebanke.com
- 技术文档: https://docs.jiebanke.com
- 问题反馈: https://github.com/jiebanke/issues
紧急联系
- 生产环境问题: 24小时技术热线
- 安全问题: security@jiebanke.com
- 数据问题: dba@jiebanke.com
文档版本:v1.0
最后更新:2025年1月
维护团队:结伴客技术团队