2025-05-07 16:29:45 +08:00
2025-05-07 16:29:45 +08:00
2025-05-07 16:29:45 +08:00
2025-05-07 17:08:25 +08:00

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.11.0
    • camel-vertx-httpCamel与Vert.x HTTP集成
    • camel-restCamel REST DSL支持
    • camel-jacksonJSON序列化支持
  • 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配置减少代码量

全局异常处理

项目实现了统一的全局异常处理机制,可以处理多种类型的异常:

// 配置全局异常处理
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

数据库设置

  1. 创建PostgreSQL数据库:
CREATE DATABASE userdb;
  1. 运行初始化脚本 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          # 请求超时时间,单位毫秒

心跳机制工作流程:

  1. 服务实例注册后Nacos客户端会自动创建心跳任务
  2. 客户端按照配置的间隔周期性地向Nacos服务器发送心跳包
  3. 如果心跳发送失败,客户端会重试,最多重试配置的次数
  4. 如果Nacos服务器在一定时间内未收到心跳会将该实例标记为不健康

您可以通过以下方法检查服务的健康状态:

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
  2. 解压下载的压缩包
  3. 启动服务器:
    • Windows: 执行 bin\startup.cmd -m standalone
    • Linux/Mac: 执行 sh bin/startup.sh -m standalone
  4. 访问控制台: 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调用服务
}

后续扩展

本项目可以进一步扩展以支持更多功能:

  1. 集成Spring Cloud Alibaba实现与Spring Cloud生态的无缝对接
  2. 添加Nacos配置中心功能实现配置的集中管理和动态更新
  3. 集成Sentinel进行服务限流和熔断
  4. 添加OpenAPI/Swagger支持自动生成API文档
Description
使用camel 4.11.0、vertx、mybatis和postgres,集成nacos验证测试版,使用camelmain启动
Readme 79 KiB
Languages
Java 100%