ABAP

CL_SALV_TABLE vs ALV Grid 코드 비교 #shorts #SAP #ABAP

1. ALV 구현이 자꾸 실패하는 진짜 이유

ABAP 리포트 개발에서 가장 흔한 요구사항은 "내부 테이블을 화면에 그리드로 보여달라"입니다. 그런데 처음 ALV(ABAP List Viewer)를 접한 개발자 상당수가 REUSE_ALV_GRID_DISPLAY 같은 함수 모듈이나 CL_GUI_ALV_GRID 클래스부터 시작하다가, 필드 카탈로그 오류·화면(Dynpro) 미생성·이벤트 미동작이라는 3가지 실패를 연달아 겪습니다. 이 글은 그 실패 패턴 3가지를 재현하고, SAP NetWeaver 7.0 이상에서 일반적으로 권장되는 CL_SALV_TABLE로 같은 요구사항을 최소 코드로 해결하는 과정을 다룹니다.

이 글을 끝까지 읽으면 다음을 스스로 점검할 수 있습니다.

  • 클래식 ALV(함수 모듈 / CL_GUI_ALV_GRID)와 SALV 모델의 구조적 차이를 설명할 수 있다
  • 필드 카탈로그 없이 내부 테이블을 그리드로 출력하는 최소 코드를 작성할 수 있다
  • 컬럼 텍스트, 표준 툴바, 이벤트(더블클릭)까지 SALV로 처리할 수 있다
  • CX_SALV_MSG 등 예외 클래스를 올바르게 처리할 수 있다

2. 시작 전에 알아두면 좋은 것

ABAP 기본 문법(내부 테이블, SELECT문, 구조체)과 SE38/ADT에서 실행 가능한 리포트 프로그램을 만들어 본 경험이 있으면 충분합니다. 객체지향 ABAP은 몰라도 따라올 수 있도록 팩토리 메서드 호출 문법을 그때그때 설명하지만, TRY...CATCH 예외 처리의 기본 개념은 미리 알아두면 3단계 코드를 이해하기 수월합니다.

3. 환경과 버전 요구사항

CL_SALV_TABLE은 SAP NetWeaver 7.0(2005년 출시) 이후 모든 릴리스에 포함되어 있습니다. 즉 SAP ECC 6.0, S/4HANA 온프레미스(1909, 2021, 2023 등) 어디서든 동일하게 동작합니다. 다만 주의할 점이 하나 있습니다.

  • ABAP Cloud / BTP ABAP Environment(Steampunk)에서는 사용 불가 — SALV를 포함한 SAP GUI 기반 UI 기술은 클라우드 릴리스 대상이 아닙니다. 클라우드에서는 RAP + Fiori Elements가 대안입니다.
  • S/4HANA 온프레미스에서도 SAP GUI(또는 GUI for HTML) 접속 환경에서만 화면이 렌더링됩니다.
  • 예제 실습에는 표준 테이블 EKKO(구매오더 헤더)를 사용하므로 별도 데이터 준비가 필요 없습니다. 개발 권한(S_DEVELOP)과 SE38 또는 Eclipse ADT만 있으면 됩니다.

4. 핵심 개념 — 클래식 ALV와 SALV 모델의 구조 차이

ALV 기술의 세대를 비유하자면 이렇습니다. WRITE 리스트가 손글씨라면, REUSE_ALV_GRID_DISPLAY 함수 모듈은 수동 타자기입니다. 출력은 되지만 필드 카탈로그라는 "활자판"을 개발자가 한 글자씩 직접 조립해야 합니다. CL_GUI_ALV_GRID는 전동 타자기쯤 됩니다. 강력하지만 커스텀 컨테이너, Dynpro 화면, PBO/PAI 모듈이라는 부속품을 전부 직접 배선해야 합니다. 반면 CL_SALV_TABLE은 워드프로세서입니다. "이 테이블을 보여줘"라고 선언하면 나머지(필드 카탈로그 생성, 화면 관리, 툴바)를 프레임워크가 대신 처리합니다.

구조적으로 SALV 모델은 다음 3가지가 클래식 방식과 다릅니다.

  1. 팩토리 패턴CREATE OBJECT가 아니라 정적 메서드 cl_salv_table=>factory( )가 인스턴스를 생성해 돌려줍니다. 내부 테이블의 타입 정보(RTTI)를 팩토리가 읽어 필드 카탈로그를 자동 생성하기 때문에, DDIC 구조를 쓰면 컬럼 제목·정렬·통화 참조까지 사전 정의에서 그대로 가져옵니다.
  2. 기능별 서브 객체 분리 — 툴바는 CL_SALV_FUNCTIONS_LIST, 컬럼은 CL_SALV_COLUMNS_TABLE, 이벤트는 CL_SALV_EVENTS_TABLE이 담당합니다. 메인 객체에서 get_functions( ), get_columns( )처럼 게터로 꺼내 설정하는 일관된 API 구조입니다.
  3. 화면 자동 관리 — 전체 화면 모드로 쓰면 Dynpro, 컨테이너, GUI 상태를 만들 필요가 없습니다. display( ) 한 줄이 화면 호출까지 처리합니다.

클래식: 내부 테이블 → 필드 카탈로그 수작업 → (화면+컨테이너 생성) → 함수/메서드 호출 → 이벤트용 콜백 FORM/핸들러 배선

SALV: 내부 테이블 → factory( ) → 옵션 설정(선택) → display( )

한 가지 트레이드오프는 알아둬야 합니다. SALV의 표준 팩토리 방식은 읽기 전용 표시가 기본입니다. 셀 편집이 핵심 요구라면 여전히 CL_GUI_ALV_GRID가 일반적인 선택이며, 최신 릴리스(S/4HANA 2020 이후 일부 SP)에서는 SALV에도 제한적 편집 API가 추가되는 흐름이 있으니 시스템 릴리스 노트를 확인하는 것이 좋습니다.

5. 실패 재현과 해결 — 3단계 실전 코드

실패 패턴 요약: ① 함수 모듈 방식에서 필드 카탈로그의 fieldname 오타·누락으로 짧은 덤프 또는 빈 그리드 발생, ② CL_GUI_ALV_GRID를 화면·컨테이너 없이 호출해 아무것도 표시되지 않음, ③ 그리드는 떴지만 툴바 버튼이 비어 있고 더블클릭이 무반응. 아래 3단계는 이 세 가지를 SALV로 순서대로 해소합니다.

[1단계] 최소 구현 — 구매오더 목록 출력

필드 카탈로그 수십 줄 대신, 실질 로직은 factorydisplay 두 줄입니다.

REPORT zpo_salv_step1.

DATA lt_po_header TYPE STANDARD TABLE OF ekko.

SELECT ebeln, bukrs, bsart, lifnr, aedat
  FROM ekko
  INTO CORRESPONDING FIELDS OF TABLE @lt_po_header
  UP TO 200 ROWS.

DATA lo_grid TYPE REF TO cl_salv_table.

TRY.
    cl_salv_table=>factory(
      IMPORTING r_salv_table = lo_grid
      CHANGING  t_table      = lt_po_header ).

    lo_grid->display( ).

  CATCH cx_salv_msg INTO DATA(lx_salv).
    MESSAGE lx_salv->get_text( ) TYPE 'E'.
ENDTRY.

포인트는 두 가지입니다. 첫째, t_tableCHANGING 파라미터라서 지역 임시 테이블을 인라인으로 넘길 수 없고 참조 가능한 변수여야 합니다. 둘째, factoryCX_SALV_MSG를 던지므로 TRY 블록이 필수입니다(생략하면 구문 오류). EKKO 구조를 그대로 썼기 때문에 컬럼 제목이 DDIC 데이터 엘리먼트에서 자동으로 채워집니다 — 실패 패턴 ①이 원천 차단되는 이유입니다.

[2단계] 실무 시나리오 — 툴바·컬럼 제어·예외 로깅

실무에서는 사용자 정의 구조를 쓰는 경우가 많고, 이때 컬럼 텍스트가 비어 나오는 문제와 툴바 버튼(정렬·필터·엑셀 다운로드)이 없는 문제를 함께 해결해야 합니다.

REPORT zpo_salv_step2.

TYPES: BEGIN OF ty_po_line,
         po_number   TYPE ekko-ebeln,
         vendor      TYPE ekko-lifnr,
         doc_type    TYPE ekko-bsart,
         net_total   TYPE ekko-rlwrt,
         currency    TYPE ekko-waers,
       END OF ty_po_line.

DATA lt_po_list TYPE STANDARD TABLE OF ty_po_line.

SELECT ebeln AS po_number, lifnr AS vendor,
       bsart AS doc_type, rlwrt AS net_total, waers AS currency
  FROM ekko
  INTO CORRESPONDING FIELDS OF TABLE @lt_po_list
  UP TO 500 ROWS.

DATA lo_grid TYPE REF TO cl_salv_table.

TRY.
    cl_salv_table=>factory(
      IMPORTING r_salv_table = lo_grid
      CHANGING  t_table      = lt_po_list ).

    lo_grid->get_functions( )->set_all( abap_true ).

    DATA(lo_columns) = lo_grid->get_columns( ).
    lo_columns->set_optimize( abap_true ).

    DATA(lo_col) = lo_columns->get_column( 'PO_NUMBER' ).
    lo_col->set_short_text( '구매오더' ).
    lo_col->set_medium_text( '구매오더 번호' ).
    lo_col->set_long_text( '구매오더 문서번호' ).

    DATA(lo_amount) = CAST cl_salv_column_table(
                        lo_columns->get_column( 'NET_TOTAL' ) ).
    lo_amount->set_currency_column( 'CURRENCY' ).

    lo_grid->display( ).

  CATCH cx_salv_msg cx_salv_not_found INTO DATA(lx_error).
    MESSAGE lx_error->get_text( ) TYPE 'S' DISPLAY LIKE 'E'.
ENDTRY.

주의할 세부 사항: get_column( )의 컬럼명은 대문자여야 하며, 존재하지 않는 이름을 넘기면 CX_SALV_NOT_FOUND가 발생합니다. 금액 컬럼은 set_currency_column으로 통화 필드를 연결해야 JPY(소수점 0자리) 같은 통화에서 금액이 100배로 표시되는 사고를 막을 수 있습니다.

[3단계] 프로덕션 수준 — 이벤트 핸들러·클래스 구조·권한 고려

더블클릭으로 ME23N(구매오더 조회)에 점프하는 요구사항을 로컬 클래스로 구현합니다. 이벤트 핸들러 등록 누락이 실패 패턴 ③의 본체입니다.

REPORT zpo_salv_step3.

CLASS lcl_po_report DEFINITION FINAL.
  PUBLIC SECTION.
    METHODS: run,
             on_double_click FOR EVENT double_click
                             OF cl_salv_events_table
               IMPORTING row column.
  PRIVATE SECTION.
    DATA: mt_po_list TYPE STANDARD TABLE OF ekko,
          mo_grid    TYPE REF TO cl_salv_table.
ENDCLASS.

CLASS lcl_po_report IMPLEMENTATION.
  METHOD run.
    SELECT ebeln, bukrs, bsart, lifnr, aedat
      FROM ekko
      INTO CORRESPONDING FIELDS OF TABLE @mt_po_list
      UP TO 500 ROWS.

    IF mt_po_list IS INITIAL.
      MESSAGE '표시할 구매오더가 없습니다' TYPE 'S' DISPLAY LIKE 'W'.
      RETURN.
    ENDIF.

    TRY.
        cl_salv_table=>factory(
          IMPORTING r_salv_table = mo_grid
          CHANGING  t_table      = mt_po_list ).

        mo_grid->get_functions( )->set_all( abap_true ).
        mo_grid->get_columns( )->set_optimize( abap_true ).
        mo_grid->get_display_settings( )->set_striped_pattern( abap_true ).

        SET HANDLER on_double_click FOR mo_grid->get_event( ).

        mo_grid->display( ).
      CATCH cx_salv_msg INTO DATA(lx_salv).
        MESSAGE lx_salv->get_text( ) TYPE 'E'.
    ENDTRY.
  ENDMETHOD.

  METHOD on_double_click.
    READ TABLE mt_po_list INDEX row INTO DATA(ls_po).
    IF sy-subrc = 0.
      AUTHORITY-CHECK OBJECT 'S_TCODE'
        ID 'TCD' FIELD 'ME23N'.
      IF sy-subrc <> 0.
        MESSAGE 'ME23N 권한이 없습니다' TYPE 'S' DISPLAY LIKE 'E'.
        RETURN.
      ENDIF.
      SET PARAMETER ID 'BES' FIELD ls_po-ebeln.
      CALL TRANSACTION 'ME23N' WITH AUTHORITY-CHECK.
    ENDIF.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  NEW lcl_po_report( )->run( ).

프로덕션 관점의 포인트 3가지입니다. 첫째, 성능 — SALV는 데이터를 화면 프레임워크로 복사해 렌더링하므로 수십만 건을 그대로 넘기면 메모리와 응답 시간이 급격히 나빠집니다. 둘째, 보안 — 이벤트에서 다른 트랜잭션을 호출할 때는 WITH AUTHORITY-CHECK를 붙여 권한 우회를 막습니다. 셋째, 테스트 용이성 — 데이터 조회를 별도 메서드(또는 조회 클래스)로 분리하면 ABAP Unit에서 화면 없이 로직만 검증할 수 있습니다.

6. 자주 만나는 오류와 해결책

Q1. factory 호출에서 "CX_SALV_MSG를 처리하지 않았다"는 구문 오류가 납니다.
factory와 다수의 SALV 메서드는 검사 가능(class-based) 예외를 선언하고 있어 TRY...CATCH가 문법적으로 강제됩니다. 최소한 CATCH cx_salv_msg 블록을 감싸고, 컬럼 API를 쓴다면 cx_salv_not_found도 함께 잡는 것이 안전합니다.

Q2. 그리드는 뜨는데 정렬/필터/엑셀 버튼이 하나도 없습니다.
SALV 기본값은 툴바 기능 비활성입니다. get_functions( )->set_all( abap_true )display( ) 이전에 호출해야 합니다.

Q3. 사용자 정의 구조를 썼더니 컬럼 제목이 필드명 그대로(PO_NUMBER 등) 나옵니다.
로컬 TYPES 구조는 DDIC 텍스트가 없기 때문입니다. 해결책은 두 가지 — 구조 필드를 데이터 엘리먼트 타입으로 선언하거나, set_short_text / set_medium_text / set_long_text를 직접 지정합니다.

Q4. 더블클릭 이벤트가 전혀 반응하지 않습니다.
SET HANDLER ... FOR lo_grid->get_event( ) 등록이 빠졌거나, display( ) 이후에 등록한 경우입니다. 반드시 display( ) 호출 전에 핸들러를 연결하세요.

7. 실무 적용 시 주의사항 및 확장 포인트

이 글에서 다룬 것은 SALV 표시 모델의 최소 골격입니다. 이어서 살펴볼 만한 주제는 다음과 같습니다. 셀 단위 색상과 아이콘을 넣는 CL_SALV_FUNCTIONAL_SETTINGS와 컬러 컬럼, 계층 표시가 필요할 때의 CL_SALV_HIERSEQ_TABLE과 트리용 CL_SALV_TREE, 팝업 형태 표시를 위한 set_screen_popup, 그리고 편집 그리드가 필요한 경우의 CL_GUI_ALV_GRID 비교 학습입니다. 클라우드 전환을 준비한다면 SALV의 개념(메타데이터 기반 자동 UI)이 RAP + Fiori Elements의 List Report로 어떻게 계승되는지 살펴보는 것도 좋은 다음 여정입니다.

8. 더 읽어볼 자료

  • SAP Help Portal — ALV Object Model 개요 (NetWeaver 7.5)
  • SAP Help Portal — SALV Fullscreen Table 표시
  • SAP Help Portal — SALV 이벤트 처리
  • SAP Help Portal — ABAP Development Tools(ADT) 사용자 가이드
  • SAP Community — SALV Table Display 관련 블로그 아카이브

댓글 0

아직 댓글이 없습니다.