资源描述
终端页面开发流程和规范0.6版
文件状态:
[√] 草稿
[ ] 正式发布
[ ] 正在修改
文件标识:
当前版本:
0.6
撰 稿 人:
李水生
完成日期:
发布时间:
编 号:
2005年12月23日
版 本 历 史
版本/状态
作者
参与者
起止日期
备注
草稿
Hipay系统自助终端页面开发流程和规范
一:Hipay页面开发
1 目录结构:
1.1:顶层目录结构 图(1)所示
Applications: 目录里放着我们创建的应用板块。
Framework: 里是Hipay系统应用,包含实体和服务板块
Base: 里放着启动,容器和配置和组件加载等公共类。
Data: 是Hipay内建的数据库。
Logs: 是系统日志文件夹。
Hipay.bat是启动文件。
图(1)
1.2:applications 目录 图(2)所示
Accounting : 帐务管理,支付信息 ,发票等。
Content : 内容管理,调查等。
Ecommerce : 电子商务应用。
Order : 订单管理。
Party :人员组织管理
Securityext : 安全管理拓展
Product : 产品管理。
Component-load.xml : 板块加载配置文件。
图(2)
1.3:ecommerce 目录 图(3)所示
Src : java源文件。
Config : 配置文件,主要是多语言的配置文件
Data : 系统运行时需要导入的数据文件
Script : Hipay 系统 mini-lang文件(简单Java方法)
Templates : 模板页面
Webapp : web 服务需要用到的页面和脚本
Widget : 用xml描述的页面
Build.xml : 用ant工具编译src文件夹的源文件生成的classes文件和jar包放在build中。
giantstone-component.xml : 电子商务板块加载配置文件。
图(3)
1.4:webapp 目录
Webapp 下有一个应用文件夹为 ecommerce ,其目录结构如图(4)所示:
除了 WEB—INF 文件夹以外,其他的文件都是页面文件,页面文件都是以ftl为后缀的freemaker模板页面。
图(4)
1.5:WEB—INF 目录如图(5)所示
Actions : 系统脚本文件夹 ,beanshell脚本
controller.xml :流程控制器
web.xml :网站参数设置
图(5)
1.6:actions 目录 如图(6)
其文件结构和图(4)中的ftl页面结构是对应的。
比如说显示购物车信息的页面showcart.ftl放在图(4)cart文件夹中,则对应的脚本showcart.bsh放在图(6)的cart文件夹中,这样做不是必需的,但是是规范的,易于维护的。
图(6)
1.7:widget 目录
Widget是把ftl页面和bsh脚本组合起来供前端显示的工具。它用xml语言和特定标签描述页面和页面,页面和脚本之间如何组合和定制。
CommonScreens.xml 是公共模板定制页面
CartScreen.xml 是购物车相关页面定制
CatalogScreens.xml 是产品,目录的显示的页面定制
CustomerScreens.xml 是有关调查,寻价和客户方面的页面定制
ContentScreens.xml 是跟内容管理相关的页面定制
OrderScreens.xml 是跟订单和支付相关的页面定制
EcommerceSetup.bsh是公共模板加载的脚本
图(7)
其他板块的目录结构和ecommerce 是相似的。
2 开发内容
2.1:对widget组合页面要熟练掌握。
Web Widget是轻量级的Web应用程序,为使用者提供一键式的服务。它通常被设计为具有特定的功能,如提供天气、股票、拍卖等的信息。它与网页一样,使用标准的Web技术开发,如XHTML,CSS,javascript等。从这方面看,Widget是脱离浏览器UI运行的网页。
beanshell脚本准备数据,freemaker页面显示数据,而widget 工具正是组合脚本和页面的,它规定了哪个脚本为哪个页面组织数据,即起到绑定脚本和页面的作用,同时也可以定义某些变量供页面使用,当然有些页面可以没有脚本,简单的来说,widget就是用户请求页面,它把变量,标签和freemaker模板语言组合生成HTML页面,当用户请求时就发送给用户浏览器。
Widget用到的标签在framework / widget / dtd 里的xsd文件里,如图(8)
图(8)
在eclipse开发环境下,有代码预示的功能,如图(9)
图(9)
图(10)
图(10)的<!-- à的内容是注释,从图中的注释清楚地介绍的用widget如何定制一个模板。
screen
Screen标签对应的是前端请求的页面,页面的名称name属性是必须的。
section
Screen 下有一个唯一的 section ,
section下包含 condition ,actions ,widgets和fail-widgets 标签。
condition
如果 condition存在,并且condition是true 则页面显示widgets内容,否则显示fail-widgets。
如果 condition不存在,则fail-widgets标签也就没有必要。
以下是对 attrName 非空的判断:
<condition>
<not>
<if-empty field-name="attrName"/>
</not>
</condition>
<if-has-permission permission="ORDER_VIEW"/>是检查当前用户是否拥有对order的VIEW(查看)的权限
<if-compare value="常量" field-name="变量" operator="操作"/> 是把变量跟某个常量进行比较,操作包括 less greater equals less-equals greater-equals not-equals contains ,分别表示,小于 大于 等于 小于等于 大于等于 不等 包含。
<if-compare-field field-name="变量1" operator="" to-field-name="变量2" type= "String" />是把两个变量进行比较, type类型值可以为Float Double Integer Long Boolean String PlainString Date Time Timestamp 和Object,如果没有type默认为String。
and 是对多个条件进行与操作 or 或操作 xor 异或 not 非
<and>
< 条件1 >
< 条件2 >
</and>
<or> < 条件1 >< 条件2 ></or>
其他的标签请查看图(8)所示的文件中内容。
actions
actions 是加载页面之前的动作。
常用的动作是 :
set :
set定义一个变量并赋值 field 的值就是变量名 value 是变量值;
script :
script加载一个beanshell脚本文件,location是脚本的位置,
位置以” component://xyz/ ”开头,意思是在xyz这个板块下,xyz是在Hipay的安装目录下的applications和framework下的第一层子目录文件夹,如图(2)得文件夹都可以作为这里的xyz。
property-map :
property-map加载一个属性文件,resource的值是文件的名称,文件后缀为properties,可省略不写,对于多语言,比如要加载简体中文配置文件TMSBaseUiLabels_zh_CN.properties和美国英语配置文件TMSBaseUiLabels_en_US.properties,并把配置文件的键值对放在一个Map即uiLabelMap中,作为全局变量是用,只需要这样一行代码:
<property-map resource="TMSBaseUiLabels" map-name="uiLabelMap" global="true"/>
这行代码会加载所有各种语言的配置文件,然后根据用户的locale,读取当时当地的语言配置。还有一点需要注意,如果uiLabelMap在TMSBaseUiLabels_zh_CN.properties中找不到键值,它会去TMSBaseUiLabels_zh.properties查找,如果没找到,则继续查找TMSBaseUiLabels.properties,如果仍然没有值则返回键本身,如果有则返回文件中定义的值;
widgets
Widgets 是对页面的加载和布局。常用的加载页面的方法包括
1:platform-specific
<platform-specific>
<html>
<html-template location="component://TMSBase/webapp/TMSBase/includes/header.ftl"/>
</html>
</platform-specific>
component://TMSBase/webapp/TMSBase/includes/header.ftl 为要加载的文件路径和名称。即TMSBase这个板块下webapp文件夹的子文件夹TMSBase下的子文件夹includes下的header.ftl文件。
2:include-screen
<include-screen name="abc" location="component://TMSBase/widget/bcd.xml" />
这行代码的意思是加载一个页面,这个页面是在TMSBase这个板块下的widget文件夹下的bcd.xml文件里定义的abc页面。abc是screen的 name的值。
3:decorator
另外,模板常用到这行代码 <decorator-section-include name="body"/> ,
意思是页面的body部分是空的,其他页面使用以下代码使用这个模板,
<decorator-screen name="main-decorator"> main-decorator是模板的名称(screen的name的值)
则其他页面的内容出现在body部分。
4:container
Widget中可以加载容器 <container style="样式表"> 容器里面可以加载其他页面,这类似于HTML中的DIV 层。以下代码是合法的:
<container style="">
<include-screen name=""></include-screen>
<platform-specific>
<html>
<html-template location=""/>
</html>
</platform-specific>
<decorator-section-include name="body"/>
</container>
<include-screen name=""></include-screen>和<include-screen name=""/>效果是等同的,其他类似。
5:widget中的section
<widgets>
<section>
… …
</section>
</widgets>
widgets中可以放置多个section
6:其他
加载一个图片可以使用 <image src=""></image>
页面上显示一行文字可用<label text=""></label>
其他的标签请查看图(8)所示的文件中内容。
fail-widgets
等同于widget标签,是条件不满足时给用户显示的页面。
2.2:对freemaker模板语言的熟练掌握
2.2.1:各页面功能及存放位置
页面文件后缀为ftl,存放在图(4)所示的目录中,即webapp下的应用文件夹中
图(4)
自助终端目前用到的页面中有图(4)中的部分页面:
main.ftl 是主页面,用户返回时会到此页面,该页面左边显示分类,右边显示推广产品。
mainframe.ftl 框架页面分三个部分 框架上面部分占99.98% 是用户操作的业务页面,框架中间占0.01%,是用来加载终端插件,框架下部是用来加载加密插件和进行加密验证的。
mainup.ftl 是语言选择页面。
login.ftl 是用户刷卡登陆页面。
cart下的showcart.ftl页面 (购物车页面)
catalog下的sidedeepcategory.ftl (终端屏幕的左边目录翻页页面)
customer下的survey.ftl (调查页面即用户的密码,号码输入页面)
error 下的error.ftl (错误页面)
includes 下的:
header.ftl 模板头部导航栏 加载样式表 定制页面超时脚本
footer.ftl 模板底部留个按钮
hidebottom.ftl 加载终端插件,是页面底部框架固定不动的部分,对于不同的终端,申 明和条用插件的方式可能不同,此时需要编写多个厂家的底部框架页面。
jiami.ftl 工行自助终端用到的加密插件页面。
order下的
checkoutoptions.ftl 该页面显示正在支付中,请用户等候,该页面向后台传递了用户的支付方式,货物的运送方式,联系方式等等重要信息,不可或缺。
ordercomplete.ftl该页面是支付完成页面,显示支付结果,成功则用户可以选择打印凭条。
另外还用到了order板块的webapp 下ordermgr的字文件夹entry的catalog的部分文件,如图(11)
图(11)
calldetailIE.ftl 是天一终端的IE浏览器在进行银行卡打电话业务时显示的页面。
calldetailNE.ftl 是芙蓉终端mozzila浏览器银行卡打电话页面
category.ftl 是显示产品分类的页面 其指向categorydetail
categorydetail.ftl 是产品分类的详细信息页面 其指向productsummary.ftl
productsummary.ftl 是某一个分类下所有产品的简要介绍页面 ,在终端上就是显示在屏幕右边的四个按钮上的内容。
product.ftl 是产品页面 其指向 productdetail.ftl页面
productdetail.ftl 页面是根据对产品的配置的详情页面来展示产品。比如银行卡打电话这个产品就是配置成了calldetail.ftl ,如果没有配置则默认显示productdetail.ftl页面
2.2.2:常用的页面标签
以下例子中可以见到常用到了页面标签。
<div class="ecom-body">
<div class="ladyFirstPosition">
<img src="/images/motif_ty.gif"/>
</div>
<div class="textPosition">
${uiLabelMap.chooseLanguage}
<#--
<div class="R1">
${uiLabelMap.firstPagedownInformation}
</div>
-->
</div>
<#if languagesList?has_content>
<#list languagesList as language>
<#if language?has_content>
<#assign index = 4 - languagesList?size + language_index +1>
<#assign styleValue = "productcontent" + index>
<input type="button" id="${styleValue}" class="buttonImgClass" value="${uiLabelMap[language.description?if_exists]}" name="${index*2}" onclick="window.location='<@giantstoneUrl>${language.requestUri?if_exists}</@giantstoneUrl>';"/>
</#if>
</#list>
</#if>
</div>
2.2.2.1 注释<#-- -->
<#-- --> 注释的内容不能出现 -- 字样
<#--
<div class="R1">
${uiLabelMap.firstPagedownInformation}
</div>
-->
要注意区分HTML页面的注释 <!-- -->
2.2.2.2 赋值assign
设置变量 <#assign index = 5>
页面使用变量时用 ${index} ,将会显示5
2.2.2.3 条件判断 if else
使用时以尖括号和#开头 <#if boolean> 并以 </#if> 结尾
<#if (a>b)>
A 比B大
<#else>
A 不比B大
</#if>
2.2.2.4 列表 list size index
<#assign languagesList = { Chinese ,English ,French} >
languagesList size = ${languagesList?size}
<#list languagesList as language>
${language} 位置是 ${language_index} ,
</#list>
则最后显示的结果是:
Chinese位置是 0 , English位置是 1 , French位置是 2,
2.2.2.5 异常处理
如果变量值没有定义页面就会报错,加上以下一些判断,可以消除页面上的错误:
exists if_exists has_content default
exists 是对某个变量进行判断,返回值是布尔型 true or false ;
if_exists 返回是字符串,对某个变量进行判断 如果值或引用不存在则显示空串,相当于“”;
has_content 对变量进行判断,如果值或引用存在并且不为空时才为true 否则为false。
default 如果变量无值就设定默认值。
<#if someparameter?exist>
${someparameter}
</#if>
<#if someparameter?has_content >
${someparameter}
</#if>
${someparameter?if_exists}
${someparameter?default(“defaultValue”) }
2.2.2.6 其他
对于自助终端页面目前常用就是上面介绍的这些标签
更多请参考FreeMarker设计指南.doc
推荐登陆官方网站www.freemaker.org查看详细手册。
2.3:对beanshell脚本的熟悉
Beanshell 是宽松的Java,使用变量前无需定义,它完全兼容Java语法。
详情请登陆官方网站 www.beanshell.org
Flt页面负责显示后台传来的数据,对页面来说beanshell脚本是重要的后端数据源,
在beanshell里可以直接引用request变量和context变量;
通过request的getParameter(“name”) 方法bsh脚本可以获取前端页面传来的参数
通过context的put(“name”,value) 方法bsh脚本可以把经过处理的数据送回前端页面显示。
页面使用 ${ name }即可显示。
request 可以得到delegator 和 dispatcher
delegator
bsh脚本中得到delegator:
delegator = request.getAttribute("delegator");
delegator 是实体引擎对数据库增删查改的代理器;
数据库查找
根据主键查找:
Bsh脚本中最常做的事情是到数据库中查找数据供前台页面展示。
value = delegator.findByPrimaryKey( "数据库表名", inMap );
inMap放置主键键值对. UtilMisc.toMap("name","value")方法是把键值对放入Map中
比如:
orderHeader=delegator.findByPrimaryKey("OrderHeader",UtilMisc.toMap("orderId", "1000"));
意思是在表OrderHeader中查找主键(orderId)等于 1000的记录,查出后赋给orderHeader。
根据某几个字段交集查询:
valueList = delegator.findByAnd( "数据库表名", inMap );
orderHeader=delegator.findByAnd("OrderHeader",
UtilMisc.toMap("statusId", "APPROVE","grandTotal","200"));
意思是在表OrderHeader查询状态是APPROVE并且交易金额是200元的记录列表。
根据某几个字段并集查询:
valueList = delegator.findByOr( "数据库表名", inMap );
orderHeader=delegator.findByOr("OrderHeader",
UtilMisc.toMap("statusId", "APPROVE","grandTotal","200"));
意思是在表OrderHeader查询状态是APPROVE或者交易金额是200元的记录列表。
根据条件查询:
delegator.findByCondition(数据库名, 条件列表, 需要查询出来的字段列表, 字段排序列表)
需要查询出来的字段列表如果设置为 null 则默认查出所有字段。
创建条件
比如产品号等于10001:
Condition1 = new EntityExpr("productId", EntityOperator.EQUALS, "10001"));
状态是ACTIVE:
Condition2 = new EntityExpr("statusId ", EntityOperator.EQUALS, "ACTIVE"));
生产日期大于某个日期date1:
Condition3 = new EntityExpr("munaDate", EntityOperator.GREATER_THAN, date1));
过期时间小于或等于某个日期 data2:
Condition4 = new EntityExpr("overDate", EntityOperator.LESS_THAN_EQUAL_TO, date2));
总条件:
Conds = new LinkedList();
添加条件:
Conds.add(Condition1);
Conds.add(Condition2);
Conds.add(Condition3);
Conds.add(Condition4);
设置条件之间的关系为与关系:
findCondition= new EntityConditionList(Conds, EntityOperator.AND);
设置排序:按产品号倒序排列。
orderby = UtilMisc.toList("-productId ") ;
开始查询:
findResultList=delegator.findByCondition( "Product", findCondition, null, orderby );
其他查询方法请参考com.giantstone.entity.GenericDelegator类的方法。
删除数据库记录
在查询方法中介绍的比较详细,此处不再赘述相关内容。
根据主键删除:
GenericPK pk = ((GenericValue)it.next()).getPrimaryKey();
delegator.removeByPrimaryKey(pk);
根据某几个字段交集删除
delegator.removeByAnd("TermService",UtilMisc.toMap("DEVTYPEID",sDEVTYPEID));
根据条件删除
delegator.removeByCondition(“数据库表”,“条件列表”);
删除列表
delegator.removeAll(List);
可以先查出一个列表,然后删除。
其他删除方法请参考com.giantstone.entity.GenericDelegator类的方法。
增加数据库记录
delegator.create( "数据库表名", inMap );
比如:nowTimestamp是当时时间
delegator.create( "Product", UtilMisc.toMap("productId", "10002", "statusId", "CREATE", "fromDate", nowTimestamp));
意思是往表Product中插入一条产品号是10002 状态是CREATE,开始日期是nowTimestamp的记录。
更改数据库中的记录
value 是数据库的一条记录。
fields是实据库字段的键值对Map
value = makeValue(“数据库表”, fields)
delegator.store(value);
根据条件更新:
delegator.storeByCondition();
delegator.storeByCondition("数据库表名", 要更新的字段, 更新条件);
dispatcher
bsh脚本中得到dispatcher:
dispatcher = request.getAttribute("dispatcher");
dispatcher 是服务引擎的调度器。
调用服务方法:
同步调用服务:
outMap = dispatcher.runSync ("服务名" , inMap ) ;
inMap是输入参数组成的Map ;
outMap是输出参数组成的Map ;
2.4:熟悉流程控制器controller.xml
handler
控制器定义了对于各种类型请求或响应采用何种方法来处理。
<handler name="java" type="request"
class="com.giantstone.webapp.event.JavaEventHandler"/>
<handler name="soap" type="request"
class="com.giantstone.webapp.event.SOAPEventHandler"/>
<handler name="service" type="request"
class="com.giantstone.webapp.event.ServiceEventHandler"/>
<handler name="simple" type="request"
class="com.giantstone.webapp.event.SimpleEventHandler"/>
<handler name="screen" type="view"
class="com.giantstone.widget.screen.ScreenWidgetViewHandler"/>
在controller.xml里有大量的<request-map uri="xxx">
uri是页面的请求。
request-map
<request-map uri="main">
<security https="true" auth="true"/>
<response name="success" type="view" value="main"/>
</request-map>
上面代码的意思是:
如果有请求是main ,第一步安全验证,https=true,表示要走https安全协议,https =false
就走http协议,auth=true强制调用checkLogin请求,验证用户是否已登录,auth=false则不检查此项,第二步意思是如果成功则到请求main页面。main页面在view-map中介绍。
再看看checkLogin:
<request-map uri="checkLogin" >
<description>验证用户是否登陆</description>
<security https="true" auth="false"/>
<event type="java"
path="com.giantstone.securityext.login.LoginEvents" invoke="checkLogin" />
<response name="success" type="view" value="main" />
<response name="error" type="view" value="login" />
</request-map>
这个请求中https=true,走https协议,auth=false,它当然不能递归调用自己。
event 是对该请求的响应事件 type=”java” 表示后台用java方法来处理这个请求,path是java的路径,invoke的值是java类的某个静态方法。
方法会返回“success” 或者"error",如果是前者,则页面转到main页面,否则到login页面。
处理请求的事件除了java还有 service ,用一个服务来响应一个请求,服务会返回“success”或者"error"。
<event type="service" invoke="createBillingAccount"/>
常用的还有simple 是mini-lang ,即简单java语言,详情参看
安装目录\framework\minilang\dtd\simple-methods.xsd及各板块中script文件夹的例程。
<event type="simple"
path="com/giantstone/accounting/payment/PaymentMethodEvents.xml"
invoke="createCreditCard"/>
当一个请求的response的type是 “request”的时候 会根据value的值来继续找 request -map的对应值,这样就形成了链式请求,即多个请求连续调用。当最后一个请求的值肯定会落在type 是 “view”上。应为HTTP请求肯定会给用户一个回应。
view-map
当一个请求的response的type 是 “view”的时候 就会根据value的值来找 view-map的对应值。
<response name="success" type="view"
<view-map name="main" type="screen"
page="component://accounting/widget/CommonScreens.xml#main"/>
上面代码的意思是如果来了view的页面请求,就去accounting这个板块的widget文件夹下的CommonScreens.xml文件中定义的main的页面。type=“screen”表示使用widget工具生成页面。
其他依次类推。
具体标签请参看: 安装目录\framework\webapp\dtd\ site-conf.xsd
3 开发顺序
3.1:理解流程控制器 controller.xml
开发之前,设计人员设计好控制流程,即编写好板块的controller.xml文件。
controller.xml里所有的请求uri (request-map uri="xxx" )都是与freemaker页面上的请求<@giantstoneUrl>/xxx</@giantstoneUrl> 一一对应。对于用户从页面上提交的请求,流程控制器就能接受到这个请求,并按预定义的事件进行处理,处理完成之后,根据处理结果,会转到不同的页面标识
(<view-map name="页面标识" type="screen" page="widget工具定制的页面"/>)这样一次请求响应就完成了。
3.2:理解页面组合器 widget 定制XML页面文件。
在流程控制器里以下代码:
<view-map name="showforum" type="screen"
page="component://ecommerce/widget/ForumScreens.xml#forum"/>
意思是页面标识是showforum的页面在ecommerce版块下widget文件夹下的
ForumScreens.xml文件描述的screen name=”forum”部分。
此外开发人员必须熟悉2.1节内容,即widget标签使用。
3.3:页面人员开发
按照流程控制器的内容规范前台页面的请求名(必需与request-map 中的uri对应上);
按照流程控制器中页面定义建立页面文件结构。
根据业务页面文档或者PowerPoint文档编写页面。
根据显示需要编写beanshell脚本。
4 数据库表结构
需要熟悉的数据库表结构,具体的标字段定义在各自板块的entitymodel.xml文件中。
Party板块
当事人表
<entity-group group="com.giantstone"
展开阅读全文