ï»??xml version="1.0" encoding="utf-8" standalone="yes"?>青春草免费在线视频,一区二区三区色,欧美午夜精品久久久久久人妖http://www.aygfsteel.com/Goodtiger/archive/2006/11/08/79766.htmlGoodtigerZhaoGoodtigerZhaoWed, 08 Nov 2006 01:51:00 GMThttp://www.aygfsteel.com/Goodtiger/archive/2006/11/08/79766.htmlhttp://www.aygfsteel.com/Goodtiger/comments/79766.htmlhttp://www.aygfsteel.com/Goodtiger/archive/2006/11/08/79766.html#Feedback0http://www.aygfsteel.com/Goodtiger/comments/commentRss/79766.htmlhttp://www.aygfsteel.com/Goodtiger/services/trackbacks/79766.html

使用 JSF æž¶æž„˜q›è¡Œè®¾è®¡

探烦 JavaServer Faces 框架中ä‹É用的设计模式

 
  

未显½Cºéœ€è¦?JavaScript 的文档选项

ž®†æ­¤™åµä½œä¸ºç”µå­é‚®ä»¶å‘é€? /></td><td width=

ž®†æ­¤™åµä½œä¸ºç”µå­é‚®ä»¶å‘é€?/b>

 

拓展 Tomcat 应用

下蝲 IBM 开�J2EE 应用服务�WAS CE 新版�V1.1


¾U§åˆ«: 中çñ”

Anand Prakash Joshi (ananjosh@in.ibm.com), 软äšg工程å¸? IBM

2006 òq?1 æœ?04 æ—?/p>

本文中,作è€?Anand Joshi 使用 JSF 框架中的设计模式阐释äº?JavaServer Faces (JSF) 体系¾l“构。他讨论äº?JSF 体系¾l“构中ä‹É用的 GoF 设计模式åQŒä»¥åŠè¿™äº›æ¨¡å¼åœ¨ JSF 框架中的作用。ä“Q何对设计模式å’?JSF 体系¾l“构有一定了解的人都能从 Anand 详细的介¾lä¸­æœ‰æ‰€æ”¶èŽ·ã€?读者应该对 GoF 设计模式å’?JSF 技术有很好的了解ã€?/blockquote>

设计模式可以帮助用户在更高层‹Æ¡ä¸ŠæŠ½è±¡¾l†èŠ‚åQŒæ›´å¥½åœ°ç†è§£ä½“ç³»¾l“构。如果比较熟æ‚?GoF 设计模式å’?JavaServer Faces (JSF) 框架åQŒæœ¬æ–‡å¯ä»¥å¸®åŠ©æ‚¨‹zžå¯Ÿ JSF 框架中ä‹É用的设计模式åQŒæ·±å…¥ç†è§£å…¶å·¥ä½œåŽŸç†ã€?/p>

本文探讨äº?JSF 框架中ä‹É用的设计模式。详¾l†è®¨è®ºçš„设计模式包括 Singleton、Model-View-Controller、Factory Method、State、Composite、Decorator、Strategy、Template Method å’?Observer 模式ã€?

设计模式�JavaServer Faces (JSF) 技�/span>

首先½Ž€è¦åœ°ä»‹ç»ä¸€ä¸‹æ¨¡å¼å’Œ JSF 框架ã€?/p>

  • 模式ã€?/b>设计模式是对问题和解å†Ïx–¹æ¡ˆè¿›è¡ŒæŠ½è±¡çš„æ™®éé€‚用的方法。因为模式是所有开发äh员和架构师公认的åQŒæ‰€ä»¥æ¨¡å¼å¯ä»¥èŠ‚¾U¦æ—¶é—´å’Œèµ„源。用外行话来è¯ß_¼Œæ¨¡å¼ž®±æ˜¯å…³äºŽæŸä¸ªäººæ‰€å…ÞqŸ¥çš„问题的¾lè¿‡éªŒè¯çš„è§£å†Ïx–¹æ¡ˆã€‚模式可以重用,重用使得解决æ–ÒŽ¡ˆæ›´å¥å£®ã€?
  • Java Server Facesã€?/b> JSF 体系¾l“构是一¿U?Web 应用½E‹åºæ¡†æž¶ã€‚它æ˜?Java Community Process (JCP) æŽ¨åŠ¨çš„ï¼Œæœ‰æœ›æˆäØ“ Web 应用½E‹åºå¼€å‘的标准框架。目前用于开å?Web 应用½E‹åºçš„æ¡†æž¶æœ‰ 50 多个åQŒè¿™è¯´æ˜Ž˜q«åˆ‡éœ€è¦å®žçŽ°æ¡†æž¶çš„æ ‡å‡†åŒ–ï¼Œ˜q™æ­£æ˜?JSF 框架的目标!

 

 
 


深入剖析 JSF 模式

现在我们来讨è®?JSF 体系¾l“构中的各种设计模式。本文将详细讨论 Singleton、Model-View-Controller、Factory Method、State、Composite、Decorator、Strategy、Template Method å’?Observer 设计模式。我ž®†åˆ†æžæ¯¿Uæ¨¡å¼çš„用途及其在 JSF 框架中的作用ã€?/p>

 
 


Singleton 模式

Singleton 模式的目的是保证¾cÕdªæœ‰ä¸€ä¸ªå®žä¾‹è¢«åŠ è²åQŒè¯¥å®žä¾‹æä¾›ä¸€ä¸ªå…¨å±€è®‰K—®ç‚V€‚当启动å…ähœ‰ JSF 支持çš?Web 应用½E‹åºæ—Óž¼ŒWeb 容器初始化一ä¸?FacesServlet 实例。在˜q™ä¸ªé˜¶æ®µåQŒFacesServlet å¯Òޝä¸?Web 应用½E‹åºå®žä¾‹åŒ?Application å’?LifeCycle 实例一‹Æ¡ã€‚这些实例就采用众所周知çš?Singleton 模式åQŒé€šå¸¸åªéœ€è¦è¯¥¾cÕdž‹çš„一个实例ã€?/p>

使用 JSF çš?Web 应用½E‹åºåªéœ€è¦?Application å’?LifeCycle ¾cȝš„一个实例。LifeCycle ½Ž¡ç†å¤šä¸ª JSF è¯äh±‚çš„æ•´ä¸ªç”Ÿå‘½æœŸã€‚å› ä¸ºå…¶çŠ¶æ€å’Œè¡ŒäØ“åœ¨æ‰€æœ‰è¯·æ±‚ä¹‹é—´å…±äº«ï¼Œ˜q™äº›å¯¹è±¡é‡‡ç”¨ Singleton 模式合情合理。LifeCycle ¾l´æŠ¤çš?PhaseListeners 也是 Singleton 模式的。PhaseListeners 由所æœ?JSF è¯äh±‚å…׃ín。在 JSF 框架中可以广泛ä‹Éç”?Singleton 模式åQŒä»¥å‡å°‘内存占用和提供对象的全局讉K—®ã€‚NavigationHandleråQˆç”¨äºŽç¡®å®šè¯·æ±‚的逻辑¾l“æžœåQ‰å’Œ ViewHandleråQˆç”¨äºŽåˆ›å»ø™§†å›¾ï¼‰ä¹Ÿæ˜¯ä½¿ç”¨ Singleton 模式的例子ã€?/p>


 
 


Model-View-Controller (MVC)

MVC 模式的目的是从数据表½Cºï¼ˆViewåQ‰ä¸­ž®†æ•°æ®ï¼ˆå?ModelåQ‰åˆ†¼›Õd‡ºæ¥ã€‚如果应用程序有多种表示åQŒå¯ä»¥ä»…替换视图层而重用控制器和模型代码。类似的åQŒå¦‚果需要改变模型,可以在很大程度上不改变视囑ֱ‚。控制器处理用户动作åQŒç”¨æˆ·åŠ¨ä½œå¯èƒ½é€ æˆæ¨¡åž‹æ”¹å˜å’Œè§†å›¾æ›´æ–°ã€‚å½“ç”¨æˆ·è¯äh±‚一ä¸?JSF ™åµé¢æ—Óž¼Œè¯äh±‚发送到 FacesServlet。FacesServlet æ˜?JSF 使用的前端控制器 servlet。和其他很多 Web 应用½E‹åºæ¡†æž¶ä¸€æ øP¼ŒJSF 使用 MVS æ¨¡å¼æ¶ˆé™¤è§†å›¾å’Œæ¨¡åž‹ä¹‹é—´çš„è€¦åˆã€‚äØ“äº†é›†ä¸­å¤„ç†ç”¨æˆ¯‚¯·æ±‚,控制å™?servlet 改变模型òq¶å°†ç”¨æˆ·å¯ÆDˆªåˆ°è§†å›¾ã€?/p>

FacesServlet æ˜?JSF 框架中所有用戯‚¯·æ±‚都要经˜q‡çš„æŽ§åˆ¶å™¨å…ƒç´ ã€‚FacesServlet 分析用户è¯äh±‚åQŒä‹É用托½Ž?bean å¯Òލ¡åž‹è°ƒç”¨å„¿UåŠ¨ä½œã€‚åŽåŽÍ¼ˆbackingåQ‰æˆ–托管åQˆmanagedåQ‰bean ž®±æ˜¯è¯¥æ¨¡åž‹çš„例子。JSF 用户界面åQˆUIåQ‰ç»„件是视图层的例子。MVC 模式把ä“Q务分解给å…ähœ‰ä¸åŒæŠ€èƒ½çš„开发äh员,使这些ä“Q务能够同时进行,˜q™æ · GUI 设计人员ž®±å¯ä»¥ä‹É用丰富的 UI ¾l„äšg创徏 JSF ™åµé¢åQŒåŒæ—¶åŽç«¯å¼€å‘äh员可以创建托½Ž?bean 来编写专门的业务逻辑代码ã€?/p>


 
 


Factory Method 模式

Factory Method 模式的目的是定义一个用于创建对象的接口åQŒä½†æ˜¯æŠŠå¯¹è±¡å®žä¾‹åŒ–推˜qŸåˆ°å­ç±»ä¸­ã€‚在 JSF 体系¾l“构中,Factory Method 模式被用于创建对象。LifeCycleFactory 是一个创建和˜q”回 LifeCycle 实例的工厂对象。LifeCycleFactory çš?getLifeCycle (String LifeCycleId) æ–ÒŽ³•采用 Factory Method 模式åQŒæ ¹æ?LifeCycleId 创徏åQˆå¦‚果需要)òq¶è¿”å›?LifeCycle 实例。自定义çš?JSF 实现可以重新定义 getLifeCycle 抽象æ–ÒŽ³•æ¥åˆ›å»ø™‡ªå®šä¹‰çš?LifeCycle 实例。默认的 JSF 实现提供默认çš?LifeCycle 实例。此外,对于每个 JSF è¯äh±‚åQŒFacesServlet 都从 FacesContextFactory 得到 FacesContext。FacesContextFactory 是一个抽象类åQŒå…¬å¼€äº?getFacesContext APIåQŒJSF 实现提供äº?FacesContextFactory å’?getFacesContext API 的具体实现。这是另外一个ä‹Éç”?Factory Method 模式的例子,具体çš?FacesContextFactory 实现创徏 FacesContext 对象ã€?/p>


 
 


State 模式

State 模式的目的是在表½CºçŠ¶æ€çš„ä¸åŒ¾cÖM¹‹é—´åˆ†é…ä¸ŽçŠ¶æ€æœ‰å…³çš„é€»è¾‘ã€‚FacesServlet å¯?LifCycle 实例调用 execute å’?render æ–ÒŽ³•。LifeCycle 协调不同çš?Phrase 以便执行 JSF è¯äh±‚。在˜q™é‡Œ JSF 实现ž®±éµå¾ªäº† State 模式。如果没有ä‹É用这¿Uæ¨¡å¼ï¼ŒLifeCycle 实现ž®×ƒ¼šè¢«å¤§é‡çš„æ¡äšgåQˆå³ “ifâ€?语句åQ‰æ…得一塌糊涂。JSF 实现为每个状态(或阶ŒDµï¼‰åˆ›å¾å•独的类òq¶è°ƒç”?step。phase 是一个抽象类åQŒå®šäº†æ¯ä¸?step 的公共接口。在 JSF 框架中定义了六个 phraseåQˆå³ stepåQ‰ï¼šRestoreViewPhase、ApplyRequestValues、ProcessValidationsPhase、UpdateModelValuesPhase、InvokeApplicationPhase å’?RenderResponsePhaseã€?/p>

åœ?State 模式中,LifeCycle æŠ?FacesContext 对象传递给 phase。每个阶ŒD‰|ˆ–状态改变传递给它的上下文信息,然后讄¡½® FacesContext 本èín中的标志表明下一个可能的步骤。JSF 实现在每个步骤中改变其行为。每个阶ŒDµéƒ½å¯ä»¥ä½œäؓ下一个阶ŒD늚„起因。FacesContext 有两¿Uæ ‡å¿?renderResponse å’?responseComplete 可以改变执行的顺序。每个步骤执行完成后åQŒLifeCycle ‹‚€æŸ¥ä¸Šä¸€é˜¶æ®µæ˜¯å¦è®„¡½®äº†è¿™äº›æ ‡å¿—。如果设¾|®äº† responseCompleteåQŒLifeCycle 则完全放弃请求的执行。如果经˜q‡æŸä¸ªé˜¶ŒDµåŽè®„¡½®äº?renderResponse 标志åQŒJSF ž®×ƒ¼šè·Œ™¿‡å‰©ä¸‹çš„阶ŒDµè€Œç›´æŽ¥è¿›å…?Render Response 阶段。如果这两个标志都没有设¾|®ï¼ŒLifeCycle ž®×ƒ¼šæŒ‰é¡ºåºç‘ô¾l­æ‰§è¡Œä¸‹ä¸€æ­¥ã€?/p>


 
 


Composite 模式

Composite 模式让客户代码能够统一处理复合对象和基本对象。复合对象是基本对象的容器。在½W¬ä¸€é˜¶æ®µåQˆRestore View 阶段åQ‰å’Œæœ€åŽä¸€ä¸ªé˜¶ŒDµï¼ˆRender Response 阶段åQ‰ï¼Œä½¿ç”¨ JSF UI ¾l„äšgæž„é€?UI View。UIComponentBase ž®±æ˜¯ Composite 模式ä¸?Component 抽象¾cȝš„一个例子。UIViewRoot æ˜?Composite ¾c»ï¼Œè€?UIOutputåQˆæ¯”方说åQ‰å°±æ˜¯å¶å­ï¼ˆæˆ–者基本类åQ‰ã€‚UIComponentBase ¾cÕd®šä¹‰äº†å¶å­å’Œå¤åˆå¯¹è±¡çš„公共æ–ÒŽ³•åQŒå¦‚¾~–码/解码值和子节点管理函数。子节点½Ž¡ç†å‡½æ•°åQŒå¦‚ getChildrenåQŒå¯¹äºŽå¶å­èŠ‚ç‚¹è¿”å›žç©ºåˆ—è¡¨åQŒå¯¹äºŽå¤åˆèŠ‚ç‚¹åˆ™˜q”回其子节点ã€?/p>


 
 


Decorator 模式

Decorator æ¨¡å¼çš„ç›®çš„æ˜¯ä¸é€šè¿‡å­ç±»åŒ–åŠ¨æ€æ‰©å±•å¯¹è±¡çš„è¡ŒäØ“ã€‚JSF 框架有很多扩展点åQˆå³å¯æ’入机åˆÓž¼‰ã€‚JSF 实现可ä‹Éç”?Decorator 模式替换默认çš?PropertyResolver、VariableResolver、ActionListener、NavigationHandler、ViewHandler æˆ?StateManager。通常自定义实现接受通过构造函æ•îC¼ é€’给它的默认实现的引用。自定义实现仅仅改写功能的一个子集,而将其他功能委托¾l™é»˜è®¤å®žçŽ°ã€‚å¦‚æžœå¸Œæœ›å®žçŽ°è‡ªå®šä¹‰çš?ViewHandleråQŒæ”¹å†™é»˜è®?ViewHandler 实现çš?calculateLocale æ–ÒŽ³•åQŒå¯ä»¥åƒ 清单 1 那样¾~–写 CustomViewHandler ¾c»ï¼š

清单 1. CustomViewHandler 片段

public class CustomViewHandler extends ViewHandler {
 public CustomViewHandler(ViewHandler handler) {
		 super();
		 oldViewHandler = handler;
 }
private ViewHandler oldViewHandler  = null;
public void renderView (facesContext context, UIViewRoot view) {
            //delegate method to oldViewHandler
		 oldViewHandler.renderView(context, view);
}
//custom implementation of calculateLocale
public Locale calculateLocale(FacesContext context) {
}
}




 
 


Strategy 模式

Strategy 模式的目的是ž®è£…不同的概å¿üc€‚JSF 框架采用 Strategy 模式使用委托实现模型呈现 UI ¾l„äšg。JSF 技术支持两¿Uå‘ˆçŽ°æ¨¡åž‹ã€‚åœ¨ç›´æŽ¥å®žçŽ°æ¨¡åž‹ä¸­ï¼ŒUI ¾l„äšgå¯ÒŽ”¶åˆ°çš„è¯äh±‚中的数据˜q›è¡Œè§£ç åQŒç„¶åŽç¼–码这些数据进行显½Cºã€‚在委托实现模型中,解码和编码操作委托给和组建关联的专门呈现器。后一¿Uæ¨¡åž‹åˆ©ç”¨äº† Strategy 设计模式åQŒæ¯”直接实现更灵‹z…R€‚在 Strategy 模式中,ž®†ä¸åŒçš„½Ž—法ž®è£…在单独的对象中,从而可以动态地改变½Ž—法。JSF 实现可以用已有的 renderkit 实例注册另外的呈现器åQŒå½“应用½E‹åºå¯åŠ¨çš„æ—¶å€™ï¼ŒJSF 实现è¯Õd–配置文äšgž®†è¿™äº›å‘ˆçް噍å’?UI ¾l„äšg联系在一赗÷€?/p>


 
 


Template Method 模式

Template Method 模式的目的是ž®†å˜åŒ–的步骤推迟到子¾cÖM¸­åQŒè€Œåœ¨çˆ¶ç±»ä¸­å®šä¹‰é‚£äº›å›ºå®šçš„½Ž—法步骤。JSF 框架通过 PhraseListeners 展现äº?Template Method 模式提供的功能。采ç”?Template MethodåQˆæˆ–è€?“hook”)使得 Web ä½œè€…å¯ä»¥äØ“ä¸åŒé˜¶æ®µä¹‹é—´çš„å¯é€‰æ­¥éª¤æä¾›å®žçŽŽÍ¼Œè€Œä¸»è¦é˜¶ŒDµä»ç„¶å’Œ JSF 框架的定义一致。JSF 框架提供äº?PhaseListenersåQŒæ¦‚念上¾cÖM¼¼äº?Template Method 模式中的可变步骤。JSF 框架有六个预定义的阶ŒDµï¼Œåœ¨æ¯ä¸ªé˜¶ŒDµä¹‹é—ß_¼ŒWeb 作者可以实çŽ?PhaseListeners 来提供类ä¼égºŽ Template Method hook çš?hook。事实上åQŒè¿™¿Uç»“构比 Template Method 模式更具有扩展性。可以通过注册 PhraseId ä¸?ANY_PHRASE çš?PhaseListener 在每个阶ŒDµåŽæä¾› hook。如æž?PhaseId æ˜?ANY_PHASEåQŒJSF 实现ž®×ƒ¼šåœ¨æ¯ä¸ªé˜¶ŒDµä¹‹å‰å’Œä¹‹åŽè°ƒç”¨è¯?PhaseListener。JSF 框架中的实现略有不同åQŒå› ä¸ºå¯ä»¥æ ¹æœ¬æ²¡æœ?PhaseListeneråQŒä½†æ˜¯åœ¨ Template Method 模式中,子类通常重新定义父类中抽象的可变步骤ã€?/p>


 
 


Observer 模式

Observer 模式的目的是当目标对象的状态改变时自动通知所有依赖的对象åQˆå³è§‚察器)。JSF åœ?UI ¾l„äšg中实çŽîCº† Observer 模式。JSF 有两¾cÕd†…å»ÞZº‹ä»Óž¼šActionEvent å’?ValueChangedEvent。ActionEvent 用于¼‹®å®šç”¨æˆ·ç•Œé¢¾l„äšgåQˆå¦‚按钮åQ‰çš„‹È€‹z…R€‚当用户单击按钮æ—Óž¼ŒJSF 实现通知æ·ÕdŠ åˆ°è¯¥æŒ‰é’®ä¸Šçš„ä¸€ä¸ªæˆ–å¤šä¸ªåŠ¨ä½œç›‘å¬½E‹åºã€‚于是该按钮被激‹z»ï¼Œæˆ–者说按钮åQˆä¸»ä½“)的状态改变了。添加到按钮上的所有监听程序(卌™§‚察器åQ‰éƒ½æ”¶åˆ°é€šçŸ¥è¯¥ä¸»ä½“状态已¾læ”¹å˜ã€‚类似的åQŒå½“输入 UI ¾l„äšg中的值改变时åQŒJSF 实现通知 ValueChangeListenerã€?/p>


 
 


¾l“束è¯?/span>

JSF 框架利用äº?Singleton、Model-View-Controller、Factory Method、State、Composite、Decorator、Strategy、Template Method å’?Observer 设计模式。因为它的体¾pȝ»“构徏立在已经验证的设计模式的基础上,˜q™æ˜¯ä¸€ä¸ªå¥å£®çš„æ¡†æž¶åQŒæ¨¡å¼åœ¨ JSF 框架中得åˆîCº†å¾ˆå¥½çš„利用ã€?



参考资�

学习
  • 误‚®¿é—?Gang of Four Design Patterns ˜q›ä¸€æ­¥äº†è§£è¿™äº›è®¾è®¡æ¨¡å¼ã€?

  • 请阅è¯?â€?a >怀疑论者的 JSF: JSF 应用½E‹åºçš„生命周æœ?/font>â€?˜q›ä¸€æ­¥äº†è§?JavaServer Faces 框架åQˆdeveloperWorksåQ?005 òq?3 月)ã€?

  • 误‚®¿é—?developerWorks Java 技术专åŒ?/font>。这里专门发表各¿UåŸºäº?Web å’?Java 的解å†Ïx–¹æ¡ˆçš„æ–‡ç« å’Œæ•™½E‹ã€?br />

获得产品和技�/b>

讨论


关于作�/span>

Anand Joshi 的照� src=

Anand 是一ä½?Sun 认证的企业架构师åQŒå‡ òq´æ¥ä¸€ç›´ç ”½I?Web 技术。他å¯?WebSphere ½Ž¡ç†æŽ§åˆ¶å°åº”用程序的设计和开发做了多斚w¢çš„èµA献。Anand 曄¡»åœ?IBM ¾ŸŽå›½å·¥ä½œ˜q‡å‡ òqß_¼Œç›®å‰åœ?IBM 印度工作ã€?/p>




]]>[转蝲]利用JSF、SpringFrameworkå’ŒHibernate构徏Web应用的实例讲˜q?/title><link>http://www.aygfsteel.com/Goodtiger/archive/2006/11/07/79679.html</link><dc:creator>GoodtigerZhao</dc:creator><author>GoodtigerZhao</author><pubDate>Tue, 07 Nov 2006 11:46:00 GMT</pubDate><guid>http://www.aygfsteel.com/Goodtiger/archive/2006/11/07/79679.html</guid><wfw:comment>http://www.aygfsteel.com/Goodtiger/comments/79679.html</wfw:comment><comments>http://www.aygfsteel.com/Goodtiger/archive/2006/11/07/79679.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/Goodtiger/comments/commentRss/79679.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/Goodtiger/services/trackbacks/79679.html</trackback:ping><description><![CDATA[ <br /> <font face="Verdana" size="2">JSF是一¿Uæ–°çš„用于构架j2ee应用用户界面的技术,它尤光™€‚合于基于MVC架构的应用中。虽已有很多文章介绍˜q‡äº†JSFåQŒç„¶è€Œå®ƒä»¬å¤§å¤šä»Žç†è®ºé«˜åº¦æ¥ä»‹¾lJSF而不是面向于实际应用。目前对于实际应用,JSF仍有很多问题没有解决åQŒä¾‹å¦‚:如何使JSF适应于MVC整体构架中?如何ž®†JSF与其他Java 框架整合èµäh¥åQŸæ˜¯å¦åº”该将业务逻辑攄¡½®åœ¨JSFçš„backing beans中?如何处理JSF中的安全机制åQŸæ›´ä¸ºé‡è¦çš„æ˜¯å¦‚何利用JSF构架现实世界的Web应用åQ?br /><br />本文ž®†æ¶‰åŠåˆ°ä¸Šé¢çš„这些问题,它将演示如何ž®†JSF、Springå’ŒHibernateæ•´åˆåœ¨ä¸€èµøP¼Œæž„æž¶å‡ÞZ¸€ä¸ªåä¸ºJCatalog的在¾U¿äñ”品ä­h目系¾l?/font> <font face="Verdana" size="2">。利用该DemoåQŒæœ¬æ–‡æ¶µç›–了Web应用开发的每一个阶ŒDµï¼ŒåŒ…括需求收集、分析,技术选择åQŒç³»¾lŸæž¶æž„和实现。本文讨è®ÞZº†åœ¨JCatalog中涉及到的各¿UæŠ€æœ¯çš„ä¼˜ç‚¹å’Œç¼ºç‚¹åÆˆå±•ç¤ºäº†ä¸€äº›å…³é”®éƒ¨åˆ†çš„è®¾è®¡æ–ÒŽ³•ã€?br /><br />本文的对象是从事åŸÞZºŽJ2eeçš„Web应用架构人员和开发ähå‘˜ï¼Œå®ƒåÆˆä¸æ˜¯å¯¹JSF、SpringFrameworkå’ŒHibernate的简单介¾lï¼Œå¦‚果对这些领域不甚了解,请参看相兌™µ„源ã€?br /><br /><b>该范例的功能需æ±?/b><br />JCatalog是一个现实世界的Web应用åQŒæˆ‘首先描述JCatalog的需求,在通篇的技术决½{–和架构设计旉™ƒ½ž®†æ¶‰åŠåˆ°æœ¬éƒ¨åˆ†ã€?br /><br />在设计Web应用的第一阶段是收集系¾lŸçš„功能需求,范例应用是一个典型的电子商务应用¾pȝ»ŸåQŒç”¨æˆ·å¯ä»¥æµè§ˆäñ”品的catalogòq¶æŸ¥çœ‹äñ”品的详细情况åQŒè€Œç®¡ç†å‘˜å¯ä»¥½Ž¡ç†äº§å“çš„catalog。通过增加一些其他功能,如inventory½Ž¡ç†å’Œè®¢å•处理等åQŒè¯¥åº”用可成ä¸ÞZ¸€ä¸ªæˆç†Ÿçš„电子商务¾pȝ»Ÿã€?br /><br /><b>Use cases</b><br />Use-case分析被用来展½Cø™Œƒä¾‹åº”用的功能需求,å›?ž®±æ˜¯è¯¥åº”用的use-case图ã€?br />     </font> <p align="center"> <a > <font face="Verdana" size="2"> <img style="WIDTH: 324px; HEIGHT: 196px" height="127" alt="" hspace="0" src="http://www.huihoo.com/java/jsf/jw-0719-jsf1.gif" width="228" align="baseline" border="0" /> </font> </a> </p> <br /> <font face="Verdana" size="2">use-case囄¡”¨äºŽè¡¨½Cºç³»¾lŸä¸­çš„actors以及可能˜q›è¡Œçš„operationsåQŒåœ¨è¯¥åº”用中ž®†æœ‰ä¸ƒä¸ªuse-caseåQŒç”¨æˆ¯‚ƒ½å¤Ÿæµè§ˆäñ”å“?catalog和查看äñ”品的详细情况åQŒä¸€æ—¦ç”¨æˆïL™»å½•到¾pȝ»Ÿä¸­ï¼Œå¥¹å°†æˆäØ“½Ž¡ç†å‘˜ï¼Œä»Žè€Œå¯ä»¥åˆ›å»ºæ–°çš„äñ”品,¾~–辑已存在的产品或者删除老的产品½{‰ã€?br /><br /><b>Business rules</b><br />JCatalogå¿…é¡»½W¦åˆä»¥ä¸‹business rules:</font> <font face="宋体, MS Song"> </font> <ul> <li> <font face="verdana, arial, helvetica" size="2">每个产品必须å…ähœ‰å”¯ä¸€çš„ID</font> </li> <li> <font size="2">每个产品必须属于臛_°‘一个category</font> <font face="verdana, arial, helvetica" size="2"> <br /> </font> </li> <li> <font face="verdana, arial, helvetica" size="2">产品ID一旦创立不得修æ”?/font> </li> </ul> <font face="verdana, arial, helvetica" size="2"> <b> <font size="3">Assumptions</font> </b> <br />我们在系¾lŸçš„设计和实çŽîC¸­åšä»¥ä¸‹å‡å®šï¼š<br /></font> <ul> <li> <font face="verdana, arial, helvetica" size="2">è‹Þp¯­è®²æ˜¯¾~ºçœè¯­è¨€åQŒä¸”不需事先国际åŒ?/font> </li> <li> <font face="verdana, arial, helvetica" size="2">在Catalog不讲不会­‘…过500个äñ”å“?/font> </li> <li> <font face="verdana, arial, helvetica" size="2">catalogž®†ä¸ä¼šè¢«é¢‘繁的修æ”?/font> </li> </ul> <font face="verdana, arial, helvetica" size="2"> <b> <font size="3">Page flow</font> </b> <br />å›?昄¡¤ºäº†æ‰€æœ‰çš„JCatalogçš„pages以及它们之间的transitions关系åQ?br />     <p align="center"><a ><img style="WIDTH: 250px; HEIGHT: 159px" height="102" alt="" hspace="0" src="http://www.huihoo.com/java/jsf/jw-0719-jsf2.gif" width="176" align="baseline" border="0" /></a></p><br />该应用中存在两组pagesåQšå…¬å¼€çš„internet和用于管理的intranetåQŒå…¶ä¸­intranet只能被那些成功登录到¾pȝ»Ÿçš„用戯‚®¿é—®ã€?ProductSummary不作ä¸ÞZ¸€ä¸ªå•独的page展示¾l™ç”¨æˆøP¼Œå®ƒæ˜¾½Cºåœ¨Catalog page中的frame中。ProductList只对½Ž¡ç†å‘˜å¯è§†ï¼Œå®ƒåŒ…含用于创建、编辑和删除产品的链接ã€?br /><br />å›?是一个Catalog™åµé¢çš„示意图åQŒç†æƒ³çж况䏋åQŒåœ¨éœ€æ±‚文档中应该包含每一™å늚„详细½Cºæ„å›¾ã€?br />         <p align="center"><a ><img style="WIDTH: 222px; HEIGHT: 160px" height="114" alt="" hspace="0" src="http://www.huihoo.com/java/jsf/jw-0719-jsf3.gif" width="222" align="baseline" border="0" /></a></p><br /><font size="5"><b>构架设计</b></font><br />Web应用开发的下一个阶ŒD‰|˜¯æž„架设计åQŒå®ƒåŒ…括ž®†åº”ç”¨åˆ’åˆ†äØ“å¤šä¸ªåŠŸèƒ½¾l„äšgòq¶å°†˜q™äº›¾l„äšg分割¾l„合成层åQŒé«˜å±‚的构架设计应该中立于所选用的特定技术ã€?br /><br /><b><font size="3">多层架构</font></b><br />多层架构是将整个¾pȝ»Ÿæ¸…晰的分为多个功能单元:client、presentation、business-logic、integrationå’?EISåQŒè¿™ž®†ç¡®ä¿èŒè´£å¾—到清晰的划分åQŒä‹Éå¾—ç³»¾lŸæ›´æ˜“于¾l´æŠ¤å’Œæ‰©å±•。具有三层或½{‰å¤šå±‚çš„¾pȝ»Ÿè¢«è¯æ˜Žæ¯”C/S模型å…ähœ‰æ›´å¥½çš„äŽ×¾~©æ€§å’Œç‰|´»æ€§ã€?br /><br />client层是使用和表½Cºæ•°æ®æ¨¡åž‹çš„地方åQŒå¯¹äºŽä¸€ä¸ªWeb应用åQŒclient层通常是浏览器åQŒåŸºäºŽæµè§ˆå™¨çš„瘦客户端不包含ä»ÖM½•表示逻辑åQŒå®ƒä¾èµ–äº?/font> <font face="verdana, arial, helvetica" size="2">presentation</font> <font face="verdana, arial, helvetica" size="2">层ã€?br /><br />presentation层将business-logic层的服务展示¾l™ç”¨æˆøP¼Œå®ƒåº”知道如何处理用户的请求,如何同business-logic层交互,òq¶ä¸”知道如何选择下一个视图显½Cºç»™ç”¨æˆ·ã€?br /><br />business-logic层包含应用的business objectså’Œbusiness services。它接受来在于presentation层的è¯äh±‚、基于请求处理业务逻辑。业务逻辑层组件将受益于系¾lŸçñ”的服务,如安全管理、事务管理和资源½Ž¡ç†½{‰ã€?br /><br />integration层是介于</font> <font face="verdana, arial, helvetica" size="2">business-logic</font> <font face="verdana, arial, helvetica" size="2">层和EIS层之间的桥梁åQŒå®ƒž®è£…了与EIS层交互的逻辑。有æ—Óž¼Œž®†integration层和business-logic层合¿UîCؓ中间层ã€?br /><br />应用的数据被保存在EIS层中åQŒå®ƒåŒ…括关系数据库、面向对象数据库和以及遗留系¾lŸç­‰ã€?br /><br /><b><font size="3">JCatalog的构架设è®?/font></b><br />å›?昄¡¤ºäº†JCatalog的构架设计以及如何应用于多层构架¾pȝ»Ÿä¸­ã€?br />  <a ><p align="center"><img style="WIDTH: 326px; HEIGHT: 218px" height="120" alt="" hspace="0" src="http://www.huihoo.com/java/jsf/jw-0719-jsf4.gif" width="196" align="baseline" border="0" /></p></a><br />该应用采用了多层非分布式的构æžÓž¼Œå›?展示了系¾lŸçš„分层以及每一层中选择的技术,它同时又是该范例的部¾|²å›¾åQŒå®ƒçš„presentationã€?business-logicå’Œintegration层将存在于同一个web容器中。定义良好的接口ž®†å­¤ç«‹æ¯ä¸€å±‚的职责åQŒè¿™ä¸€æž¶æž„ä½¿å¾—åº”ç”¨æ›´äØ“½Ž€å•和更好的äŽ×¾~©æ€§ã€?br /><br />对于presentation层,¾léªŒè¡¨æ˜ŽåQŒæœ€å¥½çš„æ–ÒŽ³•是选择已存在的òq¶å·²å¾—到证明了的Web应用框架åQŒè€Œä¸æ˜¯è‡ªå·±åŽ»è®¾è®¡å’Œå¼€å‘æ–°çš„æ¡†æž¶ã€‚æˆ‘ä»¬æ‹¥æœ‰å¤šä¸ªå¯é€‰æ‹©çš„æ¡†æžÓž¼Œå¦‚StrutsåQŒWebWorkå’ŒJSF½{‰ï¼Œåœ¨JCatalog中,我们选择采用JSFã€?br /><br />EJBå’ŒPOJO都可以用来创å»ÞZ¸šåŠ¡é€»è¾‘å±‚ï¼Œå¦‚æžœåº”ç”¨æ˜¯åˆ†å¸ƒå¼çš„ï¼Œé‡‡ç”¨å…ähœ‰remote接口的EJB是一个好的选择åQ›ç”±äºŽJCatalog是一个典型的不需要远½E‹è®¿é—®çš„Web应用åQŒå› æ­¤é€‰ç”¨POJOåQŒåƈ充分利用Spring Framework的帮助,ž®†æ˜¯å®žçŽ°ä¸šåŠ¡é€»è¾‘å±‚çš„æ›´å¥½é€‰æ‹©ã€?br /><br />integration层利用关¾pÕdž‹æ•°æ®åº“事先数据的持箋化,存在多种æ–ÒŽ³•可用来实玎ͼš<br /></font> <ul> <li> <font face="verdana, arial, helvetica" size="2">JDBCåQšè¿™æ˜¯æœ€ä¸ºçµ‹zÈš„æ–ÒŽ³•åQŒç„¶è€Œï¼Œä½Žçñ”çš„JDBC难以使用åQŒè€Œä¸”质量差的JDBC代码很难˜qè{良好</font> </li> <li> <font face="verdana, arial, helvetica" size="2">Entity beansåQšCMPçš„Entity bean是一¿Uåˆ†¼›ÀL•°æ®è®¿é—®ä»£ç å’Œå¤„理ORM的昂è´ëŠš„æ–ÒŽ³•åQŒå®ƒæ˜¯ä»¥åº”ç”¨æœåŠ¡å™¨äØ“ä¸­å¿ƒçš„æ–¹æ³•ï¼Œå³entity bean不是ž®†åº”用与某种数据库类型而是EJB容器¾U¦æŸåœ¨ä¸€èµ—÷€?/font> </li> <li> <font face="verdana, arial, helvetica" size="2">O/R mapping frameworkåQšä¸€ä¸ªORMæ¡†æž¶é‡‡ç”¨ä»¥å¯¹è±¡äØ“ä¸­å¿ƒçš„æ–¹æ³•å®žçŽ°æ•°æ®æŒ¾l­åŒ–åQŒä¸€ä¸ªä»¥å¯¹è±¡ä¸ÞZ¸­å¿ƒçš„åº”ç”¨æ˜“äºŽå¼€å‘åÆˆå…ähœ‰é«˜åº¦çš„可¿UÀL¤æ€§ã€‚在该领域中存在几个框架可用—JDO、Hibernate、TopLink以及CocoBase½{‰ã€‚在我们的范例中ž®†é€‰ç”¨Hibernateã€?/font> </li> </ul> <font face="verdana, arial, helvetica" size="2">现在åQŒæˆ‘们将讨论每一层中的设计问题,ç”׃ºŽJSF是一个相对较新的技术,因此ž®†ç€é‡äºŽå®ƒçš„使用åQ?br /><br /></font> <font size="3"> <b> <font face="verdana, arial, helvetica">presentation</font> </b> </font> <font face="verdana, arial, helvetica" size="2"> <font size="3"> <b>层和JSF</b> </font> <br />表示层的功能是收集用æˆïLš„输入、展½Cºæ•°æ®ã€æŽ§åˆ‰™¡µé¢å¯¼èˆªåƈž®†ç”¨æˆïLš„输入传递给业务逻辑层,表示层同旉™œ€è¦éªŒè¯ç”¨æˆïLš„输入以及¾l´æŠ¤åº”用的session状态。在下面几部分中åQŒæˆ‘ž®†è®¨è®ø™¡¨½Cºå±‚设计时的考虑和模式,òq¶è¯´æ˜Žé€‰æ‹©JSFä½œäØ“JCatalog表示层的原因ã€?br /><br /><b>MVC</b><br />MVC是Java-Blueprints推荐的架构设计模式,MVCž®†å‡ ä¸ªæ–¹é¢åˆ†¼›Õd¼€æ¥ï¼Œä»Žè€Œå‡ž®‘代码的重复åQŒå®ƒä»¥æŽ§åˆ¶äؓ中心òq¶ä‹É得应用更å…äh‰©å±•性。MVC同时可帮助具有不同技能的用户更关注于自己的技能,通过定义良好的接口进行相互合作。MVC是表½Cºå±‚的架构设计模式ã€?br /><br /><b>JSF</b><br />JSF是Web应用的服务器端用æˆïL»„件框æžÓž¼Œå®ƒåŒ…含以下APIåQšè¡¨½CºUI¾l„äšg、管理它们的状态、处理事件、服务器端验证、数据è{换、定义页面导航、支持国际化åQŒåÆˆä¸ø™¿™äº›ç‰¹æ€§æä¾›æ‰©å±•能力。它同时包括两个JSPçš„tag库以在JSP™åµé¢ä¸­è¡¨½CºUI¾l„äšgåQŒä»¥åŠå°†¾l„äšgwire为服务器端对象ã€?br /><br /><b>JSFå’ŒMVC</b><br />JSF非常适合于基于MVC的表½Cºå±‚æž¶æž„åQŒå®ƒåœ¨è¡Œä¸ºå’Œè¡¨ç¤ºä¹‹é—´æä¾›äº†æ¸…晰的分离åQŒå®ƒä½¿å¾—你可以采用熟悉的UI¾l„äšgå’Œweb层概念而无需受限于某¿Uç‰¹ŒDŠçš„脚本技术或标记语言ã€?br /><br />JSF backing beans是JSFçš„Model层,此外åQŒå®ƒåŒæ ·åŒ…含actionsåQŒaction是controller层的扩展åQŒç”¨äºŽå°†ç”¨æˆ·çš„请求委‹z„¡»™ä¸šåŠ¡é€»è¾‘å±‚ã€‚è¿™é‡Œè¯·æ³¨æ„åQŒä»Žæ•´ä½“的应用构架看åQŒä¸šåŠ¡é€»è¾‘å±‚ä¹Ÿè¢«ç§°ä¸ºmodel层。包含JSF标签的JSP™åµé¢æ˜¯è¡¨½Cºå±‚åQŒFaces Servlet提供了controller的功能ã€?br /><br /><b>ä¸ÞZ»€ä¹ˆé€‰ç”¨JSFåQ?/b></font> <font face="verdana, arial, helvetica" size="2"> <br />JSF不仅仅是另外一个Web框架åQŒä¸‹é¢è¿™äº›ç‰¹æ€§æ˜¯JSF区别于其他Web框架之所在:</font> <ul> <li> <font face="verdana, arial, helvetica" size="2">¾c»Swing的面向对象的Web应用开发:服务器端有状态的UI¾l„äšg模型åQŒé…åˆevent listenerså’ŒhandlersåQŒä¿ƒ˜q›äº†é¢å‘对象的Web应用开发ã€?/font> </li> <li> <font face="verdana, arial, helvetica" size="2">backing-bean½Ž¡ç†åQ?backing bean是与™åµé¢ä¸­ä‹É用的UI¾l„äšg相关联的javabean¾l„äšgåQŒbacking-bean½Ž¡ç†ž®†UI¾l„äšg对象的定义同执行应用相关处理和拥有数据的对象分离开来。JSF在合适的范围内保存和½Ž¡ç†˜q™äº›backing-bean实例ã€?/font> </li> <li> <font face="verdana, arial, helvetica" size="2">可扩展的UI模型åQšJSFçš„UI模型是可配置的、可重用的,用以构徏JSF应用的用æˆïL•Œé¢ã€‚你可以通过扩展标准的UI¾l„äšgæ¥å¼€å‘å‡ºæ›´äØ“å¤æ‚çš„ç»„ä»Óž¼Œä¾‹å¦‚菜单条、树¾l„äšg½{‰ã€?/font> </li> <li> <font face="verdana, arial, helvetica" size="2">灉|´»çš„rendering模型åQšrenderer分离了UI¾l„äšg的功能和昄¡¤ºåQŒå¤šä¸ªrenderers可创建和用来为同一客户端或不同的客æˆïL«¯å®šä¹‰ä¸åŒçš„æ˜¾½Cºã€?/font> </li> <li> <font face="verdana, arial, helvetica" size="2">可扩展的转换和验证模型:åŸÞZºŽæ ‡å‡†çš„converterå’ŒvalidatoråQŒä½ å¯ä»¥å¼€å‘出自己的可提供更好的模型保护的converterå’Œvalidatorã€?/font> </li> </ul> <font face="verdana, arial, helvetica" size="2">ž®½ç®¡å¦‚æ­¤åQŒJSF目前ž®šæœªæˆç†ŸåQŒéšåŒJSF发布çš?components、converterså’Œvalidators都是最基础的,而且per-component验证模型不能处理components å’Œvalidatorsé—´çš„many-to-many验证。此外,JSF标签不能与JSTLé—´æ— ¾~çš„æ•´åˆåœ¨ä¸€èµ—÷€?br /><br />在下面的章节中,我将讨论几个在JCatalog实现中的关键部分和设计决½{–。我首先解释managed bean的定义和使用以及JSF中的backing beanåQŒç„¶åŽï¼Œæˆ‘将说明如何处理安全、分™åüc€caching、file upload、验证以及错误信息定制ã€?br /><br /><b>Managed bean,backing bean,view object å’Œdomain object model</b><br />JSF中引入了两个新的名词åQšmanaged beanå’Œbacking bean。JSF提供了一个强大的managed-bean工具åQŒç”±JSF来管理的JavaBean对象¿UîCØ“managed-beanåQŒä¸€ä¸?managed bean表述了一个bean如何被创建和½Ž¡ç†åQŒå®ƒä¸åŒ…含该beançš„ä“Q何功能性描˜q°ã€?br /><br />backing bean定义了与™åµé¢ä¸­ä‹É用的UI¾l„äšg相关联的属性和处理逻辑。每一个backing-bean属性邦定于一个组件实例或某实例的value。一ä¸?backing-bean同时定义了一¾l„执行组件功能的æ–ÒŽ³•åQŒä¾‹å¦‚验证组件的数据、处理组件触发的事äšg、实施与¾l„äšg相关的导航等ã€?br /><br />一个典型的JSF应用ž®†å…¶ä¸­çš„æ¯ä¸ª™åµé¢å’Œä¸€ä¸ªbacking-bean¾l“合èµäh¥åQŒç„¶è€Œåœ¨çŽ°å®žåº”ç”¨ä¸­ï¼Œå¼ºåˆ¶çš„æ‰§è¡Œè¿™¿Uone-on-one的关¾pÖM¸æ˜¯ä¸€¿Uç†æƒ³çš„解决æ–ÒŽ¡ˆåQŒå®ƒå¯èƒ½ä¼šå¯¼è‡´ä»£ç é‡å¤ç­‰é—®é¢˜ã€‚在现实的应用中åQŒå¤šä¸ªé¡µé¢å¯ä»¥å…±äº«ä¸€ä¸ªbacking-beanåQŒä¾‹å¦‚在JCatalog中, CreateProductå’ŒEditProductž®†å…±äº«åŒä¸€ä¸ªProductBean定义ã€?br /><br />model对象特定于表½Cºå±‚中的一个view对象åQŒå®ƒåŒ…含必须昄¡¤ºåœ¨view层的数据以及验证用户输入、处理事件和与业务逻辑层交互的处理逻辑½{‰ã€‚在åŸÞZºŽ JSF的应用中backing beanž®±æ˜¯view对象åQŒåœ¨æœ¬æ–‡ä¸­backing beanå’Œview对象是可互换的名词ã€?br /><br />å¯Òޝ”于struts中的ActionFormå’ŒActionåQŒåˆ©ç”¨JSF中的backing-bean˜q›è¡Œå¼€å‘将能更好的遵åó@面向对象æ–ÒŽ³•åQŒä¸€ä¸?backing-bean不仅包含view数据åQŒè€Œä¸”˜q˜åŒ…含与˜q™äº›æ•°æ®ç›¸å…³çš„行为,而在struts中,Actionå’ŒActionForm分别包含数据和逻辑ã€?br /><br />我们都应该听说过domain object modelåQŒé‚£ä¹ˆï¼Œdomain object modelå’Œview对象之间有什么区别呢åQŸåœ¨ä¸€ä¸ªç®€å•çš„Web应用中,一个domain object model能够横穿所有层中,而在复杂的应用中åQŒéœ€è¦ç”¨åˆîC¸€ä¸ªå•独的view对象模型。domain object model应该属于业务逻辑层,它包含业务数据和与特定业务对象相关的业务逻辑åQ›ä¸€ä¸ªview对象包含presentation-specific的数据和逻辑。将view对象从domain object model中分¼›Õd‡ºæ¥çš„¾~ºç‚¹æ˜¯åœ¨˜q™ä¸¤ä¸ªå¯¹è±¡æ¨¡åž‹ä¹‹é—´å¿…ž®†å‡ºçŽ°æ•°æ®æ˜ ž®„。在JCatalog中,ProductBeanBuilderå’?UserBeanBuilder利用reflection-based Commons BeanUtils来实现数据映ž®„ã€?br /><br /><b>安全</b><br />目前åQŒJSF没有内徏的安全特性,而对于范例应用来说安全需求是非常基础的:用户ç™Õd½•到administration intranet中仅需用户名和密码认证åQŒè€Œæ— éœ€è€ƒè™‘授权ã€?br />针对于JSF的认证,已有几种æ–ÒŽ³•提出åQ?br /></font> <ul> <li> <font face="verdana, arial, helvetica" size="2">利用一个backing beanåQšè¿™ä¸€ä¸ªæ–¹æ³•非常简单,然而它却将backing bean与特ŒDŠçš„¾l§æ‰¿å…³ç³»¾l“合èµäh¥äº?/font> </li> <li> <font face="verdana, arial, helvetica" size="2">利用JSFçš„ViewHandler decoratoråQšè¿™ä¸€æ–ÒŽ³•中,安全逻辑紧密åœîC¸Žä¸€ç‰¹å®šWeb层技术联¾pÕdœ¨äº†ä¸€èµ?/font> </li> <li> <font face="verdana, arial, helvetica" size="2">利用servlet filteråQšä¸€ä¸ªJSF应用与其他的Webåº”ç”¨æ²¡æœ‰ä»€ä¹ˆä¸¤æ øP¼Œfilter仍是处理认证‹‚€æŸ¥çš„æœ€å¥½åœ°æ–¹ï¼Œ˜q™ç§æ–ÒŽ³•中,认证逻辑与Web应用分离开æ?/font> </li> </ul> <font face="verdana, arial, helvetica" size="2">在我们的范例½E‹åºä¸­ï¼ŒSecurityFilter¾c»è¢«ç”¨æ¥å¤„理用户的认证,目前åQŒå—保护的资源只包含三个™åµé¢åQŒå‡ºäºŽç®€å•的考虑åQŒå°†å®ƒä»¬çš„位¾|®è¢«¼‹¬ç¼–码到Filter¾cÖM¸­ã€?br /><br /><b>分页</b><br />该应用中的Catalog™åµé¢éœ€è¦åˆ†™åµï¼Œè¡¨ç¤ºå±‚可用来处理分页åQŒå³å®ƒå–出所有的数据òq¶ä¿å­˜åœ¨˜q™ä¸€å±‚;分页同样可在business-logic层ã€?integration层、甚至EIS层中实现。由于在JCatalog中假设不­‘…过500个äñ”品,因此所有的产品信息能存攑֜¨ä¸€ä¸ªuser session中,我们ž®†åˆ†™åµé€»è¾‘攑֜¨äº†ProductListBean中,与分™å늛¸å…³çš„参数ž®†é€šè¿‡JSF managed-bean工具配置ã€?br /><br /><b>Caching</b><br />Caching是提高Web应用性能的最重要技术之一åQŒåœ¨åº”用构徏中的很多层中都可以实现caching。JSF managed-bean工具可以使在表示层实现caching非常å®ÒŽ˜“。通过改变一个managed bean的范å›ß_¼Œ˜q™ä¸ªmanaged bean中包含的数据可以在不同的范围内缓存ã€?br /><br />范例应用中采用了两çñ”cachingåQŒç¬¬ä¸€¾U§caching存在于业务逻辑层,CachedCatalogServiceImpl¾cȝ»´æŠ¤äº†ä¸€ä¸ªæ‰€æœ‰äñ”品和目录的读写cacheåQŒSpringž®†è¯¥¾cÖM½œä¸ÞZ¸€ä¸ªsingleton service bean来管理,所以,一¾U§cache是一个应用范围的è¯Õd†™cacheã€?br /><br />ä¸ÞZº†½Ž€åŒ–分™åµé€»è¾‘òq¶è¿›è€Œæé«˜åº”用的速度åQŒäñ”品同样在session范围内缓存到表示层,每一个用æˆïL»´æŠ¤ç€ä»–自å·Þqš„ProductListBeanåQŒè¿™ä¸€æ–ÒŽ³•的缺ç‚ÒŽ˜¯å†…存的消耗和数据的失效问题,在一个用户session中,如果½Ž¡ç†å‘˜æ›´æ”¹äº†catalogåQŒç”¨æˆ·å¯åˆ°çš„ž®†æ˜¯å¤±æ•ˆçš„æ•°æ®ï¼Œç„¶è€Œï¼Œç”׃ºŽæˆ‘们假设应用的数据不会经常的改变åQŒæ‰€ä»¥è¿™äº›ç¼ºç‚¹å°†èƒ½å¤Ÿå¿å—ã€?br /><br /><b>File upload</b><br />目前的JSF Sun参考实çŽîC¸­ä¸æ”¯æŒfile upload。Struts虽已å…ähœ‰éžå¸¸ä¸é”™çš„file upload能力åQŒç„¶è€Œè¦æƒ³ä‹É用这一ç‰ÒŽ€§éœ€è¦Struts-Faces整合库。在JCatalog中,一个图像与一个äñ”品相兌™”åQŒåœ¨ä¸€ä¸ªç”¨æˆ·åˆ›å»ÞZº†æ–°çš„产品后,她必™åÕd°†ç›¸åº”的图片上传,囄¡‰‡ž®†ä¿å­˜åœ¨åº”用服务器的文äšg¾pȝ»Ÿé‡Œï¼Œäº§å“çš„IDž®±æ˜¯å›‘Öƒåç§°ã€?br /><br />范例应用中采ç”?input type="file" />、Servletå’ŒJakarta Commonçš„file-upload API来实现简单的文äšg上传功能åQŒè¯¥æ–ÒŽ³•包含两个参数åQšå›¾åƒèµ\径和囑փä¸Šä¼ ¾l“æžœ™åµé¢ã€‚它们将通过ApplicationBean来配¾|®ï¼Œè¯¦ç»†å†…容请参çœ?FileUploadServlet¾c…R€?br /><br /><b>Validation</b><br />JSF中发布的标准validator是非常基¼‹€çš„,无法满èƒö现实的需要,但很å®ÒŽ˜“开发出自己的JSF validatoråQŒåœ¨èŒƒä¾‹ä¸­ï¼Œæˆ‘开发了SelectedItemsRange validatoråQŒå®ƒç”¨æ¥éªŒè¯UISelectMany¾l„äšg中选择的数量:<br /><br />  <?xml:namespace prefix = h /?><h:selectmanylistbox id="selectedCategoryIds" value="#{productBean.selectedCategoryIds}"><br />     <?xml:namespace prefix = catalog /?><catalog:validateselecteditemsrange minnum="1"></catalog:validateselecteditemsrange><br />     <?xml:namespace prefix = f /?><f:selectitems id="categories" value="#{applicationBean.categorySelectItems}"></f:selectitems><br />  </h:selectmanylistbox><br /><br />详细情况请参看范例ã€?br /><br /><b>定制错误信息</b><br />在JSFä¸­ï¼Œä½ å¯ä»¥äØ“converterså’Œvalidators创徏resource bundle和定刉™”™è¯¯ä¿¡æ¯ï¼Œä¸€ä¸ªresource bundle可在faces-config.xml中创建:<br /><br />  <message-bundle>catalog.view.bundle.Messages</message-bundle><br /><br />òq¶å°†é”™è¯¯ä¿¡æ¯çš„key-value对加到Message.propertiesæ–‡äšg中:<br /><br />  javax.faces.component.UIInput.CONVERSION=Input data is not in the correct type.<br />  javax.faces.component.UIInput.REQUIRED=Required value is missing.<br /><br /><b><font size="3">业务逻辑层和Spring Framework</font></b><br />业务对象和业务服务存在于业务逻辑层中åQŒä¸€ä¸ªä¸šåŠ¡å¯¹è±¡ä¸ä»…åŒ…å«æ•°æ®ï¼Œè€Œä¸”åŒ…å«ç›¸åº”çš„é€»è¾‘åQŒåœ¨èŒƒä¾‹åº”用中包含三个业务对象:Product、Categoryå’ŒUserã€?br /><br />ä¸šåŠ¡æœåŠ¡ä¸Žä¸šåŠ¡å¯¹è±¡äº¤äº’åÆˆæä¾›æ›´é«˜¾U§çš„业务逻辑åQŒéœ€è¦é¦–先定义一个正式的业务接口åQŒå®ƒæ˜¯ç›´æŽ¥ä¸Ž¾lˆç«¯ç”¨æˆ·äº¤äº’的服务接口。在JCatalog中,通过åœ?Spring Framework帮助下的POJO实现业务逻辑层,其中共有两个业务服务åQšCatalogService包含Catalog½Ž¡ç†ç›¸å…³çš„业务逻辑åQ?UserService中包含User½Ž¡ç†é€»è¾‘ã€?br /><br />Spring是基于IoC概念的框æžÓž¼Œåœ¨èŒƒä¾‹åº”用中用到的Springç‰ÒŽ€§åŒ…括:<br /></font> <ul> <li> <font face="verdana, arial, helvetica" size="2">Bean management with application contextsåQšSpring可以有效地组¾l‡æˆ‘们的中间层对象,它能够消除singletonçš„proliferationåQŒåƈ易于实现良好的面向对象编½E‹æ–¹æ³•,即“编½E‹åˆ°æŽ¥å£â€ã€?/font> </li> <li> <font face="verdana, arial, helvetica" size="2">Declarative Transaction management: Spring利用AOP实现事务½Ž¡ç†åQŒè€Œæ— éœ€å€ŸåŠ©äºŽEJB容器åQŒåˆ©ç”¨è¿™¿Uæ–¹æ³•,事务½Ž¡ç†å¯ä»¥ç”¨äºŽä»ÖM½•POJO中。Spring的事务管理不局限于JTAåQŒè€Œæ˜¯å¯ä»¥é‡‡ç”¨ä¸åŒçš„事务策略,在范例应用中åQŒæˆ‘们将使用declarative transaction management with Hibernate transactionã€?/font> </li> <li> <font face="verdana, arial, helvetica" size="2">Data-access exception hierarchyåQšSpring提供了非常好的异常来代替SQLExceptionåQŒäؓ利用Spring的异常,必须在Spring的配¾|®æ–‡ä»¶ä¸­å®šä¹‰ä»¥ä¸‹å¼‚常转换åQ?/font> </li> </ul> <font face="verdana, arial, helvetica" size="2">        <bean class="" id="jdbcExceptionTranslator"><br />          <property name="dataSource"><br />              <ref bean="dataSource"><br />          </ref></property><br />        </bean><br /><br />        在范例应用中åQŒå¦‚果一个具有重复ID的新产品被插入,ž®†ä¼šæŠ›å‡ºDataIntegrityViolationExceptionåQŒè¿™ä¸€å¼‚常ž®†è¢« <br />        catchòq¶rethrown一个DuplicateProductIdExceptionã€‚è¿™æ øP¼Œè¯¥å¼‚常就可以与其它的异常区别处理ã€?br /></font> <ul> <li> <font face="verdana, arial, helvetica" size="2">Hibernate integrationåQšSpring与Hibernate˜q™æ ·çš„ORM框架整合的非常好åQŒSpring提供了对Hibernate session的高效和安全的处理,它可通过application context配置Hibernateçš„SessionFactorieså’ŒJDBC数据源,òq¶ä‹É得应用易于测试ã€?/font> </li> </ul> <font face="verdana, arial, helvetica" size="2"> <br /> <b> <font size="3">Integration层和Hibernate</font> </b> <br />Hibernate是一个开源的ORM框架åQŒå®ƒå¯ä»¥æ”¯æŒæ‰€æœ‰ä¸»‹¹SQL数据库系¾lŸï¼ŒHibernate的查询语­a€ä¸ºå¯¹è±¡å’Œå…³ç³»æž¶è“v了非常好的桥梁。Hibernateæä¾›äº†å¼ºå¤§çš„åŠŸèƒ½ä»¥å®žçŽŽÍ¼šæ•°æ®è¯Õd–和更新、事务管理、数据连接池、查询和实体关系½Ž¡ç†½{‰ã€?br /><br /><b><font size="3">Data Access Ojbect(DAO)</font></b><br />JCatalog中采用了Dao模式åQŒè¯¥æ¨¡å¼æŠ½è±¡å’Œå°è£…了所有对数据源的讉K—®åQŒè¯¥åº”用中包括两个DAO接口åQšCatalogDaoå’ŒUserDaoåQŒå®ƒä»¬ç›¸åº”的实现HibernateCatalogDaoImplå’ŒHibernateUserDAoImpl包含了Hibernate特定的逻辑来实现数据的½Ž¡ç†å’ŒæŒä¹…化ã€?br /><br /><b><font size="5">实现</font></b><br />现在我们来看看如何将上面讨论的这些东西包装在一起以实现JCatalogåQŒä½ å¯ä»¥ä»Žè¿™ä¸ªåœ°å€ä¸‹è²æºç åQ?a >source code</a><br /><br /><b><font size="3">数据库设è®?/font></b><br />æˆ‘ä»¬ä¸ø™¯¥èŒƒä¾‹åº”用创徏了包å?个表的数据库åQŒå¦‚å›?所½Cºï¼š<br /><p align="center"><a ><img style="WIDTH: 290px; HEIGHT: 211px" height="150" alt="" hspace="0" src="http://www.huihoo.com/java/jsf/jw-0719-jsf5.gif" width="248" align="baseline" border="0" /></a></p><br /><b><font size="3">¾c»è®¾è®?/font></b><br />å›?昄¡¤ºäº†JCatalog的类å›?br /><p align="center"><a ><img style="WIDTH: 414px; HEIGHT: 255px" height="232" alt="" hspace="0" src="http://www.huihoo.com/java/jsf/jw-0719-jsf6.gif" width="120" align="baseline" border="0" /></a></p><br />“编½E‹åˆ°æŽ¥å£â€çš„æ€æƒ³è´¯ç©¿äº†æ•´ä¸ªè®¾è®¡å®žçŽîC¸­åQŒåœ¨è¡¨ç¤ºå±‚,å…Þq”¨åˆ°å››ä¸ªbacking beanåQšProductBean、ProductListBean、UserBeanå’ŒMessageBean;业务逻辑层包含两个业务服åŠ?(CatalogServiceå’ŒUserService)和三个业务对è±?Product、Categoryå’ŒUser);Integration层有两个Dao接口和它们相应的Hibernate实现åQŒSpringçš„application context用来½Ž¡ç†¾lå¤§å¤šæ•°çš„业务逻辑层和integration层的对象åQ›ServiceLocatorž®†JSF和业务逻辑层整合在了一赗÷€?br /><br /><b><font size="3">Wire everything up</font></b><br />ç”׃ºŽ½‹‡å¹…所限,我们仅ä‹D例说明,范例中use case CreateProduct展示了如何装配和构徏应用åQŒåœ¨è¯¦ç»†è®²è¿°¾l†èŠ‚å‰ï¼Œæˆ‘ä»¬åˆ©ç”¨sequenceå›?å›?)来说明所有层的end-tp-end整合ã€?br /><p align="center"><a ><img style="WIDTH: 470px; HEIGHT: 128px" height="128" alt="" hspace="0" src="http://www.huihoo.com/java/jsf/jw-0719-jsf7.gif" width="120" align="baseline" border="0" /></a></p><br /><br /><b>表示å±?/b>åQ?br />表示层实现包括创建JSP™åµé¢ã€å®šä¹‰é¡µå¯ÆDˆªã€åˆ›å»ºå’Œé…ç½®backing bean以及ž®†JSF与业务逻辑层整合ã€?br /></font> <ul> <li> <font face="verdana, arial, helvetica" size="2">JSP pageåQšcreateProduct.jsp是用来创建新产品的页面,它包含UI¾l„äšgòq¶å°†¾l„äšg打包成ProductBeanåQŒValidateItemsRange标签用来验证用户选择的种¾cÀL•°é‡ï¼Œå¯Òޝä¸€ä¸ªäñ”品至ž®‘要有一个种¾c»è¢«é€‰ä¸­ã€?/font> </li> </ul> <ul> <li> <font face="verdana, arial, helvetica" size="2">™åµé¢å¯ÆDˆªåQšåº”用中的导航被定义在应用的配置文äšgfaces-navigation.xml中,CreateProduct的导航准则如下:</font> </li> </ul> <blockquote> <font face="verdana, arial, helvetica" size="2"> <navigation-rule> </navigation-rule> </font> <br /> <font face="verdana, arial, helvetica" size="2">   <from-view-id>*</from-view-id></font> <br /> <font face="verdana, arial, helvetica" size="2">   <navigation-case></navigation-case></font> <br /> <font face="verdana, arial, helvetica" size="2">      <from-outcome>createProduct</from-outcome></font> <br /> <font face="verdana, arial, helvetica" size="2">      <to-view-id>/createProduct.jsp</to-view-id></font> <br /> <font face="verdana, arial, helvetica" size="2">   </font> <br /> <font face="verdana, arial, helvetica" size="2"> </font> <br /> </blockquote> <blockquote> <font face="verdana, arial, helvetica" size="2"> <navigation-rule> </navigation-rule> </font> <br /> <font face="verdana, arial, helvetica" size="2">   <from-view-id>/createProduct.jsp</from-view-id></font> <br /> <font face="verdana, arial, helvetica" size="2">   <navigation-case></navigation-case></font> <br /> <font face="verdana, arial, helvetica" size="2">      <from-outcome>success</from-outcome></font> <br /> <font face="verdana, arial, helvetica" size="2">      <to-view-id>/uploadImage.jsp</to-view-id></font> <br /> <font face="verdana, arial, helvetica" size="2">   </font> <br /> <font face="verdana, arial, helvetica" size="2">   <navigation-case></navigation-case></font> <br /> <font face="verdana, arial, helvetica" size="2">      <from-outcome>retry</from-outcome></font> <br /> <font face="verdana, arial, helvetica" size="2">      <to-view-id>/createProduct.jsp</to-view-id></font> <br /> <font face="verdana, arial, helvetica" size="2">   </font> <br /> <font face="verdana, arial, helvetica" size="2">   <navigation-case></navigation-case></font> <br /> <font face="verdana, arial, helvetica" size="2">      <from-outcome>cancel</from-outcome></font> <br /> <font face="verdana, arial, helvetica" size="2">      <to-view-id>/productList.jsp</to-view-id></font> <br /> <font face="verdana, arial, helvetica" size="2">   </font> <br /> <font face="verdana, arial, helvetica" size="2"> </font> <br /> </blockquote> <ul> <li> <font face="verdana, arial, helvetica" size="2">Backing beanåQšProductBean不仅包含有将数据映射到页面上的UI¾l„äšg的属性,˜q˜åŒ…括三个actionåQšcreateAction、editActionå’ŒdeleteActionåQŒä¸‹é¢æ˜¯createActionæ–ÒŽ³•的代码:</font> </li> </ul> <blockquote> <font face="verdana, arial, helvetica" size="2">public String createAction() {</font> <br /> <font face="verdana, arial, helvetica" size="2">   try {</font> <br /> <font face="verdana, arial, helvetica" size="2">      Product product = ProductBeanBuilder.createProduct(this);</font> <br /> <br /> <font face="verdana, arial, helvetica" size="2">      //Save the product.</font> <br /> <font face="verdana, arial, helvetica" size="2">      this.serviceLocator.getCatalogService().saveProduct(product);</font> <br /> <br /> <font face="verdana, arial, helvetica" size="2">      //Store the current product id inside the session bean.</font> <br /> <font face="verdana, arial, helvetica" size="2">      //For the use of image uploader.</font> <br /> <font face="verdana, arial, helvetica" size="2">      FacesUtils.getSessionBean().setCurrentProductId(this.id);</font> <br /> <br /> <font face="verdana, arial, helvetica" size="2">      //Remove the productList inside the cache.</font> <br /> <font face="verdana, arial, helvetica" size="2">      this.logger.debug("remove ProductListBean from cache");</font> <br /> <font face="verdana, arial, helvetica" size="2">      FacesUtils.resetManagedBean(BeanNames.PRODUCT_LIST_BEAN);</font> <br /> <font face="verdana, arial, helvetica" size="2">   } catch (DuplicateProductIdException de) {</font> <br /> <font face="verdana, arial, helvetica" size="2">      String msg = "Product id already exists";</font> <br /> <font face="verdana, arial, helvetica" size="2">      this.logger.info(msg);</font> <br /> <font face="verdana, arial, helvetica" size="2">      FacesUtils.addErrorMessage(msg);</font> <br /> <br /> <font face="verdana, arial, helvetica" size="2">      return NavigationResults.RETRY;</font> <br /> <font face="verdana, arial, helvetica" size="2">   } catch (Exception e) {</font> <br /> <font face="verdana, arial, helvetica" size="2">      String msg = "Could not save product";</font> <br /> <font face="verdana, arial, helvetica" size="2">      this.logger.error(msg, e);</font> <br /> <font face="verdana, arial, helvetica" size="2">      FacesUtils.addErrorMessage(msg + ": Internal Error");</font> <br /> <br /> <font face="verdana, arial, helvetica" size="2">      return NavigationResults.FAILURE;</font> <br /> <font face="verdana, arial, helvetica" size="2">   }</font> <br /> <font face="verdana, arial, helvetica" size="2">   String msg = "Product with id of " + this.id + " was created successfully.";</font> <br /> <font face="verdana, arial, helvetica" size="2">   this.logger.debug(msg);</font> <br /> <font face="verdana, arial, helvetica" size="2">   FacesUtils.addInfoMessage(msg);</font> <br /> <br /> <font face="verdana, arial, helvetica" size="2">   return NavigationResults.SUCCESS;</font> <br /> <font face="verdana, arial, helvetica" size="2">}</font> <br /> </blockquote> <font face="verdana, arial, helvetica" size="2"> </font> <ul> <li> <font face="verdana, arial, helvetica" size="2">Managed-bean声明åQšProductBean必须在JSF配置文äšgfaces-managed-bean.xml中配¾|®ï¼š</font> </li> </ul> <blockquote> <font face="verdana, arial, helvetica" size="2"> <managed-bean> </managed-bean> </font> <br /> <font face="verdana, arial, helvetica" size="2">   <description></description></font> <br /> <font face="verdana, arial, helvetica" size="2">      Backing bean that contains product information.</font> <br /> <font face="verdana, arial, helvetica" size="2">   </font> <br /> <font face="verdana, arial, helvetica" size="2">   <managed-bean-name>productBean</managed-bean-name></font> <br /> <font face="verdana, arial, helvetica" size="2">   <managed-bean-class>catalog.view.bean.ProductBean</managed-bean-class></font> <br /> <font face="verdana, arial, helvetica" size="2">   <managed-bean-scope>request</managed-bean-scope>    </font> <br /> <font face="verdana, arial, helvetica" size="2">   <managed-property></managed-property></font> <br /> <font face="verdana, arial, helvetica" size="2">      <property-name>id</property-name></font> <br /> <font face="verdana, arial, helvetica" size="2">      <value>#{param.productId}</value></font> <br /> <font face="verdana, arial, helvetica" size="2">   </font> <br /> <font face="verdana, arial, helvetica" size="2">   <managed-property></managed-property></font> <br /> <font face="verdana, arial, helvetica" size="2">      <property-name>serviceLocator</property-name></font> <br /> <font face="verdana, arial, helvetica" size="2">      <value>#{serviceLocatorBean}</value></font> <br /> <font face="verdana, arial, helvetica" size="2">   </font> <br /> <font face="verdana, arial, helvetica" size="2"> </font> <br /> </blockquote> <ul> <li> <font face="verdana, arial, helvetica" size="2"> 表示层和业务逻辑层之间的整合åQ?ServiceLocator抽象了查找服务的逻辑åQŒåœ¨èŒƒä¾‹åº”用中,ServiceLocatorè¢«å®šä¹‰äØ“ä¸€ä¸ªæŽ¥å£ï¼Œè¯¥æŽ¥å£å®žçŽîCؓ一个JSFçš?managed beanåQŒå³ServiceLocatorBeanåQŒå®ƒž®†åœ¨Springçš„application context中寻找服务:</font> </li> </ul> <font face="verdana, arial, helvetica" size="2"> </font> <blockquote> <font face="verdana, arial, helvetica" size="2">ServletContext context = FacesUtils.getServletContext();</font> <br /> <font face="verdana, arial, helvetica" size="2">this.appContext = WebApplicationContextUtils.getRequiredWebApplicationContext(context);</font> <br /> <font face="verdana, arial, helvetica" size="2">this.catalogService = (CatalogService)this.lookupService(CATALOG_SERVICE_BEAN_NAME);</font> <br /> <font face="verdana, arial, helvetica" size="2">this.userService = (UserService)this.lookupService(USER_SERVICE_BEAN_NAME);</font> <br /> </blockquote> <font face="verdana, arial, helvetica" size="2"> <b>业务逻辑å±?/b> <br /> </font> <ul> <li> <font face="verdana, arial, helvetica" size="2">业务对象åQšç”±äºŽé‡‡ç”¨Hibernate提供持久化,因此Productå’ŒCategoryä¸¤ä¸ªä¸šåŠ¡å¯¹è±¡éœ€è¦äØ“å®ƒä»¬çš„æ‰€æœ‰field提供getterå’Œsetterã€?/font> </li> </ul> <ul> <li> <font face="verdana, arial, helvetica" size="2">业务服务åQšCatalogService接口中定义了所有的与Catalog management相关的服务:</font> </li> </ul> <blockquote> <font face="verdana, arial, helvetica" size="2">public interface CatalogService {</font> <br /> <font face="verdana, arial, helvetica" size="2">   public Product saveProduct(Product product) throws CatalogException;</font> <br /> <font face="verdana, arial, helvetica" size="2">   public void updateProduct(Product product) throws CatalogException;</font> <br /> <font face="verdana, arial, helvetica" size="2">   public void deleteProduct(Product product) throws CatalogException;</font> <br /> <font face="verdana, arial, helvetica" size="2">   public Product getProduct(String productId) throws CatalogException;</font> <br /> <font face="verdana, arial, helvetica" size="2">   public Category getCategory(String categoryId) throws CatalogException;</font> <br /> <font face="verdana, arial, helvetica" size="2">   public List getAllProducts() throws CatalogException;</font> <br /> <font face="verdana, arial, helvetica" size="2">   public List getAllCategories() throws CatalogException;</font> <br /> <font face="verdana, arial, helvetica" size="2">}</font> <br /> </blockquote> <ul> <li> <font face="verdana, arial, helvetica" size="2">Spring ConfigurationåQšè¿™é‡Œæ˜¯CatalogServiceçš„Spring配置åQ?/font> </li> </ul> <blockquote> <font face="verdana, arial, helvetica" size="2"> <!-- Hibernate Transaction Manager Definition --> </font> <br /> <font face="verdana, arial, helvetica" size="2"> <bean class="org" id="transactionManager"> </bean> </font> <br /> <font face="verdana, arial, helvetica" size="2">   <property name="sessionFactory"><ref local="sessionFactory"></ref></property></font> <br /> <font face="verdana, arial, helvetica" size="2"> </font> <br /> <br /> <font face="verdana, arial, helvetica" size="2"> <!-- Cached Catalog Service Definition --> </font> <br /> <font face="verdana, arial, helvetica" size="2"> <bean class="catalog" id="catalogServiceTarget" init-method="init"> </bean> </font> <br /> <font face="verdana, arial, helvetica" size="2">   <property name="catalogDao"><ref local="catalogDao"></ref></property></font> <br /> <font face="verdana, arial, helvetica" size="2"> </font> <br /> <br /> <font face="verdana, arial, helvetica" size="2"> <!-- Transactional proxy for the Catalog Service --> </font> <br /> <font face="verdana, arial, helvetica" size="2"> <bean class="org" id="catalogService"> </bean> </font> <br /> <font face="verdana, arial, helvetica" size="2">   <property name="transactionManager"><ref local="transactionManager"></ref></property></font> <br /> <font face="verdana, arial, helvetica" size="2">   <property name="target"><ref local="catalogServiceTarget"></ref></property></font> <br /> <font face="verdana, arial, helvetica" size="2">   <property name="transactionAttributes"></property></font> <br /> <font face="verdana, arial, helvetica" size="2">      <props></props></font> <br /> <font face="verdana, arial, helvetica" size="2">         <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop></font> <br /> <font face="verdana, arial, helvetica" size="2">       <prop key="save*">PROPAGATION_REQUIRED</prop></font> <br /> <font face="verdana, arial, helvetica" size="2">       <prop key="update*">PROPAGATION_REQUIRED</prop></font> <br /> <font face="verdana, arial, helvetica" size="2">       <prop key="delete*">PROPAGATION_REQUIRED</prop></font> <br /> <font face="verdana, arial, helvetica" size="2">      </font> <br /> <font face="verdana, arial, helvetica" size="2">   </font> <br /> <font face="verdana, arial, helvetica" size="2"> </font> <br /> </blockquote> <ul> <li> <font face="verdana, arial, helvetica" size="2">Springå’ŒHibernate的整合:下面是HibernateSessionFactory的配¾|®ï¼š</font> </li> </ul> <blockquote> <font face="verdana, arial, helvetica" size="2"> <!-- Hibernate SessionFactory Definition --> </font> <br /> <code> <p><!-- Hibernate SessionFactory Definition --><br /><bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean"><br />   <property name="mappingResources"><br />      <list><br />         <value>catalog/model/businessobject/Product.hbm.xml</value><br />         <value>catalog/model/businessobject/Category.hbm.xml</value><br />         <value>catalog/model/businessobject/User.hbm.xml</value><br />      </list><br />   </property><br />   <property name="hibernateProperties"><br />      <props><br />         <prop key="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect</prop><br />       <prop key="hibernate.show_sql">true</prop><br />       <prop key="hibernate.cglib.use_reflection_optimizer">true</prop><br />       <prop key="hibernate.cache.provider_class">net.sf.hibernate.cache.HashtableCacheProvider</prop><br />      </props><br />   </property> <br />   <property name="dataSource"><br />      <ref bean="dataSource"/><br />   </property><br /></bean><br /></p> </code> <p> <code>CatalogDao</code> uses <code>HibernateTemplate</code> to integrate between Hibernate and Spring. Here's the configuration for <code>HibernateTemplate</code>: </p> <p> <code> <p><!-- Hibernate Template Defintion --><br /><bean id="hibernateTemplate" class="org.springframework.orm.hibernate.HibernateTemplate"> <br />   <property name="sessionFactory"><ref bean="sessionFactory"/></property> <br />   <property name="jdbcExceptionTranslator"><ref bean="jdbcExceptionTranslator"/></property> <br /></bean> <br /></p> </code> </p> <p> <br /> <br /> </p> </blockquote> <font face="verdana, arial, helvetica" size="2"> <b>Integrationå±?/b> <br />Hibernate通过xml配置文äšg来映ž®„业务对象和关系数据库,在JCatalog中,Product.hbm.xml表示了Product对象的映ž®„,Category.hbm.xml则用来表½CºCategory的映ž®„,Product.hbm.xml如下åQ?br /></font> <blockquote> <font face="verdana, arial, helvetica" size="2"> <code> <p><?xml version="1.0"?><br /><!DOCTYPE hibernate-mapping PUBLIC <br />      "-//Hibernate/Hibernate Mapping DTD 2.0//EN"<br />      "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"><br /><hibernate-mapping package="catalog.model.businessobject"><br />   <class name="Product" table="product"><br />      <id name="id" column="ID" unsaved-value="null"><br />         <generator class="assigned"/><br />      </id><br />      <property name="name" column="NAME" unique="true" not-null="true"/><br />      <property name="price" column="PRICE"/>     <br />      <property name="width" column="WIDTH"/>      <br />      <property name="height" column="height"/>      <br />      <property name="description" column="description"/>   <br />      <set name="categoryIds" table="product_category" cascade="all"><br />         <key column="PRODUCT_ID"/><br />         <element column="CATEGORY_ID" type="string"/><br />      </set><br />   </class><br /></hibernate-mapping><br /></p> </code> <p> <code>CatalogDao</code> is wired with <code>HibernateTemplate</code> by Spring: </p> <p> <code> <p><!-- Catalog DAO Definition: Hibernate implementation --><br /><bean id="catalogDao" class="catalog.model.dao.hibernate.CatalogDaoHibernateImpl"><br />   <property name="hibernateTemplate"><ref bean="hibernateTemplate"/></property> <br /></bean> <br /></p> </code> </p> <p> </p> </font> </blockquote> <font face="verdana, arial, helvetica" size="2"> <b> <font size="5">¾l“论</font> </b> <br />本文主要讲述了如何将JSF与Spring、Hibernate整合在一èµäh¥æž„徏实际的Web应用åQŒè¿™ä¸‰ç§æŠ€æœ¯çš„¾l„合提供了一个强大的Web应用开发框架。在Web应用的高层设计中应该采用多层构架体系åQŒJSF非常适合MVC设计模式以实现表½Cºå±‚åQŒSpring可用在业务逻辑层中½Ž¡ç†ä¸šåŠ¡å¯¹è±¡åQŒåƈ提供事物½Ž¡ç†å’Œèµ„源管理等åQŒSpring与Hibernate¾l“合的非常出è‰ÔŒ¼ŒHibernate是强大的O/R映射框架åQŒå®ƒå¯ä»¥åœ¨integration层中提供最好的服务ã€?br /><br />通过ž®†æ•´ä¸ªWeb应用分割成多层,òq¶å€ŸåŠ©äºŽâ€œç¼–½E‹åˆ°æŽ¥å£â€ï¼Œåº”用½E‹åºçš„æ¯ä¸€å±‚所采用的技术都是可替换的,例如Struts可以用来替换JSFåQŒJDO可替换Hibernate。各层之间的整合不是不值得研究åQŒé‡‡ç”¨IoCå’ŒServiceLocator设计模式可ä‹É得整合非常容易。JSF提供了其它Web框架‹Æ ç¼ºçš„功能,然而,˜q™åƈ不意味着你马上抛弃Struts而开始ä‹É用JSFåQŒæ˜¯å¦é‡‡ç”¨JSF取决于项目目前的状况和功能需求,以及开发团队的意见½{‰ã€?br /></font> <img src ="http://www.aygfsteel.com/Goodtiger/aggbug/79679.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/Goodtiger/" target="_blank">GoodtigerZhao</a> 2006-11-07 19:46 <a href="http://www.aygfsteel.com/Goodtiger/archive/2006/11/07/79679.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转蝲]JSF与Struts的异å?/title><link>http://www.aygfsteel.com/Goodtiger/archive/2006/11/07/79677.html</link><dc:creator>GoodtigerZhao</dc:creator><author>GoodtigerZhao</author><pubDate>Tue, 07 Nov 2006 11:38:00 GMT</pubDate><guid>http://www.aygfsteel.com/Goodtiger/archive/2006/11/07/79677.html</guid><wfw:comment>http://www.aygfsteel.com/Goodtiger/comments/79677.html</wfw:comment><comments>http://www.aygfsteel.com/Goodtiger/archive/2006/11/07/79677.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/Goodtiger/comments/commentRss/79677.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/Goodtiger/services/trackbacks/79677.html</trackback:ping><description><![CDATA[ <p align="center"> <a >板桥里äh</a> http://www.jdon.com 2005/09/05</p> <p>  Strutså’ŒJSF/Tapestry都属于表现层框架åQŒè¿™ä¸¤ç§åˆ†å±žä¸åŒæ€§è´¨çš„æ¡†æžÓž¼ŒåŽè€…是一¿Uäº‹ä»‰™©±åŠ¨åž‹çš„ç»„ä»¶æ¨¡åž‹ï¼Œè€ŒStruts只是单纯的MVC模式框架åQŒè€å¤–æ€ÀL˜¯æ€¥å¼åÆD¯´äº‹äšg驱动型就比MVC模式框架好,何以见得åQŒæˆ‘们下面进行详¾l†åˆ†æžæ¯”较一下到底是怎么回事åQ?/p> <p>  首先事äšg是指从客æˆïL«¯™åµé¢åQˆæµè§ˆå™¨åQ‰ç”±ç”¨æˆ·æ“ä½œè§¦å‘的事ä»Óž¼ŒStruts使用Action来接受浏览器表单提交的事ä»Óž¼Œ˜q™é‡Œä½¿ç”¨äº†Command模式åQŒæ¯ä¸ªç‘ô承Action的子¾c»éƒ½å¿…须实现一个方法executeã€?/p> <p>  在struts中,实际是一个表单Form对应一个Action¾c?或DispatchAction)åQŒæ¢ä¸€å¥è¯è¯ß_¼šåœ¨Struts中实际是一个表单只能对应一个事ä»Óž¼Œstruts˜q™ç§äº‹äšg方式¿UîCØ“application eventåQŒapplication eventå’Œcomponent event相比是一¿Uç²—¾_’度的事件ã€?/p> <p>  struts重要的表单对象ActionForm是一¿Uå¯¹è±¡ï¼Œå®ƒä»£è¡¨äº†ä¸€¿Uåº”用,˜q™ä¸ªå¯¹è±¡ä¸­è‡³ž®‘包含几个字ŒDµï¼Œ˜q™äº›å­—段是Jsp™åµé¢è¡¨å•中的input字段åQŒå› ä¸ÞZ¸€ä¸ªè¡¨å•对应一个事ä»Óž¼Œæ‰€ä»¥ï¼Œå½“我们需要将事äšg¾_’度¾l†åŒ–到表单中˜q™äº›å­—段æ—Óž¼Œä¹Ÿå°±æ˜¯è¯´åQŒä¸€ä¸ªå­—ŒDµå¯¹åº”一个事件时åQŒå•¾U¯ä‹É用Strutsž®×ƒ¸å¤ªå¯èƒ½ï¼Œå½“然通过¾l“合JavaScript也是可以转弯实现的ã€?/p> <p>  而这¿Uæƒ…况ä‹É用JSFž®±å¯ä»¥æ–¹ä¾¿å®žçŽŽÍ¼Œ</p> <table width="90%" bgcolor="#cccccc" border="0"> <tbody> <tr> <td><h:inputText id="userId" value="#{login.userId}"><br />  <f:<strong>valueChangeListener</strong> type="logindemo.UserLoginChanged" /><br /></h:inputText></td> </tr> </tbody> </table> <p>  #{login.userId}表示从名为loginçš„JavaBeançš„getUserId获得的结果,˜q™ä¸ªåŠŸèƒ½ä½¿ç”¨struts也可以实玎ͼŒname="login" property="userId" </p> <p>  关键是第二行åQŒè¿™é‡Œè¡¨½Cºå¦‚æžœuserIdçš„å€¼æ”¹å˜åÆˆä¸”ç¡®å®šæäº¤åŽåQŒå°†è§¦å‘调用¾c»UserLoginChangedçš„processValueChanged(...)æ–ÒŽ³•ã€?/p> <p>  JSF可以为组件提供两¿Uäº‹ä»Óž¼šValue Changedå’?Action. 前者我们已¾låœ¨ä¸ŠèŠ‚è§è¯†˜q‡ç”¨å¤„,后者就相当于struts中表单提交Action机制åQŒå®ƒçš„JSF写法如下åQ?/p> <table width="90%" bgcolor="#cccccc" border="0"> <tbody> <tr> <td><h:commandButton id="login" commandName="login"><br />  <f:<strong>actionListener</strong> type=”logindemo.LoginActionListenerâ€?/><br /></h:commandButton></td> </tr> </tbody> </table> <p>  从代码可以看出,˜q™ä¸¤¿Uäº‹ä»¶æ˜¯é€šè¿‡Listerner˜q™æ ·è§‚察者模式脓在具体组件字ŒDµä¸Šçš„,而Struts此类事äšg是原始的一¿Uè¡¨å•提交Submit触发机制。如果说前者比较语­a€åŒ–(¾~–程语言习惯做法¾cÖM¼¼Swing¾~–程åQ‰ï¼›åŽè€…是属于WEBåŒ–ï¼Œå› äØ“å®ƒæ˜¯æ¥è‡ªHtml表单åQŒå¦‚果你èµäh­¥æ˜¯ä»ŽPerl/PHP开始,反而容易接受Struts˜q™ç§é£Žæ ¼ã€?/p> <p> <strong>基本配置</strong> </p> <p>  Strutså’ŒJSF都是一¿Uæ¡†æžÓž¼ŒJSF必须需要两¿UåŒ…JSF核心包、JSTL包(标签库)åQŒæ­¤å¤–,JSF˜q˜å°†ä½¿ç”¨åˆ°Apache™å¹ç›®çš„一些commons包,˜q™äº›Apache包只要部¾|²åœ¨ä½ çš„æœåŠ¡å™¨ä¸­æ—¢å¯ã€?/p> <p>  JSF包下载地址åQ?a target="_blank">http://java.sun.com/j2ee/javaserverfaces/download.html</a>选择其中<b>Reference Implementationã€?/b></p> <p>  JSTL包下载在<a target="_blank">http://jakarta.apache.org/site/downloads/downloads_taglibs-standard.cgi</a><br /><br />  所以,从JSF的驱动包¾l„成看,其开源基因也占据很大的比重,JSF是一个SUNä¼™ä¼´ä»¬å·¥ä¸šæ ‡å‡†å’Œå¼€æºä¹‹é—´çš„ä¸€ä¸ªæØœè¡€å„ѝ€?/p> <p>  上述两个地址下蝲的jaråˆåÆˆåœ¨ä¸€èµ·å°±æ˜¯JSF所需要的全部驱动包了。与Strutsçš„é©±åŠ¨åŒ…ä¸€æ øP¼Œ˜q™äº›é©±åŠ¨åŒ…å¿…™åÖM½äºŽWeb™å¹ç›®çš„WEB-INF/libåQŒå’ŒStruts一æ ïLš„æ˜¯ä¹Ÿå¿…须在web.xml中有如下配置åQ?/p> <table width="90%" bgcolor="#cccccc" border="0"> <tbody> <tr> <td><web-app><br />  <servlet><br />    <servlet-name>Faces Servlet</servlet-name><br />    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class><br />    <load-on-startup>1</load-on-startup><br />  </servlet> <p>  <servlet-mapping><br />    <servlet-name>Faces Servlet</servlet-name><br />    <url-pattern>*.faces</url-pattern><br />  </servlet-mapping> <br /></web-app></p></td> </tr> </tbody> </table> <p>  ˜q™é‡Œå’ŒStrutsçš„web.xmlé…ç½®ä½•å…¶ç›æ€¼¼åQŒç®€ç›´ä¸€æ¨¡ä¸€æ —÷€?/p> <p>  正如Strutsçš„struts-config.xmlä¸€æ øP¼ŒJSF也有¾cÖM¼¼çš„faces-config.xml配置文äšgåQ?/p> <table width="90%" bgcolor="#cccccc" border="0"> <tbody> <tr> <td> <br /><faces-config><br />  <navigation-rule><br />    <from-view-id>/index.jsp</from-view-id><br />    <navigation-case><br />      <from-outcome>login</from-outcome><br />      <to-view-id>/welcome.jsp</to-view-id><br />    </navigation-case><br />  </navigation-rule> <p>  <managed-bean> <br />    <managed-bean-name>user</managed-bean-name><br />    <managed-bean-class>com.corejsf.UserBean</managed-bean-class> <br />    <managed-bean-scope>session</managed-bean-scope> <br />  </managed-bean><br /></faces-config></p><p> </p></td> </tr> </tbody> </table> <p>  在Struts-config.xml中有ActionForm Action以及Jsp之间的流½E‹å…³¾p»ï¼Œåœ¨faces-config.xml中,也有˜q™æ ·çš„æµ½E‹ï¼Œæˆ‘们具体解释一下NavigationåQ?/p> <p>  在index.jsp中有一个事ä»Óž¼š</p> <p><h:commandButton label="Login" action="login" /></p> <p>  action的值必™åÕdŒ¹é…form-outcomeå€û|¼Œä¸Šè¿°Navigation配置表示åQšå¦‚果在index.jsp中有一个login事äšgåQŒé‚£ä¹ˆäº‹ä»¶è§¦å‘后下一个页面将是welcome.jsp</p> <p>  JSF有一个独立的事äšg发生和页面导航的‹¹ç¨‹å®‰æŽ’åQŒè¿™ä¸ªæ€èµ\比struts要非常清晰ã€?/p> <p>  managed-bean¾cÖM¼¼Strutsçš„ActionFormåQŒæ­£å¦‚可以在struts-config.xml中定义ActionFormçš„scopeä¸€æ øP¼Œ˜q™é‡Œä¹Ÿå®šä¹‰äº†managed-beançš„scope为sessionã€?/p> <p>ã€€ã€€ä½†æ˜¯å¦‚æžœä½ åªä»¥äØ“JSFçš„managed-beanž®Þp¿™ç‚¹åŠŸèƒ½å°±é”™äº†åQŒJSF融入了新的Ioc模式/依赖性注ž®„等技术ã€?/p> <p> <strong>Ioc模式</strong> </p> <p>  对于Userbean˜q™æ ·ä¸€ä¸ªmanaged-beanåQŒå…¶ä»£ç å¦‚下åQ?/p> <p>public class UserBean {<br />  private String name;<br />  private String password;</p> <p>  // PROPERTY: name<br />  public String getName() { return name; }<br />  public void setName(String newValue) { name = newValue; }</p> <p>  // PROPERTY: password<br />  public String getPassword() { return password; }<br />  public void setPassword(String newValue) { password = newValue; }<br />}<br /></p> <table width="90%" bgcolor="#cccccc" border="0"> <tbody> <tr> <td> <p> </p> <p><managed-bean><br />  <managed-bean-name>user</managed-bean-name><br />  <managed-bean-class>com.corejsf.UserBean</managed-bean-class><br />  <managed-bean-scope>session</managed-bean-scope><br /><br />  <managed-property><br />    <property-name>name</property-name><br />    <value>me</value><br />  </managed-property><br /><br />  <managed-property><br />    <property-name>password</property-name><br />    <value>secret</value><br />  </managed-property><br /></managed-bean></p> </td> </tr> </tbody> </table> <p>  faces-config.xml˜q™æ®µé…ç½®å…¶å®žæ˜¯å°†"me"赋值给nameåQŒå°†secret赋值给passwordåQŒè¿™æ˜¯é‡‡å?a target="_blank">Ioc模式中的Setter注射方式</a>ã€?/p> <p> <strong>Backing Beans</strong> </p> <p>  对于一个web formåQŒæˆ‘们可以ä‹É用一个bean包含其涉及的所有组ä»Óž¼Œ˜q™ä¸ªbeanž®Þq§°ä¸ºBacking BeanåQ?Backing Bean的优ç‚ÒŽ˜¯åQšä¸€ä¸ªå•个类可以ž®è£…相关一¾pÕdˆ—功能的数据和逻辑ã€?/p> <p>  说白了,ž®±æ˜¯ä¸€ä¸ªJavabean里包含其他JavabeanåQŒäº’相调用,属于Facade模式或Adapter模式ã€?/p> <p> <br />  对于一个Backing Beans来说åQŒå…¶ä¸­åŒ…含了几个managed-beanåQŒmanaged-bean一定是有scope的,那么˜q™å…¶ä¸­çš„几个managed-beans如何配置它们的scope呢?</p> <table width="90%" bgcolor="#cccccc" border="0"> <tbody> <tr> <td><managed-bean><br />  ...<br />  <managed-property><br />    <property-name>visit</property-name><br />    <value>#{sessionScope.visit}</value><br />  </managed-property><br /></td> </tr> </tbody> </table> <p>  ˜q™é‡Œé…ç½®äº†ä¸€ä¸ªBacking Beans中有一个setVisitæ–ÒŽ³•åQŒå°†˜q™ä¸ªvisit赋å€égØ“session中的visitåQŒè¿™æ ·ä»¥åŽåœ¨½E‹åºä¸­æˆ‘们只½Ž¡è®¿é—®visit对象åQŒä»Žä¸­èŽ·å–æˆ‘ä»¬å¸Œæœ›çš„æ•°æ®åQˆå¦‚用户登陆注册信息åQ‰ï¼Œè€Œvisit是保存在session˜q˜æ˜¯application或request只需要配¾|®æ—¢å¯ã€?/p> <p> <strong>UI界面</strong> </p> <p>  JSFå’ŒStrutsä¸€æ øP¼Œé™¤äº†JavaBeans¾cÖM¹‹å¤–,˜q˜æœ‰™åµé¢è¡¨çŽ°å…ƒç´ åQŒéƒ½æ˜¯æ˜¯ä½¿ç”¨æ ‡ç­¾å®Œæˆçš„,Struts也提供了struts-faces.tld标签库向JSF˜q‡æ¸¡ã€?/p> <p>  使用Struts标签库编½E‹å¤æ‚页面时åQŒä¸€ä¸ªæœ€å¤§é—®é¢˜æ˜¯ä¼šå¤§é‡ä‹É用logic标签åQŒè¿™ä¸ªlogic如同if语句åQŒä¸€æ—¦å†™èµäh¥åQŒæžçš„JSP™åµé¢è±¡ä¿„¾|—æ–¯æ–¹å—ä¸€æ øP¼Œä½†æ˜¯ä½¿ç”¨JSF标签ž®Þq®€‹zä¼˜¾ŸŽï¼š</p> <table width="90%" bgcolor="#cccccc" border="0"> <tbody> <tr> <td> <p><jia:navigatorItem name="inbox" label="InBox"<br />  icon="/images/inbox.gif"<br />  action="inbox"<br />  disabled="#{!authenticationBean.inboxAuthorized}"/><br /></p> </td> </tr> </tbody> </table> <p>  如果authenticationBean中inboxAuthorized˜q”回是假åQŒé‚£ä¹ˆè¿™ä¸€è¡Œæ ‡½{‘Ö°±ä¸ç”¨æ˜„¡¤ºåQŒå¤šòq²å‡€åˆ©çƒ¦åQ?/p> <p>  先写到这里,我会¾l§ç®‹å¯¹JSF深入比较下去åQŒå¦‚果研½I¶è¿‡Jdon框架的ähåQŒå¯èƒ½ä¼šå‘现åQŒJdon框架的jdonframework.xml中service配置和managed-bean一样都使用了依赖注ž®„,看来对Javabean的依赖注ž®„å·²¾lè¿…é€Ÿåœ°æˆäØ“ä¸€¿Uæ–°æŠ€æœ¯è±¡å¾ï¼Œå¦‚果你还不了解Ioc模式åQŒèµ¶ç´§è¡¥è¯¾ã€?/p> <p>附Jsf核心教程一个JSF案例:<a target="_blank">login.rar</a></p> <p>相关讨论åQ?/p> <p> <a target="_blank">表现层框架Struts/Tapestry/JSF架构比较</a> </p> <p> <a target="_blank">讨论</a> </p> <img src ="http://www.aygfsteel.com/Goodtiger/aggbug/79677.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/Goodtiger/" target="_blank">GoodtigerZhao</a> 2006-11-07 19:38 <a href="http://www.aygfsteel.com/Goodtiger/archive/2006/11/07/79677.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <a href="http://www.aygfsteel.com/" title="狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频">狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频</a> </div> </footer> Ö÷Õ¾Ö©Öë³ØÄ£°å£º <a href="http://" target="_blank">½ðËþÏØ</a>| <a href="http://" target="_blank">ÍÁÄ¬ÌØÓÒÆì</a>| <a href="http://" target="_blank">ÀÖ¶¼ÏØ</a>| <a href="http://" target="_blank">°ÝÈªÏØ</a>| <a href="http://" target="_blank">ƽÎäÏØ</a>| <a href="http://" target="_blank">¹âÉ½ÏØ</a>| <a href="http://" target="_blank">³¤ÖÎÊÐ</a>| <a href="http://" target="_blank">ãòÎ÷ÏØ</a>| <a href="http://" target="_blank">º£ÄþÊÐ</a>| <a href="http://" target="_blank">ÆÕÀ¼ÏØ</a>| <a href="http://" target="_blank">×Þ³ÇÊÐ</a>| <a href="http://" target="_blank">ÐÂÃñÊÐ</a>| <a href="http://" target="_blank">×ÊÏªÏØ</a>| <a href="http://" target="_blank">Õ¿½­ÊÐ</a>| <a href="http://" target="_blank">°ÍÖÐÊÐ</a>| <a href="http://" target="_blank">´óÓ¢ÏØ</a>| <a href="http://" target="_blank">ãä½­ÊÐ</a>| <a href="http://" target="_blank">½¨Ê¼ÏØ</a>| <a href="http://" target="_blank">±£¿µÏØ</a>| <a href="http://" target="_blank">ººÊÙÏØ</a>| <a href="http://" target="_blank">Íþº£ÊÐ</a>| <a href="http://" target="_blank">ÔÆºÍÏØ</a>| <a href="http://" target="_blank">¶þÁ¬ºÆÌØÊÐ</a>| <a href="http://" target="_blank">³£É½ÏØ</a>| <a href="http://" target="_blank">ƽºþÊÐ</a>| <a href="http://" target="_blank">ÎÚÀ­ÌØÇ°Æì</a>| <a href="http://" target="_blank">ä¬ÄÏÊÐ</a>| <a href="http://" target="_blank">¸·¿µÊÐ</a>| <a href="http://" target="_blank">¶«Ý¸ÊÐ</a>| <a href="http://" target="_blank">ÈýÃÅÏØ</a>| <a href="http://" target="_blank">»ÆÁêÏØ</a>| <a href="http://" target="_blank">äðºÓÊÐ</a>| <a href="http://" target="_blank">¿µ±£ÏØ</a>| <a href="http://" target="_blank">ÄÏÑôÊÐ</a>| <a href="http://" target="_blank">ÊÓÆµ</a>| <a href="http://" target="_blank">ÎÞé¦ÏØ</a>| <a href="http://" target="_blank">ÎÚ³ľÆëÏØ</a>| <a href="http://" target="_blank">ÎijÉÏØ</a>| <a href="http://" target="_blank">á·É½ÏØ</a>| <a href="http://" target="_blank">É£Ö²ÏØ</a>| <a href="http://" target="_blank">°×Ë®ÏØ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>