SALV로 간결한 ALV 리포트 만들기
SALV란?
SALV(Simple ALV)는 CL_SALV_TABLE 클래스를 기반으로 한 OOP 방식의 ALV 프레임워크입니다. 기존 REUSE_ALV_GRID_DISPLAY 함수 모듈 대비 훨씬 간결한 코드로 ALV를 구현할 수 있습니다.
REUSE ALV vs SALV 비교
REUSE ALVFM 방식
📋 Field Catalog 수동 구성 필요
🔧 Layout 구조체 설정
📡 이벤트: FORM 기반 콜백
✏️ 편집 모드: 지원
📊 코드량: 많음
SALVOOP 방식
📋 Field Catalog 자동 생성
🔧 메서드 체이닝으로 설정
📡 이벤트: 클래스 이벤트 핸들러
✏️ 편집 모드: 기본 미지원
📊 코드량: 적음
언제 SALV을 선택할까? 조회 전용 리포트, 빠른 프로토타이핑, 코드 간결성이 중요할 때 적합합니다. 셀 편집이 필요하면 CL_GUI_ALV_GRID 또는 REUSE_ALV_GRID_DISPLAY를 사용하세요.
최소 코드로 ALV 출력
SALV의 가장 큰 장점은 단 3줄로 ALV를 출력할 수 있다는 점입니다.
1REPORT Z_SALV_SIMPLE.
2
3TABLES: mara.
4
5SELECT-OPTIONS: so_mtart FOR mara-mtart.
6
7DATA: lt_mara TYPE TABLE OF mara.
8
9START-OF-SELECTION.
10
11 SELECT * FROM mara
12 INTO TABLE lt_mara
13 WHERE mtart IN so_mtart
14 UP TO 100 ROWS.
15
16
17 DATA: lo_salv TYPE REF TO cl_salv_table.
18
19 cl_salv_table=>factory(
20 IMPORTING r_salv_table = lo_salv
21 CHANGING t_table = lt_mara
22 ).
23
24 lo_salv->display( ).
이것만으로 정렬, 필터, 엑셀 다운로드 등 ALV 기본 기능이 모두 포함된 리포트가 완성됩니다.
SALV 핵심 클래스 구조
SALV는 기능별로 클래스가 분리되어 있습니다. CL_SALV_TABLE에서 각 기능 객체를 가져와 설정합니다.
| 클래스 | 역할 | 접근 메서드 |
|---|
CL_SALV_TABLE | SALV 메인 객체 | factory( ) |
CL_SALV_COLUMNS_TABLE | 컬럼 전체 관리 | get_columns( ) |
CL_SALV_COLUMN_TABLE | 개별 컬럼 설정 | get_column( 'FIELDNAME' ) |
CL_SALV_SORTS | 정렬 설정 | get_sorts( ) |
CL_SALV_FILTERS | 필터 설정 | get_filters( ) |
CL_SALV_AGGREGATIONS | 합계/집계 설정 | get_aggregations( ) |
CL_SALV_DISPLAY_SETTINGS | 표시 설정 (줄무늬 등) | get_display_settings( ) |
CL_SALV_LAYOUT | Variant 저장 | get_layout( ) |
CL_SALV_SELECTIONS | 선택 모드 | get_selections( ) |
CL_SALV_FUNCTIONS_LIST | Toolbar 기능 | get_functions( ) |
CL_SALV_EVENTS_TABLE | 이벤트 핸들러 | get_event( ) |
컬럼 설정
컬럼 숨기기 / 텍스트 변경
1DATA: lo_columns TYPE REF TO cl_salv_columns_table,
2 lo_column TYPE REF TO cl_salv_column_table.
3
4lo_columns = lo_salv->get_columns( ).
5
6
7lo_columns->set_optimize( abap_true ).
8
9
10lo_column ?= lo_columns->get_column( 'MANDT' ).
11lo_column->set_visible( if_salv_c_bool_sap=>false ).
12
13lo_column ?= lo_columns->get_column( 'ERNAM' ).
14lo_column->set_visible( if_salv_c_bool_sap=>false ).
15
16
17lo_column ?= lo_columns->get_column( 'MATNR' ).
18lo_column->set_short_text( '자재No' ).
19lo_column->set_medium_text( '자재번호' ).
20lo_column->set_long_text( '자재번호 (Material)' ).
21
22lo_column ?= lo_columns->get_column( 'MTART' ).
23lo_column->set_long_text( '자재유형' ).
24
25
26lo_column->set_output_length( 10 ).
컬럼 색상 / 핫스팟
1
2lo_column ?= lo_columns->get_column( 'MATNR' ).
3lo_column->set_cell_type( if_salv_c_cell_type=>hotspot ).
4
5
6lo_column->set_key( abap_true ).
표시 설정 (Display Settings)
1DATA: lo_display TYPE REF TO cl_salv_display_settings.
2
3lo_display = lo_salv->get_display_settings( ).
4
5
6lo_display->set_striped_pattern( abap_true ).
7
8
9lo_display->set_list_header( '자재 마스터 리포트' ).
정렬 (Sort)
1DATA: lo_sorts TYPE REF TO cl_salv_sorts.
2
3lo_sorts = lo_salv->get_sorts( ).
4
5
6lo_sorts->add_sort(
7 columnname = 'MTART'
8 position = 1
9 sequence = if_salv_c_sort=>sort_up
10 subtotal = abap_true
11).
12
13
14lo_sorts->add_sort(
15 columnname = 'MATNR'
16 position = 2
17 sequence = if_salv_c_sort=>sort_up
18).
합계 (Aggregation)
1DATA: lo_aggr TYPE REF TO cl_salv_aggregations.
2
3lo_aggr = lo_salv->get_aggregations( ).
4
5
6lo_aggr->add_aggregation(
7 columnname = 'MENGE'
8 aggregation = if_salv_c_aggregation=>total
9).
Toolbar (Functions)
1DATA: lo_functions TYPE REF TO cl_salv_functions_list.
2
3lo_functions = lo_salv->get_functions( ).
4
5
6lo_functions->set_all( abap_true ).
7
8
9
10
11
12
Variant (Layout 저장)
1DATA: lo_layout TYPE REF TO cl_salv_layout,
2 ls_key TYPE salv_s_layout_key.
3
4lo_layout = lo_salv->get_layout( ).
5
6ls_key-report = sy-repid.
7lo_layout->set_key( ls_key ).
8
9
10lo_layout->set_save_restriction( if_salv_c_layout=>restrict_none ).
선택 모드
1DATA: lo_selections TYPE REF TO cl_salv_selections.
2
3lo_selections = lo_salv->get_selections( ).
4
5
6lo_selections->set_selection_mode( if_salv_c_selection_mode=>row_column ).
이벤트 처리
SALV의 이벤트는 OOP 방식으로 이벤트 핸들러 클래스를 만들어 등록합니다.
이벤트 핸들러 클래스 정의
1
2
3
4CLASS lcl_event_handler DEFINITION.
5 PUBLIC SECTION.
6
7 METHODS on_double_click
8 FOR EVENT double_click OF cl_salv_events_table
9 IMPORTING row column.
10
11
12 METHODS on_link_click
13 FOR EVENT link_click OF cl_salv_events_table
14 IMPORTING row column.
15ENDCLASS.
16
17CLASS lcl_event_handler IMPLEMENTATION.
18 METHOD on_double_click.
19
20 READ TABLE lt_mara INTO DATA(ls_mara) INDEX row.
21 IF sy-subrc = 0.
22
23 SET PARAMETER ID 'MAT' FIELD ls_mara-matnr.
24 CALL TRANSACTION 'MM03' AND SKIP FIRST SCREEN.
25 ENDIF.
26 ENDMETHOD.
27
28 METHOD on_link_click.
29
30 READ TABLE lt_mara INTO DATA(ls_mara) INDEX row.
31 IF sy-subrc = 0.
32 MESSAGE |자재 { ls_mara-matnr } 클릭| TYPE 'S'.
33 ENDIF.
34 ENDMETHOD.
35ENDCLASS.
이벤트 등록
1
2DATA: lo_handler TYPE REF TO lcl_event_handler.
3CREATE OBJECT lo_handler.
4
5
6DATA: lo_events TYPE REF TO cl_salv_events_table.
7lo_events = lo_salv->get_event( ).
8
9
10SET HANDLER lo_handler->on_double_click FOR lo_events.
11SET HANDLER lo_handler->on_link_click FOR lo_events.
TOP-OF-PAGE (헤더)
1DATA: lo_header TYPE REF TO cl_salv_form_layout_grid,
2 lo_flow TYPE REF TO cl_salv_form_layout_flow.
3
4CREATE OBJECT lo_header.
5
6
7lo_header->create_header_information(
8 row = 1
9 column = 1
10 text = '자재 마스터 리포트'
11).
12
13
14lo_flow = lo_header->create_flow( row = 2 column = 1 ).
15lo_flow->create_text( text = |실행일: { sy-datum DATE = USER }| ).
16
17lo_flow = lo_header->create_flow( row = 2 column = 2 ).
18lo_flow->create_text( text = |사용자: { sy-uname }| ).
19
20
21lo_salv->set_top_of_list( lo_header ).
실무 예제: SALV 자재 목록 리포트
컬럼 설정, 정렬, 합계, 이벤트, Variant까지 포함한 종합 예제입니다.
1REPORT Z_SALV_MATERIAL_REPORT.
2
3
4
5
6TYPES: BEGIN OF ty_material,
7 matnr TYPE matnr,
8 maktx TYPE maktx,
9 mtart TYPE mtart,
10 matkl TYPE matkl,
11 meins TYPE meins,
12 brgew TYPE brgew,
13 ntgew TYPE ntgew,
14 END OF ty_material.
15
16
17
18
19TABLES: mara.
20
21SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-001.
22 SELECT-OPTIONS: so_matnr FOR mara-matnr,
23 so_mtart FOR mara-mtart.
24 PARAMETERS: p_maxrow TYPE i DEFAULT 100.
25SELECTION-SCREEN END OF BLOCK b1.
26
27
28
29
30DATA: lt_materials TYPE TABLE OF ty_material.
31
32
33
34
35CLASS lcl_handler DEFINITION.
36 PUBLIC SECTION.
37 METHODS on_double_click
38 FOR EVENT double_click OF cl_salv_events_table
39 IMPORTING row column.
40ENDCLASS.
41
42CLASS lcl_handler IMPLEMENTATION.
43 METHOD on_double_click.
44 READ TABLE lt_materials INTO DATA(ls_mat) INDEX row.
45 IF sy-subrc = 0.
46 SET PARAMETER ID 'MAT' FIELD ls_mat-matnr.
47 CALL TRANSACTION 'MM03' AND SKIP FIRST SCREEN.
48 ENDIF.
49 ENDMETHOD.
50ENDCLASS.
51
52
53
54
55START-OF-SELECTION.
56
57 SELECT a~matnr b~maktx a~mtart a~matkl
58 a~meins a~brgew a~ntgew
59 FROM mara AS a
60 INNER JOIN makt AS b
61 ON a~matnr = b~matnr
62 INTO CORRESPONDING FIELDS OF TABLE lt_materials
63 UP TO p_maxrow ROWS
64 WHERE a~matnr IN so_matnr
65 AND a~mtart IN so_mtart
66 AND b~spras = sy-langu.
67
68 IF sy-subrc <> 0.
69 MESSAGE '조회된 데이터가 없습니다.' TYPE 'S' DISPLAY LIKE 'E'.
70 RETURN.
71 ENDIF.
72
73
74
75
76 DATA: lo_salv TYPE REF TO cl_salv_table,
77 lo_columns TYPE REF TO cl_salv_columns_table,
78 lo_column TYPE REF TO cl_salv_column_table.
79
80 TRY.
81 cl_salv_table=>factory(
82 IMPORTING r_salv_table = lo_salv
83 CHANGING t_table = lt_materials
84 ).
85 CATCH cx_salv_msg INTO DATA(lx_msg).
86 MESSAGE lx_msg->get_text( ) TYPE 'E'.
87 RETURN.
88 ENDTRY.
89
90
91 lo_columns = lo_salv->get_columns( ).
92 lo_columns->set_optimize( abap_true ).
93
94 TRY.
95 lo_column ?= lo_columns->get_column( 'MATNR' ).
96 lo_column->set_long_text( '자재번호' ).
97 lo_column->set_cell_type( if_salv_c_cell_type=>hotspot ).
98 lo_column->set_key( abap_true ).
99
100 lo_column ?= lo_columns->get_column( 'MAKTX' ).
101 lo_column->set_long_text( '자재내역' ).
102 lo_column->set_output_length( 30 ).
103
104 lo_column ?= lo_columns->get_column( 'MTART' ).
105 lo_column->set_long_text( '자재유형' ).
106
107 lo_column ?= lo_columns->get_column( 'MATKL' ).
108 lo_column->set_long_text( '자재그룹' ).
109
110 lo_column ?= lo_columns->get_column( 'MEINS' ).
111 lo_column->set_long_text( '기본단위' ).
112
113 lo_column ?= lo_columns->get_column( 'BRGEW' ).
114 lo_column->set_long_text( '총중량' ).
115
116 lo_column ?= lo_columns->get_column( 'NTGEW' ).
117 lo_column->set_long_text( '순중량' ).
118 CATCH cx_salv_not_found.
119 ENDTRY.
120
121
122 DATA(lo_display) = lo_salv->get_display_settings( ).
123 lo_display->set_striped_pattern( abap_true ).
124 lo_display->set_list_header( '자재 마스터 리포트' ).
125
126
127 DATA(lo_sorts) = lo_salv->get_sorts( ).
128 TRY.
129 lo_sorts->add_sort(
130 columnname = 'MTART'
131 position = 1
132 sequence = if_salv_c_sort=>sort_up
133 subtotal = abap_true
134 ).
135 CATCH cx_salv_not_found cx_salv_existing cx_salv_data_error.
136 ENDTRY.
137
138
139 lo_salv->get_functions( )->set_all( abap_true ).
140
141
142 DATA(lo_layout) = lo_salv->get_layout( ).
143 lo_layout->set_key( VALUE salv_s_layout_key( report = sy-repid ) ).
144 lo_layout->set_save_restriction( if_salv_c_layout=>restrict_none ).
145
146
147 DATA(lo_handler) = NEW lcl_handler( ).
148 SET HANDLER lo_handler->on_double_click FOR lo_salv->get_event( ).
149
150
151 DATA: lo_header TYPE REF TO cl_salv_form_layout_grid.
152 CREATE OBJECT lo_header.
153 lo_header->create_header_information( row = 1 column = 1
154 text = '자재 마스터 리포트' ).
155 DATA(lo_flow) = lo_header->create_flow( row = 2 column = 1 ).
156 lo_flow->create_text(
157 text = |조회 건수: { lines( lt_materials ) } / 실행일: { sy-datum DATE = USER }|
158 ).
159 lo_salv->set_top_of_list( lo_header ).
160
161
162 lo_salv->display( ).
이 예제에서는 SALV의 핵심 기능인 컬럼 설정(set_long_text, set_cell_type), 표시 설정(set_striped_pattern), 정렬(add_sort + 소계), Toolbar 활성화, Variant 저장, 이벤트 핸들러(더블클릭 → MM03), 헤더(TOP-OF-PAGE)를 모두 활용했습니다.
Disclaimer — 이 포스트는 AI(Claude)를 활용하여 작성된 초안을 바탕으로 검수 및 보완하여 작성되었습니다. 내용 중 오류나 오타가 있다면 댓글로 알려주시면 감사하겠습니다.