ABAP oData Service

ABAP oData Service

🎯 概述

本文介绍SAP后端系统基于数据结构创建==OData服务==的过程。OData(Open Data Protocol)是一种标准化的Web服务协议,用于对数据进行CRUD(创建、读取、更新、删除)操作。



graph TD
    A[创建OData服务流程] --> B["1. 创建数据字典<br>结构"]
    B --> C["2. 创建Gateway<br>服务项目(SEGW)"]
    C --> D["3. 创建Data Model<br>(Entity/EntitySet)"]
    D --> E["4. Generate<br>Runtime Objects"]
    E --> F["5. 服务注册"]
    F --> G["6. 实现CRUD方法"]
    G --> H["7. 测试服务"]

📋 创建Gateway Service Project

事务码:SEGW

Gateway Service Project分为四个部分:

组成部分 说明
==Data Model== 数据模型,包括Entity type、Entity set和Association
==Service Implementation== Entity set的CRUD实现
==Runtime Artifacts== 基于Entity set的代码框架
==Service maintenance== 注册服务、测试服务

🏗️ 创建Data Model

创建Entity

  1. 选中Data Model,右键 → Import → DDIC Structure
  2. 输入Entity Name以及数据表结构(如 ZRICO_USR
  3. 勾选 ==Create Default entity set== 自动创建Entity set
  4. 选中所有字段,点击 NEXT
  5. 选择主键字段(如 MANDT、USRID),Name值首字符需大写
  6. 点击 Finish

调整Entity Sets

设置Entity集合的CRUD操作权限。

💡 Generate Runtime Objects

  1. 选中项目名,右键 → Generate Runtime
  2. 保持所有值默认,点击 Continue
  3. 系统自动生成Runtime objects

🔍 服务注册

  1. 在 Service Maintenance 下可以看到已创建的Gateway Service别名
  2. 此时 Register Status ==没有状态==,点击 ==Register== 按钮
  3. 选择系统别名 ==LOCAL==
  4. 确认后完成服务注册,状态已改变

📋 测试OData Service

浏览器测试

点击 Maintain 进入激活并维护服务界面,调用浏览器测试。

⚠️浏览器测试可能的问题
问题1:主机名或端口未配置
使用事务码 SMICM → Goto → Services,检查主机和端口是否配置好。

问题2:无法通过Internet访问
需要设置本机 hosts 文件:C:\Windows\System32\drivers\etc

Gateway客户端测试

使用事务代码 /N/IWFND/GW_CLIENT 进行测试。

💡事务码注意
输入事务码时需要加 /O 前缀,如 /O/IWFND/MAINT_SERVICE/O/IWFND/GW_CLIENT

🏗️ 服务实现(CRUD)

服务实现是提供CRUD的具体实现。SAP把读取Entity叫做 ==Read==,读取EntitySet叫做 ==Query==。



graph LR
    A[CRUD操作] --> B["Query<br>GetEntitySet"]
    A --> C["Read<br>GetEntity"]
    A --> D["Create"]
    A --> E["Update"]
    A --> F["Delete"]

Query重定义(GetEntitySet)

选中 GetEntitySet(Query),右键 → Go to ABAP Workbench:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
METHOD zusrset_get_entityset.
DATA: lt_usr TYPE TABLE OF zrico_usr.

" 查询数据
SELECT * FROM zrico_usr INTO TABLE lt_usr.

" 转换数据格式
et_entityset = VALUE #(
FOR ls_usr IN lt_usr (
mandt = ls_usr-mandt
usrid = ls_usr-usrid
name = ls_usr-name
email = ls_usr-email
created_at = ls_usr-created_at
)
).
ENDMETHOD.
ℹ️ET_ENTITYSET
ET_ENTITYSET 是类方法预设的参数,基于ZRICO_USR内表结构。

Read重定义(GetEntity)

选中 GetEntity(Read),进入ABAP工作台:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
METHOD zusrset_get_entity.
DATA: ls_usr TYPE zrico_usr.
DATA: ls_entity TYPE zcl_zrico_stru_usr_mpc=>ts_zuser.

" 根据主键查询数据
SELECT SINGLE * FROM zrico_usr
WHERE mandt = is_entity_key-mandt
AND usrid = is_entity_key-usrid
INTO @ls_usr.

IF sy-subrc = 0.
ls_entity-mandt = ls_usr-mandt.
ls_entity-usrid = ls_usr-usrid.
ls_entity-name = ls_usr-name.
ls_entity-email = ls_usr-email.
ls_entity-created_at = ls_usr-created_at.

es_entity = ls_entity.
ENDIF.
ENDMETHOD.

Postman测试地址:

1
http://XXX.XXXXXXXXX.com:8000/sap/opu/odata/sap/ZRICO_STRU_USR_SRV/ZUSERSet(Mandt='300',Usrid='1')?$format=json

Create重定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
METHOD zusrset_create_entity.
DATA: ls_usr TYPE zrico_usr.
DATA: ls_entity LIKE er_entity.

" 转换实体数据到内部表结构
ls_usr-mandt = is_entity-mandt.
ls_usr-usrid = is_entity-usrid.
ls_usr-name = is_entity-name.
ls_usr-email = is_entity-email.
ls_usr-created_at = sy-datum.
ls_usr-created_by = sy-uname.

" 插入数据
INSERT zrico_usr FROM ls_usr.
IF sy-subrc = 0.
es_entity = is_entity. " 返回创建的实体
ENDIF.
ENDMETHOD.
CSRF Token
Postman测试Create服务前,必须先通过GET请求获取CSRF Token:
1
Headers: KEY = X-CSRF-Token, VALUE = Fetch

获取Token后在后续POST请求中使用。

Update重定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
METHOD zusrset_update_entity.
DATA: ls_usr TYPE zrico_usr.
DATA: ls_entity LIKE is_entity.

" 转换实体数据
ls_entity = is_entity.
ls_usr-mandt = ls_entity-mandt.
ls_usr-usrid = ls_entity-usrid.
ls_usr-name = ls_entity-name.
ls_usr-email = ls_entity-email.
ls_usr-changed_at = sy-datum.
ls_usr-changed_by = sy-uname.

" 更新数据
UPDATE zrico_usr FROM ls_usr.
ENDMETHOD.

使用 PUT 或 MERGE 方式发送更新请求。

Delete重定义

1
2
3
4
5
6
METHOD zusrset_delete_entity.
" 根据主键删除数据
DELETE FROM zrico_usr
WHERE mandt = is_entity_key-mandt
AND usrid = is_entity_key-usrid.
ENDMETHOD.

使用 DELETE 方式发送删除请求。

💡 Function Import函数导入

如果操作不适合CRUD方案,可以通过==函数导入==来执行自定义操作。

创建Function Import

  1. 选中 DataModel,右键 → Create → Function Import
  2. 输入导入名称(如 UserByName
  3. 设置参数:
参数
Return type Entity type: ZUSER
Return Cardinality 0…n(返回实体集合)
HTTP GET

创建导入参数

双击 Function Import Parameters,创建参数:UsrName,类型 Edm.String

重定义Function Import方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
METHOD zusrset_userbyname.
DATA: lt_usr TYPE TABLE OF zrico_usr.
DATA: ls_entity TYPE zcl_zrico_stru_usr_mpc=>ts_zuser.

" 根据用户名查询
SELECT * FROM zrico_usr
WHERE name = iv_usname
INTO TABLE @lt_usr.

" 转换数据格式
et_entityset = VALUE #(
FOR ls_usr IN lt_usr (
mandt = ls_usr-mandt
usrid = ls_usr-usrid
name = ls_usr-name
email = ls_usr-email
created_at = ls_usr-created_at
)
).
ENDMETHOD.

Postman测试:

1
http://XXX.XXXXX.com:8000/sap/opu/odata/sap/ZRICO_STRU_USR_SRV/UserByName?UsrName='12'

🔍 常见问题解决

问题 解决方案
登录错误 删除Cookies重新登录,检查用户权限
CSRF Token失败 Headers中添加 X-CSRF-Token: Fetch
数据格式问题 使用 ?$format=json 获取JSON格式
服务未激活 确保所有方法已激活,检查语法错误

⚠️ 注意事项

  1. 创建服务前确保==数据字典结构==已定义
  2. Postman测试需要先获取==CSRF Token==
  3. 方法实现后必须==激活==才能生效
  4. URI中的参数需要==区分大小写==
  5. 建议使用 ?$format=json 获取JSON格式数据