Logical Databases逻辑数据库
逻辑数据库提供了另外一种获得数据的方式,它可以代替Open SQL语句从数据库中读取数据。LDB不是一种可以进行数据存储的物理上的数据库,而是ABAP报表程序设计中用到的一种事先定义好了的数据库读取程序。
可以通过以下两种方式打开LDB编辑器:
l SE36、SLDB
l
可以通过LDB的GOTO菜单来在LDB的各组件之间进行切换:
创建新的LDB时,LDB的名称一定要以Z或者Y打头(其实其他用户定制对象也一样,如报表程序也需要Z或Y开头),否则需要开发Key:
主要组成部分
LDB主要由三部分组成:.
结构(Structure)
数据库表(T类型节点):节点名称(上图中的根节点名称输入框)必须为数据库表名(上图中的数据库表输入框)或者view,且不可以为纵深结构。此类型(数据库表或视图)的节点情况下,可执行程序里,你可以使用NODES or TABLES语句来定义工作区,在LDB的数据库程序中,需要对每个节点使用NODESor TABLES来定义,不能有TYPE选项。如果节点是非数据库表,只能使用NODES来定义。
使用NODESor TABLES定义的工作区可以供数据库程序与可执行程序(或LDB_PROCESS函数)共享数据,进行数据的传输。
词典类型(S类型节点):数据字典中的定义的data type,词典类型名(上图中的词典类型输入框)与节点名称(上图中的根节点名称输入框)不需要一致,且可以为纵深结构。此类型节点情况下,可执行报表程序与LDB数据库程序里都只能使用NODES语句来定义。
类型组(上图中的数据类型,C类型节点):节点类型可以来自于类型组中定义的类型,其名称必须为Type group字段值。一般应参照DDIC类型生成,以便其他使用逻辑数据库的应用可以访问该节点(如SAP Query)。此类型节点情况下,可执行报表程序与LDB数据库程序里都只能使用NODES语句来定义。
动态类型(A类型节点):这种节点没有固定类型,实际的类型是在可执行报表程序里通过NODES语句的TYPE选项来决定。在可执行程序里,必须使用NODES语句的TYPE选项来指定某个data type.
在程序里,可以使用
NODES node [TYPE type].
NODES的唯一作用就是在LDB与可执行程序之间传递数据。它定义了一个interface work area,并只能在报表程序的全局声明区或者LDB数据库程序中出现。
比如节点类型为S的节点:root_node,数据类型为INT4,LDB的数据库程序的最TOP Include文件包括以下语句:
NODES root_node.
另外,在LDB数据库程序包括了以下过程:
FORM put_root_node.
DO 10 TIMES.
root_node = sy-index.
PUT root_node.
ENDDO.
ENDFORM.
在与此LDB关连的可执行程序:
REPORT demo_nodes.
NODES root_node.
GET root_node.
WRITE root_node.
选择(Selections)
中。如果是通过函数LDB_PROCESS来调用LDB,则该选择屏幕会以接口参数的形式出现在LDB_PROCESS函数中。
在LDB中,可以使用PARAMETERS, SELECT-OPTIONS; andSELECTION-SCREEN来定义选择屏幕,在LDB中,还可以使用VALUE-REQUEST and HELPREQUEST语句。
三个数据库表的层次结构:一个航线(SPFLI,如北京到新加坡)中可能有多个班次(SFLIGHT,如每天一班),每个班次中有多个订票数据(SBOOK,机票预定信息),这个层次化的结构的处理方式与用传统Open SQL的SELECT语句进行三个循环次的嵌套很相似:
第一次进入LDB选择屏幕程序时,系统会为每个LDB生成一个名为DB<LDB_Name>SELInclude选择屏幕的文件(注:此Include文件不需要在LDB数据库程序中使用INCLUDE语句来包含它,系统会自动加载),生成的过程中需要选择哪些表需要自动开启动态选择条件(dynamic selections)与字段选择(field selections):
而且,所有表(T类型的节点)的主键都会出现在SELECT-OPTIONS语句中,成为屏幕选择字段(自动生成的需要去掉注释,并设置屏幕选择字段名):
除了上面自动生成的LDB屏幕字段外,还可以使用以下面语句来扩展LDB选择屏幕:
l 使用PARAMETERS语句为增加一个单值输入条件框(PARAMETERS语句一般在LDB中只用于除节点表外的非表字段屏幕参数),在PARAMETERS语句中必须使用选项FOR NODE(所属类型节点)或者FOR TABLE(T类型节点)
l 使用SELECTION-SCREEN语句来格式化屏幕
l SELECTION-SCREEN DYNAMIC SELECTIONS FOR NODE|TABLE <node>.语句允许你为更多的表开启动态选择条件功能。如果节点类型为T,可以使用TABLE来代替NODE。只有开启了动态选择条件功能的表,才可以在LDB数据库程序中对表的进行动态选择条件处理(具体请参考LDB_PROCESS函数EXPRESSIONS参数部分)
l SELECTION-SCREEN FIELD SELECTION FOR NODE|TABLE <node>.允许你为其他表开启动态选择字段。如果节点类型为T,可以使用TABLE来代替NODE。在报表程序中,可以通过GET语句中的fields选项来指定需要读取的字段列表;在LDB_PROCESS函数中,可以通过FIELD_SELECTION参数来指定需读取的字段列表(具体请参考LDB_PROCESS函数 FIELD_SELECTION参数部分)
l SELECTION-SCREEN BEGIN OF VERSION <dynnr>
...
SELECTION-SCREEN EXCLUDE <f>.
...
SELECTION-SCREEN BEGIN OF VERSION <dynnr>.
允许你创建不同的版本的LDB选择屏幕,<dynnr>需要小于1000,你可以将<f> Selections或者Parameters屏幕字段隐藏,这样可执行程序可以有不同版本的选择屏幕。
假设有名为TEST_LDB的LDB,结构如下:
默认生成的Include选择屏幕如下:
字符)替换问号
* 1. Replace ? by suitable names (at most 8 characters).
* 激活 SELECT-OPTIONS 与 PARAMETERS 语句(去除前面的注释星号)
* 2. Activate SELECT-OPTIONS and PARAMETERS (delete stars).
* 保存修改后的源代码
* 3. Save source code.
* 修改LDB数据库程序
* 4. Edit database program.
*
* 提示:Include不能进行单独的语法检测!它将在LDB数据库程序在执行
* 语法检测时,一起进行语法检测
* Hint: Syntax-Check is not possible within this Include!
* It will be checked during syntax-check of database program.
*-----------------------------------------------------------*
* SELECT-OPTIONS : ? FOR LFA1-LIFNR.
*
* 搜索帮助
* Parameter for search pattern selection (Type SY-LDB_SP):
* PARAMETERS p_sp AS SEARCH PATTERN FOR TABLE LFA1.
*
* SELECT-OPTIONS :
* ? FOR LFB1-LIFNR,
* ? FOR LFB1-BUKRS.
* SELECT-OPTIONS :
* ? FOR LFC1-LIFNR,
* ? FOR LFC1-BUKRS,
* ? FOR LFC1-GJAHR.
* SELECT-OPTIONS :
* ? FOR BKPF-BUKRS,
* ? FOR BKPF-BELNR,
* ? FOR BKPF-GJAHR.
*
* 开启节点的动态选择条件
* Enable DYNAMIC SELECTIONS for selected nodes :
* 开启节点的动态字段选择
* Enable FIELD SELECTION for selected nodes :
也可使用PARAMETERS为节点BKPF自定义选择屏幕参数:
PARAMETERS PSTIDA LIKE SY-DATUM FOR NODE BKPF.
数据库程序(Database program)
包含了具体的从数据库表读取的逻辑,以及将读取的数据传递给LDB用户的代码。该程序是一系列子程序的集合,具体的结构取决于逻辑数据库的结构和选择(屏幕)。LDB中的其他元素包括了文档、文本及用户定义的选择屏幕等。
名为<F1S>的LDB的数据库程序名为SAPDB<F1S>,它包含了ABAP运行时调用的特定名称的Form。当第一次打开LDB数据库程序时,系统会自动生成LDB数据库程序代码
一个LDB程序一般包含以下这些FORM:
?FORM LDB_PROCESS_INIT
Called once only before the logical database is processed. It prepares it to be calledmore than once by the function module LDB_PROCESS.
在LDB处理前仅调用一次。通过函数方式访问LDB时,可以调用多次???????
If you want to call a logical database more than once in succession, the database program must
contain the following subroutine:
FORM LDB_PROCESS_INIT CHANGING SUBRC LIKE SY-SUBRC.
...
SUBRC = 0.
ENDFORM.
此过程是LDB数据库程序第一个被调用的FORM。一旦参数SUBRC设置为0,则LDB就会接着往处理数据,否则如果设置为0,则LDB_PROCESS函数会触发LDB_NOT_REENTRANT异常。
This is the first subroutine to be called in the database program. Once the parameter SUBRC
has been set to 0, the logical database can perform the initialization routines required to allow it
to be called more than once. If the parameter SUBRC is not set to 0, the function module
LDB_PROCESS triggers the exception LDB_NOT_REENTRANT.
? FORM INIT
Called once only before the selection screen is processed.
在选择屏幕处理前仅调用一次(在PBO之前调用)。
? FORM PBO
在选择屏幕每次显示之前调用,即LDB选择屏幕的PBO事件块。通常情况下,只有在可执行程序里使用LDB时才调用,在LDB_PROCESS 函数里不会调用。
? FORM PAI
用户在选择屏幕上输入之后调用,即LDB选择屏幕的PAI事件块。只有在可执行程序里使用LDB时才调用,在LDB_PROCESS 函数里不会调用。
该FORM带两个接口参数FNAME and MARK将会传到subroutine 中。FNAME存储了选择屏幕中用户所选择的选择条件(SELECT-OPTION)与参数(PARAMETERS)的屏幕字段名,MARK标示了用户选择的是单值还是多值条件:MARK = SPACE意味着用户输入了一个简单单值或者范围取值,MARK = '*'意味着用户在Multiple Selection screen 的输入(即多个条件值)。MARK = SPACE means that the userhas entered a simple single value or range selection. MARK = '*' means that the user hasalso made entries on the Multiple Selection screen
联合使用 FNAME = '*' 和 MARK = 'ANY', 表示所有的屏幕参数都已检验完成,即可以对屏幕整体参数做一个整体的检测了(这里的意思应该就是相当于AT SELECTION-SCREEN)。
? FORM LDB_PROCESS_CHECK_SELECTIONS
用来在函数中LDB_PROCESS替代subroutine PAI,此过程可以对通过LDB_PROCESS函数参数接口传递进来的LDB屏幕选择条件参数进行检测
当通过LDB_PROCES函数来调用LDB时,LDB选择屏幕是不会显示的,这样,LDB选择屏幕参数就只能通过LDB_PROCES函数的接口参数传递到LDB数据库程序中了,此是,LDB数据库程序中的 FORM PAI 是不会再被执行(只在LDB与报表程序通过属性绑定时才调用)。但时,如果此时你仍然想对通过LDB_PROCES函数接口参数传递进来的LDB选择屏幕字段进行检测时,你可以在LDB数据库程序中定义如下的FORM:
FORM LDB_PROCESS_CHECK_SELECTIONS CHANGING SUBRC LIKE SY-SUBRC
MSG ..LIKE SYMSG.
...
SUBRC = ...
ENDFORM.
如果SUBRC不为0,则LDB_PROCESS函数会抛LDB_SELECTIONS_NOT_ACCEPTED异常。
? FORM PUT_<node>
最顶层节点<node>所对应的FORM PUT_<node>会在START-OF-SELECTION事件结束后自动被调用,而其他下层节点所对应的FORM会由它的上层节点所对应的FORM中的PUT <node>语句来触发(在上层节点所对应的可执行程序中的相应GET事件块执行之后触发)。
PUT <node>.
此语句用是上面的PUT_<node>子过程中的特定语句,它是与PUT_<node>一起使用的,通常是放在循环处理数据循环过程中。LDB必须包含节点<node>,并且所对应的子过程名为PUT_<node>。PUT语句根据LDB的结构指引了报表程序的逻辑。该语句会触发相应的ABAP报表程序的GET <node>事件。当GET事件块执行完后,如果有下层节点,则还会调用下层节点所对应的FORM PUT_<node>。PUT语句是该Form(PUT_<node>)中最主要的语句:此语句仅仅只能在LDB数据库程序的Form中使用。
当PUT_<node>调用结束后,报表程序中相应GET <node> LATE事件块也会自动调用。
首先,LDB的子过程中根节点所对应的PUT_<root>会自动执行,此子过程中的PUT语句会以下面的先后顺序来执行程序:
1、 如果LDB数据库程序包含了AUTHORITY_CHECK_<table>语句,则PUT语句的第一件事就是调用它
2、 然后,PUT语句会触发报表程序相应的GET事件,或者,去调用LDB_PROCESS的CALLBACK参数指定的函数
3、 再后,PUT语句会去调用LDB程序中下一节点的PUT_<node>子过程(此过程又会按照这里的三步来运行),直到下层所有子孙节点PUT_<node>过程处理完成,又会回到最上一层节点的PUT语句
4、 当控制权从下层节点的PUT_<node>返回时,PUT语句还会触发当前节点的GET <node> LATE报表事件
?FORM AUTHORITY_CHECK_<node>
由PUT <node>语句自动调用。在该FORM中可以对数库节点<node>权限进行检查。
?FORM PUT_<ldb>_SP
Called when the user makes a selection using a search help to process the key chosenin the search help. <ldba> is the name of the logical database. From this subroutine, youcan use the entries in the search help tables to read the relevant entries from the rootnode <root>. The processing in the program can then be triggered using PUT <root>.The subroutine PUT_<root> is then not called automatically.
?FORM BEFORE_EVENT
在某个报表事件块执行前调用,至于是哪个事件块,可以由此FORM的参数EVENT来指定。目前,EVENT参数的值只能为START-OF-SELECTION:即在START-OF-SELECTION事件块调用之前调用此FORM。
?FORM AFTER_EVENT
在某个报表事件块执行后调用,至于是哪个事件块,可以由此FORM的参数EVENT来指定。目前,EVENT参数的值只能为END-OF-SELECTION:即在END-OF-SELECTION事件块调用之后调用此FORM。
?FORM <par>_VAL, <selop>_VAL, <selop>-LOW_VAL, <selop>-HIGH_VAL
调用用户按F4(values help)时调用,<par>为LDB选择屏幕的parameter,<selop>为LDB选择屏幕的select-options参数。
?FORM <par>_HLP, <selop>_HLP, <selop>-LOW_HLP, <selop>-HIGH_HLP
调用用户按F1(input help)时调用,<par>为LDB选择屏幕的parameter,<selop>为LDB选择屏幕的select-options参数。
LDB程序结构
自动生成的LDB数据库程序的组织结构如下:
注:上图中,每个FORM中的 PUT XXXX循环调用一次后立即调用下层节点的FORM PUT_XXX,而不是等到SELECT…ENDSELECT循环完后才去调用下层节点,而且是每一次整个链调用完后,再向上一层层返回,至到最顶层时,最顶层才算一次成功调用(此程序中使用了SELECT…ENDSELECT语句,这里只是个演示,在实行的应用中不会这么使用的)。
FORM PUT_XXX性能问题
一般自动生成的LDB数据库程序中,用来访问数据库表的FORM都是使用SELECT…ENDSELECT来读取语句,这样性能低下,尽量避免使用此类语句,而是将数据一次性读取到内表,则对该内表进行循环,再在循环中使用PUT XXX语句与报表程序进行交互:
FORM PUT_SBOOK.
SELECT * FROM SBOOK
INTO SBOOK....
PUT SBOOK.
ENDSELECT.
ENDFORM.
GET_EVENT内表
Some internal tables are automatically generated, and can be used in theprogram.
The internal table GET_EVENT contains the nodes of the logical database that are
requested by the user in GET statements. The table is generated as follows:
DATA: BEGIN OF GET_EVENTS OCCURS 10,
NODE(10),
KIND,
END OF GET_EVENTS.
Each line contains the name of a node of the logical database in the NODE field. The
KIND field specifies whether and how the node is requested by the user.
? KIND = 'X': Node is addressed in GET and GET LATE.
? KIND = 'G': Node is addressed only in GET.
? KIND = 'L': Node is addressed only in GET LATE.
? KIND = 'P': Node is addressed neither in GET nor in GET LATE. However, a
subordinate node is addressed in GET or GET LATE.
? KIND = ' ': Node is addressed neither in GET nor in GET LATE. No subordinate
node is addressed either.
报表程序的LDB事件
GET事件
从逻辑数据库读取数据主要使用GET事务
LDB节点访问前需要在程序中使用NODES语句进行声明:
NODES node.
在旧版本中也经常使用TABLES语句来声明。在声明后,系统将创建一个与该节点同名结构相同的工作区,并通过GET事件循环对该工作区进行填充:
GET事件块会在LDB程序从数据库表中读取到一行数据时被触发。
GET node [LATE] [FIELDS f1 f2 ...]
在事件触发后,表工作区(node所定义的)存储了刚读到的数据,接着可以在GET事件块中对读取到当前行数据进行处理,数据库中有多少条数据,GET事件块就会相应执行多少次。使用FIELDS选项,可以指定从LDB读取哪些表字段(但同时还必须读取表关键字)。
GET LATE:当当前层次的Node的所有GET事件结束之后,并在返回邻近上一层节点之前,则会触发当前层次节点为的GET…LATE事件(仅执行一次,这与GET事件不一样),因此,该事件可以实现该级数据库节点中的数据统计功能。
出于性能问题考虑,使用FIELDS选择指定需要的读取的字段。
此外,如果在程序中没有指定所有的逻辑节点,则执行到指定的最低一级节点后将返回上一级节点,其下方的所有节点中的数据将无法被读出。
中止GET事件
更多事件终止请参考这里
STOP.
结束后续整个还没有读取的所有节点,并且触发 END-OF-SELECTION 事件
EXIT.
退出所有的GET代码块,并且不触发任何后续事件,直接转向基础列表屏幕(Basic List Screen)的输出显示。其功能与STOP基本一致,只是它不会触发后事件
其中STOP语句和EXIT语句的用法与其他事件块完全相同
REJECT.
中止当前GET事件并转向逻辑数据同一层的下一个GET事件,即转向数据库中的下一行数据。
REJECT node_name.
中止当前和所有同一级别节点的所有后续GET事件,执行当前的高层次(即node_name所指层次)的下一个逻辑数据库GET事件。
注:这里的node_name在LDB表的层次结构中,应该是位于当前GET事件中数据表的高层。
REJECT语句与上下无关,即使在循环和子程序中使用也一样只是离开当前GET事件,而不是离开循环。
CHECK XXX
CHECK语句可以条件中止GET事件,之后系统将执行LDB同一层的下一行数据的GET事件,即读取当前节点表的下一行数据。
除此之外,CHECK语句还有另一种使用方式,检查当前行的内容是否满足所有与该数据库相连的选择表中存储的选择标准(就是读取一行数据后,与选择屏幕中输入的相应条件进行比较):
CHECK SELECT-OPTIONS
这种只用于GET事件块内部,在用LDB读入数据库表的一行数据之后使用该语句,将检查所有参照当前GET事件所对应的节点数据表中的选择标准。并且一般只有当LDB提供的选择不能满足要求,并且相关表不具有动态选择时才使用该形式。
使用LDB
逻辑数据库可以用为 QuickViews、SAP Queries以及ABAP程序的数据源。
SAP Queries中,LDB可以直接作为数据源;在Query中,LDB通过在其基础上定义的功能区域(functional area)成为间接数据源;
在可执行程序中,可以在通过程序的属性项“Logical database”链接到LDB:
或者在ABAP程序中直接通过LDB_PROCESS函数来调用相应的LDB。如果通过程序属性项“Logical database”链接到LDB,则在报表程序中可以通过LDB的GET事件来获取数据。
当使用可执行程序的属性与LDB绑定时,用户可以在LDB选择屏幕上输入条件值。如果你采用函数的形式来调用LDB的话,LDB的选择屏幕是不会显示的,此时可以通过LDB_PROCESS函数的接口参数来来代替。
报表程序与LDB程序交互过程
在绑定了LDB的报表程序的执行顺序如下:
1. 选择屏幕处理以前初始化
先调用LDB程序中的过程:FORMINIT,该过程仅仅只在选择屏幕第一次显示之前被调用
再触发报表程序中的事件:INITIALIZATION,该事件仅仅只在选择屏幕第一次显示之前被触发
2. 每次选择屏幕显示之前屏幕初始化PBO
先调用LDB程序中的过程:FORM PBO,选择屏幕每次显示之前都会被调用
再触发报表程序中的事件:AT SELECTION-SCREEN OUTPUT,选择屏幕每次显示之前都会被触发
3. 显示选择屏幕,与用户进行交互
4. 如果用户按F4(values help)或者按下了字段帮助(F1)时
先调用LDB程序中的以下过程:
FORM <par>_VAL.
FORM <selop>_VAL.
FORM <selop>-LOW_VAL.
FORM <selop>-HIGH_VAL.
以上是按F4时调用,其中<par>为LDB选择屏幕的parameter,<selop>为LDB选择屏幕的select-options参数
如果是按F1时,将上面的 _VAL 换成_HLP即是被调用的过程
再触发选择屏幕事件:
AT SELECTION-SCREEN ON VALUE-REQUEST FOR <par>.
AT SELECTION-SCREEN ON VALUE-REQUEST FOR <selop>-LOW.
AT SELECTION-SCREEN ON VALUE-REQUEST FOR <selop>-HIGH.
以上是按F4时调用,其中<par>为LDB选择屏幕的parameter,<selop>为LDB选择屏幕的select-options参数
如果是按F1时,将上面的VALUE-REQUEST换成HELP-REQUEST即是被触发的屏幕事件
5. 选择屏幕的PAI事件。检查用户的输入是否正确,如果输入数据不正确,可以提示用户,并要求再次重新输入相关字段。
此时先调用LDB程序中的过程:FORM PAI USING FNAME MARK.
FNAME代表选择屏幕参数字段名。如果MARK=SPACE,表示用户输入是一个单值或者是一个范围;如果MARK=*,则表示用户输入了多行值。
Using the combination FNAME = '*' and MARK = 'ANY', you can check all entries at
once when the user chooses a function or presses ENTER.联合使用 FNAME = '*' 和 MARK = 'ANY', 则可以在用户选择“执行”后立即检查所有条目(这里的意思应该就是相当于AT SELECTION-SCREEN)。
再触发选择屏幕事件:
AT SELECTION-SCREEN ON <fname>.
针对于选择屏幕某字段输入的PAI事件(ON事件表示当对应字段的值被传递给程序时被触发)
AT SELECTION-SCREEN ON END OF <fname>.
这个事件只能使用SELECT-OPTIONS屏幕参数上,用于整个选择表输入结束后对整个输入的选择条件列表进行检查。.
AT SELECTION-SCREEN.
选择屏幕的基本PAI事件,所有用户输入的数据都被传输到程序中之后才触发,也是选择屏幕中最后被触发的事件
6. 数据读取前的处理
此时先调用LDB程序中的过程:BEFORE EVENT 'START-OF-SELECTION',可以通过此过程,在读取数据前做一些运动作,如初始化内表
再触发报表程序事件:START-OF-SELECTION,这是报表程序的在选择屏幕处理结束后执行的第一个事件。可以在此事件块中为数据的处理做一些准备
7. 从LDB中读取数据,并在可执行程序进行数据处理
此时先调用LDB程序中的过程:FORM PUT_<node>,从节点<node>中读取数据
当<node>及子孙节点所对应的PUT_XXX执行完后,再触发报表程序事件:GET <node> [LATE],此过程中可以对数据做阶段型处理,这有点像LOOP循环中的SUM
8. 数据读取后的处理
此时先调用LDB程序中的过程:AFTER EVENT 'END-OF-SELECTION',可以通过此过程,在读取数据后做一些动作,如释放内存
再触发报表程序事件:END-OF-SELECTION,这是最后一个报表事件
9. 如果在上面一些步骤中生成了LIST,则程序会交给list processor,并显示LIST
LDB选择屏幕字段的显示与否
在报表选择屏幕上是否显示LDB的普通选择条件(即静态的,与动态选择条件相对应),则要看报表程序中是否使用了对应的
TABLE <node>语句,如果有,则与<node>节点相关的所有LDB选择条件都会显示在报表程序的选择屏幕上,如果没有此语句,则与<node>节点相关的所有LDB选择条件都会不会显示(但如果某个节点没有在TABLE语句中进行定义,但其子节点,或子孙节点在TABLE语句中进行了定义,则这些子孙节点所对应的父节点所对应LDB屏幕选择条件还是会嵌入到报表选择屏幕中)。有几种情况:
则报表程序的选择屏幕只会将spfli节点相关的普通选择条件内嵌进来,子孙节点不会显示出来:
则报表程序的选择屏幕中,会将sbook的父节点SFLIGHT以及爷节点SPFLI相关的LDB静态选择内嵌进来:
如果LDB的选择屏幕在没有创建选择视图的情况下:动态选择是否显示在报表程序的选择屏幕中,首先要看报表程序中是否使用了 TABLE <node>对需要动态显示的节点进行了定义(如果这个节点是上层节点,则此节点为本身也可以不在TABLE语句定义,而是对其子孙节点进行定义也是可以的),再者,还需要相应的<node>节点在LDB屏幕选择Include程序中的SELECTION-SCREEN DYNAMIC SELECTIONS FOR TABLE <node>语句中进行定义,注:要显示,则对应节点一定要在此语句中定义过,而不是像报表程序中的节点只对其子孙节点进行定义即可,而是谁需要动态显示,则谁就得要在动态定义语句中进行定义,如下面在LDB选择屏幕Include程序中只对SBOOK的上层节点SPFLI,SFLIGHT进行了定义,并没有对SBOOK进行定义:
而在报表程序中只能SBOOK进行了定义:
但最后在报表动态选择屏幕中,只有SPFLI,SFLIGHT两个表的条件(需使用SELECTION-SCREEN DYNAMIC SELECTIONS语句对SPFLI,SFLIGHT节点进行定义),而SBOOK并没有:
在没有创建选择视图的情况下,以表名来建小分类,且动态条件字段为整个表的所有字段
如果LDB的选择屏幕在有选择视图的情况下:只要存在选择视图,则只显示选择视图里被选择的字段,其他任何字段一概不显示。
下面只将SPFLI-CARRID与SFLIGHT-CONNID两个字段已分别纳入到了01与02分组中,而SBOOK节点中没有字段纳入:
报表程序里将SBOOK节点定义在了TABLES语句中,所以,从SBOOK这一级开始(包括)向上所有节点的所对应的字段,如果纳入了选择视图中,则选择屏幕显示如下:
LDB中的权限检查
可以在报表程序相应事件块或者是LDB数据库程序的相应子过程中,通过AUTHORITY-CHECK语句来对LDB进行权限检查:
LDB程序的子过程中:
? PAI
? AUTHORITY_CHECK_<table>
报表程序事件中:
? AT SELECTION-SCREEN
? AT SELECTION-SCREEN ON <fname>
? AT SELECTION-SCREEN ON END OF <fname>
? GET <table>
通过LDB_PROCESS函数访问LDB
Calling a Logical Database Using a Function Module
可以将LDB当做Function来调用。通过函数访问LDB,可以在同一程序中访问多个LDB,也有可能在同一程序中对同一个LDB进行多次调用。在4.5A版以前,如果一个报表程序需要访问多个LDB,或多次访问同一LDB时时,只能在这个报表程序里通过SUBMIT语句来调用另一个报表程序,且被SUBMIT语句调用的报表程序与其它LDB进行了绑定,数据只能通过ABAP memory将数据传回到主调程序中。
如果你采用函数的形式来调用LDB的话,LDB的选择屏幕是不会显示的,但是你可以通过LDB_PROCESS函数的接口参数来给LDB选择屏幕条件字段赋值。此时LDB不会触发主调程序中的GET事件,但数据可以通过LDB_PROCESS函数参数接口中指定的回调函数传回。
如果不是在同一报表程序中调对某个LDB多次进行调用时,就没有必要采用LDB_PROCESS函数访问LDB。
采用函数访问LDB时,LDB数据库程序中的PAI子过程是不会被调用的,所以不会对LDB选择屏幕条件进行检查,但可以通过后面讲解的LDB数据库程序中的LDB_PROCESS_INIT、LDB_PROCESS_CHECK_SELECTIONS函数来检验
通过函数LDB_PROCESS访问LDB时,LDB数据库程序的子过程会按以下先后顺序来执行:
1. LDB_PROCESS_INIT
2. INIT
3. LDB_PROCESS_CHECK_SELECTIONS
4. PUT <node>.
LDB_PROCESS函数的参数
import parameters
? LDBNAME
你想调用的LDB名称
? VARIANT
变式名
Name of a variant to fill the selection screen of the logical database. The variant must
already be assigned to the database program of the logical database. The data is passed
in the same way as when you use the WITH SELECTION-TABLE addition in a SUBMIT
[Page 1060] statement.
?EXPRESSIONS SQL动态选择条件(参考《User Dialogs.docx》中的 Calling Programs——WITH FREE SELECTION <freesel>章节)
In this parameter, you can pass extra selections for the nodes of the logical database for
which dynamic selections are allowed. The data type of the parameter RSDS_TEXPR is
defined in the type group RSDS. The data is passed in the same way as when you use
the WITH FREE SELECTION addition in a SUBMIT statement.
由于采用调用函数LDB_PROCESS的方式来调用LDB时,LDB的选择屏幕(以及LDB动态选择屏幕)是不会的,但如果此时想在查询某个节点时,其Where从句后要使用动态的内表条件时,就需要在主调程序中使用此参数来传递节点(表)的动态选择条件字段。在主调程序中,首先使用以下语句来定义动态条件内表texpr:
TYPE-POOLS: rsds.
DATA: texpr TYPE rsds_texpr."rsds_texpr为类型组RSDS中定义的内表类型
然后,在主调程序中按照以下行结构类型来初始化动态条件内表texpr:
(其中主调程序中用到的类型组RSDS源码如下:)
最后,在主调程序中调用LDB_PROCESS函数时,通过其入参数EXPRESSIONS将动态条件内表texpr传递到LDB数据库程序中,然后LDB数据库程序中相应节点(表)的Form PUT_XXX 中读取数据时,就可以使用此动态条件内表作为Where从句中的条件了(注:如果动态内表为空,则会忽略此条件,查找所有记录):
上面LDB数据库程序中的RSDS_WHERE条件内表来自RSDS类型组,相应源码如下:
(另外,上面LDB数据库程序中要能从DYN_SEL-CLAUSES内表读取数据,则必须在LDB选择屏幕里开启相应节点的动态选择条件:)
其中,DYN_SEL-CLAUSES内表行结构如下:
?FIELD_SELECTION SQL动态选择字段
You can use this parameter to pass a list of the required fields for the nodes of the logical
database for which dynamic selections are allowed. The data type of the parameter is
the deep internal table RSFS_FIELDS, defined in the type group RSFS. The component
TABLENAME contains the name of the node and the deep component FIELDS contains
the names of the fields that you want to read.
为了从数据库表中读取数据时,只读取有用的字段,则使用此参数来进行设定,些功能与GET事件中的FIELDS选项功能相同(均是读取部分数据库表字段,而不是将所有字段数据读取):GET node [LATE] [FIELDSf1 f2 ...]
在主调程序中,首先使用以下语句来定义动态字段内表 fsel :
TYPE-POOLS: rsfs.
DATA: fsel TYPE rsfs_fields."rsfs_fields为类型组RSFS中定义的内表类型
(rsfs_fields内表类型所在RSFS内类组源码如下:)
最后,在主调程序中调用LDB_PROCESS函数时,通过其入参数FIELD_SELECTION将动态字段内表fsel传递到LDB数据库程序中,然后LDB数据库程序中相应节点(表)的FORM PUT_XXX 中读取数据时,就可以使用此动态字段内表作为Select从句中的字段选择了(注:如果动态内表为空,则会忽略此条件,查找查询所有字段):
(另外,上面LDB数据库程序中要能从SELECT_FIELDS内表读取数据,则必须在LDB选择屏幕里开启相应节点的动态选择字段:)
(其中,SELECT_FIELDS内表行结构如下:)
内表parameters
?CALLBACK
You use this parameter to assign callback routines to the names of nodes and events.
The parameter determines the nodes of the logical database for which data is read, and
when the data is passed back to the program and in which callback routine.
CALLBACK为行类型为LDBCB结构类型的内表
LDBNOE:需要读取的LDB节点名
GET:如果为 X ,则使用LDB_PROCESS函数方式调用LDB时,也可以具有好比可执行报表程序属性绑定LDB方式情况下的GET事件,会调用CB_FORM参数指定的FORM
GET_LATE:如果为 X ,则使用LDB_PROCESS函数方式调用LDB时,也可以具有好比可执行报表程序属性绑定LDB方式情况下的GET LATE事件,会调用CB_FORM参数指定的FORM
CB_PROG:CB_FORM参数指定的回调过程所属程序名
CB_FORM:回调的Form过程
如果你给CALLBACK参数传了个内表,则对于每个节点行数据,只少GET或GET_LATEe有一个值为X,或者两个都可以为X
回调的过程必须具有以下方法签名:
FORM <subr> USING <node> LIKE LDBCB-LDBNODE
<wa> [TYPE <t>]
<evt>
<check>.
这些参数会被LDB_PROCESS函数自动传递过来,各参数的意义如下:
<node>:节点名称
<wa>:节点内表所对应的工作区。在主调程序以及该过程所在的程序不必要使用NODES or TABLES来声明工作区。如是该过程
只是用来处理某一个节点时,你可以使用TYPE选项来为<wa>工作区指定具体类型,此类型即为某节点所对应的数据词典类型。如果该过程要处理多个节点数据,则不要使用TYPE选项,此时需要通过 field symbol 来读取工作区各组件字段的值。
<evt>:值为G or L,分别表示该过程是由GET与GET LATE事件触发调用的。
<check>:
The callback routine (in <evt> 'G' only) can influence further processing. When the routine starts, the parameter contains the value 'X'. If it has the value SPACE at the end of the routine, the system interprets this as a sign that the callback routine has discarded the data record. As a result, none of the subordinate nodes are processed. This can lead to a considerable performance gain. Furthermore, it means that the checks do not have to be repeated for the subordinate nodes. Resetting <check> to SPACE is the equivalent of a negative CHECK in th e GET event.
?SELECTIONS
通过此参数可以给LDB的选择屏幕字段传递值。其数据类型为行结构为RSPARAMS的内表,与SUBMIT语句中的WITH SELECTION-TABLE选项用法一样
SELECTIONS and EXPRESSIONS 选项中的值会覆盖VARIANT选项中同名字段
LDB程序中的Dynamic Selections
SELECTION-SCREEN DYNAMIC SELECTIONS FOR NODE|TABLE <node>.语句用在LDB屏幕选择Include文件中,用来开启<node>节点的LDB dynamic selections功能,即可以在WHERE从句中使用动态选择条件(形如:…WHERE field1 = value1 AND (条件内表) …)
在PUT_<node> Form中的SELECT语句中使用dynamic selections,需要用到数据对象DYN_SEL,该数据对象是在LDB数据库程序中自动生成的,其类型如下(不必在LDB程序中加入下面代码行就可以直接使用DYN_SEL):
TYPE-POOLS RSDS.
DATA DYN_SEL TYPE RSDS_TYPE.
你不必在程序中定义它就可以直接使用,但它只能在LDB数据库程序中使用,而不能用在报表程序中。RSDS_TYPE数据类型是在类型组RSDS中定义的:
.
TYPES: BEGIN OF RSDS_TYPE,
CLAUSES TYPE RSDS_TWHERE,
TEXPR TYPE RSDS_TEXPR,
TRANGE TYPE RSDS_TRANGE,
END OF RSDS_TYPE.
RSDS_TYPE是一个深层结构的结构体:
字段CLAUSES
Where从句部分,实则存储了可直接用在WHERE从句中的动态Where条件内表,可以在Where动态语句中直接使用,该组件为内表,存储了用户在选择屏幕上选择的LDB动态选择字段
每个被选择的LDB屏幕动态选择字段都会形成一个条件,并存储到RSDS_TYPE-CLAUSES-WHERE_TAB内表中WHERE_TAB内表中存储的就是直接可以用在Where从句中的动态选择条件中。
每个表(节点)都会有自己的CLAUSES-WHERE_TAB动态条件内表,这是通过CLAUSES-TABLENAME来区别的。
现假设有名为 ZHK 的LDB,SCARR为该LDB的根节点,且仅有SPFLI一个子节点。LDB选择屏幕 Include文件 DBZHKSEL内容如下:
SELECT-OPTIONS S_CARRID FOR SCARR-CARRID.
SELECT-OPTIONS S_CONNID FOR SPFLI-CONNID.
"需要先开始动态选择条件功能
SELECTION-SCREEN DYNAMIC SELECTIONS FOR TABLE SCARR.
LDB数据库程序SAPDBZHK中,PUT_SCARR过程中使用dynamic selection的过程如下:
FORM PUT_SCARR.
STATICS: DYNAMIC_SELECTIONS TYPE RSDS_WHERE,FLAG_READ.定义成静态类型的是防止再次进入此Form时,再次初始化DYNAMIC_SELECTIONS结构,即只执行一次初始化代码
IF FLAG_READ = SPACE.
DYNAMIC_SELECTIONS-TABLENAME = 'SCARR'.
READ TABLE DYN_SEL-CLAUSES WITH KEY DYNAMIC_SELECTIONS-TABLENAME INTO DYNAMIC_SELECTIONS.
FLAG_READ = 'X'.
ENDIF.
SELECT * FROM SCARR WHERE CARRID IN S_CARRID AND (DYNAMIC_SELECTIONS-WHERE_TAB).使用动态Where条件
PUT SCARR.
ENDSELECT.
ENDFORM.
字段TEXPR
TEXPR contains the selections of the dynamic selections in an internal format (Polish
notation).You can use this format with function modules FREE_SELECTIONS_INIT and
FREE_SELECTIONS_DIALOG in order to work with dynamic selections within a program (for
more information, see the documentation of these function modules).
字段TRANGE
该字段是一个内表,存储了CLAUSES的原数据,CLAUSES内表里的数据实质就是来源于TEXPR内表,只是CLAUSES已经将每个表字段的条件拼接成了一个或多个条件串了(形如:“XXX字段 = XXX条件”),但是TEXPR内表与RANGES tables相同,存储的是字段最原始的条件值,使用时,在WHERE 从句中使用 IN 关键字来使用这些条件值(这与SELECT-OPTIONS类型的屏幕参数用户是完全一样的)。
但是,使用TEXPR没有直接使用CLAUSES灵活,因为使用TEXPR时,WHERE从句里的条件表字段需要事先写好,这实质上不是动态条件了,可以参考以下实例,与上面CLAUSES用法相比就更清楚了:
现假设有名为 ZHK 的LDB,SCARR为该LDB的根节点,且仅有SPFLI一个子节点。LDB选择屏幕 Include文件 DBZHKSEL内容如下:
SELECT-OPTIONS S_CARRID FOR SCARR-CARRID.
SELECT-OPTIONS S_CONNID FOR SPFLI-CONNID.
"需要先开始动态选择条件功能
SELECTION-SCREEN DYNAMIC SELECTIONS FOR TABLE SCARR.
LDB数据库程序SAPDBZHK中,PUT_SCARR过程中使用dynamic selection的过程如下:
FORM PUT_SCARR.
STATICS: DYNAMIC_RANGES TYPE RSDS_RANGE, "存储某个表的所有屏幕字段的Ranges
DYNAMIC_RANGE1 TYPE RSDS_FRANGE,"存储某个屏幕字段的Ranges
DYNAMIC_RANGE2 TYPE RSDS_FRANGE,
FLAG_READ."确保DYN_SEL只读取一次
IF FLAG_READ = SPACE.
DYNAMIC_RANGES-TABLENAME = 'SCARR'.
"先取出 SCARR 表的所有屏幕字段的Ranges
READ TABLE DYN_SEL-TRANGE WITH KEY DYNAMIC_RANGES-TABLENAME
INTO DYNAMIC_RANGES.
"再读取出属于某个字段的Ranges
DYNAMIC_RANGE1-FIELDNAME = 'CARRNAME'.
READ TABLE DYNAMIC_RANGES-FRANGE_T WITH KEY DYNAMIC_RANGE1-FIELDNAME
INTO DYNAMIC_RANGE1.
DYNAMIC_RANGE2-FIELDNAME = 'CURRCODE'.
READ TABLE DYNAMIC_RANGES-FRANGE_T WITH KEY DYNAMIC_RANGE2-FIELDNAME
INTO DYNAMIC_RANGE2.
FLAG_READ = 'X'.
ENDIF.
SELECT * FROM SCARR
WHERE CARRID IN S_CARRID
AND CARRNAME IN DYNAMIC_RANGE1-SELOPT_T"使用IN 关键字使用Ranges内表
AND CURRCODE IN DYNAMIC_RANGE2-SELOPT_T."(与select-options屏幕参数是一样的用法)
PUT SCARR.
ENDSELECT.
ENDFORM.
更多详情的可以参考LDB_PROCESS函数的EXPRESSIONS参数
LDB程序中的Field Selections
SELECTION-SCREEN FIELD SELECTION FOR NODE|TABLE <node>.语句的作用是开启节点<node>的动态字段选择的功能(形如: SELECT (选择字段内表) FROM…,而不是 SELECT * FROM …,即选择了哪些字段,就只查询哪些字段,而不是将所有字段查询出来,进而可以提高性能)。
在可执行报表程序里,可以通过GET node [FIELDS f1 f2 ...]语句中的 FIELDS选项来指定要读取字段;
如果是通过LDB_PROCESS函数来调用LDB时,可以通过其参数FIELD_SELECTION来指定要读取的字段,并且在LDB数据库程序中,通过从SELECT_FIELDS内表中就可以读取这些传递进来的选择字段,SELECT_FIELDS是LDB数据库程序自动生成的,其类型如下(不必在LDB程序中加入下面代码行,直接就可以使用SELECT_FIELDS内表,另外在相连的报表程序中也可以使用,这与DYN_SEL不同):
TYPE-POOLS RSFS.
DATA SELECT_FIELDS TYPE RSFS_FIELDS.
RSDS_FIELDS中的FIELDS里存储的就是GET…FIELDS…语句或者是FIELD_SELECTION参数传递过来的用户指定的查询字段,FIELDS内表可以直接使用在 SELECT…从句中。
现假设有名为 ZHK 的LDB,SCARR为该LDB的根节点,且仅有SPFLI一个子节点。LDB选择屏幕 Include文件 DBZHKSEL内容如下:
SELECT-OPTIONS S_CARRID FOR SCARR-CARRID.
SELECT-OPTIONS S_CONNID FOR SPFLI-CONNID.
"需要先开始动态选择字段功能
SELECTION-SCREEN FIELD SELECTION FOR TABLE SPFLI.
LDB数据库程序SAPDBZHK中,PUT_SCARR过程中使用dynamic selection的过程如下:
FORM PUT_SPFLI.
STATICS: FIELDLISTS TYPE RSFS_TAB_FIELDS,
FLAG_READ."确保SELECT_FIELDS只读取一次
IF FLAG_READ = SPACE.
FIELDLISTS-TABLENAME = 'SPFLI'.
"读取相应表的动态选择字段
READ TABLE SELECT_FIELDS WITH KEY FIELDLISTS-TABLENAME INTO FIELDLISTS.
FLAG_READ = 'X'.
ENDIF.
SELECT (FIELDLISTS-FIELDS)"动态选择
INTO CORRESPONDING FIELDS OF SPFLI FROM SPFLI
WHERE CARRID = SCARR-CARRID
AND CONNID IN S_CONNID.
PUT SPFLI.
ENDSELECT.
ENDFORM.
在相应的可执行报表程序里,相应的代码可能会是这样的:
TABLES SPFLI.
GET SPFLI FIELDS CITYFROM CITYTO.
...
GET语句中的FIELDS选项指定了除主键外需要查询来的字段,主键不管是否选择都会被从数据库表中读取出来,可以由下面报表程序中的代码来证明:
DATA: ITAB LIKE SELECT_FIELDS,
ITAB_L LIKE LINE OF ITAB,
JTAB LIKE ITAB_L-FIELDS,
JTAB_L LIKE LINE OF JTAB.
START-OF-SELECTION.
ITAB = SELECT_FIELDS.
LOOP AT ITAB INTO ITAB_L.
IF ITAB_L-TABLENAME = 'SPFLI'.
JTAB = ITAB_L-FIELDS.
LOOP AT JTAB INTO JTAB_L.
WRITE / JTAB_L.
ENDLOOP.
ENDIF.
ENDLOOP.
如果报表程序中的GET语句是这样的:GET SPFLI FIELDS CITYFROM CITYTO.,则输入结果为:
CITYTO
CITYFROM
MANDT
CARRID
CONNID
可以从输出结果看出,主键MANDT、CARRID、CONNID会自动的加入到SELECT_FIELDS内表中,一并会从数据库中读取出来
LDB程序中的Search Help
PARAMETERS <p> AS SEARCH PATTERN FOR TABLE <node>
已过时,新创建的LDB不再建议使用
Logical Databases逻辑数据库的更多相关文章
- 通过LDB_PROCESS函数使用逻辑数据库
1.概览 通过LDB_PROCESS函数可以允许任何程序访问逻辑数据库,允许一个程序访问多个逻辑数据库,当然也允许多次连续访问访问同个逻辑数据库.当使用LDB_PROCESS函数来访问逻辑数据库 ...
- [SAP ABAP开发技术总结]逻辑数据库
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- 逻辑数据库设计 - 需要ID(谈主键Id)
本文的目标就是要确认那些使用了主键,却混淆了主键的本质而造成的一种反模式. 一.确立主键规范 每个了解数据库设计的人都知道,主键对于一张表来说是一个很重要,甚至必需的部分.这确实是事实,主键是好的数据 ...
- 【ABAP系列】SAP 的逻辑数据库解析
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP 的逻辑数据库解析 前 ...
- 学会4种备份MySQL数据库(基本备份方面没问题了)
前言 我们试着想一想, 在生产环境中什么最重要?如果我们服务器的硬件坏了可以维修或者换新, 软件问题可以修复或重新安装, 但是如果数据没了呢?这可能是最恐怖的事情了吧, 我感觉在生产环境中应该没有什么 ...
- 学会用各种姿势备份MySQL数据库
学会用各种姿势备份MySQL数据库 前言 为什么需要备份数据? 数据的备份类型 MySQL备份数据的方式 备份需要考虑的问题 设计合适的备份策略 实战演练 使用cp进行备份 使用mysqldump+复 ...
- 备份MySQL数据库的方法
前言 我们试着想一想, 在生产环境中什么最重要?如果我们服务器的硬件坏了可以维修或者换新, 软件问题可以修复或重新安装, 但是如果数据没了呢?这可能是最恐怖的事情了吧, 我感觉在生产环境中应该没有什么 ...
- MySQL数据库备份的4种方式
MySQL备份的4种方式 总结: 备份方法 备份速度 恢复速度 便捷性 功能 一般用于 cp 快 快 一般.灵活性低 很弱 少量数据备份 mysqldump 慢 慢 一般.可无视存储引擎的差异 一般 ...
- 使用Xtrabackup 备份mysql数据库
##创建逻辑卷 [root@node1 ~]# pvcreate /dev/sdb1 Physical volume "/dev/sdb1" successfully create ...
随机推荐
- Spring之AOP面向切片
一.理论基础: AOP(Aspectoriented programming)面向切片/服务的编程,在Spring中使用最多的是对事物的处理.而AOP这种思想在程序中很多地方可以使用的,比如说, ...
- Jquery中$(document).ready()与传统JavaScript中的window.onload方法的区别(2016/8/3)
Jquery中$(document).ready()的作用类似于传统JavaScript中的window.onload方法,不过与window.onload方法还是有区别的. 1.执行时间 ...
- sersync实现触发式同步
金山的一个居于inotify+rsync进行二次开发实现文件同步的小工具sersync,能够很方便的实现文件触发式同步 Inotify 是基于inode级别的文件系统监控技术,是一种强大的.细粒度的. ...
- Linux驱动学习笔记(6)信号量(semaphore)与互斥量(mutex)【转】
转自:http://blog.chinaunix.net/uid-24943863-id-3193530.html 并发导致竟态,从而导致对共享数据的非控制访问,产生非预期结果,我们要避免竟态的发生. ...
- [转]AngularJS的$resource
转自:http://blog.csdn.net/violet_day/article/details/17403207 $http $http服务是基于$q服务的,提供了promise封装,它接受一个 ...
- CentOS 7 更新源 – 使用国内 163 yum 源
突然想起试试 Docker,在一台计算机上安装了 CentOS 7,准备开工,突然想起还需要做一件事情,更改源,不然安装肯定会很慢,网上搜索了一下,文章很多,但是会出一些问题,所以将自己的成功的日志写 ...
- editPlus,3.7V 注册码
editPlus,3.7V 注册码: username:linzhihui password:5A2B6-69740-D9CDE-79702-C9CCD
- [ Laravel 5.3 文档 ] 安全 ―― API认证(Passport)保障安全性。
1.简介 Laravel通过传统的登录表单已经让用户认证变得很简单,但是API怎么办?API通常使用token进行认证并且在请求之间不维护session状态.Laravel使用LaravelPassp ...
- HDU 4315:Climbing the Hill(阶梯博弈)
http://acm.hdu.edu.cn/showproblem.php?pid=4315 题意:有n个人要往坐标为0的地方移动,他们分别有一个位置a[i],其中最靠近0的第k个人是king,移动的 ...
- ecshop底部版权修改和组成分析
我们在ecshop二次开发和ecshop使用过程中,往往需要对ecshop底部进行处理和修改.比如ecshop底部版权问题,ecshop底部程序结构问题.也有很多朋友咨询ecshop底部的一些修改问题 ...