内容
# 事件管理 API
[](https://github.com/albonidrizi/Event-Management-API/actions/workflows/ci.yml)
[](https://openjdk.org/)
[](MCP.md)
[](LICENSE)
事件管理后端,提供两个一流的接口:一个用于应用程序的 JAX-RS REST API 和一个用于 AI 客户端的 Model Context Protocol 服务器。两个接口都重用相同的验证、事务、服务、JDBC 存储库和 MySQL 数据。
## 为什么这个项目与众不同
- 一个领域通过 REST、本地 MCP stdio 和远程 MCP Streamable HTTP 公开。
- `32` 个 MCP 工具、`7` 个资源和 `8` 个参数化资源模板。
- 真实的业务工作流:容量检查、事务批量注册、取消、签到、审计日志、状态历史、分页、报告和 CSV 导出。
- 没有 ORM:SQL、连接、聚合、事务和存储库边界是明确的。
- 使用 Docker Compose、Maven Wrapper、种子 MySQL、CI 和集成测试进行可复制的设置,线覆盖率门控为 `60%`。
- 默认安全配置:没有提交的数据库密码和受保护的远程 MCP 绑定。
## 技术栈
- Java 17+
- Jersey / JAX-RS
- Apache Tomcat 9
- JDBC
- MySQL
- Maven
- JSON 请求/响应体
- Model Context Protocol 服务器通过 stdio
- 没有 ORM
## 架构
```mermaid
flowchart LR
App["REST 客户端"] --> REST["JAX-RS 资源"]
AI["Gemini / Claude / Copilot / ChatGPT"] --> MCP["MCP stdio 或 HTTP"]
REST --> Service["共享服务和业务规则"]
MCP --> Service
Service --> Repo["JDBC 存储库"]
Repo --> DB[("MySQL")]
```
REST 和 MCP 作为单独的进程运行,但它们重用相同的业务逻辑、验证、事务、存储库和 MySQL 数据库。
软件包:
```text
config JAX-RS、Jackson、数据库连接配置
model 实体模型和状态枚举
dto 请求/响应 DTO
resource REST 端点
mcp MCP 服务器、工具、资源和资源模板
service 业务逻辑、验证、事务
repository JDBC SQL 访问
exception JSON 错误处理
```
## 主要业务模块
- 事件类别
- 事件
- 参与者
- 事件注册
- 签到流程
- 注册摘要报告
## 使用 Docker 快速启动
要求:Docker Desktop 和 Git。
```bash
cp .env.example .env
# 替换 .env 中的每个占位符,然后:
docker compose up --build
```
验证 REST API:
```text
GET http://localhost:8081/event-management-api/api/events/health
```
运行可选的受保护的 MCP HTTP 容器:
```bash
docker compose --profile mcp-http up --build
```
MCP 端点是 `http://localhost:8090/mcp`,需要 `.env` 中配置的 Bearer token。
## 数据库设置
数据库 URL 和用户名有本地默认值。密码是故意需要的,必须在 Git 之外提供:
```text
DB_URL=jdbc:mysql://localhost:3306/event_management?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
DB_USERNAME=root
DB_PASSWORD=your-local-password
```
您可以通过环境变量或 JVM 系统属性覆盖这些:
```text
-Devent.db.url=jdbc:mysql://localhost:3306/event_management?useSSL=false&serverTimezone=UTC
-Devent.db.username=root
-Devent.db.password=your_password
```
创建数据库:
```sql
CREATE DATABASE event_management;
USE event_management;
```
然后运行:
```text
src/main/resources/schema.sql
```
可选的样本数据:
```text
src/main/resources/seed-data.sql
```
模式包括主键、外键、唯一约束、索引、软删除标志和审计列。
它还包括用于注册状态历史和审计日志的扩展表。
## 构建
```bash
./mvnw clean package
```
输出:
```text
target/event-management-api.war
target/event-management-mcp.jar
target/event-management-mcp-http.jar
```
## MCP 服务器
该项目包括一个使用官方 Java MCP SDK 和 `stdio` 传输的可执行 Model Context Protocol 服务器。
它公开:
- `32` 个用于读取和更改事件管理数据的工具
- `7` 个静态只读资源
- `8` 个参数化资源模板
- 类别、参与者、事件和注册的 CRUD 操作
- 注册、批量注册、取消、签到、报告、CSV 导出、状态历史和审计日志
MCP 资源是只读的。MCP 工具可以读取、创建、更新和删除数据。
两个 MCP 传输可用:
- `event-management-mcp.jar`:用于 Gemini CLI 和类似客户端的本地 stdio 传输
- `event-management-mcp-http.jar`:用于 ChatGPT 和远程 MCP 客户端的 Streamable HTTP 传输
stdio 服务器在 VS Code 中与 Gemini CLI、Claude Code 和 GitHub Copilot 进行了测试。
构建 REST API 和 MCP 服务器:
```bash
./mvnw clean package
```
通常,MCP 客户端使用以下命令自动启动服务器:
```bash
java -jar target/event-management-mcp.jar
```
### 连接 Gemini CLI
从项目目录注册 MCP 服务器:
```bash
gemini mcp add --scope project --transport stdio --timeout 30000 event-management java -- -jar "C:\absolute\path\to\target\event-management-mcp.jar"
```
验证连接:
```bash
gemini mcp list
```
预期状态:
```text
event-management - Connected
```
示例提示:
```text
使用 event-management MCP 列出所有活动参与者。
使用 event-management MCP 创建一个名为 Music 的类别。
显示事件 ID 1 的注册摘要。
```
### 连接 ChatGPT
启动 Streamable HTTP 服务器:
```bash
java -jar target/event-management-mcp-http.jar
```
它监听:
```text
http://127.0.0.1:8090/mcp
```
暂时通过 HTTPS 公开:
```bash
ngrok http 8090
```
在 ChatGPT 中启用开发者模式,创建一个自定义应用/连接器,并使用:
```text
https://your-ngrok-domain.ngrok.app/mcp
```
本地模式可以在没有身份验证的情况下运行。设置 `MCP_HTTP_BEARER_TOKEN` 以保护兼容的客户端。
服务器拒绝在没有令牌的情况下绑定到 localhost 以外的范围,除非明确设置 `MCP_HTTP_ALLOW_INSECURE_REMOTE=true` 用于临时测试数据演示。
生产部署应使用稳定的 HTTPS 和 OAuth 2.1。
### 连接 Claude Code
```bash
claude mcp add --transport stdio --scope local event-management -- java -jar target/event-management-mcp.jar
claude mcp list
```
### 连接 GitHub Copilot
包含的 `.vscode/mcp.json` 配置了本地 stdio 服务器。在 VS Code 中,打开 Copilot Chat,选择 `Agent`,并从工具选择器中启用 `event-management`。
完整的 MCP 设置、客户端配置、工具和资源在以下文件中记录:
```text
MCP.md
```
## 在本地运行
REST 和 MCP 不需要一个共享进程:
- 使用 Maven Cargo 在测试 HTTP 端点时运行 REST。
- Gemini CLI 或另一个 MCP 客户端在需要 MCP 工具时启动 MCP JAR。
- 两个进程直接连接到同一个 MySQL 数据库。
使用 Maven Cargo 嵌入式 Tomcat 9:
```bash
./mvnw package cargo:run
```
项目配置为端口 `8081`。
健康检查:
```text
GET http://localhost:8081/event-management-api/api/events/health
```
响应:
```json
{
"status": "API is running"
}
```
MCP 健康提示:
```text
使用 event-management MCP 检查服务器健康状况。
```
## 验证
运行自动化测试:
```bash
./mvnw verify
```
集成测试验证 MCP 通过 stdio 和 Streamable HTTP 初始化、Bearer token 保护、完整的写入生命周期、所有读取工具和资源、参数化资源、并发工具调用、数据库行计数和在 stdio 客户端断开连接后的干净关闭。
CI 运行相同的验证以对抗真正的 MySQL 服务,强制执行至少 `60%` 的行覆盖率,并将 JaCoCo 报告作为工件发布。
快速 REST 演练后:
```powershell
./scripts/demo-rest.ps1
```
## 部署到 Tomcat
1. 安装 Apache Tomcat 9。
2. 使用 `mvn clean package` 进行构建。
3. 将 `target/event-management-api.war` 复制到 Tomcat `webapps`。
4. 启动 Tomcat。
5. 使用:
```text
http://localhost:8080/event-management-api/api/events/health
```
使用 Tomcat 9 而不是 Tomcat 10,因为该项目使用 `javax.ws.rs` 和 Servlet 4。
## 错误格式
所有处理的错误都返回 JSON:
```json
{
"errorCode": "VALIDATION_ERROR",
"message": "capacity must be greater than 0"
}
```
常见状态码:
- `400 Bad Request`:验证错误
- `404 Not Found`:缺少实体
- `409 Conflict`:业务冲突、重复注册、活动已满
- `500 Internal Server Error`:意外失败
## 状态值
事件状态:
```text
ACTIVE
CANCELLED
COMPLETED
```
注册状态:
```text
REGISTERED
CANCELLED
ATTENDED
```
## 端点
### 事件类别 CRUD
```text
GET /api/event-categories
GET /api/event-categories/{id}
POST /api/event-categories
PUT /api/event-categories/{id}
DELETE /api/event-categories/{id}
```
### 事件 CRUD
```text
GET /api/events
GET /api/events?status=ACTIVE
GET /api/events?categoryId=1
GET /api/events/{id}
POST /api/events
PUT /api/events/{id}
DELETE /api/events/{id}
```
### 参与者 CRUD
```text
GET /api/participants
GET /api/participants/{id}
POST /api/participants
PUT /api/participants/{id}
DELETE /api/participants/{id}
```
### 注册 CRUD
```text
GET /api/registrations
GET /api/registrations/{id}
POST /api/registrations
PUT /api/registrations/{id}
DELETE /api/registrations/{id}
```
### 业务端点
```text
POST /api/events/{id}/register
POST /api/events/{id}/register-bulk
POST /api/events/{id}/cancel-registration
POST /api/registrations/{id}/check-in
GET /api/registrations/{id}/status-history
GET /api/events/{id}/participants
GET /api/events/{id}/participants/export
GET /api/events/available
GET /api/events/search?search=java&page=1&size=10
GET /api/events/{id}/registration-summary
GET /api/audit-logs
```
### 添加的扩展
- 状态历史:`registration_status_history` 存储旧的和新的注册状态。
- 分页和搜索:`GET /api/events/search` 支持 `search`、`status`、`categoryId`、`page` 和 `size`。
- 审计表:`audit_log` 记录注册操作,如注册、批量注册、取消和签到。
- CSV 导出:`GET /api/events/{id}/participants/export` 以 `text/csv` 返回参与者。
- 批量操作:`POST /api/events/{id}/register-bulk` 在一个事务中注册多个参与者。
## 业务端点设计
每个端点的完整业务设计在以下文件中记录:
```text
BUSINESS_DESIGN.md
```
`POST /api/events/{id}/register`
目的:为具有可用容量的活动注册参与者。
请求:
```json
{
"participantId": 1
}
```
验证:
- 活动必须存在。
- 参与者必须存在。
- 活动状态必须是 `ACTIVE`。
- 活动日期不得在过去。
- 参与者不得已经注册。
- 容量不得已满。
处理:
- 打开 JDBC 事务。
- 读取事件和参与者。
- 检查现有注册和容量。
- 插入 `event_registration`。
- 提交或回滚。
失败情况:
- `400` 缺少 participantId
- `404` 事件或参与者丢失
- `409` 重复注册或活动已满
`POST /api/registrations/{id}/check-in`
目的:标记已注册的参与者为已出席。
验证:
- 注册必须存在。
- 已取消的注册不能签到。
- 已经出席的注册返回冲突。
处理:
- 打开事务。
- 读取注册。
- 更新状态为 `ATTENDED`。
- 提交或回滚。
`GET /api/events/{id}/participants`
目的:列出为活动注册的参与者。
SQL 概念:使用 `event_registration` 和 `participant` 之间的 `JOIN`。
`GET /api/events/{id}/registration-summary`
目的:返回容量、已注册、已出席、已取消和剩余座位。
SQL 概念:使用 `SUM(CASE ...)`、`GROUP BY` 和计算的剩余容量。
实现还包括此汇总查询中的 `COUNT` 和 `AVG`。
示例响应:
```json
{
"eventId": 1,
"eventTitle": "Java Backend Workshop",
"capacity": 40,
"totalRegistrations": 22,
"registered": 12,
"attended": 8,
"cancelled": 2,
"remaining": 28,
"attendanceRate": 0.36
}
```
## 示例请求
使用:
```text
src/main/resources/api-examples.http
```
或在 Postman 或 Charles 中导入相同的 URL。
## 项目文档
- [MCP.md](MCP.md):传输、客户端、功能和安全设置
- [BUSINESS_DESIGN.md](BUSINESS_DESIGN.md):每个端点的业务规则
- [CONTRIBUTING.md](CONTRIBUTING.md):贡献者设置和工作流程
- [SECURITY.md](SECURITY.md):安全策略和部署边界