ADF 入门帮助

本文是由英文帮助翻译所得:前端

1>task flowsjava

“任务流 task flows”能够包括非可视化的组件,好比方法调用。
“页片断 page fragment”能够运行在一个页面的某个局部区域,最大限度地提升复用性。
ADF Task Flow是在JSF Controller的基础上扩展而来的,它除了包括View Activities和导航规则以外,还能够包括method calls等非可视化Activity。
ADF Task Flow分为两种:Bounded task flow和Unbounded task flow
一、Bounded task flow
 (1)、做为局部、分支的页面流程。
 (2)、有一个惟一入口和零到多个出口。
 (3)、拥有本身私有的Control flow rules,Activities,Managed bean,Transactions.
 (4)、能够重用。
二、Unbounded task flow
 (1)、做为顶级的页面流程。
 (2)、出口不固定。
ADF ManagedBean与JSF Managed Bean的区别在于,ADF Managed Bean的Scope比JSF Managed Bean多了pageFlowScope、viewScope、backingBeanScope。
. pageFlowScope:Managed Bean在Task Flow中的全部Page可见,且访问的同一个实例。若是其它Task flow中 Page访问该Managed Bean,将会建立一个新实例,供这个Task flow中的全部Page使用。
. viewScope:只在当前这个view(多是root browser window,也多是region)可见,当viewId发生改变后,该Managed Bean被释放掉。
. backingBeanScope:一个Page中含有一个Task Flow,而且这个Task flow使用了多个region,设置此值能够起到隔离各个region的做用(会在每一个region中建立一个实例),避免数据冲突。web

 

2>布局
为了使组件可以自适应浏览器窗口大小,首先须要放置根一级的可伸缩的布局组件。 如下组件能够根据父容器的大小自动伸缩(加星号的还能够伸缩其子组件):
. * Decorative Box
. Panel Accordion
. Panel Box (当type="stretch"或"default")
. Panel Collection
. Panel Dashboard
. Panel Group Layout (当layout="scroll"或"vertical")
. * Panel Spliter
. * Panel Stretch Layout
. Panel Tabbed
对于这些组件,不要设置其宽度、高度的百分比,设置了反而很差。
如下组件不能根据父容器的大小自动伸缩:
. Panel Border Layout
. Panel Box (当type="flow"或"vertical")
. Panel Form Layout
. Panel Group Layout (当layout="default"或"horizontal")
. Panel Header
. Panel Label and Message
. Panel List
若是你必须使用一个不能自动伸缩的容器,但又想达到自动伸缩的效果,能够为该容器套上一个能够自动伸缩的容器,如Panel Group Layout(当layout="scroll"或"vertical")。
最佳实践:(1)、布局时,根容器要能够自动伸缩。(2)、没法伸缩的容器,能够考虑外套一个Panel Group Layout(当layout="scroll"或"vertical")。数据库

 

3>eo的自定义属性express

为Entity Object增长Transient Attribute,好比自动计算订单总价:单价*数量。
(1)、由于是Transient Attribute,因此不要选择Persistent。
(2)、在View Object中增长该Attribute。
(3)、设置从新计算的条件:Always--每次都从新计算;Never--只在建立时计算一次;Based on the following expression--根据表达式返回值(True or false)来计算是否从新计算。浏览器

为Entity Object增长Association,好比订单项目中的产品与产品关系。
(1)、Association命名规则是<DetailEntityMasterEntity>FKAssoc。
(2)、搞清楚一对多的关系中,谁是1、谁是多。缓存

 

4>vo添加View Link性能优化

为View Object增长View Link,好比订单项目中的产品与产品关系。
View Object是对Entity Object的查询结果,结果包括Entity Object的所有或部分属性。通常来讲,一个View Object对应一个Entity Object。固然,你也能够彻底根据SQL语句自定义一个View Object。View Link代表的是两个View Object之间的关系,一个View Link对应一个Association。
(1)、View Link命名规则也是<DetailEntityMasterEntity>FkLink。
(2)、一样,也要搞清楚一对多的关系中,谁是1、谁是多。服务器

 

5>am添加Data Modelsession

为Application Module增长Data Model。
View Object代表数据被访问的方式。客户端经过访问View Object而访问Data Model。Data Model保存在Application Module中。Application Module是一种类型的业务服务,其它类型的业务服务有Web Service、EJB。在Data Model中,View Object所带的数字“1”、“2”、“3”....,代表这是该View Object的第几个实例。

 

6>LOV

ADF BC特点功能之一:级联式下拉列表
在实际应用中,常常会使用两个级联式下拉列表的状况,好比先选择国家列表,在根据选择的国家显示 城市列表。你能够把View Object某个Attribute定义成LoVs(全称:List of Values)。这样,因为是定义在模型层上,UI界面无需作任何改动。

 

7>ADF BC特点功能之二:强大的自动计算与验证功能
一、经过新建Transient Attribute来实现自动计算。
二、验 证Foreign Keys:Key Exists。LOVs能够限制用户只能从已有的外键中选择,但有时界面要求使用文本输入框,而不是下拉列表,这时候就须要使用Key Exists来验证用户输入的外键是否正确。而且,Key Exists可让咱们在程序中使用该功能,不经过界面。LOVs是定义在View Object上的,而Key Exists是定义在Entity Object上的。
三、约束性条件依赖:Compare。某个Attribute的值与设定值进行比较,为真则知足要求,不然报错。其中能够设定触发条件和触发Attributes。
四、使用Groovy脚本验证。若是脚本中有对象为null,Groovy不会抛出NullPointerException,而是表达式结果为null,null对应的Boolean值为false。

 

8>使用ADF Faces之一:开发用户界面
如何使用其它Project的资源:共享资源如servlet classes,helper classes,images和templatess,能够经过建立ADF library来为其它Project所共用。

 

9>使用ADF Task Flows之一:菜单与页面导航
一个应用的页面之间的上下级关系就像一棵树。每一个节点都是一个页面。
一个典 型的ADF应用由一个或多个unbounded task flow和bounded task flows组成。建立unbounded task flow时不要选择“Create as Bounded Task Flow”,而且以adfc-xxx-config.xml的格式来命名,好比adfc-sale-config.xml。adfc- config.xml是应用默认的unbounded task flow,它应该做为应用的总入口、根节点。

 

10>客制化:个性化的一种服务(customize(v),customization(n))
表示根据客户的需求进行特别的定制,已知足其须要。通常用于软件/服务/加工制造等方面。针对顾客的需求,对一个标准的产品进行改变、用新的部件替换标准的部件、或是在一个标准产品中加入特殊的功能,提供顾客一个更完整的产品组合。
个性化:就是非通常大众化的东西。在大众化的基础上增长独特、另类、拥有本身特质的须要,独具一格,别开生面,打造一种不同凡响的效果。
问题:在ADF中如何定制ADF应用?
根据行业的不一样,客户的不一样,须要对ADF应用作一些定制化操做,ADF应用的定制化分为两种:
(1)、个性化:容许用户运行时对应用进行定制。
(2)、客制化:容许用户设计时对应用进行定制。
不管是那种定制方法,这些定制的内容均不会对已开发完成的应用做出修改,而是存储在MDS(Metadata Service repository)中。MDS支持两种方式的实现:文件和数据库。ADF应用默认使用基于文件的MDS。
基于文件的MDS:选择Application -> Application Properties -> RUN -> MDS。Directory Content:你能够设置是否在每次执行应用前清空MDS存储的定制化信息。

如何实现用户客制化(Customize)
客制化是在设计时,在原有ADF应用的基础上,增长定制化层,每一层可能对应不一样的行业、不一样的公司。这样作的好处就是,既能知足不一样风格的展示要求,同时又不改变原有应用的基础代码。
(1)、一个ADF应用容许设置多个客制化层,如industry层及site层。
(2)、每个客制化层容许具备多个客制化值,如industry层能够具备healthcare和financial等。
(3)、运行时,每个层只有一个客制化层值有效。
(4)、客制化层的顺序由adfc-config.xml中各个客制化类的顺序决定。
实现客制化的具体步骤以下:
one、定义CustomizationLayerValues.xml。
 打开文件C:\Oracle\Middleware\jdeveloper\jdev\CustomizationLayerValues.xml,该文件定义了全部客制化层以及每层的值。
two、建立customization.properties文件
 在Model Project中,新建一个文件customization.properties。该文件代表运行时,每一个客制化层设定为哪一个值。
three、建立和发布客制化类
 MDS使用客制化类来决定应用哪一个客制化层,一个客制化类对应一个客制化层,其接口以下:
 . CacheHint getCacheHint();
   决定customization的类型,返回值包括ALL_USERS、MULTI_USER、REQUEST、USER四种。
   ALL_USERS:customization为针对某应用全局有效的,一般用于static类型的customization层。
   MUTI_USER:针对复数用户有效的customization。
   REQUEST:针对当前请求有效的customization。
   USER:针对某特定用户有效的customization,经过用户访问应用的Session来决定具体用户。
   . String getName();
   返回当前customization类对应customization层的名称。
 . String generateIDPrefix(RestrictedSession sess, MetadataObject mo);
   返回在MDS中对应当前customization层元素加的前缀,以使该客制化层的元素在MDS中具备惟一标示。这一前缀在全部customization层中必须是惟一的,出于性   能考虑应小于4个字符。
 . String[] getValue(RestrictedSession sess, MetadataObject mo);
   返回反映客户化层加载顺序的列表,按照列表顺序加载。一般只须要有一个customization层,故该列表一般只返回一个值。
 在Model Project中,新建一个Java类:SiteCCTV.java,内容本身再去看。写好类后,编译Model Project,发布Model Project为一个Jar文件。这里须要注意三 点:
 (1)、选中Include Manifest File。
 (2)、只选中定制化类和customization.properties文件。
 (3)、必须把该Jar文件Copy到C:\Oracle\Middleware\jdeveloper\jdev\lib\patches目录下。
four、修改adf-config.xml文件
 选择Application Resource -> Descriptors -> ADF META_INF,双击adf-config.xml打开overview editor。增长前面新建的定制化类。
five、为ViewController Project选中Enable Seeded Customizations。
six、建立基础应用:TaskFlows,JSF Pages等等。
seven、 在基础应用上客制化应用。这时,要以Customization Developer角色从新进入JDeveloper。方法是Tools -> Preferences -> Roles,选择Customization        Developer。重启JDeveloper后,应该能看到以前作的设置。

 

11>开发端到端的ADF应用之一:开发富互联网应用
一、建立Read-Only Vo:建立此种Vo通常做为下拉列表选项出如今UI中。
二、 为EO的字段定义验证规则:除了能够为EO的字段定义验证规则(Attributes Level Validator)以外,你还能够为整个EO定义验证规则(Entity Level Validator)。Attributes Level Validator在attribute值变时触发;Entity Level Validator在验证Entity时触发。若是想要自定义Java验证规则,则Rule Type选择Method方式,会自动帮你生成相应的方法,Java验证规则也能够定义在Attributes或Entity上。
三、在EO的字段设置默认值
   当前日期,adf.currentDate,显示格式。当前时间,adf.currentDateTime。注意,必须选择Expression方式。
四、建立一对多的UI界面(部门与员工是一对多的关系)
   注意,拖放EmployeesVo时,要选择DepartmentsVo下的EmployeesVo,这样才能自动关联一对多的关系。
五、建立VO(Updatable access throuth entity objects)
   (1)、建立VO的方式除了从Tables的方式建立之外,也能够经过抽取多个EO的属性来建立。
   (2)、为VO增长自动计算的Transient属性,如SumSalary=Salary*12。
   (3)、为EmpDetails VO增长View Accessors:Job VO,供如下拉列表的方式选择Job。
   注意,手工建立的VO必须加入Application Model的Data Model中才能使用。
六、建立VO(Read-only access through SQL query)
   能够用自定义SQL query的方式来建立Read-Only VO,能够带查询参数,参数直接定义在查询语句中,如select first_name from employees where email=:p_email。这种方式定义的VO,生成Data Control时,会在该VO的Operations下生成对应的ExecuteWithParams。

 

12>开发端到端的ADF应用之二:使用EJB、JPA、JSF开发Web应用

一、使用EJB3和JPA创建业务服务层。
 (1)从数据库表建立JPA Entities,生成相应的java文件,主要包括Entities的属性和CRUD方法。之后能够根据须要,手工添加一些方法。
 (2) 建立EJB Session Bean,选择Persistence Type=JPA,选择暴露哪些Entities上的方法。Entity若是增长了新的方法想要经过Session Bean调用,右键点击EJB     Session Bean,选择Edit Session Facade,把新方法加进来便可。
 (3)测试Session Bean很是方便,右键点击EJB Session Bean,选择New Sample Java Client,就会帮你生成测试代码,你只须要传一些必要的参数便可。测试前    ,先要运行Session Bean(把Session Bean发布到WLS上,并启动),而后右键点击Java Client,选择Run。
 (4)JPA Entities也能够不经过Java EE Container——直接在Java SE Container中就能够调用。你须要建立一个新的persistence unit,右键点击    persistence.xml选择New Java Service Facade,选择Persistence Type=JPA,选择暴露哪些Entities上的方法。在main函数中,能够增长你的测试代码,并    直接运行——不须要先运行Session Bean。
二、为Session Bean建立Data Control。
 右键点击EJB Session Bean,选择Create Data Control,选择暴露的Session Bean的Interface:Local或Remote。
三、如何让一个普通Project可使用JSF/ADF组件?
 (1) 右键点击Project,选择Project Properties,选择JSP Tag Libraries,选择Select Distributed libraries,增长ADF Faces Components 11,(只选这个就    能够,其它的会带过来)。
 (2)继续选择Technology Scope,选择JSF(只选这个就能够,其它的会带过来)。

 

13>如何显示提示信息
一、显示在某个组件的旁边
   要想显示在组件的旁边,首先要获得这个组件的ID,而后就是构造FacesMessage,并显示出来。
   (1)组件已经绑定在MB中
 FacesContext context = FacesContext.getCurrentInstance();
 FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,"Please supply a valid file name to upload",null);
 context.addMessage(this.getFileInputComponent().getId(),message);
   (2)经过组件上的事件获取组件
 FacesContext context = FacesContext.getCurrentInstance();
 FacesMessage messagge = new FacesMessage("Successfully uploaded file"+file.getFilename()+"("+file.getLength()+"bytes)");
 context.addMessage(event.getComponent().getClientId(context),message);
   (3)获取根组件
 public static void addFacesErrorMessage(String attrName, String msg){
  FacesContext ctx = FacesContext.getCurrentInstance();
  FacesMessage fm = new FacesMessage(FacesMessage.SEVERITY_ERROR, attrName, msg);
  ctx.addMessage(JSFUtils.getRootViewComponentId(), fm);
 }
   (4)经过根组件+组件ID查找组件
 pubic static void addFacesErrorMessage(String attrName, String msg){
  FacesContext ctx = FacesContext.getCurrentInstance();
  FacesMessage fm = new FacesMessage(FacesMessage.SEVERITY_ERROR, attrName, msg);
  ctx.addMessage(JSFUtils.getRootViewComponentId().findComponent("productpriceIT").getClientId(ctx), fm);
 }


14>页面之间传值的几种方法:
两个页面,第一个页面点击某个command component,传一个参数到第二个页面。
方法一:选中task flow中的某个View Activity,设置属性Input Page Parameters,from, to。设置到pageFlowScope中。
方法二:在按钮上设置set action listener事件,导航前该listener被触发。使用set action listener设置from,to,将当前页面的某个值设置到pageFlowScope中。
方法三:在按钮上设置set property listener事件,设置from, to, type。type=action,代表监听该command component的action event。
说明:建议使用set property listener。
两个页面,第二个页面接收第一个页面传过来的参数值
Map pageFlowScope = RequestContext.getCurrentInstance().getPageFlowScope();
Object myObject = pageFlowScope.get("myObjectName");
RequestContext adfContext = RequestContext.getCurrentInstance();
adfContext.getPageFlowScope().clear();

 

15>commit操做

由于Commit操做每每须要保存到数据库,操做相对费时,所以最好不要让用户随便点击。须要Enable时才Enable,其判断依据就是表单数据是否已经更改。
实际应用中,在作其它操做时,咱们也须要判断数据是否已经更改,好比:用户修改了某个表单,没有提交,而后直接转到其它页,这时咱们应该提醒它数据已经修改,是否保存?也就是说,咱们须要在MB中判断bindings.Commit.enabled的值,方法以下:
public boolean isCommitEnabled(){
 Boolean commitState = (Boolean)JSFUtils.getManagedBeanValue("bindings.Commit.enabled");
 boolean commitEnabled = commitState != null ? commitState.booleanValue() : false;
 return commitEnabled;
}
判断数据是否已经更改的一种更底层方法(由于是在AM上判断的),只要AM上的VO发生了改变,均可以用这个方法监测到。方法以下:
public boolean isDirty(){
 ApplicationModule am = ADFUtils.getDCBindingContainer().getDataControl().getApplicationModule();
 return am.getTransaction().isDirty();
}
在使用ADF Commit按钮时,还有一个常见问题:当用户修改某一个表单项后,即便焦点转移后,Commit按钮也不会被Enable。若是出现这种状况,须要增长两个参数:(1)增长autoSubmit="true"。(2)刷新Commit按钮。
建议方法:设定Commit按钮的PPR,指向该表单项,这样当该表单项变更后,会局部刷新Commit按钮。

 

16>关于Table

关于Table:点击某个按钮后,传入选中行的整个对象

方法:为该按钮添加setActionListener,其from值绑定到 Table对应iterator的currentRow,to值绑定到页面对应MB中ViewRowImpl类型的变量rowObject(该变量就是用 来接收传进来的行对象的)。实例<af:setActionListener from="#{bindings.tableIterator.currentRow}" to="#{MB.rowObject}">,而后在rowObject的set方法中就能够设置行中字段值了。


关于Table:Table显示时为只读模式,点击Table后,选中行变为修改模式,保存后回到只读模式:
适合场景:表列项比较少的状况,增长,修改,删除功能都在一个页面完成,不用打开新页面。
方法:拖放Table时,选择ADF Table(不要选择ADF ReadOnly Table),而后设置属性EditingMode=clickToEdit(默认是editAll,通常不用这种方式)。


关于Table:Table显示时为只读模式,点击某个按钮后,弹出一个窗口修改选中行,保存后关闭弹出窗口,Table回到只读模式:
方法:一、拖放Table时,选择ADF ReadOnly Table(由于修改是在弹出窗口中,所以Table只读便可)。
      二、使用Popup窗口是比较好的选择,由于Popup窗口支持popupCanceledListener,当直接关闭窗口时,能够捕捉到该事件。
      三、在按钮中设置showPopupBehavior。
      四、在合适的位置放置popup组件,内嵌一个dialog组件。设置popup的popupCanceledListener事件、 popupFetchListener事件及Dialog的dialogListener事件,都将  对应方法绑定到页面对应的MB中。
      五、MB中对应的各个listener代码。好比:
  public void cancelListener(PopupCancelEvent popupCancelEvent){//cancel listener
  BindingContainer bc = getBindings();
  OperationBinding ob = bc.getOperationBinding("Rollback");
  ob.execute();
  }
  public void fetchListener(PopupFetchEvent popupFetchEvent){//fetch listener
  //根据触发事件的source client id,来判断点击的是哪一个按钮:Edit or Insert。
  if(popupFetchEvent.getLaunchSourceClientId().contains("insert")){
   BindingContainer bc = getBindings();
   OperationBinding ob = bc.getOperationBinding("CreateInsert");
   ob.execute();
  }
  }
  public void dialogListener(DialogEvent dialogEvent){//dialog listener
  if(dialogEvent.getOutcome().name().equals("ok")){
   BindingContainer bc = getBindings();
   OperationBinding ob = bc.getOperationBinding("Commit");
   ob.execute();
  }else{
   BindingContainer bc = getBindings();
   OperationBinding ob = bc.getOperationBinding("Rollback");
   ob.execute();
  }
  }

 

17>LOV

Vo中制做LOV时,将字段UI Hints中的Default List Type设为Input Text with List of Values:
(1)、 为JobId增长LOV,并设置Default List Type:Input Text with List of Values;选择显示JobId和JobTitle,即在Display Attributes下Available中的将JobId和     JobTitle拉入Selected中。
(2)、拖放view至页面,选择生成ADF Form,发现JobId的显示组件自动设置为ADF List of Values Input。若是选中Query List Automatically,弹出查询页面时,会直接     显示全部结果。
(3)、运行,JobId为一个文本输入框,旁边有一个查询按钮,点击后能够查询,选择一条记录,会返回到文本输入框。注意,不管查询显示的是哪些字段,返回的都是     JobId。
(4)、设置inputListOfValues组件的autoSubmit="true"。除了(3)的运行效果以外:
 . 当输入AD_,按下Tab键,会弹出全部以AD_开头的JobId选项。
 . 当输入AD_V,按下Tab键,会直接补全为AD_VP,由于只有一个值知足条件。
(5)、 为inputListOfValues组件增长autoSuggestBehavior,如:<af:autoSuggestBehavior suggestedItems="#{bindings.JobId.suggestedItems}"/>此时,除了(4)的运     行效果以外,会新增一种效果:随着用户的输入,会自动下拉显示匹配的结果。通过测试,中文也能够支持自动匹配。
(6)、有时候咱们须要为弹出的查 询窗口预设置一些过滤LOV,这是能够考虑使用LaunchPopupListener。inputListOfValues组件增长了属性 launchPopupListener,如:     launchPopupListener="#{backing_Bean.filterLOV}",绑定MB中方法。最后在MB中添加方法,以下:
     public void filterLOV(LaunchPopupEvent launchPopupEvent){
 BindingContainer bc = getBindings();
 FacesCtrlLOVBinding lov = (FacesCtrlLOVBinding)bc.get("JobId");
 lov.getListIterBinding().getViewObject().setNamedWhereClauseParam("salary",4000);
     }

 

18>popup

popup组件经常嵌套组件Note Window、Dialog、Menu,一块儿使用。
点击一个按钮,根据某些条件,动态来决定是否弹出一个窗口?
此种状况适合如下场景:
(1)当用户修改了表单,若是没有保存,接着直接转到其它地方,此时应该提示:“数据已更改,是否保存?”;若是保存了,则不提示。
(2)容许用户删除多条记录功能:
   当用户点击Delete按钮时,须要确认用户选择了哪些记录,若是超过一条(包括一条),则提示用户:“数据将被删除,是否确认?”;不然提示“你没有选 择任何数   据”。固然,若是前端能够控制成以下效果则更好:当用户选择了一条以上(包括一条)的记录时,Enable Delete按钮;不然Desable Delete按钮。
   实现步骤:
 (1)在页面中建立popup对象。
 (2)在按 钮上,添加actionListener(不要添加showPopupBehavior组件,由于showPopupBehavior组件会在 Action事件以前触发,也就是说,只要点击按钮就会弹    出窗口,这不符合要求),咱们只在actionListener对应MB中的方法中写代码条件弹出popup窗口。
    public void dialogListener(DialogEvent dialogEvent){
  if(dialogEvent.getOutcome() == DialogEvent.Outcome.ok) {
   FacesContext facesContext = FacesContext.getCurrentInstance();
   ExtendedRenderKitService extendedRenderKitService = Service.getRenderKitService(facesContext, ExtendedRenderKitService.class);
   String script = "var popup; popup = AdfPage.PAGE.findComponent('"+"p2"+"'); popup.show();";
   extendedRenderKitService.addScript(facesContext, script);
  }else if(dialogEvent.getOutcome() == Dialog.Outcome.cancel) {
   //Nothing to do here...
  }
    }

 

18>am

Nested AM与Root AM的Transaction关系
在实际应用中,为了达到逻辑重用的目的,会使用嵌套的AM。在Root AM和Nested AM中都有各自的VO,在一个页面中,可能同时用到了不一样AM的不一样VO,那么当一个AM提交时,另外一个AM是否也会提交呢?
实验略,实验中须要巩固的代码:
若是VO中字段为Number类型,那么给该字段设置值时,应该这样--vo.setMinSalary(new oracle.jbo.domain.Number(1000));
获取AM对象的代码:
ApplicationModule am = ADFUtils.getApplicationModuleForDataControl("AppModuleDataControl");
AppModuleImpl service = (AppModuleImpl)am;
NestedAppModuleImpl nestedService = (NestedAppModuleImpl)service.getNestedAppModule();//从Root AM中获取Nested AM对象
结论:
(1)Nested AM与Root AM使用的是同一个Transaction,都是Root AM中的Transaction,不管使用哪一个AM提交,另外一个AM中的VO也会被提交。
(2)多个Root AM之间的Transaction互不干涉,各自管理本身的。
(3)因此,想要避免提交本不想提交的表单,该表单所对应的VO的AM必须是Root AM。
注:Nested AM并非另一种AM,只不过是次AM是嵌套在另外一个AM中的,因此叫它Nested(嵌套的)AM。

Transaction和DBTransaction的区别与联系
DBTransaction和Transaction都是接口,DBTransaction是Transaction的子类,Transaction主要提供了一些事务经常使用到的方法:
.commit:Commits the transaction and saves all changes to the database.
.connect: Attempts(试图) to establish(创建) a connection to the given database URL.
.disconnect: DisConnects the server from the database.
.getLockingMode: Gets the preferred(首先的、当前的) locking mode for this transaction.
.rollback: Rolls back the transaction and discards(丢弃) all changes.
.setLockingMode: Sets the preferred(首选的、当前的) locking mode for this transaction.
DBTransaction则继承了以上方法,并提供了一些针对EO的方法:
. findByPrimaryKey()
. getSession()
. getEnvironment()
验证明例略,需记住和巩固代码:
当给vo中添加row时,vo.createRow()后必定要记住vo.insertRow(row)。
在MB中先获取DataControl对象,在从中获取AM对象代码,
DCDataControl dc = BindingContext。getCurrent().getDefaultDataControl();
ApplicationModule am = (ApplicationModule)dc.getDataProvider();
AppModuleImpl service = (AppModuleImpl)am;
验证结论:
(1)使用getTransaction().commit()和getDBTransaction().commit(),数据库都提交了。
(2)通常状况下,使用Transaction就能够了,除非你须要使用DBTransaction上独有的方法。

 

19>Database Connection Pool调优
在AM的配置项中,有Connection Pool一项,其分为两种:JDBC URL和JDBC Datasource。
(1)在开发环境中,通常使用JDBC URL,由ADF管理ConnectionPool。这时,你能够修改相关的参数。但通常来讲,开发时不会关心数据库链接池的优化。所以,通常不修改   这些参数。
(2) 在生产环境中,通常使用JDBC Datasource,由应用服务器管理Connection Pool,与ADF无关。全部在AM上设置的Connection Pool参数将被忽略。AM也将从应用服务器   管理的Connection Pool中获取数据库链接。
使用JDBC Datasource好处是不用在开发端配置数据库的具体信息,未来数据库变了,只要JNDI名字不变,程序就不用修改。
因此,总的来讲,咱们不须要修改Connection Pool的配置,由于这个是由应用服务器管理的,不一样的应用服务器配置不一样,须要查相关手册。

 

20>Application Module Pool调优
Application Module Pool使用用来存放有同一类型的AM实例的池子,多个浏览器客户端能够“共享使用”少许的Application Module实例,这样就能够提升应用的性能。只有根一级的Application Module才能够创建Pool,换句话说,内嵌的Application Module也将“共享使用”根一级的Application Module Pool,包括数据库链接,事务,缓存。
Application Module实例也分为状态和无状态两种。对于有状态的AM实例,它保存用户session的相关信息,用户作下一步操做时,将会继续使用该AM实例。如 果用户请求不少,AM实例已经接近峰值,那么将会“钝化”这些有状态的AM实例,即把有状态信息持久化。而后把这些AM实例腾出来供其它用户使用,等到该 用户继续作下一个有状态操做时,再用一个新的AM实例,并匹配“激活”刚才“钝化”的信息。
AM Pool主要参数说明以下:
一、Pool Behavior Parameters
   . Failover(失效备援) Transaction State Upon Managed Release: 默认false,建议设置为true。
     在有状态的AM实例被释放回池中时执行“钝化”。
   . Disconnect Application Module Upon Release:默认值false,建议设置为false。
     强制AM实例每次释放回池中时,同时释放掉其对应的JDBC链接。默认为false,好处是不只不用再从数据库链接池获取链接,而且连prepared statements也能够直接     拿来就用。
   . Support Dynamic JDBC Credentials(文凭、信用状): 默认值true,建议设置为true。
     容许程序在新的用户Session开始的时候经过代码来修改数据库的链接的用户和口令。
   . Reset Non-Transactional State Upon Unmanaged Release: 默认true,建议设置true。
     当AM实例以无状态的方式释放回池中时,重置全部的Non-Transaction State,好比VO的运行时设置,JDBC的Prepared Statements,绑定变量等等,保证放回池中的     AM实例是“干净”的
   . Enable Application Module pooling: 默认false,建议设置为true。
   . Row-Level Locking Behavior Upon Release: 默认false,建议设置为true。
     强制AM实例被释放回池时不去在数据库中建立一个pending transaction state。
     ADF web application应该设置锁定模式为乐观锁“optimistic”(默认为悲观锁“pessimistic”),以免建立行级锁。

关于参数“Disconnect Application Module Upon Release”实验结论:
(1)在使用AM Pool时,发现数据库链接消耗的特别快。用户每次访问一个页面,都会新占用一个数据库链接,这是不合理的。
(2)Disconnect Application Module Upon Release参数默认不选中是有利于性能优化的。
(3) 参数Idle Instance Timeout、Pool Polling Interval、Maximum Instance Time to Live应该配合使用,基本原则是:Maximum Instance Time to Live > Idle    Instance Timeout + Pool Polling Interval(不然还没等AM Pool标记清除以前,AM实例就已经被清除了)。
(4)每 个AM池的设置能够根据自身状况有所不一样,好比若是AM的调用时间比较长,能够适当增大Maximum Instance Time to Live;Maximum Pool Size基本接近或略高于用    户并发数的峰值,若是用户并发数很高,能够适当减少Maximum Instance Time to Live,便于回收AM实例和数据库链接;对应操做频繁,但事务较小的AM,能够适当增   大。
(5)ADF 自带的数据库链接池通常不用于生产环境。在生产环境下,应该使用JDBC Datasource的方式,使用WLS的数据库链接池来管理。基本原则是数据库链接池的最大值   =AM Maximum Pool Size。Idle Instance Timeout、Pool Polling Interval,尽可能直接重用AM实例,无需从新获取。

对AutoSubmit、PartialSubmit、Immediate、PartialTriggers更深层次的了解:
一、autoSubmit只在输入组件上才有的一个属性,如RichIputText。
二、partialSubmit只在命令组件上才有的一个属性,如CommandLink。
autoSubmit 与partialSubmit的区别是,后者仅处理更改的组件自己以及在其partialTriggers属性中包含引用的全部组件,不会触发表单中的必 填项的验证,除非这些  必填项的partialTriggers指向设置了autoSubmit=true的组件。
值得注意的 是,CommandToolBarButton默认partialSubmit=true,因此若是你须要刷新某个组件,必须设置 partialTriggers,不然页面不会被刷新。而CommandButton默认partialSubmit=false,默认会刷新整个页面。

技术因素不是网站成功的因素,决定网站成功的关键因素是内容。

若是你定一个高得离谱的目标,就算失败了,那你的失败也在任何人的成功之上——詹姆斯.卡梅隆。

 

22>TaskFlow之Reentry属性的使用
在实际应用中,用户可能会点击浏览器的回退按钮回到上一页面,在有些状况下会致使一些问题。 ADF Bounded TaskFlow有一个选项(Unbounded TaskFlow无此选项)能够设置是否容许用户使用浏览器的回退按钮回到上一页面,这个属性就是Reentry。
Reentry能够设置为:
. reentry-allowed:默认选项。容许该bounded task flow中的全部页面实用化浏览器的回退按钮从新进入上一页面。
. reentry-not-allowed: 不容许该bounded task flow中的全部页面使用浏览器的回退按钮从新进入上一页面。这里的不容许不是禁止用户点击浏览器的回退按钮,这个是  没有办法禁止的。它的不容许时这样体现的:当用户点击浏览器的回退按钮后,能够从新进入上一页面,但若是你在该页面作任何事情,也如点击按钮,将会抛出异 常:  InvalidTaskFlowReentry。
. reentry-outcome-dependent:可否容许该bounded task flow中的全部页面使用浏览器的回退按钮从新进入上一页面取决于上一次从该bounded task flow返回的outcome  ,也就是说,取决于Return Activity上的Reentry属性设置。适合的典型场景:购物网站若是用户取消了某此采购,那么容许回退;若是订单已经提交,则不容许回退。
注:reentry- not-allowed的行为和咱们想象的不同,过后警告用户抛异常,这个页面效果确定不太友好,这时,咱们应该建立一个exception handler来处理这个异常,提示用户页面过时,须要从新登陆之类的警告,并在几秒以后自动跳转到登陆页面。

几个须要明确的问题:
(1)、从新进入Task Flow后,Task Flow上的输入参数将使用当前值(若是有新的赋值的话),而不是初始值。
(2)、从新进入Task Flow后,Manage Bean中的值也跟着回退到以前的值,全部在用户回退以后的修改将丢失。能够经过设置View Activity上的redirect属性来改变这一行     为。这个有待实验考证。

 

23>TaskFlow之Transaction的使用
ADF TaskFlow有一个很重要的特性:在Bounded TaskFlow上能够设置事务。也就是说,在这个TaskFlow中的全部Activity(View和其它非可视化的)都将属于一个事务。区别于 Java EE Container上的事务设置(要么是直接设置在EJB的方法上,要么是设置在ejb.xml中,运行时由Container解析);TaskFlow 这个是设置在控制器层的,这使得咱们很容易控制一个TaskFlow的事务。
打开一个Bounded Task Flow,在Property中找到Behavior,其中Transaction属性:找到
. No Controller Transaction:不加入任何事务中。
. Always Begin New Transaction:开始一个新的事务,不管是否已经在一个事务之中。
. Always Use Existing Transaction:加入已有的事务,若是没有事务可加入,抛异常。
. Use Existing Transaction If Possible:加入已有的事务,若是没有事务可加入,开始一个新的事务。
事务的提交是在Task Flow Return Activity上完成的,在Property中找到Behavior,其中End Transaction属性,咱们能够设置如何提交事务(commit or rollback)。
进一步对Bounded TaskFlow对事务支持程度的研究,如下实验结论:
实验一结论:Bounded TaskFlow中的全部View Activity都属于一个事务。
实验二结论:Bounded TaskFlow中事务处理是跨AM的,即不一样AM中的VO的事务操做,也能够做为一个全局事务来管理。页面都没有
实验三结论:Bounded TaskFlow中事务处理是跨AM、跨数据库的,即不一样AM中的VO的事务操做,VO来自于不一样的数据库,也能够做为一个全局事务来管理。
实验四:2个AM,3个DB Connection,1个Bounded TaskFlow(包含两个修改页面和一个Method Call,每一个页面都没有事务提交功能,而是交给Task Flow Return Activity负责)。
实验四结论:EJB Transaction由Java EE Container负责,不能与TaskFlow Transaction一块儿做为一个全局事务来管理两者的事务各自独立,互不干涉。

 

转载自:http://blog.csdn.net/qq136722979/article/details/12856843

相关文章
相关标签/搜索