这是一个使用 Java 和 Apache Olingo 实现的 OData 服务示例项目,包含详细的中文注释,帮助理解 OData 的核心概念。
OData(Open Data Protocol,开放数据协议)是一种基于 REST 的协议,用于构建和使用数据 API。
-
Entity Type(实体类型)
- 定义数据的结构,类似于数据库中的表结构
- 例如:Car 实体类型定义了汽车的数据结构
-
Entity Set(实体集)
- 实体类型的集合,类似于数据库中的表
- 例如:Cars 实体集包含多个 Car 实体
-
Property(属性)
- 实体的字段,如 Car 的 id、model、manufacturer 等
-
Key(键)
- 唯一标识实体的属性,如 Car 的 id
-
EDM(Entity Data Model,实体数据模型)
- OData 的元数据模型,描述了服务的数据结构
- 客户端可以通过
/$metadata端点获取 EDM 定义
odata/
├── pom.xml # Maven 配置文件
├── README.md # 项目说明文档
└── src/
└── main/
├── java/
│ └── com/
│ └── odata/
│ └── demo/
│ ├── model/
│ │ └── Car.java # 实体模型类
│ ├── provider/
│ │ └── CarEdmProvider.java # EDM 元数据提供者
│ ├── processor/
│ │ ├── CarEntityCollectionProcessor.java # 实体集合处理器
│ │ ├── CarEntityProcessor.java # 实体处理器
│ │ └── CarPrimitiveProcessor.java # 原始值处理器
│ ├── service/
│ │ └── CarService.java # 业务逻辑层
│ ├── servlet/
│ │ └── ODataServlet.java # Servlet 入口
│ └── util/
│ └── ODataUtil.java # 工具类
└── webapp/
└── WEB-INF/
└── web.xml # Web 应用配置(可选)
- Java 8+ - 编程语言
- Apache Olingo 4.7.1 - OData 服务实现库
- Maven 3.x - 项目构建工具
- Servlet API 3.1+ - Web 服务 API
- Jetty - 嵌入式 Web 服务器(用于测试)
- JDK 8 或更高版本
- Maven 3.x
mvn clean compile使用 Jetty Maven 插件运行:
mvn jetty:run服务将在 http://localhost:8080 启动。
GET http://localhost:8080/odata/$metadata
返回服务的 EDM 元数据定义(XML 格式)。
重要说明:
- 根据 OData V4 规范,
$metadata端点主要支持 XML 格式 - JSON 格式的元数据在 OData V4 中并不是标准格式
- 如果请求 JSON 格式,Apache Olingo 可能返回服务文档(Service Document)而不是元数据文档
- 服务文档只包含实体集的列表,不包含完整的元数据信息(实体类型、属性定义等)
- 因此,
$metadata端点始终返回 XML 格式,确保返回完整的元数据信息
XML 格式的元数据包含:
- 实体类型定义(Entity Type)
- 属性定义(Property)
- 键定义(Key)
- 实体集定义(Entity Set)
- 命名空间(Namespace)
如果需要 JSON 格式的数据,请使用数据端点:
GET /odata/Cars- 返回 JSON 格式的汽车数据GET /odata/Cars('1')- 返回 JSON 格式的单个汽车数据
GET http://localhost:8080/odata/Cars
返回所有汽车的 JSON 数据。
注意:
- 浏览器直接访问时,默认返回 JSON 格式(已配置)
- 如果使用工具(如 Postman),可以通过设置
Accept: application/json明确指定 JSON 格式 - 如果设置
Accept: application/xml,则返回 XML 格式
GET http://localhost:8080/odata/Cars('1')
返回 ID 为 '1' 的汽车的 JSON 数据。
响应格式说明:
- 默认返回 JSON 格式(当 Accept 头为
*/*或未指定时) - 可以通过设置
Accept: application/json明确请求 JSON 格式 - 可以通过设置
Accept: application/xml请求 XML 格式
前端和 RESTful API 使用:
- ✅ 可以直接使用:OData URL 格式完全符合 RESTful 规范
- ✅ 前端使用:JavaScript、React、Vue 等都可以直接调用
- ✅ RESTful API 调用:curl、Postman、HttpClient 等都支持
- 📖 详细使用指南:请参考 FRONTEND_USAGE.md
快速示例:
// JavaScript / React
fetch("http://localhost:8080/odata/Cars('1')")
.then(response => response.json())
.then(data => console.log(data));
// 使用 axios
axios.get("http://localhost:8080/odata/Cars('1')")
.then(response => console.log(response.data));GET http://localhost:8080/odata/Cars('1')/Model
返回 ID 为 '1' 的汽车的 Model 属性值。
OData 提供了丰富的查询选项,用于过滤、排序、分页等操作。
只返回满足条件的实体:
GET http://localhost:8080/odata/Cars?$filter=manufacturer eq 'Tesla'
支持的运算符:
eq- 等于ne- 不等于gt- 大于ge- 大于等于lt- 小于le- 小于等于and- 逻辑与or- 逻辑或not- 逻辑非
按指定属性排序:
GET http://localhost:8080/odata/Cars?$orderby=price asc
GET http://localhost:8080/odata/Cars?$orderby=price desc
限制返回的记录数和跳过记录数:
GET http://localhost:8080/odata/Cars?$top=5&$skip=2
返回第 3-7 条记录。
只返回指定的属性:
GET http://localhost:8080/odata/Cars?$select=id,model,manufacturer
返回实体总数:
GET http://localhost:8080/odata/Cars/$count
创建新汽车:
POST http://localhost:8080/odata/Cars
Content-Type: application/json
{
"Id": "9",
"Model": "Model X",
"Manufacturer": "Tesla",
"Year": 2023,
"Price": 99990.0,
"Color": "White"
}读取汽车:
GET http://localhost:8080/odata/Cars('1')部分更新汽车(PATCH):
PATCH http://localhost:8080/odata/Cars('1')
Content-Type: application/json
{
"Price": 89990.0
}完全更新汽车(PUT):
PUT http://localhost:8080/odata/Cars('1')
Content-Type: application/json
{
"Id": "1",
"Model": "Model S",
"Manufacturer": "Tesla",
"Year": 2021,
"Price": 89990.0,
"Color": "Red"
}删除汽车:
DELETE http://localhost:8080/odata/Cars('1')定义了 Car 实体类,包含汽车的属性(id、model、manufacturer 等)。
定义了 OData 服务的元数据,包括:
- 实体类型(Entity Type)定义
- 实体集(Entity Set)定义
- 属性(Property)定义
- 键(Key)定义
提供数据的 CRUD 操作和查询功能。
- CarEntityCollectionProcessor: 处理实体集合请求(GET /Cars)
- CarEntityProcessor: 处理单个实体请求(GET /Cars('1')、POST、PATCH、DELETE)
- CarPrimitiveProcessor: 处理属性请求(GET /Cars('1')/Model)
处理所有 OData 请求,初始化 OData 框架,注册处理器。
-
理解 EDM 模型
- EDM 是 OData 的核心,定义了服务的数据结构
- 通过
CarEdmProvider了解如何定义实体类型和实体集
-
理解请求处理流程
- Servlet 接收请求 → 创建 Handler → 调用 Processor → 返回响应
- 通过
ODataServlet了解请求处理流程
-
理解数据转换
- Java 对象(Car)↔ OData Entity
- 通过
ODataUtil了解数据转换方法
-
理解查询选项
- $filter、$orderby、$top、$skip、$select 等
- 通过
CarEntityCollectionProcessor了解查询选项的处理
-
理解 CRUD 操作
- Create、Read、Update、Delete
- 通过
CarEntityProcessor了解 CRUD 操作的实现
-
理解响应格式控制
- OData 服务根据
Accept请求头决定返回 JSON 或 XML - 浏览器默认
Accept: */*,本示例已配置为默认返回 JSON - 使用 Olingo Client 时会自动设置
Accept: application/json
- OData 服务根据
-
添加更多实体类型
- 例如:添加 Owner(车主)实体类型
- 添加 Navigation Property(导航属性)关联 Car 和 Owner
-
实现复杂的查询
- 实现完整的 $filter 解析
- 支持嵌套查询和关联查询
-
添加认证和授权
- 实现 OAuth 2.0 认证
- 实现基于角色的访问控制
-
连接真实数据库
- 使用 JPA/Hibernate 连接数据库
- 实现数据持久化
答案:✅ 完全可以!
OData URL 格式(如 Cars('1'))完全符合 RESTful 规范,可以:
-
前端直接使用
- JavaScript、TypeScript、React、Vue、Angular 等都支持
- 使用
fetch、axios等 HTTP 客户端即可 - 注意 URL 中的单引号在 JavaScript 字符串中需要转义
-
RESTful API 调用
- curl、Postman、HttpClient、requests(Python)等都支持
- 标准的 HTTP GET/POST/PUT/DELETE 请求
- 完全符合 RESTful API 规范
详细使用指南和代码示例请参考: FRONTEND_USAGE.md
JavaScript:
// 获取单个实体
fetch("http://localhost:8080/odata/Cars('1')")
.then(response => response.json())
.then(data => console.log(data));
// 获取实体集合
fetch("http://localhost:8080/odata/Cars")
.then(response => response.json())
.then(data => console.log(data.value));curl:
curl "http://localhost:8080/odata/Cars('1')"
curl -H "Accept: application/json" "http://localhost:8080/odata/Cars"Python:
import requests
response = requests.get("http://localhost:8080/odata/Cars('1')")
print(response.json())Olingo Server(本项目):
- 作用:提供 OData 服务,接收和处理 OData 请求
- 依赖:
odata-server-core、odata-server-api - 职责:定义 EDM 元数据、处理请求、序列化响应
Olingo Client:
- 作用:调用 OData 服务,发送请求并解析响应
- 依赖:
odata-client-core、odata-client-api - 职责:构建 OData URL、发送请求、解析响应
- 架构分离:Server 提供数据,Client 消费数据,职责清晰
- 独立部署:可以独立开发、测试、部署
- 避免依赖冲突:Server 不需要 Client 依赖,Client 不需要 Server 依赖
- 微服务架构:符合微服务架构的最佳实践
- 团队协作:不同团队可以并行开发
- ✅ 简化调用:自动构建 URL、处理编码、解析响应
- ✅ 类型安全:提供类型安全的 API
- ✅ 代码复用:封装了 OData 协议的细节
- ✅ 易于维护:统一的调用方式
详细说明和示例代码请参考:
- OLINGO_CLIENT_EXPLANATION.md - 详细的理论说明
- odata-client-demo/ - 完整的客户端示例项目
- OData 官方文档
- Apache Olingo 文档
- OData V4 规范
- 前端使用指南 - 详细的前端和 RESTful API 使用示例
- Olingo Client 说明 - Server vs Client 详细对比
本项目仅用于学习目的。