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

posted @ 2015-02-01 16:37  江正军  阅读(5438)  评论(0编辑  收藏  举报