好多程序在SAP GUI上已运行正常,是想快速转程序到FIORI中使用,最直接的办法是从并头做FIORI,我们的多数SAPgui程序在读取数据显示到ALV,然后再对ALV选中行处理,而读取数据时逻辑很复杂,并不能使用简单的SELECL及SELECT关连来得到,使用association,JOIN等来关联数据得不到我们需要的结果 ,所以取数据需要用ABAP来实现,而如取数据常用已在SAP gui中实现,所以可以调用SAP gui的程序来实现读取,但SAPGUI中程序通常是用于ALV显示,所以需要在现有ALV中增加代码判断不是前台事务码GUI显示时不显示ALV,而把ALV保存到内存中,并在CDS的查询中取出此内存数据,这样来实现使用现有SAPGUI程序的读取逻辑。
对数据行的按钮处理逻辑也是类似的,可以最好把现有GUI处理逻辑写为一个函数,这样在CDS中增加ACTION时也可直接调用函数功能,
1.创建CDS
使用define root custom entity来创建CDS,创建时可参考现在ALV显示的结构来创建,所以为了方便最好在创建GUI的程序时,ALV显示的结构 最好也是SE11先定义好,
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
@EndUserText.label: 'gui 程序 到FIORI测试' @Metadata.allowExtensions: true @ObjectModel.query.implementedBy: 'ABAP:ZCL_GUI_TO_FIORI' define root custom entity ZI_GUI_TO_FIORI { @UI.lineItem: [ { position: 10 } ] @UI.selectionField: [ { position: 10 } ] key bukrs : bukrs ; @UI.lineItem: [ { position: 20 } ] key belnr : belnr_d ; @UI.lineItem: [ { position: 30 } ] key gjahr : gjahr ; @UI.lineItem: [ { position: 40 } ] blart : blart; @UI.lineItem: [ { position: 50 } ] bldat : bldat; @UI.lineItem: [ { position: 60 } ] @UI.selectionField: [ { position: 10 } ] budat : budat; @UI.lineItem: [ { position: 70 } ] monat : monat; @UI.lineItem: [ { position: 80 } ] cpudt : cpudt; @UI.lineItem: [ { position: 90 } ] cputm : cputm; @UI.lineItem: [ { position: 100 } ] aedat : aedat_bkpf; @UI.lineItem: [ { position: 110 } ] upddt : upddt; @UI.lineItem: [ { position: 120 } ] wwert : wwert_d; @UI.lineItem: [ { position: 130 } ] usnam : usnam; tcode : tcode; bvorg : bvorg; xblnr : xblnr1; dbblg : dbblg; dbblg_gjahr : dbblg_gjahr; dbblg_bukrs : dbblg_bukrs; stjah : stjah; bktxt : bktxt; waers : waers; } |
2.创建查询类
在CDS的定义中使用了@ObjectModel.query.implementedBy: ‘ABAP:ZCL_GUI_TO_FIORI’,这里定义了当此CDS在FIORI中查询时会调用ZCL_GUI_TO_FIORI,此类引用了接口IF_RAP_QUERY_PROVIDER,我们把查询数据的功能写在IF_RAP_QUERY_PROVIDER~SELECT中,在此方法中SUBMIT ztest_21现有程序,并返回,需要注意,现在程序如是ALV程序需要在显示 ALV程序地方做一些判断处理SY-CALLD = ‘X’(),通用可以在ALV显示前判断 一下,如是正常的GUI操作就继续,否则把数据保存到内表中并退出。
|
1 2 3 4 5 |
IF SY-CALLD = 'X'. " 通过 SUBMIT Z_PROGRAM_A WITH... AND RETURN 调用 EXPORT LT_cached_DATA FROM LT_DATA TO MEMORY ID 'ZTEST_21_DATA' . RETURN. ENDIF. |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
class ZCL_GUI_TO_FIORI definition public final create public . public section. interfaces IF_RAP_QUERY_PROVIDER . types: ty_string_table TYPE STANDARD TABLE OF string WITH EMPTY KEY . PROTECTED SECTION. PRIVATE SECTION. TYPES: BEGIN OF ty_cache_key, uname TYPE sy-uname, sessid TYPE string, " 应用会话ID(如前端会话) END OF ty_cache_key. TYPES: BEGIN OF ty_cached_data, key TYPE ty_cache_key, data TYPE STANDARD TABLE OF zi_gui_to_fiori WITH DEFAULT KEY, timestamp TYPE timestampl, END OF ty_cached_data. CLASS-DATA: gt_caches TYPE HASHED TABLE OF ty_cached_data WITH UNIQUE KEY key. ENDCLASS. CLASS ZCL_GUI_TO_FIORI IMPLEMENTATION. METHOD if_rap_query_provider~select. DATA: lt_data TYPE TABLE OF zi_gui_to_fiori, ls_data TYPE zi_gui_to_fiori. DATA rs_bukrs TYPE trty_bukrs_range. DATA rs_datum TYPE datum_range_tab. " TODO: variable is assigned but never used (ABAP cleaner) DATA l_datum TYPE sy-datum. " 关键日期 DATA l_bukrs TYPE bukrs. DATA LT_cached_DATA TYPE TABLE OF bkpf."与调用程序中的结构 相同 DATA: l_is_detail TYPE flag. " TODO: variable is assigned but never used (ABAP cleaner) DATA(lt_req_elements) = io_request->get_requested_elements( )."获取请求的元素列表,可以根据请求的元素来判断是列表显示还是明细显示 DATA(lV_ENTITY_ID) = io_request->get_entity_id( )."得到实体ID,单一实体时可以不用判断,复杂实体时需要根据实体ID进行不同处理 IF io_request->is_data_requested( )."只有在请求数据时才进行数据查询和处理,其他如获取元数据等请求不需要执行数据查询逻辑。 DATA(lv_top) = io_request->get_paging( )->get_page_size( )."获取分页信息中的页面大小,判断是列表显示还是明细显示,如果页面大小小于等于0,则认为是明细显示,需要返回全部数据。 IF lv_top < 0. lv_top = 1. l_is_detail = 'X'."明细显示 ENDIF. " TODO: variable is assigned but never used (ABAP cleaner) DATA(lv_skip) = io_request->get_paging( )->get_offset( )."获取分页信息中的偏移量,可以用于实现分页功能,但在这个示例中没有使用。 " TODO: variable is assigned but never used (ABAP cleaner) DATA(lt_sort) = io_request->get_sort_elements( )."获取排序元素列表,可以根据请求的排序信息来对数据进行排序,但在这个示例中没有使用。 " TODO: variable is assigned but never used (ABAP cleaner) DATA(lv_search_string) = io_request->get_search_expression( )."获取搜索表达式,可以根据请求的搜索条件来过滤数据,但在这个示例中没有使用。 DATA(lv_conditions) = io_request->get_filter( )->get_as_sql_string( )."获取过滤条件并转换为SQL字符串,可以根据请求的过滤条件来查询数据,但在这个示例中直接使用SQL字符串来获取查询条件。 IF lv_conditions = ''. io_response->set_data( lt_data ). RETURN. " 初始化时没有查询条件,不返回数据。 ENDIF. " DATA(ii_bukrs) = zcl_rap_cache=>get_ranges_from_sql( iv_sql_condition = lv_conditions iv_field_name = 'BUKRS' ). rs_bukrs = CORRESPONDING #( ii_bukrs ). l_bukrs = rs_bukrs[ 1 ]-low. IF l_bukrs = ''. io_response->set_data( lt_data ). RETURN. " 初始化时没有查询条件,不返回数据。 ENDIF. " DATA(ii_datum) = zcl_rap_cache=>get_ranges_from_sql( iv_sql_condition = lv_conditions iv_field_name = 'BUDAT' ). rs_datum = CORRESPONDING #( ii_datum ). IF rs_datum IS INITIAL. rs_datum = VALUE #( ( sign = 'I' option = 'EQ' low = sy-datum ) ). ENDIF. IF l_is_detail = 'X'."明细显示 " 明细请求:直接返回空数据,不显示任何明细 io_response->set_data( lt_data ). io_response->set_total_number_of_records( 0 ). RETURN. ENDIF. l_datum = rs_datum[ 1 ]-low. SUBMIT ztest_21 " FBL5N WITH p_bukrs = l_bukrs " 公司 WITH s_budat IN rs_datum " AND RETURN. IMPORT LT_cached_DATA = LT_cached_DATA FROM MEMORY ID 'ZTEST_21_DATA'. FREE MEMORY ID 'ZTEST_21_DATA'. LOOP AT LT_cached_DATA INTO DATA(Ls_cached_DATA). MOVE-CORRESPONDING Ls_cached_DATA TO ls_data. APPEND ls_data TO lt_data. ENDLOOP. IF io_request->is_total_numb_of_rec_requested( ). " 对象页时不需要指定记录数,当LT_REQ_ELEMENTS只有主银行时,在这里设置一下,就会调用明细类 io_response->set_total_number_of_records( lines( lt_data ) ). ENDIF. io_response->set_data( lt_data ). " DELETE LT_DATA WHERE NOT BUKRS = P_BUKRS. ELSE. io_response->set_total_number_of_records( '0' ). ENDIF. ENDMETHOD. ENDCLASS. |
3.创建WHERE查询条件转换为RANGES的功能类
在上一个类中lv_conditions的值是SELCET 中WHERE后面的条件字符串值 。所以在调用现在程序时需要把条件值转换为RANGES值 ,使用类似DATA(ii_bukrs) = zcl_rap_cache=>get_ranges_from_sql( iv_sql_condition = lv_conditions
iv_field_name = ‘BUKRS’ ).
rs_bukrs = CORRESPONDING #( ii_bukrs ).的调用方式得到ranges值。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 |
CLASS ZCL_RAP_CACHE DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. TYPES: TY_STRING_TABLE TYPE STANDARD TABLE OF STRING WITH EMPTY KEY . CLASS-METHODS GET_RANGES_FROM_SQL IMPORTING !IV_SQL_CONDITION TYPE STRING !IV_FIELD_NAME TYPE STRING RETURNING VALUE(RT_RANGES) TYPE /IWBEP/T_COD_SELECT_OPTIONS RAISING CX_STATIC_CHECK . PROTECTED SECTION. PRIVATE SECTION. CLASS-METHODS: " 解析简单条件 PARSE_SIMPLE_CONDITION IMPORTING IV_CONDITION TYPE STRING EXPORTING EV_FIELD TYPE STRING EV_OPERATOR TYPE STRING EV_VALUE TYPE STRING RAISING CX_STATIC_CHECK, " 获取 RANGES 的 OPTION GET_RANGE_OPTION IMPORTING IV_OPERATOR TYPE STRING RETURNING VALUE(RV_OPTION) TYPE DDOPTION, " 处理值(去除引号、处理通配符等) PROCESS_VALUE IMPORTING IV_VALUE TYPE STRING IV_OPTION TYPE DDOPTION RETURNING VALUE(RV_VALUE) TYPE STRING, " 按 OR 分割条件(保持括号完整性) SPLIT_BY_OR IMPORTING IV_EXPRESSION TYPE STRING RETURNING VALUE(RT_PARTS) TYPE TY_STRING_TABLE, " 按 AND 分割条件(保持括号完整性) SPLIT_BY_AND IMPORTING IV_EXPRESSION TYPE STRING RETURNING VALUE(RT_PARTS) TYPE TY_STRING_TABLE, " 去除外层括号 TRIM_OUTER_PARENTHESES IMPORTING IV_STRING TYPE STRING RETURNING VALUE(RV_STRING) TYPE STRING, " 检查是否为运算符 IS_OPERATOR IMPORTING IV_CHAR TYPE CHAR1 RETURNING VALUE(RV_BOOL) TYPE ABAP_BOOL, " 从条件中提取字段的值(用于 IN 和 BETWEEN) EXTRACT_VALUES_FROM_IN IMPORTING IV_IN_CONDITION TYPE STRING RETURNING VALUE(RT_VALUES) TYPE TY_STRING_TABLE. ENDCLASS. CLASS ZCL_RAP_CACHE IMPLEMENTATION. METHOD EXTRACT_VALUES_FROM_IN. DATA: LV_TEMP TYPE STRING, LV_POS TYPE I. LV_TEMP = IV_IN_CONDITION. " 移除外层括号 SHIFT LV_TEMP LEFT DELETING LEADING '('. SHIFT LV_TEMP RIGHT DELETING TRAILING ')'. " 按逗号分割 SPLIT LV_TEMP AT ',' INTO TABLE RT_VALUES. " 清理每个值 LOOP AT RT_VALUES INTO DATA(LV_VAL). CONDENSE LV_VAL. SHIFT LV_VAL LEFT DELETING LEADING ''''. SHIFT LV_VAL RIGHT DELETING TRAILING ''''. LV_VAL = CONDENSE( LV_VAL ). MODIFY RT_VALUES FROM LV_VAL. ENDLOOP. ENDMETHOD. METHOD GET_RANGES_FROM_SQL. DATA LV_SQL_COND TYPE STRING. DATA LT_OR_PARTS TYPE TABLE OF STRING. DATA LT_AND_PARTS TYPE TABLE OF STRING. DATA LV_FIELD TYPE STRING. DATA LV_OPERATOR TYPE STRING. DATA LV_VALUE TYPE STRING. " 初始化返回表 RT_RANGES = VALUE #( ). IF IV_SQL_CONDITION IS INITIAL. RETURN. ENDIF. " 去除外层括号 LV_SQL_COND = TRIM_OUTER_PARENTHESES( IV_SQL_CONDITION ). " --------------------------------------------------------------------- " 按 OR 分割 LT_OR_PARTS = SPLIT_BY_OR( LV_SQL_COND ). DATA(L_LINE_OR) = LINES( LT_OR_PARTS ). IF L_LINE_OR > 1. " 处理每个 OR 分支 LOOP AT LT_OR_PARTS INTO DATA(LV_OR_PART). " 嵌套调用 " 去除外层括号 LV_OR_PART = TRIM_OUTER_PARENTHESES( LV_OR_PART ). DATA(LT_SUB_RANGES_OR) = GET_RANGES_FROM_SQL( IV_SQL_CONDITION = LV_OR_PART IV_FIELD_NAME = IV_FIELD_NAME ). APPEND LINES OF LT_SUB_RANGES_OR TO RT_RANGES. ENDLOOP. ENDIF. " --------------------------------------------------------------------- " --------------------------------------------------------------------- " 按 AND 分割 LT_AND_PARTS = SPLIT_BY_AND( LV_SQL_COND ). DATA(L_LINE_AND) = LINES( LT_AND_PARTS ). IF L_LINE_AND > 1. " 处理每个 and 分支 LOOP AT LT_AND_PARTS INTO DATA(LV_AND_PARTS). " 嵌套调用 " 去除外层括号 LV_AND_PARTS = TRIM_OUTER_PARENTHESES( LV_AND_PARTS ). DATA(LT_SUB_RANGES_AND) = GET_RANGES_FROM_SQL( IV_SQL_CONDITION = LV_AND_PARTS IV_FIELD_NAME = IV_FIELD_NAME ). APPEND LINES OF LT_SUB_RANGES_AND TO RT_RANGES. ENDLOOP. ENDIF. " --------------------------------------------------------------------- IF L_LINE_OR <= 1 AND L_LINE_AND <= 1. PARSE_SIMPLE_CONDITION( EXPORTING IV_CONDITION = LV_SQL_COND IMPORTING EV_FIELD = LV_FIELD EV_OPERATOR = LV_OPERATOR EV_VALUE = LV_VALUE ). " 检查是否为目标字段 IF LV_FIELD = IV_FIELD_NAME. " 处理值并添加到 RANGES APPEND INITIAL LINE TO RT_RANGES ASSIGNING FIELD-SYMBOL(<FS_RANGE>). <FS_RANGE>-SIGN = 'I'. <FS_RANGE>-OPTION = GET_RANGE_OPTION( LV_OPERATOR ). <FS_RANGE>-LOW = PROCESS_VALUE( IV_VALUE = LV_VALUE IV_OPTION = <FS_RANGE>-OPTION ). " 处理 BETWEEN 需要 HIGH 值 IF <FS_RANGE>-OPTION = 'BT'. " 提取 BETWEEN 的两个值 DATA(LT_VALUES) = EXTRACT_VALUES_FROM_IN( LV_VALUE ). IF LINES( LT_VALUES ) >= 2. <FS_RANGE>-LOW = PROCESS_VALUE( IV_VALUE = LT_VALUES[ 1 ] IV_OPTION = '' ). <FS_RANGE>-HIGH = PROCESS_VALUE( IV_VALUE = LT_VALUES[ 2 ] IV_OPTION = '' ). ENDIF. ENDIF. ENDIF. ENDIF. " 去重并合并相同值的 RANGES SORT RT_RANGES BY LOW. DELETE ADJACENT DUPLICATES FROM RT_RANGES COMPARING LOW. ENDMETHOD. METHOD GET_RANGE_OPTION. CASE IV_OPERATOR. WHEN '=' OR 'EQ'. RV_OPTION = 'EQ'. WHEN '<>' OR 'NE'. RV_OPTION = 'NE'. WHEN '<'. RV_OPTION = 'LT'. WHEN '<='. RV_OPTION = 'LE'. WHEN '>'. RV_OPTION = 'GT'. WHEN '>='. RV_OPTION = 'GE'. WHEN 'LIKE' OR 'CP'. RV_OPTION = 'CP'. WHEN 'IN'. RV_OPTION = 'EQ'. " IN 会被拆分为多个 OR WHEN 'BETWEEN'. RV_OPTION = 'BT'. WHEN OTHERS. RV_OPTION = 'EQ'. ENDCASE. ENDMETHOD. METHOD IS_OPERATOR. RV_BOOL = XSDBOOL( IV_CHAR = '=' OR IV_CHAR = '<' OR IV_CHAR = '>' OR IV_CHAR = '!' OR IV_CHAR = 'L' OR IV_CHAR = 'l' ). ENDMETHOD. METHOD PARSE_SIMPLE_CONDITION. DATA LV_STR TYPE STRING. DATA LV_TEMP TYPE STRING. LV_STR = IV_CONDITION. LV_STR = CONDENSE( LV_STR ). LV_TEMP = TO_UPPER( LV_STR ). " 检查每个操作符 IF LV_TEMP CS ' NOT BETWEEN '. EV_OPERATOR = 'NOT BETWEEN'. DATA(LV_POS) = SY-FDPOS. DATA(LV_LEN) = 12. ELSEIF LV_TEMP CS ' NOT LIKE '. EV_OPERATOR = 'NOT LIKE'. LV_POS = SY-FDPOS. LV_LEN = 9. ELSEIF LV_TEMP CS ' NOT IN '. EV_OPERATOR = 'NOT IN'. LV_POS = SY-FDPOS. LV_LEN = 7. ELSEIF LV_TEMP CS ' BETWEEN '. EV_OPERATOR = 'BETWEEN'. LV_POS = SY-FDPOS. LV_LEN = 8. ELSEIF LV_TEMP CS ' LIKE '. EV_OPERATOR = 'LIKE'. LV_POS = SY-FDPOS. LV_LEN = 5. ELSEIF LV_TEMP CS ' IN '. EV_OPERATOR = 'IN'. LV_POS = SY-FDPOS. LV_LEN = 3. ELSEIF LV_TEMP CS ' <= '. EV_OPERATOR = '<='. LV_POS = SY-FDPOS. LV_LEN = 3. ELSEIF LV_TEMP CS ' >= '. EV_OPERATOR = '>='. LV_POS = SY-FDPOS. LV_LEN = 3. ELSEIF LV_TEMP CS ' <> '. EV_OPERATOR = '<>'. LV_POS = SY-FDPOS. LV_LEN = 3. ELSEIF LV_TEMP CS ' = '. EV_OPERATOR = '='. LV_POS = SY-FDPOS. LV_LEN = 2. ELSEIF LV_TEMP CS ' < '. EV_OPERATOR = '<'. LV_POS = SY-FDPOS. LV_LEN = 2. ELSEIF LV_TEMP CS ' > '. EV_OPERATOR = '>'. LV_POS = SY-FDPOS. LV_LEN = 2. ELSEIF LV_TEMP CS '='. EV_OPERATOR = '='. LV_POS = SY-FDPOS. LV_LEN = 1. ELSE. CLEAR: EV_FIELD, EV_OPERATOR, EV_VALUE. RETURN. ENDIF. " 提取字段名 IF LV_POS > 0. EV_FIELD = SUBSTRING( VAL = LV_STR OFF = 0 LEN = LV_POS ). ELSE. EV_FIELD = LV_STR. ENDIF. EV_FIELD = CONDENSE( EV_FIELD ). " 提取值 DATA(LV_VALUE) = SUBSTRING( VAL = LV_STR OFF = LV_POS + LV_LEN ). CONDENSE LV_VALUE. " 移除引号 - 使用 SHIFT 和直接访问 IF LV_VALUE IS NOT INITIAL. " 移除开头的引号 IF LV_VALUE(1) = '''' OR LV_VALUE(1) = '"'. SHIFT LV_VALUE LEFT BY 1 PLACES. ENDIF. " 移除结尾的引号 DATA(LV_VAL_LEN) = STRLEN( LV_VALUE ). LV_VAL_LEN = LV_VAL_LEN - 1. IF LV_VAL_LEN > 0. IF LV_VALUE+LV_VAL_LEN(1) = '''' OR LV_VALUE+LV_VAL_LEN(1) = '"'. LV_VALUE = LV_VALUE(LV_VAL_LEN). ENDIF. ENDIF. ENDIF. EV_VALUE = LV_VALUE. CONDENSE: EV_FIELD, EV_VALUE. ENDMETHOD. METHOD PROCESS_VALUE. RV_VALUE = IV_VALUE. " 处理 LIKE 的通配符 IF IV_OPTION = 'CP'. " SQL % -> ABAP * REPLACE ALL OCCURRENCES OF '%' IN RV_VALUE WITH '*'. " SQL _ -> ABAP + REPLACE ALL OCCURRENCES OF '_' IN RV_VALUE WITH '+'. ENDIF. " 转义特殊字符 REPLACE ALL OCCURRENCES OF '''' IN RV_VALUE WITH SPACE. ENDMETHOD. METHOD SPLIT_BY_AND. DATA: LV_STR TYPE STRING, LV_LEN TYPE I, LV_POS TYPE I, LV_PAREN_CNT TYPE I, LV_CHAR TYPE C, LV_START TYPE I, LV_PART TYPE STRING. LV_STR = IV_EXPRESSION. LV_LEN = STRLEN( LV_STR ). LV_PAREN_CNT = 0. LV_START = 0. CLEAR RT_PARTS. DO LV_LEN TIMES. LV_POS = SY-INDEX - 1. LV_CHAR = SUBSTRING( VAL = LV_STR OFF = LV_POS LEN = 1 ). IF LV_CHAR = '('. LV_PAREN_CNT = LV_PAREN_CNT + 1. ELSEIF LV_CHAR = ')'. LV_PAREN_CNT = LV_PAREN_CNT - 1. ELSEIF LV_PAREN_CNT = 0 AND LV_POS + 2 < LV_LEN. " 检查 AND IF SUBSTRING( VAL = LV_STR OFF = LV_POS LEN = 3 ) = 'AND' OR SUBSTRING( VAL = LV_STR OFF = LV_POS LEN = 3 ) = 'And' OR SUBSTRING( VAL = LV_STR OFF = LV_POS LEN = 3 ) = 'aNd' OR SUBSTRING( VAL = LV_STR OFF = LV_POS LEN = 3 ) = 'ANd' OR SUBSTRING( VAL = LV_STR OFF = LV_POS LEN = 3 ) = 'anD' OR SUBSTRING( VAL = LV_STR OFF = LV_POS LEN = 3 ) = 'and'. " 检查边界 DATA(LV_PREV_CHAR) = COND #( WHEN LV_POS > 0 THEN SUBSTRING( VAL = LV_STR OFF = LV_POS - 1 LEN = 1 ) ELSE ' ' ). DATA(LV_NEXT_CHAR) = COND #( WHEN LV_POS + 3 < LV_LEN THEN SUBSTRING( VAL = LV_STR OFF = LV_POS + 3 LEN = 1 ) ELSE ' ' ). IF ( LV_PREV_CHAR CO ' (=' ) AND ( LV_NEXT_CHAR CO ' (=' ). LV_PART = SUBSTRING( VAL = LV_STR OFF = LV_START LEN = LV_POS - LV_START ). CONDENSE LV_PART. IF LV_PART IS NOT INITIAL. APPEND LV_PART TO RT_PARTS. ENDIF. LV_START = LV_POS + 3. LV_POS = LV_POS + 2. ENDIF. ENDIF. ENDIF. ENDDO. " 添加最后一部分 IF LV_START < LV_LEN. LV_PART = SUBSTRING( VAL = LV_STR OFF = LV_START ). CONDENSE LV_PART. IF LV_PART IS NOT INITIAL. APPEND LV_PART TO RT_PARTS. ENDIF. ENDIF. IF LINES( RT_PARTS ) = 0. APPEND LV_STR TO RT_PARTS. ENDIF. ENDMETHOD. METHOD SPLIT_BY_OR. DATA: LV_STR TYPE STRING, LV_LEN TYPE I, LV_POS TYPE I, LV_PAREN_CNT TYPE I, LV_CHAR TYPE C, LV_START TYPE I, LV_PART TYPE STRING. LV_STR = IV_EXPRESSION. LV_LEN = STRLEN( LV_STR ). LV_PAREN_CNT = 0. LV_START = 0. CLEAR RT_PARTS. DO LV_LEN TIMES. LV_POS = SY-INDEX - 1. LV_CHAR = SUBSTRING( VAL = LV_STR OFF = LV_POS LEN = 1 ). IF LV_CHAR = '('. LV_PAREN_CNT = LV_PAREN_CNT + 1. ELSEIF LV_CHAR = ')'. LV_PAREN_CNT = LV_PAREN_CNT - 1. ELSEIF LV_PAREN_CNT = 0 AND LV_POS + 1 < LV_LEN. " 检查 OR(不区分大小写) IF SUBSTRING( VAL = LV_STR OFF = LV_POS LEN = 2 ) = 'OR' OR SUBSTRING( VAL = LV_STR OFF = LV_POS LEN = 2 ) = 'Or' OR SUBSTRING( VAL = LV_STR OFF = LV_POS LEN = 2 ) = 'oR' OR SUBSTRING( VAL = LV_STR OFF = LV_POS LEN = 2 ) = 'or'. " 检查边界 DATA(LV_PREV_CHAR) = COND #( WHEN LV_POS > 0 THEN SUBSTRING( VAL = LV_STR OFF = LV_POS - 1 LEN = 1 ) ELSE ' ' ). DATA(LV_NEXT_CHAR) = COND #( WHEN LV_POS + 2 < LV_LEN THEN SUBSTRING( VAL = LV_STR OFF = LV_POS + 2 LEN = 1 ) ELSE ' ' ). IF ( LV_PREV_CHAR CO ' (=' ) AND ( LV_NEXT_CHAR CO ' (=' ). " 提取 OR 前的部分 LV_PART = SUBSTRING( VAL = LV_STR OFF = LV_START LEN = LV_POS - LV_START ). CONDENSE LV_PART. IF LV_PART IS NOT INITIAL. APPEND LV_PART TO RT_PARTS. ENDIF. LV_START = LV_POS + 2. LV_POS = LV_POS + 1. ENDIF. ENDIF. ENDIF. ENDDO. " 添加最后一部分 IF LV_START < LV_LEN. LV_PART = SUBSTRING( VAL = LV_STR OFF = LV_START ). CONDENSE LV_PART. IF LV_PART IS NOT INITIAL. APPEND LV_PART TO RT_PARTS. ENDIF. ENDIF. IF LINES( RT_PARTS ) = 0. APPEND LV_STR TO RT_PARTS. ENDIF. ENDMETHOD. METHOD TRIM_OUTER_PARENTHESES. DATA LV_STR TYPE STRING. DATA LV_LEN TYPE I. DATA LV_FIRST_CHAR TYPE C LENGTH 1. DATA LV_LAST_CHAR TYPE C LENGTH 1. DATA LV_PAREN_CNT TYPE I. DATA LV_IS_WHOLE_EXPRESSION TYPE ABAP_BOOL. LV_STR = IV_STRING. LV_LEN = STRLEN( LV_STR ). IF LV_LEN <= 2. RV_STRING = LV_STR. RETURN. ENDIF. " 获取第一个和最后一个非空格字符 LV_FIRST_CHAR = SUBSTRING( VAL = LV_STR OFF = 0 LEN = 1 ). LV_LAST_CHAR = SUBSTRING( VAL = LV_STR OFF = LV_LEN - 1 LEN = 1 ). " 只有当整个字符串被一对括号完全包围时才去除 IF LV_FIRST_CHAR = '(' AND LV_LAST_CHAR = ')'. " 检查这对括号是否匹配整个表达式 LV_PAREN_CNT = 0. LV_IS_WHOLE_EXPRESSION = ABAP_TRUE. DO LV_LEN TIMES. DATA(LV_POS) = SY-INDEX - 1. DATA(LV_CHAR) = SUBSTRING( VAL = LV_STR OFF = LV_POS LEN = 1 ). IF LV_CHAR = '('. LV_PAREN_CNT += 1. ELSEIF LV_CHAR = ')'. LV_PAREN_CNT -= 1. ENDIF. " 如果在中间位置括号计数归零,说明不是整个表达式被包围 IF LV_PAREN_CNT = 0 AND LV_POS > 0 AND LV_POS < LV_LEN - 1. LV_IS_WHOLE_EXPRESSION = ABAP_FALSE. EXIT. ENDIF. ENDDO. " 只有整个表达式被括号包围时才去除 IF LV_IS_WHOLE_EXPRESSION = ABAP_TRUE. LV_STR = SUBSTRING( VAL = LV_STR OFF = 1 LEN = LV_LEN - 2 ). LV_STR = CONDENSE( LV_STR ). ENDIF. ENDIF. RV_STRING = LV_STR. ENDMETHOD. ENDCLASS. |
后面就可以发布为FIORI,使用RAP的结构方式创建Service Definitions,Service Bindings就可以生成ODATA了,也可以直接在Service Bindings测试FIORI APP.也可以使用VSCODE发布一个APP并上传到SAP中。
4.其它问题说明
上面生成的FIORI APP有一个直接的问题,当在列表中点击一行显示一行数据的对象页时不能显示数据,而此时并不能得到前一步骤中执行ztest_21得到的数据列表,而此时如果要显示数据还得重新再次执行一次数据查询,而现实中,明细行的数据查询条件并不能直接带入到现在GUI程序中,并且再次按现有GUI逻辑查询数据也影响速度,
使用了IMPORT FROM MEMORY ID,还使用的也静太类方法,全局变量等方法都不能解决这个问题,所以的结论是,要解决点击行快速显示行对象页,最好的解决办法就是,在查询列表页数据查询完成后,把数据保存到透明表中,DBKEY使用查询条件MD5加密后得到,这样在一些不会变化的结果查询查,可以使用此作为查询条件快速查询出结果数据。
设想了一个表结构如下:
” 表名: ZRAP_CACHE
” 类型: 透明表 (SE11)
“
| 字段名 | 类型 | 说明 |
|---|---|---|
| MANDT | MANDT | 客户端(主键) |
| DBKEY | CHAR32 | MD5唯一标识(主键) |
| CDS_NAME | CHAR30 | CDS视图名称(主键)(如’ZI_GUI_TO_FIORI’) |
| USER_NAME | SYUNAME | 创建用户 |
| SESSION_ID | CHAR32 | 会话ID(可选,用于更细粒度隔离) |
| CREATE_TIME | TIMESTAMPL | 创建时间戳(精度到毫秒) |
| DATA_RAW | STRING | 序列化后的表数据(XML/JSON) |
| DATA_SIZE | INT4 | 数据大小(字节,可选) |
| HITS | INT4 | 命中次数(可选,用于统计) |
这样在读取到列表后把数据调用CALL TRANSFORMATION id SOURCE data = lt_data RESULT XML DATA(lv_new_xml).生成XML数据,并保存到表中,并把自己历史的此CDS的数据都删除,
在确认是明细对象页时l_is_detail = ‘X’.”明细显示时按用户+日期从表中取出所有的数据并转换为DATA( CALL TRANSFORMATION id SOURCE XML lv_xml RESULT data = lt_data.
)来分析出查询条件的数据,如找到一行就显示这一行,如没找只能出错(理论上应该都能找到)
