18 KiB
18 KiB
🛠️ 开发指南
版本: 1.0 更新时间: 2026-03-04
📋 目录
🚀 开发环境搭建
前置要求
| 工具 | 版本 | 说明 |
|---|---|---|
| JDK | 17+ | 推荐使用OpenJDK 17或21 |
| Maven | 3.8+ | 构建工具 |
| PostgreSQL | 12+ | 数据库 |
| Redis | 6.0+ | 缓存(可选,开发环境可用内存模式) |
| Git | 2.30+ | 版本控制 |
| IDE | - | 推荐IntelliJ IDEA或VS Code |
1. 克隆项目
git clone https://github.com/your-org/mosquito.git
cd mosquito
2. 安装依赖
# 安装PostgreSQL(Ubuntu/Debian)
sudo apt-get update
sudo apt-get install postgresql postgresql-contrib
# 安装Redis(可选)
sudo apt-get install redis-server
# 或使用Docker
docker run -d --name mosquito-postgres -e POSTGRES_PASSWORD=dev_password -p 5432:5432 postgres:15
docker run -d --name mosquito-redis -p 6379:6379 redis:7-alpine
3. 配置数据库
# 创建数据库
sudo -u postgres psql -c "CREATE DATABASE mosquito_dev;"
sudo -u postgres psql -c "CREATE USER mosquito WITH PASSWORD 'dev_password';"
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE mosquito_dev TO mosquito;"
4. 配置开发环境
复制配置模板:
cp src/main/resources/application-dev.yml.example src/main/resources/application-dev.yml
编辑 application-dev.yml:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mosquito_dev
username: mosquito
password: dev_password
data:
redis:
host: localhost
port: 6379
app:
api-key:
encryption-key: dev_32_char_encryption_key_12
5. 构建项目
# 编译项目
mvn clean compile
# 运行测试
mvn test
# 打包
mvn package
6. 启动应用
# 使用Maven
mvn spring-boot:run -Dspring-boot.run.profiles=dev
# 或使用JAR
java -jar target/mosquito-1.0.0.jar --spring.profiles.active=dev
访问 http://localhost:8080/actuator/health 验证启动成功。
7. 工作区定期清理
为避免构建产物和测试产物污染仓库,建议在本地定期执行以下命令:
# 只检查(发现 target/frontend/*/dist 或测试产物即返回非零)
npm run clean:workspace:check
# 归档清理(将产物移动到 /tmp/mosquito-archives/<tag>)
npm run clean:workspace:apply
# 历史日志归档(保留最近 1 天)
npm run logs:health:check
npm run logs:archive:check
npm run logs:archive:apply
npm run logs:archive:index
说明:
clean:workspace:check对应scripts/ci/clean-artifacts.sh --include-build-outputs --fail-on-found。clean:workspace:apply默认使用归档模式,不直接删除文件,便于回溯。logs:health:check对应scripts/ci/logs-health-check.sh,用于输出日志体积和历史候选文件数量(仅告警,不阻断)。logs:archive:*对应scripts/ci/archive-logs.sh,将按时间戳命名的历史运行日志移动到logs/archive/<tag>/。logs:archive:index对应scripts/ci/update-log-archive-index.sh,用于刷新logs/archive/README.md索引。- 若本地正在运行
spring-boot:run、vite或scripts/e2e_continuous_runner.sh,target与frontend/e2e/*可能被立即重建。建议先停止后台进程再执行清理。
8. IDE配置
IntelliJ IDEA:
- 导入项目:
File > Open选择项目根目录 - 配置JDK:
File > Project Structure > Project SDK选择JDK 17 - 启用注解处理:
Settings > Build > Compiler > Annotation Processors勾选Enable annotation processing - 配置运行配置:
Run > Edit Configurations- 添加
Spring Boot配置 - Main class:
com.mosquito.project.MosquitoApplication - Active profiles:
dev
VS Code:
安装扩展:
- Extension Pack for Java
- Spring Boot Extension Pack
- Lombok Annotations Support
配置 .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Spring Boot-MosquitoApplication",
"request": "launch",
"cwd": "${workspaceFolder}",
"mainClass": "com.mosquito.project.MosquitoApplication",
"projectName": "mosquito",
"args": "--spring.profiles.active=dev",
"envFile": "${workspaceFolder}/.env"
}
]
}
📁 项目结构
mosquito/
├── src/
│ ├── main/
│ │ ├── java/com/mosquito/project/
│ │ │ ├── config/ # 配置类
│ │ │ │ ├── CacheConfig.java
│ │ │ │ ├── OpenApiConfig.java
│ │ │ │ └── WebMvcConfig.java
│ │ │ ├── controller/ # REST控制器
│ │ │ │ ├── ActivityController.java
│ │ │ │ ├── ApiKeyController.java
│ │ │ │ ├── ShareTrackingController.java
│ │ │ │ └── UserExperienceController.java
│ │ │ ├── dto/ # 数据传输对象
│ │ │ │ ├── ApiResponse.java
│ │ │ │ ├── CreateActivityRequest.java
│ │ │ │ └── ActivityStatsResponse.java
│ │ │ ├── exception/ # 异常处理
│ │ │ │ ├── GlobalExceptionHandler.java
│ │ │ │ ├── BusinessException.java
│ │ │ │ └── ResourceNotFoundException.java
│ │ │ ├── persistence/ # 持久层
│ │ │ │ ├── entity/ # JPA实体
│ │ │ │ └── repository/ # JPA仓库
│ │ │ ├── service/ # 业务逻辑
│ │ │ │ ├── ActivityService.java
│ │ │ │ ├── ShortLinkService.java
│ │ │ │ └── ShareTrackingService.java
│ │ │ ├── security/ # 安全相关
│ │ │ │ └── UserIntrospectionService.java
│ │ │ ├── web/ # Web层(拦截器等)
│ │ │ │ ├── ApiKeyAuthInterceptor.java
│ │ │ │ └── RateLimitInterceptor.java
│ │ │ └── MosquitoApplication.java
│ │ └── resources/
│ │ ├── db/migration/ # Flyway迁移脚本
│ │ ├── application.properties
│ │ ├── application-dev.yml
│ │ └── logback-spring.xml
│ └── test/
│ └── java/com/mosquito/project/
│ ├── controller/ # 控制器测试
│ ├── service/ # 服务测试
│ ├── integration/ # 集成测试
│ └── config/ # 测试配置
├── docs/ # 文档
│ ├── api.md
│ ├── PRD.md
│ └── data-model.md
├── pom.xml
└── README.md
分层架构
┌─────────────────────────────────────┐
│ Controller Layer │ REST API端点
│ (ActivityController, etc.) │
└─────────────┬───────────────────────┘
│
┌─────────────▼───────────────────────┐
│ Service Layer │ 业务逻辑
│ (ActivityService, etc.) │
└─────────────┬───────────────────────┘
│
┌─────────────▼───────────────────────┐
│ Repository Layer │ 数据访问
│ (JPA Repositories) │
└─────────────┬───────────────────────┘
│
┌─────────────▼───────────────────────┐
│ Database Layer │ PostgreSQL + Redis
└──────────────────────────────────────┘
📝 开发规范
代码风格
Java代码规范:
- 遵循Google Java Style Guide
- 使用4个空格缩进
- 类名使用PascalCase
- 方法名和变量名使用camelCase
- 常量使用UPPER_SNAKE_CASE
示例:
public class ActivityService {
private static final int DEFAULT_PAGE_SIZE = 20;
private final ActivityRepository activityRepository;
public ActivityService(ActivityRepository activityRepository) {
this.activityRepository = activityRepository;
}
public Activity createActivity(CreateActivityRequest request) {
// 实现逻辑
}
}
命名规范
Controller:
- 类名:
XxxController - 方法名:动词开头,如
createActivity,getActivity,updateActivity
Service:
- 类名:
XxxService - 方法名:业务动作,如
create,findById,update,delete
Repository:
- 类名:
XxxRepository - 方法名:遵循Spring Data JPA规范,如
findByActivityId,existsByCode
DTO:
- 请求:
XxxRequest - 响应:
XxxResponse - 通用:
XxxDto
注释规范
类注释:
/**
* 活动管理服务
*
* 提供活动的创建、查询、更新和删除功能
*
* @author Your Name
* @since 1.0.0
*/
public class ActivityService {
}
方法注释:
/**
* 创建新活动
*
* @param request 活动创建请求
* @return 创建的活动实体
* @throws BusinessException 当活动名称重复时
*/
public Activity createActivity(CreateActivityRequest request) {
}
Git提交规范
遵循Conventional Commits规范:
<type>(<scope>): <subject>
<body>
<footer>
类型(type):
feat: 新功能fix: 修复bugdocs: 文档更新style: 代码格式调整refactor: 重构test: 测试相关chore: 构建/工具相关
示例:
feat(activity): add activity leaderboard endpoint
- Implement leaderboard query with pagination
- Add caching for leaderboard results
- Add integration tests
Closes #123
API设计规范
RESTful风格:
GET /api/v1/activities # 获取活动列表
POST /api/v1/activities # 创建活动
GET /api/v1/activities/{id} # 获取单个活动
PUT /api/v1/activities/{id} # 更新活动
DELETE /api/v1/activities/{id} # 删除活动
统一响应格式:
{
"code": 200,
"message": "Success",
"data": { ... },
"timestamp": "2026-03-04T10:00:00Z"
}
错误响应:
{
"code": 400,
"message": "Invalid request",
"error": {
"code": "VALIDATION_ERROR",
"details": {
"name": "Activity name is required"
}
},
"timestamp": "2026-03-04T10:00:00Z"
}
🧪 测试指南
测试分层
测试金字塔:
┌─────────┐
│ E2E │ 10% - 端到端测试
├─────────┤
│ 集成测试 │ 30% - 集成测试
├─────────┤
│ 单元测试 │ 60% - 单元测试
└─────────┘
单元测试
Service层测试:
@ExtendWith(MockitoExtension.class)
class ActivityServiceTest {
@Mock
private ActivityRepository activityRepository;
@InjectMocks
private ActivityService activityService;
@Test
@DisplayName("应成功创建活动")
void shouldCreateActivity_whenValidRequest() {
// Given
CreateActivityRequest request = new CreateActivityRequest();
request.setName("春季活动");
ActivityEntity entity = new ActivityEntity();
entity.setId(1L);
entity.setName("春季活动");
when(activityRepository.save(any())).thenReturn(entity);
// When
Activity result = activityService.create(request);
// Then
assertThat(result.getId()).isEqualTo(1L);
assertThat(result.getName()).isEqualTo("春季活动");
verify(activityRepository).save(any());
}
}
集成测试
Controller集成测试:
@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
class ActivityControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ActivityRepository activityRepository;
@BeforeEach
void setUp() {
activityRepository.deleteAll();
}
@Test
@DisplayName("应成功创建活动并返回201")
void shouldCreateActivity() throws Exception {
String requestBody = """
{
"name": "春季活动",
"startTime": "2025-03-01T10:00:00+08:00",
"endTime": "2025-03-31T23:59:59+08:00"
}
""";
mockMvc.perform(post("/api/v1/activities")
.contentType(MediaType.APPLICATION_JSON)
.header("X-API-Key", "test-key")
.content(requestBody))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.code").value(201))
.andExpect(jsonPath("$.data.name").value("春季活动"));
}
}
运行测试
# 运行所有测试
mvn test
# 运行单个测试类
mvn test -Dtest=ActivityServiceTest
# 运行单个测试方法
mvn test -Dtest=ActivityServiceTest#shouldCreateActivity_whenValidRequest
# 生成覆盖率报告
mvn clean test jacoco:report
# 查看覆盖率报告
open target/site/jacoco/index.html
测试覆盖率目标
| 指标 | 目标 | 当前 |
|---|---|---|
| 指令覆盖率 | ≥80% | 87% ✅ |
| 分支覆盖率 | ≥70% | 66% 🟡 |
| 行覆盖率 | ≥90% | 93% ✅ |
🐛 调试技巧
日志调试
启用调试日志:
logging:
level:
com.mosquito.project: DEBUG
org.springframework.web: DEBUG
org.hibernate.SQL: DEBUG
使用SLF4J日志:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ActivityService {
private static final Logger log = LoggerFactory.getLogger(ActivityService.class);
public Activity create(CreateActivityRequest request) {
log.debug("Creating activity: {}", request.getName());
// ...
log.info("Activity created: id={}", activity.getId());
return activity;
}
}
远程调试
启动应用时启用远程调试:
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 \
-jar target/mosquito-1.0.0.jar
IntelliJ IDEA配置:
Run > Edit Configurations- 添加
Remote JVM Debug - Host:
localhost, Port:5005 - 点击Debug按钮连接
数据库调试
查看SQL语句:
spring:
jpa:
show-sql: true
properties:
hibernate:
format_sql: true
使用H2 Console(测试环境):
spring:
h2:
console:
enabled: true
path: /h2-console
访问 http://localhost:8080/h2-console
Redis调试
使用Redis CLI:
# 连接Redis
redis-cli
# 查看所有键
KEYS *
# 查看键值
GET rate_limit:api_key_123
# 查看TTL
TTL rate_limit:api_key_123
# 清空缓存
FLUSHDB
🤝 贡献指南
开发流程
- Fork项目
# Fork到你的GitHub账号
# 克隆你的Fork
git clone https://github.com/your-username/mosquito.git
cd mosquito
git remote add upstream https://github.com/your-org/mosquito.git
- 创建功能分支
git checkout -b feature/add-leaderboard
- 开发功能
- 编写代码
- 添加测试
- 更新文档
- 提交代码
git add .
git commit -m "feat(activity): add leaderboard endpoint"
- 同步上游
git fetch upstream
git rebase upstream/main
- 推送分支
git push origin feature/add-leaderboard
- 创建Pull Request
- 访问GitHub仓库
- 点击 "New Pull Request"
- 填写PR描述
- 等待代码审查
Pull Request检查清单
- 代码遵循项目规范
- 添加了单元测试
- 添加了集成测试
- 测试覆盖率不降低
- 更新了相关文档
- 通过了CI/CD检查
- 代码已经过自我审查
- 提交信息遵循规范
代码审查标准
必须检查:
- 功能是否正确实现
- 是否有安全漏洞
- 是否有性能问题
- 测试是否充分
- 代码是否可维护
建议检查:
- 命名是否清晰
- 注释是否充分
- 是否有重复代码
- 是否可以简化
❓ 常见问题
Q1: 数据库连接失败
问题: Connection refused: connect
解决:
# 检查PostgreSQL是否运行
sudo systemctl status postgresql
# 启动PostgreSQL
sudo systemctl start postgresql
# 检查连接
psql -U mosquito -h localhost -d mosquito_dev
Q2: Redis连接失败
问题: Unable to connect to Redis
解决:
# 检查Redis是否运行
sudo systemctl status redis
# 启动Redis
sudo systemctl start redis
# 测试连接
redis-cli ping
Q3: 测试失败
问题: TestContainers: Could not find a valid Docker environment
解决:
# 安装Docker
sudo apt-get install docker.io
# 启动Docker
sudo systemctl start docker
# 添加用户到docker组
sudo usermod -aG docker $USER
Q4: 端口被占用
问题: Port 8080 is already in use
解决:
# 查找占用端口的进程
lsof -i :8080
# 杀死进程
kill -9 <PID>
# 或使用其他端口
java -jar target/mosquito-1.0.0.jar --server.port=8081
Q5: Flyway迁移失败
问题: Flyway migration failed
解决:
# 查看迁移状态
mvn flyway:info
# 修复失败的迁移
mvn flyway:repair
# 清空数据库重新迁移(仅开发环境)
mvn flyway:clean flyway:migrate
📚 相关资源
文档版本: 1.0 最后更新: 2026-03-04