15 KiB
15 KiB
Camel Vert.x RESTful API 演示
这是一个使用Apache Camel和Vert.x开发的响应式RESTful API示例项目,采用MyBatis与PostgreSQL进行数据访问。本项目充分利用Camel REST DSL来实现API端点,避免直接使用Vert.x Router。
特性
- 使用Apache Camel最新版本(4.4.0)结合Vert.x构建响应式API
- 充分使用Camel REST DSL定义RESTful API端点
- 使用MyBatis纯XML方式进行数据库操作,无实体类和Mapper接口
- 扁平化结构设计,无Service层,减少代码量
- 完整的用户CRUD操作和分页查询
- 强大的通用参数验证机制
- 全局统一异常处理
- 响应式编程模型
技术栈
- Apache Camel 4.4.0
- camel-vertx-http:Camel与Vert.x HTTP集成
- camel-rest:Camel REST DSL支持
- camel-jackson:JSON序列化支持
- Vert.x 4.5.1(核心组件)
- MyBatis 3.5.15
- 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 # 主应用类
代码优化
本项目采用了以下优化策略减少代码量并提高开发效率:
- 扁平化结构:移除传统的Service层,将数据库操作直接集成到路由处理中
- 直接使用MyBatis:在路由处理器中直接使用SqlSession进行数据库操作
- 链式验证API:简化参数验证,通过链式调用提高代码可读性
- 纯XML映射:不使用Java实体类和Mapper接口,完全依赖XML配置减少代码量
全局异常处理
项目实现了统一的全局异常处理机制,可以处理多种类型的异常:
// 配置全局异常处理
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: 参数错误
- 其他未捕获的异常
错误响应格式
{
"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} | 删除用户 |
通用参数验证
项目实现了强大的通用参数验证机制,支持链式调用和多种验证规则:
// 链式调用验证示例
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
数据库设置
- 创建PostgreSQL数据库:
CREATE DATABASE userdb;
- 运行初始化脚本
src/main/resources/db/init.sql
构建和运行
# 克隆项目
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
文件中:
# 服务器配置
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
响应
{
"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 |
响应
{
"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 |
响应
{
"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
请求体
{
"name": "运营管理员",
"code": "OPERATION_ADMIN",
"description": "负责内容运营和审核的管理员"
}
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
name | string | 是 | 角色名称,长度在2-50个字符之间 |
code | string | 是 | 角色编码,大写字母和下划线组合,长度在2-50个字符之间 |
description | string | 否 | 角色描述 |
响应
{
"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 |
请求体
{
"name": "运营总监",
"code": "OPERATION_DIRECTOR",
"description": "负责全站内容运营和审核的管理员"
}
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
name | string | 是 | 角色名称,长度在2-50个字符之间 |
code | string | 是 | 角色编码,大写字母和下划线组合,长度在2-50个字符之间 |
description | string | 否 | 角色描述 |
响应
{
"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)
{
"error": true,
"status": 400,
"message": "角色数据验证失败",
"errors": {
"name": ["角色名称不能为空", "角色名称长度必须在2-50个字符之间"],
"code": ["角色编码必须是大写字母和下划线组合"]
}
}
资源不存在 (404 Not Found)
{
"error": true,
"status": 404,
"message": "角色 ID: 999 不存在"
}
服务器错误 (500 Internal Server Error)
{
"error": true,
"status": 500,
"message": "服务器内部错误,请稍后重试"
}
Nacos服务注册集成
本项目已集成Nacos服务注册中心,支持服务的自动注册和发现。
配置Nacos
在application.properties
中配置Nacos相关参数:
# 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服务器。心跳机制的主要配置参数包括:
# 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 # 请求超时时间,单位毫秒
心跳机制工作流程:
- 服务实例注册后,Nacos客户端会自动创建心跳任务
- 客户端按照配置的间隔周期性地向Nacos服务器发送心跳包
- 如果心跳发送失败,客户端会重试,最多重试配置的次数
- 如果Nacos服务器在一定时间内未收到心跳,会将该实例标记为不健康
您可以通过以下方法检查服务的健康状态:
boolean isHealthy = NacosConfig.isServiceHealthy("camel-vertx-service");
if (isHealthy) {
logger.info("服务健康状态正常");
} else {
logger.warn("服务可能不健康,请检查");
}
手动启动Nacos服务器
在使用本应用前,请确保Nacos服务器已经启动。如果没有安装Nacos,可以按照以下步骤快速启动:
- 下载Nacos服务器: https://github.com/alibaba/nacos/releases
- 解压下载的压缩包
- 启动服务器:
- Windows: 执行
bin\startup.cmd -m standalone
- Linux/Mac: 执行
sh bin/startup.sh -m standalone
- Windows: 执行
- 访问控制台: http://localhost:8848/nacos (默认用户名/密码: nacos/nacos)
服务发现
其他服务可以通过Nacos API发现并调用本服务:
// 获取命名服务
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调用服务
}
后续扩展
本项目可以进一步扩展以支持更多功能:
- 集成Spring Cloud Alibaba,实现与Spring Cloud生态的无缝对接
- 添加Nacos配置中心功能,实现配置的集中管理和动态更新
- 集成Sentinel进行服务限流和熔断
- 添加OpenAPI/Swagger支持,自动生成API文档