zoukankan      html  css  js  c++  java
  • [SAP ABAP开发技术总结]将文件存储到数据库表中,并可发送邮件

     


    将文件转换为可邮件发送的字节码后存储到数据库表中

    以后考虑将CONTENT_HEX字段定义为LRAW类型,这样直接存储二进制,数据不会膨胀一倍了(也可采用其他方式,请参考 数据共享与传递->DATABASE章节
    "Table: ZJZJPDF 表结构设计如下:
    "Field name     Key     Data element      Datatype       Length
    "MANDT          X       MANDT             CLNT           3
    "ROW_ORDER      X                         NUMC           10
    "CHR_COUNT                                INT4           10
    "CONTENT_HEX                              LCHR           510 ":内类型为 C,并非 X
    "LCHR类型的字段前必须有一个INT4类型的字段,并且该字段不能是主键,该字段的值为后面
    "CONTENT_HEX的字符个数,并且需要在插入表时一并进行插入,否则CONTENT_HEX字段的值不能Select出来

    DATA: BEGIN OF xtab255 OCCURS 0,
       
    x(255) TYPE x,"一个字节需使用两个十六进制字符来表示
     
    END OF xtab255.
    DATA: ctab255 TYPE STANDARD TABLE OF solisti1 WITH HEADER LINE.
    DATA: BEGIN OF pdf_table OCCURS 0,
        mandt
    TYPE zjzjpdf-mandt,
        row_order
    TYPE zjzjpdf-row_order,
        chr_count
    TYPE zjzjpdf-chr_count,
        content_hex
    (510),"实为字符类型
     
    END OF pdf_table.
    ********==========================================插入
     
    CALL FUNCTION 'GUI_UPLOAD'
     
    EXPORTING
        filename
    = 'c:1.txt'
        filetype
    = 'BIN'
     
    TABLES
       data_tab
    = xtab255.
    *CALL FUNCTION 'GUI_UPLOAD'
    *  EXPORTING
    *    filename = 'c:1.JPG'
    *    filetype = 'BIN'
    *  TABLES
    *    "接收上传数据时,按收的内表行类型也可以是Char类型内表
    *    ",尽管是以BIN 模式上传的,因为该上传函数内部还是以
    *    "X类型视图来维护ctab255内表的
    *    data_tab = ctab255.

    LOOP AT xtab255.
      pdf_table
    -row_order = sy-tabix.
      pdf_table
    -content_hex xtab255-x.
     
    "chr_count为内容content_hex字段值的长度,一定要设置,否则下次不能Select出来
      pdf_table
    -chr_count = strlen( pdf_table-content_hex ).
     
    APPEND  pdf_table .
    ENDLOOP.
    DELETE FROM zjzjpdf."清空数据库表中的所有数据
    MODIFY zjzjpdf FROM TABLE pdf_table[]."插入到数据库
    ********==========================================读取
    CLEAR: pdf_table[].
    SELECT * INTO TABLE pdf_table FROM zjzjpdf.
    SORT pdf_table BY row_order.
    CLEAR:xtab255[].
    LOOP AT pdf_table.
     
    "将数据库表中字面上的HEX字符串转换为真正的HEX二进制
      xtab255
    -x = pdf_table-content_hex.
     
    APPEND xtab255.
    ENDLOOP.

    "注意:虽然是原生态下载,但这里生成的文件在字节数上会多于源文本,并且字节数是255的整数倍,因为在上传的过程中使用的是xtab255类型的内表,当最后一行不满255个字节时,也会在后面补上直到255个字节,但补的都是00这样的字节,所以文件大小还是有区别的,但经过测试pdfmp3在码流后面补00字节好像没有什么影响唯独是文件大小变大了。但如果是TXT文件,打开后发现多了很多空格(按理来说也是什么也没有,因为空格的ASCII码为32,但后面补的是00字节)
    CALL FUNCTION 'GUI_DOWNLOAD'
     
    EXPORTING
        filename
    = 'c:2.txt'
        filetype
    = 'BIN'
     
    TABLES
        data_tab
    = xtab255.
    *************************************************************************************
    如果需要将PDF以邮件的形式发送出去时,上面的 xtab255 内表接口就已适合于使用cl_document_bcs类的add_attachment方法来发送邮件的i_att_content_hex内表参数接口;但如果使用SO_DOCUMENT_SEND_API1函数的方式来发送邮件时,并使用CONTENTS_BIN过时(可以使用新参参数CONTENTS_HEX内表接口时不需转换为下面的ctab255内表接口,也可以直接使用上面的xtab255内表接口)的内表参数接口传递PDF文件内容时,需要使用下面方式经过转换后的内表ctab255,即需要将上面的 xtab255 内表中每两行转换为 ctab255(行类型为 Char255)内表中的一行(因为一个X类型为一个字节,但在Unicode中一个C可存两个字节的内容,所以需二行转换一行操作)
    *************************************************************************************
    FIELD-SYMBOLS: <x> TYPE x.
    DATA: c_tmp1(510) TYPE c.
    DATA: c_tmp2(510) TYPE c.
    DATA: c_total(1020) TYPE c.
    DATA: tabix TYPE i,mod TYPE i.
    CLEAR: ctab255[].
    LOOP AT xtab255.
      tabix
    = sy-tabix.
     
    mod = tabix MOD 2.
     
    IF mod = 1.
       
    CLEAR: ctab255.
       
    "原来是准备使用字段符号<c>FIELD-SYMBOLS <c> type c 指向xtab255-x使用 assign xtab255-x to <c>,但该语句使用时有限制:xtab255-x的类型的长度(所定义的字节数)一定要是4的倍数,否则编译出错,所以换成了现在这样,思路:将赋值双方中不是X类型的需要以X类型视图来操作,这样X类型与X类型赋值时不会发生数据的丢失或者是类型的转换,而不是将原本为X类型的一方以C或者其类型视图来看待,这样在非X类型间的赋值可能会导致数据丢失或发生类型转换
       
    ASSIGN COMPONENT 'LINE'  OF STRUCTURE ctab255 TO <x> CASTING.
        c_tmp1
    = xtab255-x.
     
    ELSE.
        c_tmp2
    = xtab255-x.
       
    CONCATENATE c_tmp1 c_tmp2 INTO c_total .
        <x>
    = c_total. "因为4个字面上的十六进制字符才能表示一个字符C,所以从c_total以十六进制方式赋值给ctab255 时,缩短了3/4
       
    APPEND ctab255.
       
    CLEAR: c_tmp1.
     
    ENDIF.
    ENDLOOP.
    "可能是奇数后,所以需要判断一下,将最后一行也要附加上去
    IF c_tmp1 IS NOT INITIAL.
      <x>
    = c_tmp1.
     
    APPEND ctab255.
    ENDIF.

    发送邮件

    FORM send_email.
     
    DATA: BEGIN OF addr_email OCCURS 0,
          smtp_addr
    (241),
       
    END OF addr_email.


     
    DATA: i_receivers LIKE somlreci1 OCCURS 0 WITH HEADER LINE,
        i_message
    LIKE solisti1 OCCURS 0 WITH HEADER LINE.

     
    DATA: l_subject       TYPE so_obj_des,
            l_filename
    TYPE string.

     
    SELECT smtp_addr FROM zmm_invtr_email INTO TABLE addr_email.
     
    CHECK addr_email[] IS NOT INITIAL.

     
    LOOP AT addr_email.
       
    CLEAR:i_receivers.
        i_receivers
    -receiver = addr_email-smtp_addr.
        i_receivers
    -rec_type = 'U'.
        i_receivers
    -com_type = 'INT'.
    *     i_receivers-copy = 'X'."CC
    *     i_receivers-blind_copy = 'X'."BCC
        i_receivers
    -express = 'X'."TO
       
    APPEND i_receivers.
     
    ENDLOOP.

      l_subject
    = `hi,baby`."邮件标题
      l_filename
    = 'attach.txt'."附件文件名

      i_message
    -line = `邮件的内容`.
     
    APPEND i_message.


     
    DATA: t_atthead  TYPE STANDARD TABLE OF string,
           
    return TYPE bapiret1.

     
    PERFORM send_email_with_att_xls TABLES i_receivers
                                             i_message
                                             t_atthead
                                             <stat_tab>
                                     
    USING 
    l_subject
                                             sy
    -
    uname
                                             l_filename
                                            
    return.

    *  MESSAGE return-message TYPE 'S' DISPLAY LIKE return-type.
    ENDFORM.                    "export_xls

    *&---------------------------------------------------------------------*
    *&      Form  send_email_with_att_xls
    *&---------------------------------------------------------------------*
    *       XLS附件的邮件发送
    *----------------------------------------------------------------------*
    *      -->T_RECEIVERS  邮件接收者
    *      -->T_MESSAGE    邮件内容
    *      -->T_ATTHEAD    XLS附件中标题(XLS首行内容)
    *      -->T_ATTTAB     附件内容
    *      -->IM_SUBJECT   邮件标题
    *      -->IM_UNAME     邮件发送者
    *      -->IM_FILENAME  附件名称
    *      -->RETURN       返回信息
    *----------------------------------------------------------------------*
    FORM send_email_with_att_xls TABLES t_receivers STRUCTURE somlreci1
                                        t_message
    STRUCTURE
    solisti1
                                        t_atthead
                                        t_atttab
                                
    USING  im_subject TYPE
    so_obj_des
                                        im_uname
    TYPE
    uname
                                        im_filename
    TYPE
    string
                                       
    return TYPE bapiret1.

     
    CONSTANTS: c_tab  TYPE c VALUE cl_abap_char_utilities=>horizontal_tab,
                
    "回车换行,实质上对应 Xstring: 000D000A
                 c_crlf
    (2) TYPE c VALUE cl_abap_char_utilities=>cr_lf.

     
    DATA: xstr TYPE xstring,
            it_binary_attach
    TYPE solix_tab.

    ************************将内表所有的内容存储到一个字符串中

     
    DATA: lc_descr_ref TYPE REF TO cl_abap_structdescr,
            lv_value    
    TYPE char128,
            lv_temp     
    TYPE string,
            lv_mid      
    TYPE string.

     
    FIELD-SYMBOLS: <fs_table> TYPE ANY.
     
    FIELD-SYMBOLS: <intable_wa> TYPE abap_compdescr.

     
    CLEAR lv_temp.
     
    "将头内表拼接成一个字符串
     
    IF t_atthead[] IS NOT INITIAL.
       
    LOOP AT t_atthead.
         
    IF sy-tabix = 1.
            lv_temp
    = t_atthead.
           
    CONTINUE.
         
    ENDIF.
         
    CONCATENATE lv_temp t_atthead
                
    INTO lv_temp SEPARATED BY c_tab.

       
    ENDLOOP.
       
    CONCATENATE lv_temp c_crlf INTO lv_mid.
     
    ENDIF.

     
    "将主体内表拼接成一个字符串
     
    LOOP AT t_atttab.
        lc_descr_ref ?= cl_abap_typedescr
    =>describe_by_data( t_atttab ).
       
    LOOP AT lc_descr_ref->components ASSIGNING <intable_wa>.

         
    ASSIGN COMPONENT sy-tabix OF STRUCTURE  t_atttab TO <fs_table>.
         
    "如果是数字类型时
         
    IF <intable_wa>-type_kind = 'P' OR <intable_wa>-type_kind = 'F'
           
    OR <intable_wa>-type_kind = 'I' OR <intable_wa>-type_kind = 'b'
           
    OR <intable_wa>-type_kind = 's'.
           
    IF <fs_table> = 0.
             
    CLEAR lv_value.
           
    ELSE.
             
    WRITE <fs_table> TO lv_value.
             
    CONDENSE lv_value NO-GAPS.
             
    IF <fs_table> < 0."将负号提前
               
    CALL FUNCTION 'CLOI_PUT_SIGN_IN_FRONT'
                 
    CHANGING
                   
    value = lv_value.
               
    CONDENSE lv_value NO-GAPS.
             
    ENDIF.
           
    ENDIF.
         
    ELSE.
            lv_value
    = <fs_table>.
           
    CONDENSE lv_value.
         
    ENDIF.

         
    IF sy-tabix = 1.
            lv_temp
    = lv_value.
           
    CONTINUE.
         
    ENDIF.
         
    CONCATENATE lv_temp lv_value
                
    INTO lv_temp SEPARATED BY c_tab.

       
    ENDLOOP.
       
    CONCATENATE lv_mid lv_temp c_crlf INTO lv_mid.
     
    ENDLOOP.
    ************************将字符进行编码转换,转换为二进制字节码流
     
    DATAl_codepage(4) TYPE n .
     
    DATAl_encoding(20).

     
    "
    将外部字符集名转换为内部编码

     
    CALL FUNCTION 'SCP_CODEPAGE_BY_EXTERNAL_NAME'
       
    EXPORTING
          external_name
    = 'UTF-8'
       
    IMPORTING
          sap_codepage 
    = l_codepage.
      l_encoding
    = l_codepage.

     
    DATA: convout TYPE REF TO cl_abap_conv_out_ce.
     
    "创建编码对象
      convout
    = cl_abap_conv_out_ce=>create( encoding = l_encoding ).
      convout
    ->write( data = lv_mid )."
    编码

      xstr
    convout->get_buffer( )."获取码流

    ************************接口转换:将码流按使用的参数接口要求进行重组转换
     
    " xstring 的字符串存储到行结构为 X 类型的内表中,以适合于邮件发
     
    "送接口。该函数并不是将 xstring 字符转换为 二进制(因为xstring本身就
     
    "是原生态,从函数名上看容易误导)。
     
    CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
       
    EXPORTING
         
    buffer     = xstr
       
    TABLES

          binary_tab
    = it_binary_attach.

     

    *另外,也可以将行结构为 X 类型的内表中所有HEX内容拼接成一个Xstring并存储在l_xstr变量中,也不要被函*数名给迷糊了:并不是将二进制什么的转换为Xstring类型了,而只不过是将将内表结构转换为单一的字符串了

    *data: l_xstr type xstring.
    *  clear l_xstr.
    *  call function 'SCMS_BINARY_TO_XSTRING'
    *    exporting
    *      input_length = l_len
    *    importing
    *      buffer       = l_xstr
    *    tables
    *      binary_tab   = it_binary_attach.

    *-----------------------------------------------------------------------
    * Send Email
    *-----------------------------------------------------------------------

     
    DATA: lv_title      TYPE so_obj_des,             " Email Title
            lv_email     
    TYPE adsmtp-smtp_addr" Receiver
            lv_attitle   
    TYPE char50.           " Attachment Title

     
    DATA: send_request  TYPE REF TO cl_bcs,
            document     
    TYPE REF TO cl_document_bcs,
            conlengths   
    TYPE so_obj_len,
            html         
    TYPE TABLE OF w3html,
            recipient    
    TYPE REF TO if_recipient_bcs,
            sent_to_all  
    TYPE os_boolean,
            bcs_exception
    TYPE REF TO cx_bcs,
            bcs_message  
    TYPE string.
     
    DATA:   sender        TYPE REF TO cl_sapuser_bcs.

     
    TRY.
    *     创建发送请求
         
    CLEAR send_request.
          send_request
    = cl_bcs=>create_persistent( ).
         
    CLEAR: lv_title.

          lv_title
    = im_subject.

    *     创建并设置邮件文档
         
    CLEAR html.
         
    REFRESH html.
          html
    = t_message[].

         
    CLEAR document .
          document 
    cl_document_bcs=>create_document(
                                        i_type   
    'RAW'
                                        i_text   
    html
                                        i_length 
    conlengths
                                        i_subject
    lv_title )
    .

         
    CALL METHOD send_request->set_document( document )
    .
    ****************
    这里也可以从数据库表中读取码流

    *      DATA: BEGIN OF xtab255 OCCURS 0,
    *              x(255) TYPE x,
    *            END OF xtab255.
    *      FIELD-SYMBOLS: <cc> TYPE c.
    *
    *      DATA: ctab255 TYPE STANDARD TABLE OF solisti1 WITH HEADER LINE.
    *
    *      DATA: BEGIN OF pdf_table OCCURS 0,
    *          mandt TYPE zjzjpdf-mandt,
    *          row_order TYPE zjzjpdf-row_order,
    *          chr_count TYPE zjzjpdf-chr_count,
    *          content_hex(510),
    *        END OF pdf_table.
    *
    *      CLEAR: pdf_table[].
    *      SELECT  * INTO TABLE pdf_table FROM zjzjpdf.
    *      SORT pdf_table BY row_order.
    *
    *      CLEAR:  xtab255[].
    *      LOOP AT pdf_table.
    *        "将字面上的HEX转换为真正的HEX
    *        xtab255-x =  pdf_table-content_hex.
    *        APPEND xtab255.
    *      ENDLOOP.
    ****************************

    *     添加附件:如果有多个,则需要调用该方法多次
          lv_attitle
    = im_filename.
         
    CALL METHOD document->add_attachment
           
    EXPORTING

     
    *          i_attachment_type    = 'BIN'"在邮件中点击附件会弹出文件保存对话框。其他类型请参考SAPFSSOA程序include文件RSSOCONS
    *          i_attachment_type    = 'PDF'
    *          i_attachment_type    = 'TXT'
              i_attachment_type   
    = 'XLS'"文件类型,在邮件中就可以打开文件,不会弹出保存对话框
              i_attachment_subject
    = lv_attitle
              i_att_content_hex   
    = it_binary_attach.

    *          i_att_content_hex    = xtab255[].

    *     设置发送者
          sender
    = cl_sapuser_bcs=>create( im_uname ).
         
    CALL METHOD send_request->
    set_sender
           
    EXPORTING

              i_sender
    = sender.

    *     设置接收者
         
    CLEAR recipient.
         
    LOOP AT t_receivers.
           
    CLEAR lv_email.
            lv_email
    = t_receivers-receiver.
            recipient
    =
              cl_cam_address_bcs
    =>create_internet_address( lv_email ).
           
    CALL METHOD send_request->
    add_recipient
             
    EXPORTING

                i_recipient 
    = recipient
                i_express   
    = t_receivers-
    express
                i_copy      
    = t_receivers-copy

                i_blind_copy
    = t_receivers-blind_copy.
         
    ENDLOOP.

    *     E-mail
         
    CALL METHOD send_request->set_status_attributes
           
    EXPORTING

              i_requested_status
    = 'E'
              i_status_mail     
    = 'E'.
         
    CALL METHOD send_request->set_send_immediately( 'X' ).

    *    
    发送邮件

         
    CALL METHOD send_request->send(
          
    EXPORTING
           i_with_error_screen
    = 'X'
           RECEIVING
           result
    = sent_to_all ).

         
    COMMIT WORK AND WAIT.


         
    IF sent_to_all = 'X'.
           
    return-message = 'E-mail send successfully'.
           
    return-type = 'S'.
         
    ELSE.
           
    return-message = 'E-mail send unsuccessfully'.
           
    return-type = 'E'.
         
    ENDIF.

       
    CATCH cx_bcs INTO bcs_exception.
          bcs_message
    = bcs_exception->get_text( ).
         
    return-message = bcs_message.

         
    return-type = 'E'.
         
    EXIT.
     
    ENDTRY.
    ENDFORM.

  • 相关阅读:
    vue实例讲解之vuex的使用
    实例讲解webpack的基本使用第一篇
    如何写一个jquery插件
    《改变你一生的108个心理学法则》读书笔记
    用css绘制各种图形
    关于js浮点数计算精度不准确问题的解决办法
    非常有用的css使用总结
    网页meta标签总结
    Object.defineProperty()方法的用法详解
    js中set和get的用法
  • 原文地址:https://www.cnblogs.com/jiangzhengjun/p/4265704.html
Copyright © 2011-2022 走看看