589 lines
15 KiB
Markdown
589 lines
15 KiB
Markdown
# Camel Vert.x RESTful API 演示
|
||
|
||
这是一个使用Apache Camel和Vert.x开发的响应式RESTful API示例项目,采用MyBatis与PostgreSQL进行数据访问。本项目充分利用Camel REST DSL来实现API端点,避免直接使用Vert.x Router。
|
||
|
||
## 特性
|
||
|
||
- 使用Apache Camel最新版本(4.11.0)结合Vert.x构建响应式API
|
||
- 充分使用Camel REST DSL定义RESTful API端点
|
||
- 使用MyBatis纯XML方式进行数据库操作,无实体类和Mapper接口
|
||
- 扁平化结构设计,无Service层,减少代码量
|
||
- 完整的用户CRUD操作和分页查询
|
||
- 强大的通用参数验证机制
|
||
- 全局统一异常处理
|
||
- 响应式编程模型
|
||
|
||
## 技术栈
|
||
|
||
- Apache Camel 4.11.0
|
||
- camel-vertx-http:Camel与Vert.x HTTP集成
|
||
- camel-rest:Camel REST DSL支持
|
||
- camel-jackson:JSON序列化支持
|
||
- Vert.x 4.5.14(核心组件)
|
||
- MyBatis 3.5.19
|
||
- PostgreSQL
|
||
- HikariCP
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
src/main/java/com/example/
|
||
├── config/ # 配置类
|
||
│ ├── AppConfig.java # 应用配置
|
||
│ └── DatabaseConfig.java # 数据库配置
|
||
├── exception/ # 异常类
|
||
│ ├── ApiException.java # 异常基类
|
||
│ ├── BusinessException.java # 业务异常
|
||
│ ├── GlobalExceptionHandler.java # 全局异常处理器
|
||
│ ├── ResourceNotFoundException.java # 资源未找到异常
|
||
│ └── ValidationException.java # 验证异常
|
||
├── route/ # Camel路由和REST定义
|
||
│ └── UserRoute.java # 用户API路由和数据库操作
|
||
├── validation/ # 参数验证
|
||
│ ├── RequestValidator.java # 通用验证器
|
||
│ └── ValidationExample.java # 验证器使用示例
|
||
└── Application.java # 主应用类
|
||
```
|
||
|
||
## 代码优化
|
||
|
||
本项目采用了以下优化策略减少代码量并提高开发效率:
|
||
|
||
1. **扁平化结构**:移除传统的Service层,将数据库操作直接集成到路由处理中
|
||
2. **直接使用MyBatis**:在路由处理器中直接使用SqlSession进行数据库操作
|
||
3. **链式验证API**:简化参数验证,通过链式调用提高代码可读性
|
||
4. **纯XML映射**:不使用Java实体类和Mapper接口,完全依赖XML配置减少代码量
|
||
|
||
## 全局异常处理
|
||
|
||
项目实现了统一的全局异常处理机制,可以处理多种类型的异常:
|
||
|
||
```java
|
||
// 配置全局异常处理
|
||
GlobalExceptionHandler exceptionHandler = new GlobalExceptionHandler();
|
||
|
||
// 处理各种异常类型
|
||
onException(ValidationException.class)
|
||
.handled(true)
|
||
.process(exceptionHandler);
|
||
|
||
onException(ResourceNotFoundException.class)
|
||
.handled(true)
|
||
.process(exceptionHandler);
|
||
|
||
onException(BusinessException.class)
|
||
.handled(true)
|
||
.process(exceptionHandler);
|
||
|
||
onException(SecurityException.class)
|
||
.handled(true)
|
||
.process(exceptionHandler);
|
||
|
||
onException(TimeoutException.class)
|
||
.handled(true)
|
||
.process(exceptionHandler);
|
||
```
|
||
|
||
### 支持的异常类型
|
||
|
||
- **ValidationException**: 参数验证失败
|
||
- **ResourceNotFoundException**: 资源未找到
|
||
- **BusinessException**: 业务逻辑错误
|
||
- **SecurityException**: 安全/权限错误
|
||
- **TimeoutException**: 操作超时
|
||
- **IllegalArgumentException**: 参数错误
|
||
- 其他未捕获的异常
|
||
|
||
### 错误响应格式
|
||
|
||
```json
|
||
{
|
||
"error": true,
|
||
"status": 400,
|
||
"message": "用户数据验证失败",
|
||
"errors": {
|
||
"username": ["用户名不能为空"],
|
||
"email": ["邮箱格式不正确"]
|
||
}
|
||
}
|
||
```
|
||
|
||
## API 端点
|
||
|
||
| 方法 | URL | 描述 |
|
||
|--------|-----------------------|---------------------|
|
||
| GET | /api/users | 获取所有用户 |
|
||
| GET | /api/users/page?page=1&size=10 | 分页获取用户|
|
||
| GET | /api/users/{id} | 根据ID获取用户 |
|
||
| POST | /api/users | 创建新用户 |
|
||
| PUT | /api/users/{id} | 更新用户 |
|
||
| DELETE | /api/users/{id} | 删除用户 |
|
||
|
||
## 通用参数验证
|
||
|
||
项目实现了强大的通用参数验证机制,支持链式调用和多种验证规则:
|
||
|
||
```java
|
||
// 链式调用验证示例
|
||
RequestValidator.validate()
|
||
.field("username", json.getString("username", ""))
|
||
.notEmpty("用户名不能为空")
|
||
.length(3, 50, "用户名长度必须在3-50个字符之间")
|
||
|
||
.field("email", json.getString("email", ""))
|
||
.notEmpty("邮箱不能为空")
|
||
.email("邮箱格式不正确")
|
||
|
||
.field("password", json.getString("password", ""))
|
||
.notEmpty("密码不能为空")
|
||
.passwordStrength("密码必须至少8位,包含大小写字母、数字和特殊字符")
|
||
|
||
// 自定义验证规则
|
||
.field("confirmPassword", json.getString("confirmPassword", ""))
|
||
.notEmpty("确认密码不能为空")
|
||
.custom(value -> value.equals(json.getString("password", "")), "两次输入的密码不一致")
|
||
|
||
.validate("验证失败");
|
||
```
|
||
|
||
### 内置验证规则
|
||
|
||
- `notEmpty`: 非空验证
|
||
- `length`: 长度范围验证
|
||
- `email`: 电子邮箱格式验证
|
||
- `phone`: 手机号格式验证
|
||
- `passwordStrength`: 密码复杂度验证
|
||
- `idCard`: 身份证号验证
|
||
- `matches`: 正则表达式匹配
|
||
- `custom`: 自定义验证规则
|
||
|
||
## Camel路由
|
||
|
||
本项目使用Camel的REST DSL来定义API端点,并使用Direct组件(direct:xxx)处理具体业务逻辑。主要路由包括:
|
||
|
||
- direct:getAllUsers - 获取所有用户
|
||
- direct:getUsersByPage - 分页获取用户
|
||
- direct:getUserById - 根据ID获取用户
|
||
- direct:createUser - 创建用户
|
||
- direct:updateUser - 更新用户
|
||
- direct:deleteUser - 删除用户
|
||
|
||
## 快速开始
|
||
|
||
### 前提条件
|
||
|
||
- JDK 17+
|
||
- Maven 3.6+
|
||
- PostgreSQL
|
||
|
||
### 数据库设置
|
||
|
||
1. 创建PostgreSQL数据库:
|
||
|
||
```sql
|
||
CREATE DATABASE userdb;
|
||
```
|
||
|
||
2. 运行初始化脚本 `src/main/resources/db/init.sql`
|
||
|
||
### 构建和运行
|
||
|
||
```bash
|
||
# 克隆项目
|
||
git clone <repository-url>
|
||
cd camel-vertx-demo
|
||
|
||
# 构建
|
||
mvn clean package
|
||
|
||
# 运行
|
||
java -jar target/camel-vertx-demo-1.0-SNAPSHOT.jar
|
||
```
|
||
|
||
## 配置
|
||
|
||
应用程序配置在 `src/main/resources/application.properties` 文件中:
|
||
|
||
```properties
|
||
# 服务器配置
|
||
server.port=8080
|
||
server.host=localhost
|
||
|
||
# 数据库配置
|
||
db.host=localhost
|
||
db.port=5432
|
||
db.name=userdb
|
||
db.username=postgres
|
||
db.password=postgres
|
||
db.pool.maxSize=10
|
||
```
|
||
|
||
## 与Camel集成的优势
|
||
|
||
- **声明式路由定义**: 使用Camel REST DSL可以更清晰地定义API端点
|
||
- **强大的错误处理机制**: Camel提供了丰富的异常处理功能
|
||
- **组件化设计**: 可以轻松集成其他Camel组件(如JMS、AMQP等)
|
||
- **更高层次的抽象**: 减少样板代码,专注于业务逻辑
|
||
|
||
## 角色管理API接口
|
||
|
||
### 1. 获取所有角色
|
||
|
||
**请求**
|
||
|
||
```
|
||
GET /api/roles
|
||
```
|
||
|
||
**响应**
|
||
|
||
```json
|
||
{
|
||
"roles": [
|
||
{
|
||
"id": 1,
|
||
"name": "管理员",
|
||
"code": "ADMIN",
|
||
"description": "系统管理员,拥有所有权限",
|
||
"createdAt": "2023-07-15T10:30:20.123Z",
|
||
"updatedAt": "2023-07-15T10:30:20.123Z"
|
||
},
|
||
{
|
||
"id": 2,
|
||
"name": "普通用户",
|
||
"code": "USER",
|
||
"description": "普通用户,拥有基本权限",
|
||
"createdAt": "2023-07-15T10:30:20.123Z",
|
||
"updatedAt": "2023-07-15T10:30:20.123Z"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 2. 分页获取角色
|
||
|
||
**请求**
|
||
|
||
```
|
||
GET /api/roles/page?page=1&size=10
|
||
```
|
||
|
||
**参数说明**
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 | 默认值 |
|
||
|--------|--------|------|--------------------------|--------|
|
||
| page | int | 否 | 页码,从1开始 | 1 |
|
||
| size | int | 否 | 每页大小,最大值为100 | 10 |
|
||
|
||
**响应**
|
||
|
||
```json
|
||
{
|
||
"content": [
|
||
{
|
||
"id": 1,
|
||
"name": "管理员",
|
||
"code": "ADMIN",
|
||
"description": "系统管理员,拥有所有权限",
|
||
"createdAt": "2023-07-15T10:30:20.123Z",
|
||
"updatedAt": "2023-07-15T10:30:20.123Z"
|
||
},
|
||
{
|
||
"id": 2,
|
||
"name": "普通用户",
|
||
"code": "USER",
|
||
"description": "普通用户,拥有基本权限",
|
||
"createdAt": "2023-07-15T10:30:20.123Z",
|
||
"updatedAt": "2023-07-15T10:30:20.123Z"
|
||
}
|
||
],
|
||
"page": 1,
|
||
"size": 10,
|
||
"total": 5,
|
||
"totalPages": 1
|
||
}
|
||
```
|
||
|
||
### 3. 根据ID获取角色
|
||
|
||
**请求**
|
||
|
||
```
|
||
GET /api/roles/{id}
|
||
```
|
||
|
||
**参数说明**
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|--------|------|------------|
|
||
| id | long | 是 | 角色ID |
|
||
|
||
**响应**
|
||
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"name": "管理员",
|
||
"code": "ADMIN",
|
||
"description": "系统管理员,拥有所有权限",
|
||
"createdAt": "2023-07-15T10:30:20.123Z",
|
||
"updatedAt": "2023-07-15T10:30:20.123Z"
|
||
}
|
||
```
|
||
|
||
### 4. 创建角色
|
||
|
||
**请求**
|
||
|
||
```
|
||
POST /api/roles
|
||
Content-Type: application/json
|
||
```
|
||
|
||
**请求体**
|
||
|
||
```json
|
||
{
|
||
"name": "运营管理员",
|
||
"code": "OPERATION_ADMIN",
|
||
"description": "负责内容运营和审核的管理员"
|
||
}
|
||
```
|
||
|
||
**参数说明**
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|-------------|--------|------|-------------------------------------|
|
||
| name | string | 是 | 角色名称,长度在2-50个字符之间 |
|
||
| code | string | 是 | 角色编码,大写字母和下划线组合,长度在2-50个字符之间 |
|
||
| description | string | 否 | 角色描述 |
|
||
|
||
**响应**
|
||
|
||
```json
|
||
{
|
||
"id": 6,
|
||
"name": "运营管理员",
|
||
"code": "OPERATION_ADMIN",
|
||
"description": "负责内容运营和审核的管理员",
|
||
"createdAt": "2023-07-15T10:30:20.123Z",
|
||
"updatedAt": "2023-07-15T10:30:20.123Z"
|
||
}
|
||
```
|
||
|
||
### 5. 更新角色
|
||
|
||
**请求**
|
||
|
||
```
|
||
PUT /api/roles/{id}
|
||
Content-Type: application/json
|
||
```
|
||
|
||
**参数说明**
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|--------|------|------------|
|
||
| id | long | 是 | 角色ID |
|
||
|
||
**请求体**
|
||
|
||
```json
|
||
{
|
||
"name": "运营总监",
|
||
"code": "OPERATION_DIRECTOR",
|
||
"description": "负责全站内容运营和审核的管理员"
|
||
}
|
||
```
|
||
|
||
**参数说明**
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|-------------|--------|------|-------------------------------------|
|
||
| name | string | 是 | 角色名称,长度在2-50个字符之间 |
|
||
| code | string | 是 | 角色编码,大写字母和下划线组合,长度在2-50个字符之间 |
|
||
| description | string | 否 | 角色描述 |
|
||
|
||
**响应**
|
||
|
||
```json
|
||
{
|
||
"id": 6,
|
||
"name": "运营总监",
|
||
"code": "OPERATION_DIRECTOR",
|
||
"description": "负责全站内容运营和审核的管理员",
|
||
"createdAt": "2023-07-15T10:30:20.123Z",
|
||
"updatedAt": "2023-07-15T11:25:15.456Z"
|
||
}
|
||
```
|
||
|
||
### 6. 删除角色
|
||
|
||
**请求**
|
||
|
||
```
|
||
DELETE /api/roles/{id}
|
||
```
|
||
|
||
**参数说明**
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|--------|------|------------|
|
||
| id | long | 是 | 角色ID |
|
||
|
||
**响应**
|
||
|
||
```
|
||
状态码: 204 No Content
|
||
```
|
||
|
||
### 错误响应
|
||
|
||
#### 验证错误 (400 Bad Request)
|
||
|
||
```json
|
||
{
|
||
"error": true,
|
||
"status": 400,
|
||
"message": "角色数据验证失败",
|
||
"errors": {
|
||
"name": ["角色名称不能为空", "角色名称长度必须在2-50个字符之间"],
|
||
"code": ["角色编码必须是大写字母和下划线组合"]
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 资源不存在 (404 Not Found)
|
||
|
||
```json
|
||
{
|
||
"error": true,
|
||
"status": 404,
|
||
"message": "角色 ID: 999 不存在"
|
||
}
|
||
```
|
||
|
||
#### 服务器错误 (500 Internal Server Error)
|
||
|
||
```json
|
||
{
|
||
"error": true,
|
||
"status": 500,
|
||
"message": "服务器内部错误,请稍后重试"
|
||
}
|
||
```
|
||
|
||
## Nacos服务注册集成
|
||
|
||
本项目已集成Nacos服务注册中心,支持服务的自动注册和发现。
|
||
|
||
### 配置Nacos
|
||
|
||
在`application.properties`中配置Nacos相关参数:
|
||
|
||
```properties
|
||
# Nacos服务注册配置
|
||
nacos.server-addr=127.0.0.1:8848
|
||
nacos.service.name=camel-vertx-service
|
||
nacos.service.group=DEFAULT_GROUP
|
||
nacos.namespace=public
|
||
nacos.cluster-name=DEFAULT
|
||
```
|
||
|
||
### 配置说明
|
||
|
||
| 参数名 | 说明 | 默认值 |
|
||
|--------|------|--------|
|
||
| nacos.server-addr | Nacos服务器地址,格式为host:port | 127.0.0.1:8848 |
|
||
| nacos.service.name | 服务名称 | camel-vertx-service |
|
||
| nacos.service.group | 服务分组 | DEFAULT_GROUP |
|
||
| nacos.namespace | 命名空间 | public |
|
||
| nacos.cluster-name | 集群名称 | DEFAULT |
|
||
|
||
### 服务注册
|
||
|
||
服务启动时会自动注册到Nacos服务中心,注册信息包括:
|
||
|
||
- 服务名称:配置文件中的`nacos.service.name`
|
||
- 服务分组:配置文件中的`nacos.service.group`
|
||
- 服务地址:应用程序主机地址和端口
|
||
- 元数据:
|
||
- application.name: camel-vertx-demo
|
||
- version: 1.0.0
|
||
- hostname: 主机名
|
||
- preserved.register.source: CAMEL_VERTX
|
||
|
||
### 服务注销
|
||
|
||
应用程序关闭时会自动从Nacos注销服务。
|
||
|
||
### Nacos心跳机制
|
||
|
||
Nacos客户端会自动为注册的实例创建和维护心跳,确保服务的健康状态被正确报告到Nacos服务器。心跳机制的主要配置参数包括:
|
||
|
||
```properties
|
||
# Nacos心跳配置
|
||
nacos.naming.client.beat.thread.count=1 # 心跳线程数
|
||
nacos.naming.client.beat.interval=5000 # 心跳间隔,单位毫秒
|
||
nacos.naming.client.max.retry.times=3 # 最大重试次数
|
||
nacos.naming.client.timeout=3000 # 请求超时时间,单位毫秒
|
||
```
|
||
|
||
心跳机制工作流程:
|
||
|
||
1. 服务实例注册后,Nacos客户端会自动创建心跳任务
|
||
2. 客户端按照配置的间隔周期性地向Nacos服务器发送心跳包
|
||
3. 如果心跳发送失败,客户端会重试,最多重试配置的次数
|
||
4. 如果Nacos服务器在一定时间内未收到心跳,会将该实例标记为不健康
|
||
|
||
您可以通过以下方法检查服务的健康状态:
|
||
|
||
```java
|
||
boolean isHealthy = NacosConfig.isServiceHealthy("camel-vertx-service");
|
||
if (isHealthy) {
|
||
logger.info("服务健康状态正常");
|
||
} else {
|
||
logger.warn("服务可能不健康,请检查");
|
||
}
|
||
```
|
||
|
||
### 手动启动Nacos服务器
|
||
|
||
在使用本应用前,请确保Nacos服务器已经启动。如果没有安装Nacos,可以按照以下步骤快速启动:
|
||
|
||
1. 下载Nacos服务器: [https://github.com/alibaba/nacos/releases](https://github.com/alibaba/nacos/releases)
|
||
2. 解压下载的压缩包
|
||
3. 启动服务器:
|
||
- Windows: 执行 `bin\startup.cmd -m standalone`
|
||
- Linux/Mac: 执行 `sh bin/startup.sh -m standalone`
|
||
4. 访问控制台: [http://localhost:8848/nacos](http://localhost:8848/nacos) (默认用户名/密码: nacos/nacos)
|
||
|
||
### 服务发现
|
||
|
||
其他服务可以通过Nacos API发现并调用本服务:
|
||
|
||
```java
|
||
// 获取命名服务
|
||
Properties properties = new Properties();
|
||
properties.setProperty("serverAddr", "127.0.0.1:8848");
|
||
NamingService naming = NacosFactory.createNamingService(properties);
|
||
|
||
// 发现服务实例
|
||
List<Instance> instances = naming.selectInstances("camel-vertx-service", true);
|
||
|
||
// 使用服务实例
|
||
if (!instances.isEmpty()) {
|
||
Instance instance = instances.get(0);
|
||
String url = "http://" + instance.getIp() + ":" + instance.getPort() + "/api/users";
|
||
// 使用该URL调用服务
|
||
}
|
||
```
|
||
|
||
## 后续扩展
|
||
|
||
本项目可以进一步扩展以支持更多功能:
|
||
|
||
1. 集成Spring Cloud Alibaba,实现与Spring Cloud生态的无缝对接
|
||
2. 添加Nacos配置中心功能,实现配置的集中管理和动态更新
|
||
3. 集成Sentinel进行服务限流和熔断
|
||
4. 添加OpenAPI/Swagger支持,自动生成API文档 |