[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.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM