SAP ABAP 上传、下载文件到文件服务器_abap 上传文件到al11-程序员宅基地

技术标签: Others  abap  

需求:项目上要和外围系统做接口,把传过来的文件写入到sap的文件服务器或者存入表中,让外围系统过来存取,但是为了减少SAP应用服务器的负担,需要一台独立的文件服务器共享目录到SAP应用服务器,实现往SAP应用服务器上写文件,实际上是写在了这台独立的文件服务器上。我们需要让Basis把文件服务器和SAP应用服务器做NFS,开放给SAP相应权限。

AL11可以进入SAP应用服务器查看文件服务器的目录,SAP中可以在该目录上新建文件夹,也就是在该目录里新建目录。做好NFS后,SAP上用AL11进去点击配置后进入该界面,点击新建/保存,建立相对应目录,如下图
在这里插入图片描述

<本文是使用的是Http的Restful方式制作的接口>
因为涉及到存取,所以我们这里分为Get 和 Post。
在这里插入图片描述

下载文件

下载文件分为1. PDF直接存系统表2. 读取AL11的文件服务器 两种

  DATA:
    lv_uuid    TYPE string,
    lv_insplot TYPE string,
    lv_regex   TYPE string.

* 请求参数
  DATA(lv_query) = server->request->get_header_field( '~query_string' ).
  IF lv_query IS INITIAL.
    server->response->set_status( code = 404 reason = '文件请求参数未指定' ).
    RETURN.
  ENDIF.
  TRANSLATE lv_query TO LOWER CASE.

* 存入AL11文件服务器
  CLEAR lv_uuid.
  lv_regex = '^uuid=(.*)'.
  FIND REGEX lv_regex IN lv_query SUBMATCHES lv_uuid.
  IF sy-subrc = 0.
* 去掉 & 符号
    REPLACE FIRST OCCURRENCE OF '&' IN lv_uuid WITH space.
    IF lv_uuid IS INITIAL.
      server->response->set_status( code = 404 reason = '文件唯一标识未指定' ).
    ELSE.
      CALL METHOD me->download_file_by_uuid
        EXPORTING
          server  = server
          iv_uuid = lv_uuid.
    ENDIF.
    RETURN.
  ENDIF.


* PDF存入系统表
  CLEAR lv_uuid.
  lv_regex = '^pdf=(.*)'.
  FIND REGEX lv_regex IN lv_query SUBMATCHES lv_uuid.
  IF sy-subrc = 0.
    IF lv_uuid IS INITIAL.
      server->response->set_status( code = 404 reason = '文件唯一标识未指定' ).
    ELSE.
      CALL METHOD me->download_file_by_pdf
        EXPORTING
          server  = server
          iv_uuid = lv_uuid.
    ENDIF.
    RETURN.
  ENDIF.
  
* else请求参数不支持
  server->response->set_status( code = 404 reason = '文件请求参数不支持' ).

1.读取文件服务器(AL11)
包含的数据库表ZBCT_APP_FILE,用来记录上传时对应的uuid和相应文件路径:
在这里插入图片描述

METHOD download_file_by_uuid.

  DATA:
    lt_return       TYPE bapiret2_t,
    lt_header       TYPE tihttpnvp,
    ls_header       TYPE ihttpnvp,
    lv_uuid         TYPE string,
    lv_file_name    TYPE string,
    lv_file_content TYPE xstring,
    lv_file_length  TYPE i,
    lv_content_type TYPE string,
    lv_failed       TYPE abap_bool.

* 获取文件唯一标识
  lv_uuid = iv_uuid.
  TRANSLATE lv_uuid TO LOWER CASE.

* 获取文件信息
  IF lv_uuid IS NOT INITIAL.
    SELECT SINGLE *
      FROM zbct_app_file
      INTO @DATA(ls_app_file)
     WHERE file_name = @lv_uuid.
    IF sy-subrc <> 0.
      CLEAR ls_app_file.
    ENDIF.
  ENDIF.

* 下载文件内容
  IF ls_app_file-file_fullname IS NOT INITIAL.
    CLEAR lt_return.
    CALL FUNCTION 'ZBC_FM_FILE_DOWNLOAD'
      EXPORTING
        iv_file_name    = ls_app_file-file_fullname
      IMPORTING
        et_return       = lt_return
        ev_file_content = lv_file_content
        ev_file_length  = lv_file_length.
    IF lv_file_content IS INITIAL.
      lv_failed = abap_true.
    ENDIF.
  ENDIF.

  IF lv_failed IS INITIAL.
* 文件名称
    lv_file_name = ls_app_file-file_name.
    IF ls_app_file-file_extension IS NOT INITIAL.
      lv_file_name = lv_file_name && '.' && ls_app_file-file_extension.
    ENDIF.

* 文件类型
    lv_content_type = ls_app_file-mime_type.
    IF lv_content_type IS INITIAL.
      lv_content_type = 'image/jpeg'.
    ENDIF.

* 返回文件名称
    CLEAR: lt_header, ls_header.
    ls_header-name = 'content-disposition'.
    ls_header-value = |outline; filename={ lv_file_name }|.
    server->response->set_header_fields( lt_header ).
  ENDIF.

  IF lv_failed IS NOT INITIAL.
    server->response->set_status( code = 404 reason = '文件不存在' ).
  ELSE.
    server->response->set_status( code = 200 reason = 'Ok' ).
    server->response->set_content_type( lv_content_type ).
    server->response->set_data( data = lv_file_content ).
  ENDIF.

ENDMETHOD.

内含的Function Module:ZBC_FM_FILE_DOWNLOAD 文件下载 代码如下

FUNCTION zbc_fm_file_download.
*"----------------------------------------------------------------------
*"*"本地接口:
*"  IMPORTING
*"     REFERENCE(IV_FILE_NAME)
*"     REFERENCE(IV_GUI_DOWNLOAD) OPTIONAL
*"  EXPORTING
*"     REFERENCE(ET_RETURN) TYPE  BAPIRET2_T
*"     REFERENCE(EV_FILE_NAME)
*"     REFERENCE(EV_FILE_PATH)
*"     REFERENCE(EV_FILE_EXTENSION)
*"     REFERENCE(EV_FILE_CONTENT) TYPE  XSTRING
*"     REFERENCE(EV_FILE_LENGTH)
*"     REFERENCE(ET_SOLIX) TYPE  SOLIX_TAB
*"----------------------------------------------------------------------

  DATA:
    lt_solix               TYPE solix_tab,
    ls_solix               TYPE solix,
    lv_command             TYPE sxpgcolist-name,
    lv_parameters          TYPE sxpgcolist-parameters,
    lv_opsystem            TYPE sxpgcolist-opsystem,
    lv_status              TYPE extcmdexex-status,
    lv_exitcode            TYPE extcmdexex-exitcode,
    lt_protocol            TYPE STANDARD TABLE OF btcxpm,
    lv_file_name           TYPE string,
    lv_file_path           TYPE string,
    lv_full_name           TYPE string,
    lv_path_separator      TYPE dmc_mds_path_separator,
    lv_file_length         TYPE i,
    lv_max_length          TYPE i,
    lv_actual_length       TYPE i,
    lv_window_title        TYPE string,
    lv_default_file_name   TYPE string,
    lv_prompt_on_overwrite TYPE abap_bool,
    lv_path                TYPE string,
    lv_user_action         TYPE i,
    lv_regex               TYPE string,
    lv_failed              TYPE abap_bool,
    lv_message             TYPE string.

  CLEAR: et_return,
         ev_file_name,
         ev_file_path,
         ev_file_extension,
         ev_file_content,
         ev_file_length,
         et_solix,
         lv_failed.

* 文件全名
  IF iv_file_name IS INITIAL.
    APPEND VALUE #( type = 'E' id = '00' number = '398' message = '文件名不能为空' ) TO et_return.
    RETURN.
  ENDIF.
  lv_full_name = iv_file_name.

* 判断文件是否已经存在
  lv_command = 'DIR'.
  lv_opsystem = 'UNIX'.
  lv_parameters = lv_full_name.
  CLEAR: lt_protocol, lv_status, lv_exitcode.
  CALL FUNCTION 'SXPG_COMMAND_EXECUTE'
    EXPORTING
      commandname                   = lv_command
      additional_parameters         = lv_parameters
      operatingsystem               = lv_opsystem
    IMPORTING
      status                        = lv_status
      exitcode                      = lv_exitcode
    TABLES
      exec_protocol                 = lt_protocol
    EXCEPTIONS
      no_permission                 = 1
      command_not_found             = 2
      parameters_too_long           = 3
      security_risk                 = 4
      wrong_check_call_interface    = 5
      program_start_error           = 6
      program_termination_error     = 7
      x_error                       = 8
      parameter_expected            = 9
      too_many_parameters           = 10
      illegal_command               = 11
      wrong_asynchronous_parameters = 12
      cant_enq_tbtco_entry          = 13
      jobcount_generation_error     = 14
      OTHERS                        = 15.
  IF sy-subrc <> 0 OR lv_status <> 'O' OR lv_exitcode <> 0.
    et_return = VALUE #( ( type = 'E' id = '00' number = '398' message = '文件不存在' ) ).
    RETURN.
  ENDIF.

* 打开文件
  CLEAR lv_message.
  TRY.
      OPEN DATASET lv_full_name FOR INPUT IN BINARY MODE MESSAGE lv_message.
    CATCH cx_sy_file_open INTO DATA(lx_file_open).
      lv_failed = abap_true.
      lv_message = lx_file_open->get_text( ).
    CATCH cx_sy_codepage_converter_init INTO DATA(lx_codepage_converter_init).
      lv_failed = abap_true.
      lv_message = lx_codepage_converter_init->get_text( ).
    CATCH cx_sy_conversion_codepage INTO DATA(lx_conversion_codepage).
      lv_failed = abap_true.
      lv_message = lx_conversion_codepage->get_text( ).
    CATCH cx_sy_file_authority INTO DATA(lx_file_authority).
      lv_failed = abap_true.
      lv_message = lx_file_authority->get_text( ).
    CATCH cx_sy_pipes_not_supported INTO DATA(lx_pipes_not_supported).
      lv_failed = abap_true.
      lv_message = lx_pipes_not_supported->get_text( ).
    CATCH cx_sy_too_many_files INTO DATA(lx_too_many_files).
      lv_failed = abap_true.
      lv_message = lx_too_many_files->get_text( ).
    CATCH cx_root INTO DATA(lx_root).
      lv_failed = abap_true.
      lv_message = lx_root->get_text( ).
  ENDTRY.

  IF lv_failed IS NOT INITIAL.
    APPEND VALUE #( type = 'E' id = '00' number = '398' message = lv_message ) TO et_return.
    RETURN.
  ENDIF.

* 读文件
  CLEAR: lt_solix, lv_file_length.
  DO.
    CLEAR: ls_solix, lv_actual_length, lv_message.
    lv_max_length = 255.
    TRY.
        READ DATASET lv_full_name INTO ls_solix-line MAXIMUM LENGTH lv_max_length ACTUAL LENGTH lv_actual_length.
      CATCH cx_sy_codepage_converter_init INTO lx_codepage_converter_init.
        lv_failed = abap_true.
        lv_message = lx_codepage_converter_init->get_text( ).
      CATCH cx_sy_conversion_codepage INTO lx_conversion_codepage.
        lv_failed = abap_true.
        lv_message = lx_conversion_codepage->get_text( ).
      CATCH cx_sy_file_authority INTO lx_file_authority.
        lv_failed = abap_true.
        lv_message = lx_file_authority->get_text( ).
      CATCH cx_sy_file_io INTO DATA(lx_file_io).
        lv_failed = abap_true.
        lv_message = lx_file_io->get_text( ).
      CATCH cx_sy_file_open INTO lx_file_open.
        lv_failed = abap_true.
        lv_message = lx_file_open->get_text( ).
      CATCH cx_sy_file_open_mode INTO DATA(lx_file_open_mode).
        lv_failed = abap_true.
        lv_message = lx_file_open_mode->get_text( ).
      CATCH cx_sy_pipe_reopen INTO DATA(lx_pipe_reopen).
        lv_failed = abap_true.
        lv_message = lx_pipe_reopen->get_text( ).
      CATCH cx_root INTO lx_root.
        lv_failed = abap_true.
        lv_message = lx_root->get_text( ).
    ENDTRY.
    IF lv_failed IS NOT INITIAL.
      APPEND VALUE #( type = 'E' id = '00' number = '398' message = lv_message ) TO et_return.
      EXIT.
    ENDIF.
    IF lv_actual_length IS INITIAL.
      EXIT.
    ENDIF.
    ADD lv_actual_length TO lv_file_length.
    APPEND ls_solix TO lt_solix.
  ENDDO.

* 转换二进制
  IF lt_solix IS NOT INITIAL.
    CALL FUNCTION 'SCMS_BINARY_TO_XSTRING'
      EXPORTING
        input_length = lv_file_length
      IMPORTING
        buffer       = ev_file_content
      TABLES
        binary_tab   = lt_solix
      EXCEPTIONS
        failed       = 1
        OTHERS       = 2.
  ENDIF.

* 关闭文件
  CLEAR lv_message.
  TRY.
      CLOSE DATASET lv_full_name.
    CATCH cx_sy_file_close INTO DATA(lx_file_close).
      lv_failed = abap_true.
      lv_message = lx_file_close->get_text( ).
    CATCH cx_root INTO lx_root.
      lv_failed = abap_true.
      lv_message = lx_root->get_text( ).
  ENDTRY.

  IF lv_message IS NOT INITIAL.
    APPEND VALUE #( type = 'E' id = '00' number = '398' message = lv_message ) TO et_return.
  ENDIF.

  IF lv_failed IS INITIAL.
    ev_file_length = lv_file_length.
    et_solix = lt_solix.

* 文件路径分隔符
    CLEAR lv_path_separator.
    CALL FUNCTION 'DMC_MDS_GET_PATHSEPARATOR'
      IMPORTING
        ev_path_separator     = lv_path_separator
      EXCEPTIONS
        opsys_not_supported   = 1
        filesys_not_supported = 2
        OTHERS                = 3.
    IF sy-subrc <> 0.
      lv_path_separator = '/'.
    ENDIF.

    CLEAR: lv_file_path, lv_file_name.
    FIND FIRST OCCURRENCE OF lv_path_separator IN lv_full_name.
    IF sy-subrc = 0.
      lv_regex = '(.*)\' && lv_path_separator && '(.*)'.
      FIND REGEX lv_regex IN lv_full_name SUBMATCHES lv_file_path lv_file_name.
    ELSE.
      lv_file_name = lv_full_name.
    ENDIF.
    ev_file_path = lv_file_path.

    FIND FIRST OCCURRENCE OF '.' IN lv_full_name.
    IF sy-subrc = 0.
      lv_regex = '(.*)\.(.*)'.
      FIND REGEX lv_regex IN lv_file_name SUBMATCHES ev_file_name ev_file_extension.
    ELSE.
      ev_file_name = lv_full_name.
    ENDIF.

    APPEND VALUE #( type = 'S' id = '00' number = '398' message = '文件下载成功' ) TO et_return.
  ELSE.
    APPEND VALUE #( type = 'E' id = '00' number = '398' message = '文件下载失败' ) TO et_return.
  ENDIF.

  IF iv_gui_download IS NOT INITIAL.
* 选择保存路径
    lv_window_title = '选择文件夹'.
    lv_default_file_name = lv_file_name.
    lv_prompt_on_overwrite = abap_true.
    CLEAR: lv_file_name, lv_path, lv_file_path, lv_user_action.
    CALL METHOD cl_gui_frontend_services=>file_save_dialog
      EXPORTING
        window_title              = lv_window_title
        default_file_name         = lv_default_file_name
        prompt_on_overwrite       = lv_prompt_on_overwrite
      CHANGING
        filename                  = lv_file_name
        path                      = lv_path
        fullpath                  = lv_file_path
        user_action               = lv_user_action
      EXCEPTIONS
        cntl_error                = 1
        error_no_gui              = 2
        not_supported_by_gui      = 3
        invalid_default_file_name = 4
        OTHERS                    = 5.
    IF sy-subrc <> 0.
      MESSAGE ID sy-msgid TYPE 'S' NUMBER sy-msgno DISPLAY LIKE 'E'
            WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
      RETURN.
    ENDIF.

    IF lv_user_action <> cl_gui_frontend_services=>action_ok.
      RETURN.
    ENDIF.

* 保存
    CALL METHOD cl_gui_frontend_services=>gui_download
      EXPORTING
        bin_filesize            = lv_file_length
        filename                = lv_file_path
        filetype                = 'BIN'
      CHANGING
        data_tab                = lt_solix
      EXCEPTIONS
        file_write_error        = 1
        no_batch                = 2
        gui_refuse_filetransfer = 3
        invalid_type            = 4
        no_authority            = 5
        unknown_error           = 6
        header_not_allowed      = 7
        separator_not_allowed   = 8
        filesize_not_allowed    = 9
        header_too_long         = 10
        dp_error_create         = 11
        dp_error_send           = 12
        dp_error_write          = 13
        unknown_dp_error        = 14
        access_denied           = 15
        dp_out_of_memory        = 16
        disk_full               = 17
        dp_timeout              = 18
        file_not_found          = 19
        dataprovider_exception  = 20
        control_flush_error     = 21
        not_supported_by_gui    = 22
        error_no_gui            = 23
        OTHERS                  = 24.
    IF sy-subrc <> 0.
      MESSAGE ID sy-msgid TYPE 'S' NUMBER sy-msgno DISPLAY LIKE 'E'
            WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
      RETURN.
    ELSE.
      MESSAGE '文件保存成功' TYPE 'S'.
    ENDIF.
  ENDIF.

ENDFUNCTION.
  1. PDF直接存系统表
    建立数据库表ZBCT_APP_PDF,用来记录PDF文件的二进制流
    在这里插入图片描述
METHOD download_file_by_pdf.

  TYPES:
    BEGIN OF ty_file,
      uuid      TYPE string,
      file_name TYPE string,
    END OF ty_file.

  DATA:
    lt_return       TYPE bapiret2_t,
    lt_header       TYPE tihttpnvp,
    ls_header       TYPE ihttpnvp,
    lt_file         TYPE STANDARD TABLE OF ty_file,
    ls_file         TYPE ty_file,
    lv_json         TYPE string,
    lv_uuid         TYPE sysuuid_c36,
    lv_sysuuid_c32  TYPE sysuuid_c32,
    lv_file_name    TYPE string,
    lv_file_content TYPE xstring,
    lv_file_length  TYPE i,
    lv_content_type TYPE string,
    lv_failed       TYPE abap_bool.

* 获取文件唯一标识
  lv_uuid = iv_uuid.
  TRANSLATE lv_uuid TO UPPER CASE.

  IF lv_uuid = 'HELP'.
    SELECT *
      FROM zbct_app_pdf
      INTO TABLE @DATA(lt_app_pdf)
     WHERE file_cat = @lv_uuid.

    CLEAR lt_file.
    LOOP AT lt_app_pdf INTO DATA(ls_app_pdf).
      lv_sysuuid_c32 = ls_app_pdf-guid.
      CALL METHOD cl_system_uuid=>convert_uuid_c32_static
        EXPORTING
          uuid     = lv_sysuuid_c32
        IMPORTING
          uuid_c36 = DATA(lv_uuid_c36).
      CLEAR ls_file.
      ls_file-uuid = lv_uuid_c36.
      TRANSLATE ls_file-uuid TO LOWER CASE.
      ls_file-file_name = ls_app_pdf-file_name.
      APPEND ls_file TO lt_file.
    ENDLOOP.

    SORT lt_file by file_name.

    CLEAR lv_json.
    CALL FUNCTION 'ZBC_FM_JSON_SERIALIZE'
      EXPORTING
        is_data = lt_file
      IMPORTING
        ev_json = lv_json.

    server->response->set_status( code = 200 reason = 'Ok' ).
    server->response->set_content_type( 'application/json' ).
    server->response->set_cdata( data = lv_json ).

    RETURN.
  ENDIF.

* 获取文件信息
  IF lv_uuid IS NOT INITIAL.
    CALL METHOD cl_system_uuid=>convert_uuid_c36_static
      EXPORTING
        uuid     = lv_uuid
      IMPORTING
        uuid_x16 = DATA(lv_guid).
    IF lv_guid IS NOT INITIAL.
      SELECT SINGLE *
        FROM zbct_app_pdf
        INTO @ls_app_pdf
       WHERE guid = @lv_guid.
      IF sy-subrc <> 0.
        CLEAR ls_app_pdf.
      ENDIF.
    ENDIF.
    IF ls_app_pdf IS INITIAL.
      lv_failed = abap_true.
    ENDIF.
  ENDIF.

  IF lv_failed IS INITIAL.
* 文件名称
    lv_file_name = ls_app_pdf-file_name.

* 文件类型
    lv_content_type = 'application/pdf'.

* 文件内容
    lv_file_content = ls_app_pdf-file_content.

* 返回文件名称
    CLEAR: lt_header, ls_header.
    ls_header-name = 'content-disposition'.
    ls_header-value = |outline; filename={ lv_file_name }|.
    server->response->set_header_fields( lt_header ).

    server->response->set_status( code = 200 reason = 'Ok' ).
    server->response->set_content_type( lv_content_type ).
    server->response->set_data( data = lv_file_content ).
  ELSE.
    server->response->set_status( code = 404 reason = '文件不存在' ).
  ENDIF.

ENDMETHOD.

上传文件

上传至文件服务器的对应目录下:
设计的文件传参格式如下图:
在这里插入图片描述

METHOD upload_file.

  DATA: BEGIN OF ls_action.
          INCLUDE TYPE zbc_cl_odata_file_mpc_ext=>ts_action.
  DATA:
          file_set TYPE zbc_cl_odata_file_mpc_ext=>tt_file,
        END OF ls_action,
        ls_file                  TYPE zbc_cl_odata_file_mpc_ext=>ts_file,
        lt_return                TYPE bapiret2_t,
        lt_header                TYPE tihttpnvp,
        ls_header                TYPE ihttpnvp,
        lv_content_type          TYPE string,
        lt_app_file              TYPE STANDARD TABLE OF zbct_app_file,
        ls_app_file              TYPE zbct_app_file,
        lv_upload_file_name      TYPE string,
        lv_upload_file_extension TYPE string,
        lv_guid                  TYPE guid,
        lv_full_name             TYPE string,
        lv_file_name             TYPE string,
        lv_file_path             TYPE string,
        lv_file_root_path        TYPE string,
        lv_file_sub_path         TYPE string,
        lv_file_extension        TYPE string,
        lv_file_content          TYPE xstring,
        lv_file_length           TYPE i,
        lv_json                  TYPE string,
        lv_regex                 TYPE string,
        lv_failed                TYPE abap_bool.

* 获取文件名称和文件扩展名
  CLEAR: lv_file_name, lv_upload_file_name, lv_upload_file_extension.
  lv_upload_file_name = server->request->get_header_field( 'SLUG' ).
  FIND FIRST OCCURRENCE OF '.' IN lv_upload_file_name.
  IF sy-subrc = 0.
    lv_regex = '(.*)\.(.*)'.
    FIND REGEX lv_regex IN lv_upload_file_name SUBMATCHES lv_file_name lv_upload_file_extension.
  ELSE.
    lv_file_name = lv_upload_file_name.
  ENDIF.

* 生成文件唯一标识
  CLEAR: lt_return.
  CALL FUNCTION 'ZBC_FM_FILE_APP_GEN_FILE_NAME'
    EXPORTING
      iv_file_extension = lv_upload_file_extension
      iv_date           = sy-datum
    IMPORTING
      et_return         = lt_return
      ev_guid           = lv_guid
      ev_full_name      = lv_full_name
      ev_file_name      = lv_file_name
      ev_file_path      = lv_file_path
      ev_file_root_path = lv_file_root_path
      ev_file_sub_path  = lv_file_sub_path
      ev_file_extension = lv_file_extension.

* 获取文件内容
  DATA(lo_multipart) = server->request->get_multipart( 1 ).
  IF lo_multipart IS BOUND.
    lv_file_content = lo_multipart->get_data( ).
    lv_content_type = lo_multipart->get_content_type( ).
    IF lv_content_type = 'application/octet-stream'.
      lv_content_type = 'image/jpeg'.
    ENDIF.
  ENDIF.

  CLEAR: lt_return, lv_file_length.
  CALL FUNCTION 'ZBC_FM_FILE_UPLOAD'
    EXPORTING
      iv_file_name      = lv_file_name
      iv_file_extension = lv_file_extension
      iv_file_path      = lv_file_path
      iv_file_content   = lv_file_content
    IMPORTING
      et_return         = lt_return
      ev_file_length    = lv_file_length.

  CLEAR: lt_app_file, ls_app_file.
  ls_app_file-guid = lv_guid.
  ls_app_file-file_name = lv_file_name.
  ls_app_file-file_extension = lv_file_extension.
  ls_app_file-file_length = lv_file_length.
  ls_app_file-file_path = lv_file_path.
  ls_app_file-file_rootpath = lv_file_root_path.
  ls_app_file-file_subpath = lv_file_sub_path.
  ls_app_file-file_fullname = lv_full_name.
  ls_app_file-upload_file_name = lv_upload_file_name.
  ls_app_file-mime_type = lv_content_type.
  ls_app_file-created_date = sy-datum.
  ls_app_file-created_time = sy-uzeit.
  ls_app_file-created_user = sy-uname.
  APPEND ls_app_file TO lt_app_file.
  MODIFY zbct_app_file FROM TABLE lt_app_file.
  COMMIT WORK AND WAIT.

* 返回文件唯一标识
  CLEAR ls_file.
  ls_file-uuid = lv_file_name.
  ls_file-file_name = lv_upload_file_name.
  ls_file-mime_type = lv_content_type.

  CLEAR ls_action.
  ls_action-name = 'File'.
  ls_action-method = 'Upload'.
  ls_action-param = lv_file_name.
  ls_action-desc = lv_upload_file_name.
  APPEND ls_file TO ls_action-file_set.

  CLEAR lv_json.
  CALL FUNCTION 'ZBC_FM_JSON_SERIALIZE'
    EXPORTING
      is_data = ls_action
    IMPORTING
      ev_json = lv_json.

  IF lv_failed IS NOT INITIAL.
    server->response->set_status( code = 500 reason = '文件上传失败' ).
  ELSE.
    lv_content_type = 'application/json'.
    server->response->set_status( code = 200 reason = 'Ok' ).
    server->response->set_content_type( lv_content_type ).
    server->response->set_cdata( data = lv_json ).
  ENDIF.

ENDMETHOD.

对应Function Module代码如下:
ZBC_FM_FILE_APP_GEN_FILE_NAME

FUNCTION zbc_fm_file_app_gen_file_name.
*"----------------------------------------------------------------------
*"*"本地接口:
*"  IMPORTING
*"     REFERENCE(IV_FILE_NAME) OPTIONAL
*"     REFERENCE(IV_FILE_EXTENSION) DEFAULT 'jpg'
*"     REFERENCE(IV_DATE) TYPE  SY-DATUM DEFAULT SY-DATUM
*"  EXPORTING
*"     REFERENCE(ET_RETURN) TYPE  BAPIRET2_T
*"     REFERENCE(EV_GUID)
*"     REFERENCE(EV_FULL_NAME)
*"     REFERENCE(EV_FILE_NAME)
*"     REFERENCE(EV_FILE_EXTENSION)
*"     REFERENCE(EV_FILE_PATH)
*"     REFERENCE(EV_FILE_ROOT_PATH)
*"     REFERENCE(EV_FILE_SUB_PATH)
*"----------------------------------------------------------------------

  DATA:
    lv_file_path      TYPE string,
    lv_path_separator TYPE dmc_mds_path_separator.

  CLEAR: et_return,
         ev_guid,
         ev_full_name,
         ev_file_name,
         ev_file_path,
         ev_file_extension.

* 获取APP文件夹
  CALL FUNCTION 'ZBC_FM_FILE_APP_DIR_HOME'
    IMPORTING
      ev_dir = lv_file_path.
  IF lv_file_path IS INITIAL.
    APPEND VALUE #( type = 'E' id = '00' number = '398' message = '文件服务器目录未维护' ) TO et_return.
    RETURN.
  ENDIF.

* 文件路径分隔符
  CLEAR lv_path_separator.
  CALL FUNCTION 'DMC_MDS_GET_PATHSEPARATOR'
    IMPORTING
      ev_path_separator     = lv_path_separator
    EXCEPTIONS
      opsys_not_supported   = 1
      filesys_not_supported = 2
      OTHERS                = 3.
  IF sy-subrc <> 0.
    lv_path_separator = '/'.
  ENDIF.

* 取日期作为子文件夹
  ev_file_root_path = lv_file_path.
  ev_file_sub_path = iv_date.
  ev_file_path = lv_file_path && lv_path_separator && ev_file_sub_path.

* 按uuid生成文件名称
  IF iv_file_name IS NOT INITIAL.
    ev_file_name = iv_file_name.
  ELSE.
    CALL FUNCTION 'ZBC_FM_CREATE_GUID'
      IMPORTING
        ev_guid = ev_guid
        ev_uuid = ev_file_name.
  ENDIF.

* 文件全名
  ev_full_name = ev_file_path && lv_path_separator && ev_file_name.
  IF iv_file_extension IS NOT INITIAL.
    ev_file_extension = iv_file_extension.
    ev_full_name = ev_full_name && '.' && ev_file_extension.
  ENDIF.

ENDFUNCTION.

ZBC_FM_FILE_APP_DIR_HOME 获取APP文件夹

FUNCTION zbc_fm_file_app_dir_home.
*"----------------------------------------------------------------------
*"*"本地接口:
*"  EXPORTING
*"     REFERENCE(EV_DIR)
*"----------------------------------------------------------------------

  CLEAR ev_dir.

* AL11目录
  SELECT SINGLE dirname
    FROM user_dir
    INTO @ev_dir
   WHERE aliass = 'ZAPP_FILE'.

ENDFUNCTION.

ZBC_FM_CREATE_GUID 生成GUID

FUNCTION zbc_fm_create_guid.
*"----------------------------------------------------------------------
*"*"本地接口:
*"  EXPORTING
*"     REFERENCE(EV_GUID)
*"     REFERENCE(EV_UUID)
*"----------------------------------------------------------------------

  CLEAR: ev_guid, ev_uuid.

  TRY.
      DATA(lv_uuid) = cl_system_uuid=>create_uuid_c32_static( ).
    CATCH cx_uuid_error.
  ENDTRY.

  IF ev_guid IS SUPPLIED.
    ev_guid = lv_uuid.
  ENDIF.

  IF ev_uuid IS SUPPLIED.
    CALL METHOD cl_system_uuid=>convert_uuid_c32_static
      EXPORTING
        uuid     = lv_uuid
      IMPORTING
        uuid_c36 = DATA(lv_uuid_c36).
    ev_uuid = lv_uuid_c36.
    TRANSLATE ev_uuid TO LOWER CASE.
  ENDIF.

ENDFUNCTION.

ZBC_FM_FILE_UPLOAD 文件上传

FUNCTION zbc_fm_file_upload.
*"----------------------------------------------------------------------
*"*"本地接口:
*"  IMPORTING
*"     REFERENCE(IV_FILE_NAME) OPTIONAL
*"     REFERENCE(IV_FILE_EXTENSION) OPTIONAL
*"     REFERENCE(IV_FILE_PATH)
*"     REFERENCE(IV_FILE_CONTENT) TYPE  XSTRING OPTIONAL
*"  EXPORTING
*"     REFERENCE(ET_RETURN) TYPE  BAPIRET2_T
*"     REFERENCE(EV_FILE_NAME)
*"     REFERENCE(EV_FILE_LENGTH)
*"----------------------------------------------------------------------

  DATA:
    lt_solix          TYPE solix_tab,
    lv_file_name      TYPE string,
    lv_file_path      TYPE string,
    lv_full_name      TYPE string,
    lv_path_separator TYPE dmc_mds_path_separator,
    lv_uuid           TYPE string,
    lv_file_length    TYPE i,
    lv_length         TYPE i,
    lv_failed         TYPE abap_bool,
    lv_message        TYPE string.

  CLEAR: et_return, ev_file_name, ev_file_length, lv_failed.

* 生成uuid文件名
  CLEAR lv_file_name.
  IF iv_file_name IS NOT INITIAL.
    lv_file_name = iv_file_name.
  ELSE.
    CALL FUNCTION 'ZBC_FM_CREATE_GUID'
      IMPORTING
        ev_uuid = lv_uuid.
    lv_file_name = lv_uuid.
  ENDIF.

* 创建文件夹
  lv_file_path = iv_file_path.
  CALL FUNCTION 'ZBC_FM_FILE_MKDIR'
    EXPORTING
      iv_dir    = lv_file_path
    IMPORTING
      et_return = et_return.
  LOOP AT et_return TRANSPORTING NO FIELDS
    WHERE type CA 'EAX'.
    EXIT.
  ENDLOOP.
  IF sy-subrc = 0.
    RETURN.
  ENDIF.

* 文件路径分隔符
  CLEAR lv_path_separator.
  CALL FUNCTION 'DMC_MDS_GET_PATHSEPARATOR'
    IMPORTING
      ev_path_separator     = lv_path_separator
    EXCEPTIONS
      opsys_not_supported   = 1
      filesys_not_supported = 2
      OTHERS                = 3.
  IF sy-subrc <> 0.
    lv_path_separator = '/'.
  ENDIF.

* 文件全名
  lv_full_name = lv_file_path && lv_path_separator && lv_file_name.
  IF iv_file_extension IS NOT INITIAL.
    lv_full_name = lv_full_name && '.' && iv_file_extension.
  ENDIF.

* 打开文件
  CLEAR lv_message.
  TRY.
      OPEN DATASET lv_full_name FOR OUTPUT IN BINARY MODE MESSAGE lv_message.
    CATCH cx_sy_file_open INTO DATA(lx_file_open).
      lv_failed = abap_true.
      lv_message = lx_file_open->get_text( ).
    CATCH cx_sy_codepage_converter_init INTO DATA(lx_codepage_converter_init).
      lv_failed = abap_true.
      lv_message = lx_codepage_converter_init->get_text( ).
    CATCH cx_sy_conversion_codepage INTO DATA(lx_conversion_codepage).
      lv_failed = abap_true.
      lv_message = lx_conversion_codepage->get_text( ).
    CATCH cx_sy_file_authority INTO DATA(lx_file_authority).
      lv_failed = abap_true.
      lv_message = lx_file_authority->get_text( ).
    CATCH cx_sy_pipes_not_supported INTO DATA(lx_pipes_not_supported).
      lv_failed = abap_true.
      lv_message = lx_pipes_not_supported->get_text( ).
    CATCH cx_sy_too_many_files INTO DATA(lx_too_many_files).
      lv_failed = abap_true.
      lv_message = lx_too_many_files->get_text( ).
    CATCH cx_root INTO DATA(lx_root).
      lv_failed = abap_true.
      lv_message = lx_root->get_text( ).
  ENDTRY.

  IF lv_failed IS NOT INITIAL.
    APPEND VALUE #( type = 'E' id = '00' number = '398' message = lv_message ) TO et_return.
    RETURN.
  ENDIF.

* 转换二进制
  CLEAR: lt_solix, lv_file_length.
  CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
    EXPORTING
      buffer        = iv_file_content
    IMPORTING
      output_length = lv_file_length
    TABLES
      binary_tab    = lt_solix.

  ev_file_name = lv_file_name.
  ev_file_length = lv_file_length.

* 写文件
  LOOP AT lt_solix INTO DATA(ls_solix).
    DESCRIBE FIELD ls_solix-line LENGTH lv_length IN BYTE MODE.
    IF lv_length > lv_file_length.
      lv_length = lv_file_length.
    ELSE.
      SUBTRACT lv_length FROM lv_file_length.
    ENDIF.
    CHECK lv_length > 0.
    CLEAR lv_message.
    TRY.
        TRANSFER ls_solix-line TO lv_full_name LENGTH lv_length.
      CATCH cx_sy_codepage_converter_init INTO lx_codepage_converter_init.
        lv_failed = abap_true.
        lv_message = lx_codepage_converter_init->get_text( ).
      CATCH cx_sy_conversion_codepage INTO lx_conversion_codepage.
        lv_failed = abap_true.
        lv_message = lx_conversion_codepage->get_text( ).
      CATCH cx_sy_file_authority INTO lx_file_authority.
        lv_failed = abap_true.
        lv_message = lx_file_authority->get_text( ).
      CATCH cx_sy_file_io INTO DATA(lx_file_io).
        lv_failed = abap_true.
        lv_message = lx_file_io->get_text( ).
      CATCH cx_sy_file_open INTO lx_file_open.
        lv_failed = abap_true.
        lv_message = lx_file_open->get_text( ).
      CATCH cx_sy_file_open_mode INTO DATA(lx_file_open_mode).
        lv_failed = abap_true.
        lv_message = lx_file_open_mode->get_text( ).
      CATCH cx_sy_pipe_reopen INTO DATA(lx_pipe_reopen).
        lv_failed = abap_true.
        lv_message = lx_pipe_reopen->get_text( ).
      CATCH cx_sy_too_many_files INTO lx_too_many_files.
        lv_failed = abap_true.
        lv_message = lx_too_many_files->get_text( ).
      CATCH cx_root INTO lx_root.
        lv_failed = abap_true.
        lv_message = lx_root->get_text( ).
    ENDTRY.
    IF lv_failed IS NOT INITIAL.
      APPEND VALUE #( type = 'E' id = '00' number = '398' message = lv_message ) TO et_return.
      EXIT.
    ENDIF.
  ENDLOOP.

* 关闭文件
  CLEAR lv_message.
  TRY.
      CLOSE DATASET lv_full_name.
    CATCH cx_sy_file_close INTO DATA(lx_file_close).
      lv_failed = abap_true.
      lv_message = lx_file_close->get_text( ).
    CATCH cx_root INTO lx_root.
      lv_failed = abap_true.
      lv_message = lx_root->get_text( ).
  ENDTRY.

  IF lv_message IS NOT INITIAL.
    APPEND VALUE #( type = 'E' id = '00' number = '398' message = lv_message ) TO et_return.
  ENDIF.

  IF lv_failed IS INITIAL.
    APPEND VALUE #( type = 'S' id = '00' number = '398' message = '文件上传成功' ) TO et_return.
  ELSE.
    APPEND VALUE #( type = 'E' id = '00' number = '398' message = '文件上传失败' ) TO et_return.
  ENDIF.

ENDFUNCTION.

ZBC_FM_FILE_MKDIR 创建文件夹

FUNCTION zbc_fm_file_mkdir.
*"----------------------------------------------------------------------
*"*"本地接口:
*"  IMPORTING
*"     REFERENCE(IV_DIR)
*"  EXPORTING
*"     REFERENCE(ET_RETURN) TYPE  BAPIRET2_T
*"----------------------------------------------------------------------

  DATA:
    lv_command  TYPE sxpgcolist-name,
    lv_dir      TYPE sxpgcolist-parameters,
    lv_opsystem TYPE sxpgcolist-opsystem,
    lv_status   TYPE extcmdexex-status,
    lv_exitcode TYPE extcmdexex-exitcode,
    lt_protocol TYPE STANDARD TABLE OF btcxpm.

  CLEAR et_return.

* 文件夹
  lv_dir = iv_dir.
  IF lv_dir IS INITIAL.
    et_return = VALUE #( ( type = 'S' id = '00' number = '398' message = '文件夹不能为空' ) ).
    RETURN.
  ENDIF.

* 判断文件夹是否已经存在
  lv_command = 'DIR'.
  lv_opsystem = 'UNIX'.
  CLEAR: lt_protocol, lv_status, lv_exitcode.
  CALL FUNCTION 'SXPG_COMMAND_EXECUTE'
    EXPORTING
      commandname                   = lv_command
      additional_parameters         = lv_dir
      operatingsystem               = lv_opsystem
    IMPORTING
      status                        = lv_status
      exitcode                      = lv_exitcode
    TABLES
      exec_protocol                 = lt_protocol
    EXCEPTIONS
      no_permission                 = 1
      command_not_found             = 2
      parameters_too_long           = 3
      security_risk                 = 4
      wrong_check_call_interface    = 5
      program_start_error           = 6
      program_termination_error     = 7
      x_error                       = 8
      parameter_expected            = 9
      too_many_parameters           = 10
      illegal_command               = 11
      wrong_asynchronous_parameters = 12
      cant_enq_tbtco_entry          = 13
      jobcount_generation_error     = 14
      OTHERS                        = 15.
  IF sy-subrc = 0 AND lv_status = 'O' AND lv_exitcode = 0.
    et_return = VALUE #( ( type = 'S' id = '00' number = '398' message = '文件夹已存在' ) ).
    RETURN.
  ENDIF.

  lv_command = 'ZMKDIR'.
  lv_opsystem = 'ANYOS'.
  CLEAR: lt_protocol, lv_status, lv_exitcode.
  CALL FUNCTION 'SXPG_COMMAND_EXECUTE'
    EXPORTING
      commandname                   = lv_command
      additional_parameters         = lv_dir
      operatingsystem               = lv_opsystem
    IMPORTING
      status                        = lv_status
      exitcode                      = lv_exitcode
    TABLES
      exec_protocol                 = lt_protocol
    EXCEPTIONS
      no_permission                 = 1
      command_not_found             = 2
      parameters_too_long           = 3
      security_risk                 = 4
      wrong_check_call_interface    = 5
      program_start_error           = 6
      program_termination_error     = 7
      x_error                       = 8
      parameter_expected            = 9
      too_many_parameters           = 10
      illegal_command               = 11
      wrong_asynchronous_parameters = 12
      cant_enq_tbtco_entry          = 13
      jobcount_generation_error     = 14
      OTHERS                        = 15.
  IF sy-subrc = 0 AND lv_status = 'O' AND lv_exitcode = 0.
    et_return = VALUE #( ( type = 'S' id = '00' number = '398' message = '文件夹创建成功' ) ).
  ELSE.
    et_return = VALUE #( ( type = 'E' id = '00' number = '398' message = '文件夹创建失败' ) ).
    LOOP AT lt_protocol INTO DATA(ls_protocol).
      APPEND VALUE #( type = 'E' id = '00' number = '398' message = ls_protocol-message ) TO et_return.
    ENDLOOP.
  ENDIF.

ENDFUNCTION.

以上就是此次需求的 文件上传和下载 的思路,如果对你有帮助,希望动动你的小手帮忙点赞,感谢!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_44911062/article/details/118358917

智能推荐

车载充电器OBC方案:PFC两相交错并联+DC全桥LLC+28035控制,实用范围限于项目参考学习-程序员宅基地

文章浏览阅读326次,点赞5次,收藏4次。本文将围绕车载充电器的3.3KW车载充电机OBC方案展开讨论,具体方案包括PFC两相交错并联、DC全桥LLC、28035控制和CAN通信等。通过对方案中的PFC两相交错并联、DC全桥LLC、28035控制和CAN通信的讨论,我们可以更好地理解车载充电器的设计原理和工作方式。在本方案中,使用28035控制器来实现车载充电器的控制和管理功能,通过编程控制各个模块的工作状态,实现充电器的高效、稳定运行。在本方案中,使用CAN通信来实现充电器与汽车电池管理系统之间的数据交互,实现充电过程的监控和控制。

PyQt5-计时器控件_pyqt5计时器-程序员宅基地

文章浏览阅读582次。PyQt5-计时器控件_pyqt5计时器

[leetcode] 490. The Maze @ python_leetcode 490 python-程序员宅基地

文章浏览阅读2.3k次。原题https://leetcode.com/problems/the-maze/解法DFS. 定义dfs函数, 返回球从(x, y)出发, 是否能停在目的地. 回溯的条件是如果(x,y) 等于目的地, 返回True.如果(x, y)是已经访问过的, 返回False. 我们将访问过的位置放入visited, 然后在上下左右四个方向检查, 让球一直滚, 检查停住的地方是否为目的地, 如果有一个..._leetcode 490 python

删除anaconda后出现的python环境变量问题_将软件删除后环境变量-程序员宅基地

文章浏览阅读2k次,点赞2次,收藏3次。问题没删除anaconda之前已经配置好anaconda环境变量,在cmd中默认下载包的位置是anaconda中,由于某些原因将anaconda卸载后(又重新配置了python环境变量),发现在cmd下载包成功后,在idle中找不到。解决方法:1.在cmd中输入下面这个命令:where python发现有两个python。一个是我自己安装的,另一个的位置是在C:\Users\m\AppData\Local\Microsoft\WindowsApps下。2.所以在cmd中下载的包就在c盘_将软件删除后环境变量

真的,准备点「现金」吧!-程序员宅基地

文章浏览阅读122次。loonggg读完需要3分钟速读仅需 1 分钟大家好,我是校长。当一座城市突然断电,也就是意味着突然失去了互联网,你们猜,我们的生活会怎么样?前几天,这种事就真的发生了,发生在了因暴雨肆虐..._有人说备点现金,啥意思

【编程题】字符串压缩算法和常用的substr与replace函数_小q想要给他的朋友发送一个神秘字符串,但是他发现字符串的过于长了,于是小q发明了-程序员宅基地

文章浏览阅读414次。题目描述:小Q想要给他的朋友发送一个神秘字符串,但是他发现字符串的过于长了,于是小Q发明了一种压缩算法对字符串中重复的部分进行了压缩,对于字符串中连续的m个相同字符串S将会压缩为[m|S](m为一个整数且1<=m<=100),例如字符串ABCABCABC将会被压缩为[3|ABC],现在小Q的同学收到了小Q发送过来的字符串,你能帮助他进行解压缩么?#include <..._小q想要给他的朋友发送一个神秘字符串,但是他发现字符串的过于长了,于是小q发明了

随便推点

VCG笔记-mesh元素的创建/删除_c++怎么用一个mesh的部分顶点创建一个新mesh-程序员宅基地

文章浏览阅读2.8k次。1 创建mesh元素  我们在创建简单的网格模型或者为已存在的网格模型添加元素的时候,我们应该使用AddVertices和AddFaces这两个函数,新的元素被添加到网格模型的尾部,函数会返回指向第一个新分配(或者说是添加)的第一个元素的指针。向vector添加元素会引起存储空间的重新分配(reallocation),因此可能会出现无效的指针指向网格元素。而上述的AddVertices和AddFac_c++怎么用一个mesh的部分顶点创建一个新mesh

无监督学习 聚类算法代码+原理+对比分析-程序员宅基地

文章浏览阅读1.1w次,点赞3次,收藏9次。无监督学习 聚类算法1:经典的K means纵使簇类需要专家系统与先验知识定义,K means 也依旧在当前的机器学习与深度学习使用,例如各种数据分析以及深度学习全连接以后的输出层网络连接,它与他的衍生算法,例如K means ++ ,在聚类算法中一直是老大地位,因为他的速度是极快的,相比其他算法在计算簇间相似度与簇内相似度中的速度较慢;所以就出现了很多算法,是来优化K means 家族的,例如在簇的寻找上,使用DBACAN等层次聚类算法用来给K means ++ 寻找最合适的簇个数,在此基础上,DBA

TwinCAT设置项目开机自动启动_twincat2设置开机自动运行程序-程序员宅基地

文章浏览阅读7.8k次,点赞2次,收藏10次。https://blog.csdn.net/little_snail_bing/article/details/86628856开机自动运行可以这样设置:1、右键TEST,勾选上 Autostart Boot Project2、单击SYSTEM,勾选上Run Mode,再勾选上Auto Logan,在下面的框里填入电脑的用户名和登陆密码,点击Apply,激活配置;再次开机就会自动启动..._twincat2设置开机自动运行程序

java使用file.createNewFile()创建文件时,报错目录不存在,如何解决_file.createnewfile() 报错-程序员宅基地

文章浏览阅读1.2w次,点赞15次,收藏25次。普通创建文件代码:String strPath = "E:\\test\\test1\\test.txt";File file = new File(strPath);if(!file.exists())){ file.createNewFile();}上述这段代码,当E:\test\test1目录不存在时,createNewFile()执行会报错:java.io.IOException:Parent directory of file does not existString st_file.createnewfile() 报错

2-3计算分段函数_计算分段函数(判断x是否不为0)-程序员宅基地

文章浏览阅读4.1k次,点赞5次,收藏13次。例2-4:为鼓励居民节约用水,自来水公司采取用水量按月分段计费的办法,居民应交水费y元与月用水量x吨的函数关系式如下设x≥0.输入用户的月用水量x吨,计算并输出改用户应支付的水费y(元)(保留两位小数)。y=f(x)=4x/3; x≤15y=f(x)=2.5x-10.5 x>15做这个题的时候应该注意留意题目最后的保留两位小数,并结合实际,应该不适用整型常量。#inc..._计算分段函数(判断x是否不为0)

笔记:json对象和字符串的相互转换_matlab jsonencode 转字符串-程序员宅基地

文章浏览阅读139次。原文链接:https://www.cnblogs.com/yjd_hycf_space/p/7928384.html//使用json中的parser方法转换;var str='{"name":"fendouer", "age":23}'; //这是一个json字符串''var ob=JSON.parse(str) ; //返回一个新对象console.log..._matlab jsonencode 转字符串