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  " ── SALV 최소 코드: 단 3줄! ──
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_TABLESALV 메인 객체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_LAYOUTVariant 저장get_layout( )
CL_SALV_SELECTIONS선택 모드get_selections( )
CL_SALV_FUNCTIONS_LISTToolbar 기능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" ALV 제목
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" lo_functions->set_sort_asc( abap_true ).    " 오름차순 정렬
10" lo_functions->set_sort_desc( abap_true ).   " 내림차순 정렬
11" lo_functions->set_filter( abap_true ).      " 필터
12" lo_functions->set_export_spreadsheet( abap_true ). " 엑셀 다운로드

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" 1. 타입 정의
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" 2. TABLES / Selection Screen
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" 3. 데이터 선언
29" ==============================
30DATA: lt_materials TYPE TABLE OF ty_material.
31
32" ==============================
33" 4. 이벤트 핸들러 클래스
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" 5. 데이터 조회
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" 6. SALV 생성 및 설정
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  " ── Toolbar 기능 전체 활성화 ──
139  lo_salv->get_functions( )->set_all( abap_true ).
140
141  " ── Variant 설정 ──
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  " ── ALV 출력 ──
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)를 활용하여 작성된 초안을 바탕으로 검수 및 보완하여 작성되었습니다. 내용 중 오류나 오타가 있다면 댓글로 알려주시면 감사하겠습니다.