2023年11月29日发(作者:)

ABAP开发~消息处理(Messages

14. Messages

14.1. 00消息ID中的通⽤消息

00消息ID中的001消息本⾝未设置任何消息串,这条消息可以传递8个参数,在⽤于拼接消息时很有⽤

MESSAGE e001(00) WITH 'No local currecny maintained for company:' p_bukrs.

14.2. 消息常量

直接显⽰消息常量,不引⽤消息ID与消息号

MESSAGE 'aaaa' TYPE 'S'.

14.3. 静态指定

MESSAGE () [with... ][raising ].

MESSAGE s002(00).

14.4. 动态指定

MESSAGE ID TYPE NUMBER [with...] [raising ].

DATA: t(1) VALUE 'S',

id(2) VALUE '00',

num(3) VALUE '002'.

MESSAGE ID id TYPE t NUMBER num.

14.5. 消息拼接MESSAGE …INTO

DATA mtext TYPE string.

CALL FUNCTION ... EXCEPTIONS error_message = 4.

IF sy-subrc = 4.

MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno

INTO msgtext

WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.

ENDIF.

14.6. 修改消息显⽰性为…DISPLAY LIKE…

此种⽅式不会影响到消息本⾝的处理性为,只是改变了消息的显⽰图标类型,如下⾯只是改变了S类型消息在状态栏中以错

误图标来显⽰(本来是绿⾊状态图标):

MESSAGE msg TYPE 'S' DISPLAY LIKE 'E'.

:消息以异常形式抛出">14.7. RAISING :消息以异常形式抛出

MESSAGE ID 'SABAPDEMOS' TYPE MESSAGE_TYPE NUMBER '777'

WITH MESSAGE_TYPE MESSAGE_PLACE MESSAGE_EVENT

RAISING MESS.

当使⽤该选项后,并且如果在调⽤的地⽅(CALL FUNCTION或者是 CALL METHOD的地⽅)使⽤了EXCEPTION选项来捕

RAISING抛出的异常,不再以MESSAGE的原有形式来显⽰消息,⽽是被主调捕获后进⼀步处理或者是程序DumpA

EWIS类型都能被捕获到,但X类型的Message不会⾛到被主调者捕获这⼀步,因为在被调程序中就宕掉了);反过

来,当主调者未使⽤EXCEPTION选项(或者使⽤了但未捕获到所抛出的异常),则RAISING选项会被忽略MESSAGE

句会按照⽆RAISING选项时那样运⾏(弹框还是在状态栏中显⽰、以及程序是否终⽌等性为、还是转换为error_message

出)

如果加了选项RAISING时: RAISING ,此时的Message 的处理⽅式与是否显⽰,就要依赖于主调者在

调⽤时,是否加上了exception 选项:

1如果调⽤时没有带exception 选项,此时Message语包中的RAISING 选项抛出的异常将会被忽略,Message

语句会当作正常消息来处理

2 如果调⽤时加上了exception 选项对exc 异常进⾏了捕获,则不会再显⽰消息(但如果即使加上了exception

项,但没有捕获到exc异常,则此时会忽略RAISING选项),并设置sy-subrc。只要异常被捕获,相关消息内容将会⼊存⼊到

SY-MSGID,SY-MSGTY, SY-MSGNO, and SY-MSGV1 to SY-MSGV4有关系统变量中。

下⾯程序中,第⼀次调⽤时中会弹出消息框(因为没有使⽤EXCEPTIONS选项捕获),⽽第⼆次不会弹出消息框,也不会在

状态栏中显⽰,⽽是被后继程序捕获后输出:

CLASS c1 DEFINITION.

PUBLIC SECTION.

CLASS-METHODS m1 EXCEPTIONS exc1.

ENDCLASS.

CLASS c1 IMPLEMENTATION.

METHOD m1.

MESSAGE 'Message in a Method' TYPE 'I' RAISING exc1.

ENDMETHOD.

ENDCLASS.

START-OF-SELECTION.

c1=>m1( )."第⼀次调⽤

c1=>m1( EXCEPTIONS exc1 = 4 )."第⼆次调⽤

IF sy-subrc = 4.

write: / '被捕获'.

ENDIF.

14.8. CALL FUNCTION…EXCEPTIONS

CALL FUNCTION func [EXCEPTIONS

[exc1= n1 exc2= n2]

[others= n_others] ]

[ERROR_MESSAGE = n_error].

exc1OTHERS异常只能捕获到RAISING选项或RAISE语句抛出的异常,⽽error_message是⽆法捕

RAISINGRAISE抛出的异常的

MESSAGE中的RAISING ...exc>抛出异常时,如果在Call FunctionException列表中有exc...exc

1i1i

others异常,则

异常会优先被excothers捕获到;否则RAISING选项将直接被忽略掉,MESSAGE会被error_message所捕获(在使

1i

...exc

error_message捕获的前提下)

CALL FUNCTION 'ZJZJ_FUNC1'

EXCEPTIONS

error_message = 5

"e捕获,如果注释掉下⾯E类型异常捕获列表,则会被error_message捕获

e = 4

d = 6.

14.8.1. error_message = n_error捕获消息

可以Message语句没有使⽤RAISING选项的情况下(或使⽤iothers但未捕获到),在主调程序中的CALL

FUNCTION ...Exception参数列表中使⽤隐式异常error_message选项来捕获Message,但error_message是否能捕获到

Message(实为是否设置sy-subrc = n_error),与消息类型有关:

1、对于WIS类型的消息,将不显⽰消息(本来是要显⽰的),也不会去设置 sy-subrc = n_error此时还是会将消息

的相关信息存储到SY-MSGID, SYMSGTY,SY-MSGNO, and SY-MSGV1 to SY-MSGV4这些系统变量中

2对于AE类型消息,也将不显⽰提⽰消息,但会抛出ERROR_MESSAGE异常,即这两类型的消息会⾃动被转换

error_message异常抛出,并终最被CALL FUNCTION Exception异常列表中的error_message异常所捕获,并设置sy-

subrc = n_error。此时还会将消息的相关信息存储到SY-MSGID, SYMSGTY,SY-MSGNO, and SY-MSGV1 to SY-MSGV4

些系统变量中

此时,对于A类型消息⽽⾔,ROLLBACK WORK语句将会隐式执⾏

3、对于X类型消息将会抛出runtime error,并且程序会dump

14.9. 各种消息的显⽰及处理

⾮屏幕PAI事件

PBO

AT SELECTION-SCREEN

OUTPUTINITIALIZATION

对话/选择屏幕

START-OF-SELECTIONPAI

GETAT SELECTION-SCREEN [ON]

END-OF-SELECTION

TOP-OF-PAGE

END-OF-PAGE

显⽰

显⽰在对话框中还是显⽰处理显⽰处理

状态栏中

处理

是终⽌

程序还

是继续

触发运触发运

⾏时错⾏时错

误并伴不显⽰信息不显⽰信息误并伴

随着随着

dumpdump

程序终程序终

Dialogbox以对话框Dialogbox以对话框形Dialogbox以对话框

形式显⽰式显⽰形式显⽰

List列表事件

AT LINE-SELECTION

AT USER-COMMAND

AT PF

TOP-OF-PAGE DURING

LINE-SELECTION

X不显⽰信息

触发运⾏时错误并伴随着

dump

事件块

处理终

⽌,返

回上⼀程序终

级别的显⽰在状态栏中

List

A

程序终⽌

E

PBO:与A相同,

在状态栏中显⽰在状态栏中显⽰

PAI处理结束,并且控制权返

回到当前对话/选择屏幕继续

输⼊

W

PBO:与S相同,

显⽰在状态栏中回上⼀

程序终⽌,返

在状态栏中显⽰续输⼊,但可按回车键继来在状态栏中显⽰

PAI处理结束,并且控制权返

回到当前对话/选择屏幕可继

消息会显⽰在下⼀屏S

幕的状态栏中,如果继续向屏幕的状态栏中,屏幕的状态栏中,继续向

没有下⼀屏幕,则显下执⾏如果没有下⼀屏如果没有下⼀屏下执⾏

⽰在当前屏幕的状态幕,则显⽰在当前幕,则显⽰在当前

栏中屏幕的状态栏中屏幕的状态栏中

14.10. 异常处理

程序会消息会显⽰在下⼀程序会继续向下执⾏消息会显⽰在下⼀程序会

14.10.1. RAISE [EXCEPTION]…触发异常

两种⽅式触发异常:

l RAISE . 只在函数中使⽤

l MESSAGE...RAISING .

⼀旦主调程序捕获了异常,以上两种触发异常的⽅式都会返回到主调程序,并且不会返回值Function Module参数输出)。

MESSAGE ..... RAISING语句也不会再显⽰消息,⽽是将相关的信息填充到SY-MSGID, SY-MSGTY,SY-MSGNO, and SY-

MSGV1 to SY-MSGV4这些系统变量中(即使是I,S,W三种消息类型也会设置这些系统变量)

14.10.1.1.触发类异常

RAISE [RESUMABLE] EXCEPTION { { TYPE cx_class [EXPORTING p1 = a1 p2 = a2 ...]} | oref }.

cx_class为异常ClassEXPORTING为构造此异常类的构造参数,oref可以是已存在的异常Class引⽤。

RAISE EXCEPTION语句⼀般⽤来抛出基于Class的异常类class-based exceptions,⽽RAISE⼀般是直接⽤来抛出 non-

class-based exceptions(在函数中使⽤)

DATA result TYPE p DECIMALS 2.

DATA oref TYPE REF TO cx_root.

DATA text TYPE string.

DATA i TYPE i.

TRY .

i = 1 / 0.

CATCH cx_root INTO oref.

text = oref->get_text( ).

WRITE: '---' , text.

RAISE EXCEPTION oref.

ENDTRY.

DATA: exc TYPE REF TO cx_sy_dynamic_osql_semantics,

text TYPE string.

TRY.

RAISE EXCEPTION TYPE cx_sy_dynamic_osql_semantics

EXPORTING textid = cx_sy_dynamic_osql_semantics=>unknown_table_name token = 'Test'.

CATCH cx_sy_dynamic_osql_semantics INTO exc.

text = exc->get_text( ).

MESSAGE text TYPE 'I'.

ENDTRY.

14.10.1.2.RESUMABLE选项

表⽰可恢复的异常,可以在CATCH块⾥使⽤RESUME语句直接跳到抛出异常语句后⾯继续执⾏,RESUME后⾯语句不再被

执,CLEANUP块也不会被执⾏。该选项只能⽤于BEFORE UNWIND类型的CATCH块中:

DATA oref TYPE REF TO cx_root.

DATA text TYPE string.

DATA i TYPE i.

TRY .

RAISE RESUMABLE EXCEPTION TYPE cx_demo_constructor

EXPORTING

my_text = sy-repid.

i = i + 1.

WRITE: / i.

CATCH BEFORE UNWIND cx_demo_constructor INTO oref .

text = oref->get_text( ).

IF i < 1.

RESUME.

ENDIF.

WRITE:/ '--'.

ENDTRY.

结果只输出 1

14.10.2. 捕获异常

14.10.2.1.类异常捕获TRY…CATCH

DATA myref TYPE REF TO cx_sy_arithmetic_error.

DATA err_text TYPE string.

DATA result TYPE i.

TRY.

result = 1 / 0.

CATCH cx_sy_arithmetic_error INTO myref.

err_text = myref->get_text( ).

ENDTRY.

14.10.2.2.⽼式⽅式捕获runtime errors(运⾏时异常)

CATCH SYSTEM-EXCEPTIONS [exc1 = n1 exc2 = n2 ...][OTHERS = n_others].

ENDCATCH.

DATA: result TYPE i.

CATCH SYSTEM-EXCEPTIONS arithmetic_errors = 5.

result = 1 / 0.

ENDCATCH.

IF sy-subrc = 5.

WRITE / 'Division by zero!'.

ENDIF.

14.10.3. 向上抛出异常

如果Form中出现了运⾏时错误,但Form签名⼜没有使⽤RAISING向上抛,则程序会直接挂掉,所以最好是向上抛

FORM subform RAISING cx_static_check cx_dynamic_check.

...

ENDFORM.

Funcion函数不会主动向外抛出运⾏时错误,所以要先在Function⼿动CATCH,再⼿动向外抛,如果出现运⾏时错误不抛

出,则Function与会直接宕掉

14.10.4. 类异常

l CX_STATIC_CHECK

l CX_DYNAMIC_CHECK

l CX_NO_CHECK

CX_NO_CHECK类似于Java中的ErrorCX_DYNAMIC_CHECK类似于Java中的RuntimeExceptionCX_STATIC_CHECK

类似于Java检测性异常Exception [dai?n?mik]

⾃⼰定义的异常⼀般继承CX_STATIC_CHECKCX_DYNAMIC_CHECK,但CX_NO_CHECK也可以创建,不像Java

CX_STATIC_CHECK是⼀个抽象类。在程序中使⽤RAISE EXCEPTION ⼿动抛出这类异常时,⽅法或过程接⼝上⼀定要显

⽰的通过RAISING 来向上层抛出异常、或者直接在⽅法或过程中进⾏处理也可以,否则静态编译时就会出现警告。

CX_NO_CHECK类型的异常⼀般表⽰系统资源不⾜引起的,不能在⽅法或过程接⼝后⾯抛出CX_NO_CHECK类型的异常,

它会被隐含的抛出与传递。系统中已有预定义这类异常。

如果程序逻辑能够排除可能性的潜在性错,相应的异常就可能不⽤处理或继续抛出,此类情况下可以使⽤

CX_DYNAMIC_CHECK类型的异常,这与Java中的运⾏时异常相似,⼀旦发⽣也该类异常,表⽰问题出现在程序的本⾝设

计上,程序设计不严谨(如没有判断空指针问题)。ABAP⼤多数的系统预定义的异类都是属于该类型异常,这就意味着不

需要处理或抛出ABAP语句可能出现的每⼀种异常,但⼀旦发⽣了该类异常,则表⽰程序的出现了问题,程序执⾏的结果将

不会在正确。

⾃定义的全局异常类名以ZCX_ 作为前缀

如果是通过Class Builder创建的全局异常类时,由于构造器是默认创建好的(异常相关参数已经固定下来了),不能传递⾃

定义参数,所以异常⽂本ID只能通过TEXTID传递(参考触发类异常),但局部异常类没有这个限制。

原⽂出⾃技术博客,博客链接: