Mark的技术博客

SAP顾问 | 咨询专家 | IT与AI技术探索者

吴让宇(Mark)

吴让宇(Mark)

SAP顾问 | 咨询专家 | IT与AI技术探索者

吴让宇(Mark)的个人技术博客,专注于SAP系统实施、行业方案咨询、IT技术与AI技术的研究与分享。

SAP Fiori ABAP CDS OData Dify Docker AI LLM

最新文章

单元 2:ABAP 工作台练习(8 道题)

#practice #abap #abap-workbench

相关概念

📌关键模式(点击展开)
Keyword (关键词) Answer (答案)
仓库是特定客户端的吗? 否,跨客户端
两种搜索工具? 仓库信息系统 + 应用层次结构
传输何时触发? 请求被释放时
链式语句? 具有相同开头的多个语句

问题 1 - 仓库属性 [recall]

仓库对象是特定客户端的吗?应用数据呢?

📌显示答案
仓库对象是跨客户端的——可从任何客户端访问。应用数据和配置数据通常是特定客户端的——每条记录属于一个特定的客户端。

问题 2 - 搜索工具 [recall]

说出仓库对象的两种搜索工具及其各自的适用场景。

📌显示答案
  1. 仓库信息系统——用于与应用无关的搜索(例如,某开发者的所有程序、某日期后修改的所有函数模块)
  2. 应用层次结构——用于特定应用的搜索(浏览组件树 → 包 → 对象)

问题 3 - 包规则 [recall]

客户对象可以包含在 SAP 包中吗?

📌显示答案
不可以。 客户对象必须分配到客户包(命名空间以 Y 或 Z 开头)。

问题 4 - 链式语句 [recall]

ABAP 中的链式语句是什么?请举例说明。

📌显示答案
链式语句是一种缩写表示法,用于多个共享相同开头的语句。例如:WRITE: 'Hello', name. 等同于 WRITE 'Hello'. WRITE name.

问题 5 - 激活 [application]

一个开发者保存了程序但没有激活。当另一个用户通过事务代码启动该程序时会发生什么?

📌显示答案
执行的是活动版本(之前激活的 LOAD)。开发者的更改在激活之前对其他用户不可见。只有当开发者在编辑器中按 F8(直接执行)时,才会运行非活动版本(作为临时运行时对象)。

问题 6 - 传输时机 [recall]

开发对象的传输何时触发?

📌显示答案
传输在变更请求被释放时触发(由项目经理操作)。仅仅保存或激活对象不会触发传输。

问题 7 - 对象导航器 [analysis]

解释对象导航器中导航区域和工具区域之间的关系。它们如何同步?

📌显示答案
两个区域独立导航——您可以在导航区域浏览对象而不影响工具区域,反之亦然。同步方式:(1) 在导航区域双击对象 → 在工具区域打开。(2) “显示对象列表” → 在导航树中显示当前工具区域的对象。

问题 8 - 事务类型 [application]

您需要为一个带选择屏幕的可执行程序创建事务。您选择什么事务类型?

📌显示答案
选择 “Program and Selection Screen (Report Transaction)” 作为启动对象。这是可执行程序的适当类型。事务分类应为 “Professional User Transaction”,GUI 支持选择 SAP GUI for Windows。

📌模式总结(点击展开)
Keyword (关键词) Answer (答案)
仓库 跨客户端
两种搜索工具 信息系统 + 应用层次结构
客户对象在 SAP 包中 不可以
链式语句 相同开头,冒号分隔
何时可见? 激活之后
传输触发 请求释放

开发程序与事务 (★★★★)

#abap #abap-workbench

概览表

Concept (概念) Key Point (要点)
包 (Package) 仓库对象的逻辑分组
程序类型 可执行程序(类型 1)、模块池等
事务 启动程序的入口点
激活 将非活动版本变为活动版本
传输 在系统之间移动对象

开发组织

1
2
3
4
5
6
包 (ZBC400_##)
├── 分配到应用组件(如 CA)
├── 分配到软件组件(如 HOME)
└── 对象分配到变更请求
└── 任务(每个开发者一个)
└── 开发者释放任务 → 项目经理释放请求

程序生命周期:活动与非活动

1
2
3
4
5
创建对象 → 保存(非活动版本存在)

激活 ──────────→ 语法检查 → 覆盖活动版本 → 生成运行时对象 (LOAD)

└── F8(直接执行)→ 从非活动版本生成临时运行时对象
⚠️激活与保存的区别
保存仅存储非活动版本。只有激活才能使更改在全系统范围内可见。传输请求中的所有对象在释放之前必须被激活。

创建事务

Transaction Type (事务类型) Start Object (启动对象) Use Case (使用场景)
报表事务 Program and Selection Screen 可执行程序
对话事务 Program and Screen 带屏幕的模块池

创建步骤:

  1. 程序的上下文菜单 → Create → Transaction
  2. 输入事务代码(客户命名空间:Y* 或 Z*)
  3. 选择事务类型和引用程序
  4. 设置 GUI 支持(SAP GUI for Windows)
  5. 保存并分配到包和变更请求

关键 ABAP 语法约定

Convention (约定) Example (示例)
链式语句 WRITE: 'Hello', name.
注释 * 在行首或 " 行内注释
关键字文档 在语句上按 F1 或 i 按钮

传输流程

1
2
3
4
开发者创建/更改对象 → 分配到任务 → 释放任务
→ 项目经理审核 → 释放变更请求
→ 对象导出到传输目录 → 导入到目标系统
→ 副本存储在版本数据库中

考试/测试模式

Scenario/Keyword (场景/关键词) Answer (答案)
“更改何时在全系统范围内可见?” 激活之后
“传输何时触发?” 请求被释放时
“客户对象可以放在 SAP 包中吗?” 不可以——必须放在客户包中
“F8 运行的是哪个版本?” 非活动版本(临时 LOAD)

相关笔记

第 3 单元:基本语言元素练习(10 道题)

#practice #abap #abap-syntax

相关概念

📌关键模式(点击展开)
关键词 答案
数值类型? I, F, P, DECFLOAT16, DECFLOAT34
N 类型是数值类型吗? 不是 — 仅包含数字的字符串
循环计数器? sy-index
MOVE-CORRESPONDING? 复制同名字段

第 1 题 - 数值类型 [recall]

ABAP 标准类型中哪些是数值类型?类型 N 是数值类型吗?

📌显示答案
数值类型:I, F, P, DECFLOAT16, DECFLOAT34。类型 N 不是数值类型 — 它是一种字符串类型,只允许包含数字字符,但不能用于算术运算。

第 2 题 - 类型定义 [recall]

使用哪个 ABAP 关键字来定义局部类型?

📌显示答案
TYPES 语句。示例:TYPES: gty_price TYPE p LENGTH 8 DECIMALS 2.

第 3 题 - 循环计数器 [recall]

DO 和 WHILE 循环的循环计数器在哪个系统字段中?

📌显示答案
DO 和 WHILE 循环都使用 sy-index

第 4 题 - 完整类型与不完整类型 [recall]

哪些 ABAP 标准类型是”完整的”(固定长度),哪些是”不完整的”(需要指定长度)?

📌显示答案
完整类型(固定长度):D, T, I, F, STRING, XSTRING, DECFLOAT16, DECFLOAT34。不完整类型(需指定长度):C, N, X, P

第 5 题 - 常量 [recall]

如何在 ABAP 中定义常量?

📌显示答案
使用 CONSTANTS 语句并配合 VALUE 附加项:CONSTANTS gc_pi TYPE p LENGTH 8 DECIMALS 5 VALUE '3.14159'.

第 6 题 - MOVE-CORRESPONDING [application]

你有两个结构:gs_carrier(字段:carrid, carrname, currcode, url)和 gs_flight(字段:carrid, connid, fldate)。执行 MOVE-CORRESPONDING gs_carrier TO gs_flight 后,哪些字段被复制了?

📌显示答案
只有 carrid 被复制 — 它是两个结构中唯一名称相同的字段。MOVE-CORRESPONDING 只复制源结构和目标结构中名称完全相同的字段。

第 7 题 - 链式语句 [application]

将以下语句转换为链式语句:WRITE 'Hello'. WRITE gv_name. WRITE '!'.

📌显示答案
WRITE: 'Hello', gv_name, '!'.

第 8 题 - 类型转换 [application]

将 C 类型值 ‘42’ 赋值给 I 类型变量时会发生什么?

📌显示答案
ABAP 执行自动类型转换:字符串 ‘42’ 被转换为整数 42。如果 C 类型中包含非数字字符,则会发生运行时错误。

第 9 题 - CASE 与 IF [analysis]

在什么情况下你会使用 CASE 而不是 IF?它们在结构上有什么区别?

📌显示答案
当需要检查单个变量的多个离散值时使用 CASE。CASE 使用 WHEN 子句来匹配每个值。IF/ELSEIF 更适合复杂条件(范围判断、多变量、AND/OR 逻辑)。对于基于值的分支,CASE 更简洁、更易读。

第 10 题 - 调试 [application]

你想调试一个程序但不能修改源代码。如何启动调试器?

📌显示答案
在启动程序之前,在 SAP GUI 命令字段中输入 /h。这会在不做任何代码修改的情况下激活调试模式。另外,如果你有显示权限,可以在编辑器中设置会话断点。

📌模式总结(点击展开)
关键词 答案
数值类型 I, F, P, DECFLOAT16, DECFLOAT34
N 类型 不是数值类型,是包含数字的字符串
局部类型关键字 TYPES
循环计数器 sy-index
MOVE-CORRESPONDING 仅复制同名字段
链式语句 冒号 + 逗号语法
无需代码启动调试 在命令字段中输入 /h

全局类与方法 (★★★★)

#abap #abap-modularization

概览表

概念 要点
包含属性和方法的蓝图
对象/实例 类的具体实现
静态组件 每个程序上下文一个(无需实例化)
实例组件 每个对象一个(需要 CREATE OBJECT)

类与函数组的比较

方面 函数组 全局类
多实例 否(每个上下文一个) (多个对象)
封装性 全局数据隐藏 公有 + 私有组件
方法/函数 函数模块 方法
全局数据 在函数模块间共享 属性(实例或静态)

静态与实例组件

1
2
3
4
5
6
7
8
9
静态组件
├── 每个程序上下文存在一个
├── 无需实例化即可调用
└── 语法:class_name=>component (静态选择符 =>)

实例组件
├── 每个对象一个(不同的值)
├── 需要先执行 CREATE OBJECT
└── 语法:ref_var->component (实例选择符 ->)

调用方法

静态方法调用

1
2
3
4
CALL METHOD cl_bc400_compute=>get_power
EXPORTING iv_base = pa_int1
iv_power = pa_int2
IMPORTING ev_result = gv_result.

实例方法调用

1
2
3
4
DATA go_ref TYPE REF TO cl_class.
CREATE OBJECT go_ref.
CALL METHOD go_ref->method_name
EXPORTING iv_param = lv_val.
💡方法调用生成
使用拖放Pattern → ABAP Objects Pattern → Call Method 来生成方法调用,避免错误。

方法的异常处理

传统异常 (sy-subrc)

1
2
3
4
5
CALL METHOD cl_class=>method
EXCEPTIONS error1 = 1 error2 = 2.
CASE sy-subrc.
WHEN 0. " 成功
ENDCASE.

基于类的异常 (TRY/CATCH)

1
2
3
4
5
6
7
TRY.
CALL METHOD cl_class=>method
EXPORTING iv_param = lv_val
IMPORTING ev_result = lv_result.
CATCH cx_exception_class.
" 处理错误
ENDTRY.
📌异常概念不能混合
一个方法可以使用传统异常基于类的异常 — 不能在同一方法中同时使用两者。

创建全局类

  1. 在包上点击上下文菜单 → 创建 → 类库 → 类
  2. 输入名称、描述、属性
  3. 保存 → 分配到包和传输请求
  4. 在方法标签页创建方法
  5. 定义参数和异常
  6. 实现源代码(方法 → 源代码按钮)

构造函数

  • 特殊方法 CONSTRUCTOR,在 CREATE OBJECT 后自动调用
  • 用于初始化实例属性
  • 输入参数在 CREATE OBJECT 时提供

考试/测试模式

场景/关键词 答案
“静态组件选择符?” => (双箭头)
“实例组件选择符?” -> (单箭头)
“创建实例?” CREATE OBJECT ref_var.
“方法可以混合异常类型吗?” 不可以 — 传统或基于类的二选一
“函数组可以有多个实例吗?” 不可以 — 每个上下文仅一个
“类可以有多个实例吗?” 可以 — 按需创建任意数量

相关笔记

数据类型与数据对象 (★★★★)

#abap #abap-syntax #abap-data

概览表

类别 示例 要点
标准类型 I, F, P, C, N, D, T, STRING SAP 预定义
局部类型 使用 TYPES 定义 仅在当前程序中有效
全局类型 ABAP 数据字典类型 系统范围内可用

类型分类

完整的 ABAP 标准类型(固定长度)

类型 描述 长度
D 日期 (YYYYMMDD) 8
T 时间 (HHMMSS) 6
I 整数 4
F 浮点数 8
STRING 动态字符串 可变
XSTRING 动态十六进制字符串 可变
DECFLOAT16 十进制浮点数 8
DECFLOAT34 十进制浮点数 16

不完整的 ABAP 标准类型(必须指定长度)

类型 描述 长度说明
C 字符串 LENGTH n
N 数字文本字符串 LENGTH n
X 十六进制字节序列 LENGTH n
P 压缩数字 LENGTH n + DECIMALS m
⚠️类型 N 不是数值类型!
N 是一种字符串类型,只允许包含数字字符。它不能用于算术运算。数值类型包括:I, F, P, DECFLOAT16, DECFLOAT34

定义数据对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
" 变量
DATA gv_name TYPE string.
DATA gv_count TYPE i.
DATA gv_price TYPE p LENGTH 8 DECIMALS 2.

" 带初始值
DATA gv_flag TYPE c LENGTH 1 VALUE 'X'.

" 常量
CONSTANTS gc_pi TYPE p LENGTH 8 DECIMALS 5 VALUE '3.14159'.

" 参考已有对象
DATA gv_copy LIKE gv_name.

" 字面量(固定数据对象)
" 文本字面量:'Hello World'
" 数字字面量:42

类型层次结构

1
2
3
4
5
6
7
8
9
ABAP 标准类型(预定义)

├── 局部类型(TYPES 语句,仅限程序内)
│ └── 可基于标准类型或全局类型构建

└── 全局类型(ABAP 数据字典)
├── 数据元素(语义类型)
├── 结构
└── 表类型

局部类型定义

1
2
TYPES: gty_price TYPE p LENGTH 8 DECIMALS 2,
gty_name TYPE c LENGTH 30.

全局类型使用

1
2
DATA gv_carrid TYPE s_carrid.    " 数据字典中的数据元素
DATA gs_flight TYPE bc400_s_flight. " 数据字典中的结构

命名规范

前缀 含义
g 全局(程序级)作用域
l 局部作用域
v 简单变量(值)
ty 类型
c 常量
p 参数(选择屏幕)

考试/测试模式

场景/关键词 答案
“哪些类型是数值类型?” I, F, P, DECFLOAT16, DECFLOAT34(不包括 N!)
“不完整的类型有哪些?” C, N, X, P(必须指定长度)
“定义局部类型的关键字?” TYPES
“如何定义常量?” CONSTANTS

相关笔记

结构体 (★★★★)

#abap #abap-data

概览表

方面 要点
定义 将多个组件组合在一个名称下的数据对象
用途 将相关字段组合成一个数据对象
关键语句 TYPES(定义类型),DATA(定义变量)

定义结构体

使用字典类型

1
2
DATA: gs_carrier TYPE bc400_s_carrier,
gs_flight TYPE bc400_s_flight.

使用本地类型定义

1
2
3
4
5
6
7
8
TYPES: BEGIN OF gty_s_carrierflight,
carrid TYPE bc400_s_flight-carrid,
connid TYPE bc400_s_flight-connid,
carrname TYPE bc400_s_carrier-carrname,
url TYPE bc400_s_carrier-url,
END OF gty_s_carrierflight.

DATA gs_combined TYPE gty_s_carrierflight.

结构体操作

1
2
3
4
5
6
7
8
9
10
11
12
13
" 访问组件
WRITE: gs_flight-carrid, gs_flight-connid.

" 复制同名字段
MOVE-CORRESPONDING gs_carrier TO gs_combined.

" 清除所有字段
CLEAR gs_flight.

" 检查是否为初始值
IF gs_flight IS NOT INITIAL.
" 结构体中有数据
ENDIF.
📌MOVE-CORRESPONDING 规则
只复制两个结构体中名称相同的字段。仅存在于其中一个结构体中的字段保持不变。

结构体类型的来源类型

字典元素 是否可用 示例
数据元素 是(单个字段) TYPE s_carrid
结构体 (推荐) TYPE bc400_s_flight
表类型 否(用于内表)
否(仅用于技术定义)

考试/测试模式

场景/关键词 答案
“哪些字典元素可用于结构体类型?” 结构体(数据元素可用于单个字段)
“MOVE-CORRESPONDING 的行为?” 只复制同名字段
“检查结构体是否为空?” IF gs_struct IS INITIAL

相关笔记

内表 (★★★★)

#abap #abap-data

概览表

方面 要点
定义 存储多行相同结构数据的动态数据对象
内存 由 ABAP 运行时动态管理
关键要素 行类型、表类型、主键

表类型

类型 键唯一性 访问方式 适用场景
STANDARD 非唯一 索引 顺序访问、APPEND
SORTED 唯一或非唯一 索引 部分范围访问、排序顺序
HASHED 仅唯一 键(无索引) 单条记录按键查找
1
2
3
4
5
性能决策树:
你将如何访问数据?
├── 索引顺序访问 → STANDARD
├── 部分范围访问 → SORTED
└── 单键查找 → HASHED

定义内表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
" 使用字典表类型
DATA gt_connections TYPE bc400_t_connections.

" 内联定义
DATA gt_flights TYPE TABLE OF bc400_s_flight.

" 显式指定表类型和键
DATA gt_sorted TYPE SORTED TABLE OF bc400_s_flight
WITH NON-UNIQUE KEY carrid connid.

" 工作区
DATA gs_flight TYPE bc400_s_flight.
" 或者
DATA gs_flight LIKE LINE OF gt_flights.

定义默认值(简写形式)

  • 表类型:STANDARD(默认)
  • 键唯一性:非唯一(标准表的唯一选项)
  • 主键:默认键(所有非数字字段)
⚠️默认键
默认键使用所有非数字字段,通常没有实际意义。务必定义显式键。

行操作

语句 用途 示例
APPEND wa TO itab 添加到末尾(仅标准表) APPEND ls TO gt_tab.
INSERT wa INTO TABLE itab 插入(排序位置) INSERT ls INTO TABLE gt_tab.
READ TABLE itab INTO wa 读取单行 READ TABLE gt_tab INTO ls INDEX 1.
MODIFY itab FROM wa 覆盖行 MODIFY gt_tab FROM ls.
DELETE itab 删除行 DELETE gt_tab WHERE carrid = 'LH'.
COLLECT wa INTO itab 按键汇总 COLLECT ls INTO gt_tab.

集合操作

语句 用途
LOOP AT itab INTO wa 逐行处理
DELETE itab WHERE cond 删除匹配的行
INSERT LINES OF itab1 INTO itab2 在表之间复制行
APPEND LINES OF itab1 TO itab2 在表之间追加行

按索引 vs 按键访问

1
2
3
4
5
6
7
" 按索引(仅标准表和排序表)
READ TABLE gt_tab INTO ls INDEX 1.
LOOP AT gt_tab INTO ls FROM 1 TO 5.

" 按键
READ TABLE gt_tab INTO ls WITH TABLE KEY carrid = 'LH' connid = '0400'.
LOOP AT gt_tab INTO ls WHERE carrid = 'LH'.
💡性能提示
  • 排序表以键字段作为首字段 → 最适合 WHERE 访问
  • 哈希表 → 最适合大数据集中单条记录按键访问
  • 标准表 → 最适合主要以 APPEND 方式顺序处理的场景

排序和清除

1
2
3
4
5
6
7
SORT gt_tab BY field ASCENDING.     " 或 DESCENDING
SORT gt_tab AS TEXT. " 按语言相关的排序规则
SORT gt_tab STABLE. " 保持相等键的原始顺序

REFRESH gt_tab. " 清除内容,保留内存
CLEAR gt_tab. " 与 REFRESH 相同(无表头行时)
FREE gt_tab. " 清除内容并释放内存

表头行(已过时)

⚠️不要使用表头行
表头行已经过时。在 ABAP Objects 或嵌套数据对象中不允许使用。务必使用显式工作区。

考试/测试模式

场景/关键词 答案
“三种表类型?” STANDARD、SORTED、HASHED
“APPEND 适用于所有表?” 否 — 仅标准表
“默认键?” 所有非数字字段
“推荐使用表头行?” 否 — 已过时
“循环中的索引字段?” sy-tabix
“从表定义工作区?” LIKE LINE OF itab

相关笔记

第5单元:复杂数据对象练习(10题)

#practice #abap #abap-data

相关概念

📌关键模式(点击展开)
关键词 答案
三种表类型 STANDARD、SORTED、HASHED
APPEND 适用于? 仅标准表
默认键 所有非数字字段
表头行 已过时,不要使用
sy-tabix 当前表行索引

问题 1 - 结构体类型定义 [recall]

可以通过 ABAP 字典中的哪些元素来设置结构体变量的类型?

📌显示答案
通过 ABAP 字典中的结构体类型。(数据元素可以用于定义单个字段的类型,但对于整个结构体,应使用字典结构体。)

问题 2 - MOVE-CORRESPONDING [recall]

MOVE-CORRESPONDING 语句会考虑哪些字段?

📌显示答案
只有在两个结构体中都存在名称相同的字段。仅存在于一个结构体中的字段会被忽略。

问题 3 - 内表定义 [recall]

定义内表时需要哪三个要素?

📌显示答案
  1. 行类型(行结构)
  2. 表类型(STANDARD、SORTED 或 HASHED)
  3. 主键(键字段和唯一性)

问题 4 - 表类型 [recall]

有哪三种内表类型?

📌显示答案
STANDARD(非唯一键、索引访问),SORTED(唯一/非唯一键、按键排序),HASHED(仅唯一键、哈希算法访问)。

问题 5 - 表类型(字典) [recall]

ABAP 字典中的表类型是什么?

📌显示答案
表类型是对内表的描述(而不是表本身)。它集中定义了行类型、表类型和键属性,以便重复使用。

问题 6 - 工作区定义 [application]

给定内表 gt_flights,如何定义一个合适的工作区?

📌显示答案
DATA gs_flight LIKE LINE OF gt_flights. — 这会创建一个与表的行类型兼容的结构体。

问题 7 - 单条记录读取 [recall]

哪条语句用于从内表中检索单条记录?

📌显示答案
READ TABLE,配合 INDEX(用于索引表)或 WITH TABLE KEY / WITH KEY(用于任何表)。

问题 8 - APPEND 与 INSERT 对比 [analysis]

比较 APPEND 和 INSERT 向内表添加行的区别。何时应该使用哪个?

📌显示答案
APPEND 只适用于标准表 — 将行添加到末尾。INSERT 适用于所有表类型 — 对于排序表会按键的排序位置插入,对于哈希表按哈希算法插入,对于标准表则在末尾添加。

问题 9 - 性能选择 [application]

你需要频繁地通过完整键从一个大型内表(10万+行)中读取单条记录。哪种表类型最高效?

📌显示答案
HASHED 表 — 它提供与表大小无关的按键常量时间访问。排序表使用二分查找(log n),也不错但不如哈希表在大数据集上快速。

问题 10 - 内存管理 [application]

你已经处理完一个大型内表且不再需要它。使用哪条语句来释放内存?

📌显示答案
FREE gt_tab. — 这会清除内容并释放已分配的内存。REFRESH 只清除内容但保留已分配的内存。

📌模式总结(点击展开)
关键词 答案
结构体类型定义 字典结构体类型
MOVE-CORRESPONDING 仅同名字段
内表三要素 行类型、表类型、主键
表类型 STANDARD、SORTED、HASHED
APPEND 仅标准表
单条记录读取 READ TABLE
大表按键查找 HASHED
释放内存 FREE

函数模块与 BAPI (★★★★)

#abap #abap-modularization

概览表

概念 要点
函数组 函数模块的容器
函数模块 全局可复用的模块化单元
BAPI 用于业务对象的远程调用函数模块

函数组

函数组是函数模块的容器

  • 包含所有函数模块可访问的全局数据
  • 当调用组中任意函数模块时加载到程序上下文中
  • 每个主程序上下文中仅有一个实例
1
2
3
4
5
函数组
├── 全局数据(所有函数模块共享)
├── 函数模块 1
├── 函数模块 2
└── 函数模块 N

函数模块接口

1
2
3
4
5
6
7
8
9
10
CALL FUNCTION 'BC400_MOS_POWER'
EXPORTING
iv_base = pa_int1
iv_power = pa_int2
IMPORTING
ev_result = gv_result
EXCEPTIONS
power_value_too_high = 1
result_value_too_high = 2
OTHERS = 3.
参数标签页 方向 描述
IMPORTING 调用者 → 函数模块 输入数据
EXPORTING 函数模块 → 调用者 输出数据
CHANGING 双向 修改后的数据
TABLES 双向 表参数(已过时)
EXCEPTIONS 错误名称 传统异常处理
💡生成函数模块调用
使用从导航区域的拖放Pattern 按钮来生成 CALL FUNCTION 语句,避免输入错误。

异常处理

传统异常

1
2
3
4
5
6
7
8
CALL FUNCTION '...'
EXCEPTIONS
error1 = 1
OTHERS = 2.
CASE sy-subrc.
WHEN 0. " 成功
WHEN 1. " 处理 error1
ENDCASE.

基于类的异常

1
2
3
4
5
6
7
8
9
TRY.
CALL METHOD cl_class=>method
EXPORTING iv_param = lv_val
IMPORTING ev_result = lv_result.
CATCH cx_bc400_no_data.
WRITE '未找到数据'.
CATCH cx_bc400_no_auth.
WRITE '无授权'.
ENDTRY.

创建函数模块

  1. 在对象导航器中打开函数组
  2. 上下文菜单 → 创建 → 函数模块
  3. 使用客户命名空间的名称(Z_ 或 Y_)
  4. 维护接口(导入/导出/更改/异常标签页)
  5. 在源代码标签页实现源代码
  6. 激活并测试

BAPI(业务应用编程接口)

属性 要求
命名 BAPI_<对象>_<方法>
远程调用 必须是
用户对话 不得包含任何用户对话
异常 不得抛出 — 使用 RETURN 参数
参数类型 带有 BAPI_ 前缀的结构

标准 BAPI 方法

方法 用途
GetList 返回匹配条件的对象列表
GetDetail 返回单个对象的属性
Create/Change/Delete 增删改操作
AddItem/RemoveItem 子对象操作
⚠️BAPI 异常规则
BAPI 不得抛出异常。错误通过特殊的导出参数 RETURN 报告。

考试/测试模式

场景/关键词 答案
“BAPI 命名规范?” BAPI_<对象>_<方法>
“BAPI 可以抛出异常吗?” 不可以 — 使用 RETURN 参数
“函数组加载几次?” 每个主程序上下文一次
“如何生成函数模块调用?” 拖放或 Pattern 按钮

相关笔记

模块化概述 (★★★★)

#abap #abap-modularization

概览表

技术 作用范围 可复用? 封装性
子程序 (FORM) 局部(一个程序) 差(仅 USING/CHANGING)
局部类方法 局部(一个程序) 良好
函数模块 全局(任何程序) 良好
全局类方法 全局(任何程序) 最佳

为什么要模块化?

  • 透明性:程序变得面向功能,划分为子功能
  • 复用性:多次调用相同代码而无需重新实现
  • 可维护性:在一处修复,而不是分散在主程序各处
  • 可调试性:可以跳过整个模块化单元

局部与全局模块化

1
2
3
4
5
6
7
8
9
局部(仅限程序内)
├── 子程序(FORM 例程)
└── 局部类中的方法
仅在定义程序中可用

全局(系统范围)
├── 函数模块(在函数组中)
└── 全局类中的方法
存储在仓库中,按需加载到调用者的上下文中

数据封装原则

1
2
3
4
调用程序 ←→ 接口(参数)←→ 模块化单元

理想情况:不直接访问彼此的数据对象
所有数据交换通过参数进行
📌数据封装
模块化单元不应直接使用调用程序的数据对象,反之亦然。数据交换应仅通过接口(参数)进行。

参数类型

参数类型 方向 描述
输入参数 (IMPORTING) 调用者 → 模块 传入数据
输出参数 (EXPORTING) 模块 → 调用者 返回数据
双向参数 (CHANGING) 双向 传入并在修改后返回
返回参数 (RETURNING) 模块 → 调用者 仅限方法使用;函数式调用风格

接口/签名

模块化单元的参数总和 = 其接口(也称为签名)。

⚠️子程序的局限
子程序仅支持 CHANGINGUSING 参数 — 没有 IMPORTING/EXPORTING。这严重限制了数据传输控制。建议优先使用局部类方法而非子程序。

考试/测试模式

场景/关键词 答案
“局部模块化技术有哪些?” 子程序和局部类方法
“全局模块化技术有哪些?” 函数模块和全局类方法
“子程序的参数类型?” 仅 USING 和 CHANGING
“什么是接口/签名?” 参数的总集合

相关笔记

0%