??xml version="1.0" encoding="utf-8" standalone="yes"?> 关于此特性的介绍请参考:http://jakarta.apache.org/tapestry/current/UsersGuide/page-class.html 说明Q?BR>通俗点说是您可以不定义.page文g或者定义的.page文g中不指定class 属性,而让服务器自动根?html文g的\径来L对应的类文g?配置Q?BR>?application的定义文件中dQ?
q样如果在文档根目录下有个Home.html文gQ你可以将Home.java攑ֈ org.edynasty.pages(实际开发中配置为您自己的包?包中Qtapestry自动Ҏ Home.hmtl构造org.edynasty.pages.Home来定位页面的cL?当然您也可以在WEB -INF目录下放一个Home.page,不需要定义class属性,tapestry自动按照上边的原 理定位?效果Q?BR>q样您可以不需要维?page中的class属性,直接Ҏ.html文g来写对应 的类文g。而且可以Ҏ业务逻辑来定义目录结构,例如?org.edynasty.pages.user定义为user相关的类Q?html也就可以攑ֈuser目录?边,目录l构如下Q?user/ListUsers.html user/EditUser.html course/ListCourses.html course/EditCourses.html Home.html 一、default binding types(默认的绑定类?
加粗的部分显C前后的变化Q之所以可以这样定义,是因为Insertlg定义value参数的默认绑定类型ؓongl. 修订Q?/STRONG> 从beta4版本开始,此特性已l被删除Q? Beta4的change logQ?/P>
Remove default-binding attribute from element(HLS) 但是“如果没有定义默认的l定参数Q那么在html模板中定义的默认l定参数为literalQ页面定义文仉的默认绑定参Cؓognl”这个效果经试依然存在? 怀念: 此段文字在beta3中存在,beta4后就删掉了! Tapestry 4.0 introduces a new idea: default binding types. Each component parameter may define a default binding type (using the default-binding attribute of the If a binding reference does not have a prefix, the default binding type is used. Because of this, the following two snippets are identical: This works because the Insert component defines the default-binding for the value parameter to be "ognl". Likewise, the source and value parameters of the Foreach component are defined to be "ognl". However, the element parameter of the Foreach component has a binding type of "literal". This is a decision made by the component author. If a particular parameter is (nearly) always bound using a particular binding type, then a default-binding may be set. The default binding can always be overriden with an explicit binding type prefix. What about parameters that don't define a default binding type? The answer to this question (which includes all informal parameters), is that it depends on whether the parameter is bound in an HTML template, or in a page or component specification. In an HTML template, the default binding type is "literal". In a specification, the default binding type is "ognl". W二U方法比较符合Y件的设计思维Q而且参数的类型在传入后保存,而不是想象中的统一Stringcd?BR>例如Q?BR>. . .
Tapestry4新特??-源代码标注的异常处理
Tapestry本来提供的debug功能十分强大,4.0版本中提供了更加详细的报错机Ӟ可以昄错误的代码,q在报错的地方加亮标注,具体截图L附g(谁能告诉我怎么多余的照片删除呀)
Tapestry4新特??-Friendly URLs
Tapestry4.0以前版本中的URL一直被人所诟病Q当然现在已l有很多的解x
案,4.0版本中已l对此做了改q,
因ؓ现在的版本需要通过hivemind来配|,所以需要设|hivemind.xml中的一些属
性,具体配置如下Q?BR><?xml version="1.0"?>
<module id="tapestry4" version="1.1.0">
<contribution configuration-id="tapestry.url.ServiceEncoders">
<page-service-encoder id="page" extension="html" service="page"/>
<direct-service-encoder id="direct" stateless-extension="direct"
stateful-extension="sdirect"/>
<asset-encoder id="asset" path="/assets/"/>
<extension-encoder id="extension" extension="svc" after="*"/>
</contribution>
</module>
同时web.xml中加入映:
<servlet>
<servlet-name>tapestry4</servlet-name>
<servlet-class> org.apache.tapestry.ApplicationServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>tapestry4</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>tapestry4</servlet-name>
<url-pattern>*.direct</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>tapestry4</servlet-name>
<url-pattern>*.sdirect</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>tapestry4</servlet-name>
<url-pattern>/assets/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>tapestry4</servlet-name>
<url-pattern>*.svc</url-pattern>
</servlet-mapping>
如果希望首页的调用不是通过/app来映,可以在web.xml中更改redirectQ?BR><filter-name>redirect</filter-name>
<filter-class>org.apache.tapestry.RedirectFilter</filter-class>
<init-param>
<param-name>redirect-path</param-name>
<param-value>/Home.html</param-value>
</init-param>
</filter>
q样键入http://localhost:8080/tapestry4Q系l导航到http://localhost:
8080/tapestry4/Home.html,
d一个Page面例如Test.pageQ在Home.html中加?lt;a href="#"
jwcid="@PageLink" page="Test">test</a>Q?BR>在生成的Home.html中生成的test的链接地址为:http://localhost:
8080/tapestry4/Test.html
Tapestry4新特??-自动定位面cL?/STRONG>
Tapestry4新特??-Application和Session范围对象的?/STRONG>
Application和Session范围对象的?BR>
关于此特性的介绍请参考:http://jakarta.apache.org/tapestry/UsersGuide/state.html
说明Q?BR>Application和Session范围的概念就不说了,T4以前的版本只可以分别指定一个对象,
以前版本的定义如?
<property name="org.apache.tapestry.visit-class" value="your.package.Visit"/>
<property name="org.apache.tapestry.global-class" value="your.package.Global"/>,
T4中可以指定Q意多的对象,而且默认的visit和global仍然可以使用?BR>
配置Q在hivemodule.xml的定义文件中dQ?BR><contribution configuration-id="tapestry.state.ApplicationObjects">
<state-object name="applicationUser" scope="application">
<create-instance class="org.edynasty.model.User"/>
</state-object>
<state-object name="sessionUser" scope="session">
<create-instance class="org.edynasty.model.User"/>
</state-object>
</contribution>
两个user分别对应Application和Session范围Q在需要用user的page中注入:
<inject property="applicationUser" type="state" object="applicationUser"/>
<inject property="sessionUser" type="state" object="sessionUser"/>Q通过
getter和setterҎ调用?BR>
效果Q怎么说呢Q可以不需要在一个visit中定义N多属性,因ؓSession的创建需要资源,
只要操作一个visit的属性,需要创建整个visitQ分别定义之后,可以在需要存取时分别创徏?/TD>
]]>
Tapestry4新特?一)Qdefault binding types
每一个组件的参数都可以定义默认的l定cdQ如果一个绑定的参数没有前缀Q将使用默认的绑定类型?BR> 下面的代码实现同L功能:
注意Q默认的l定参数L可以被显式的l定声明覆盖掉?BR> 如果没有定义默认的绑定参敎ͼ那么在html模板中定义的默认l定参数为literalQ页面定义文仉的默认绑定参CؓognlBinding Type Defaults
Tapestry4新特??Qlistener method
二、listener method
如果使用qtapestry的应该知道listenerҎ?.X以前版本中的定义Q如public void formSubmit(IRequestCycle cycle)Q方法必?BR>有一个IRequestCycle参数。参数的取得方式如下QObject[] parameters = cycle.getServiceParameters();
?.X中参数的取得可以通过以下两种方式Q?BR>
其中objectId为StringcdQindex为intQ声明中使用了默认的参数l定cd?
对应的方法声明如?
public void doClick(String objectId, int index)
{ . . . }
此ؓW二U方式,可见Ҏ的定义符合自然习惯,当然你也可以通过传统的方法,如下所C: public void doClick(IRequestCycle cycle)
{ Object[] parameters = cycle.getListenerParameters();
String objectId = (String)parameters[0];
int index = ((Integer)parameters[1]).intValue(); . . . }
q种方式是ؓ了向后兼容以前的版本Q当然也适用那种参数数目不确定的情况?Tapestry默认搜烦以下的方法声明:
不要试图通过参数的类型来映射listenerҎQtapestry是根据参数的数目来确定方法的?BR>
Tapestry4新特??Qglobal property source
三、Global Property Source(全局的消息属性配|?
消息属性配|听h不是很舒服,暂时q样U呼好了Q消息属性配|也是通称的国际化?BR>|,通过配置一个properties文g使不同语a的浏览者看到对应语a的版本,一?BR>的用如下,一个page面Q例如example.page,同目录下放一?BR>example.properties,?example.html中?SPAN key="key">来指定显C|
中文可以使用example_zh_CN.properties来配|。看h挺方便的Q可
tapestry4.0以前的版本的国际化不支持全局的属性配|文Ӟ必须每个面定义
自己的,无法几个面׃nQ但实际开发中Q多面׃n属性配|是很常见的Q?BR>tapestry4.0中可以通过以下方式获得全局的属性配|文Ӟ
创徏一个跟你的目全局配置文gQ如yourApp.application,此文件在4.0以前?BR>版本中是必须的,4.0中如果没有必要配|,可以不需要此文g(扯远?,yourApp
是根据你在web.xml定义的,例如
那属性定义文件就应该是tapestry4.properties,q样在此文g中定义一个:test=
试Q在Home.html中?lt; span key="test">test,看到“测试”正显C?BR>
]]>
没有一U新技术是凭空诞生的,它的萌芽或胚胎L或多或少昄于以前的技术中QJive论坛是大家潜心研I的设计型应用程序,其相兌析可见本栏的GoF设计模式专栏?/P>
Jive和Spring同ؓ由JavaBeansl成的J2EE WebpȝQJive作ؓ早期成功设计案例Q其主要架构成ؓ大多数纯JavaBeanspȝ的流行架构,Spring也不例外?/P>
Spring框架除了是一UWeb层应用框Ӟq提供了讉KEJB层的接口Q也有JDBC/ORM的直接操作。Spring框架主要力是用IoC模式和AOP实现了Jivepȝ的通用功能Q从而得Jiveq样的纯JavaBeans架构设计可以重用在其它系l中?/P>
如果你感慨于Jive的设计理念,但是又苦于无法重用其设计ӞSpring框架已经帮你实现了?/P>
同时也要注意刎ͼSpring框架cM“杂烩”,它包含了很多J2EE应用的工Pcd对EJB的调用,它的MVC与Struts JSF也是相竞争的Q以UIoc和AOP设计来说QSpring框架也是一U很重的(Heavy、Weight)框架。Spring框架是复杂的Q如果想以Spring替代EJBQ那么无疑按了葫芦QL?/P>
Jive论坛和Spring框架联系hQ会帮助更多理解设计模式的程序员q速掌握最新的设计思潮Q而不是一U蟩跃式的强q接受。如果你对Jive有很好的研究Q将会发现Spring框架是Jive设计的更加通用的提升?/P>
在Jive?ForumFactory是整个系l的入口和突破点QJive通过ForumFactory整个系l掌控在一个工厂模式下Q这样做的好处是Q便于控制系l的JavaBeansQ例如,客户端通过ForumFactory可创Z个Forum或访问一个ForumQ但是是否有权限讉K呢?如下图:
Jive通过ForumFactory这U访问引导到相应的ProxycdQ如ForumFactoryProxycȝQ通过代理模式对这些类q行权限控制讉K。这是代理模式的一个主要用处,但是研读Jive的代理模式会发现Q要为每个类实现一个Proxyc,非常琐碎Q有没有更优雅的方式呢? 当然使用动态代理?/P>
Spring框架基本是抽象上q设计,Spring框架Ҏ有JavaBeans的管理也是基于一个d口Bean Factory机制Q不同的是,BeanFactory可以 理所有应用的JavaBeansQ用者只要将自己的JavaBeans通过配置文g告诉BeanFactoryQ那么BeanFactory会加蝲q些JavaBeansQ例如:
<beans>
<bean id="exampleBean" class="eg.ExampleBean"/>
<bean id="anotherExample" class="eg.ExampleBeanTwo"/>
</beans>
在Jive中,ForumFactory加蝲Jive自己的JavaBeans是通过工厂实现DbForumFactory实现的,如下代码QDbForumFactory引发了后Cpd功能实现Q这是纵向,而return new ForumFactoryProxyq个语句则类似引来一个切面,从一个横向方面实C权限讉K{功能:
private static String className = "com.jivesoftware.forum.database.DbForumFactory"; public static ForumFactory getInstance(Authorization authorization) { try { //Now, q回 proxy.用来限制授权对forum的访? |
既然Spring框架也是通过一个Bean Factory加蝲所有的c,那么它是如何加蝲的?通过IoC模式Q也是依赖性注模式。在我以前文章?A target=_blank>IoC模式”中Q我比较了Factory工厂模式创徏对象和Ioc模式的注对象实C间的异同QIoc相比工厂模式则更加解耦了调用者和被调用者之间关p,使用Ioc模式Q无需在调用者代码中涉及被调用者的具体实现?/P>
Spring框架不但可以向自己容器中注射应用者自己定义的JavaBeansQ也是创徏它们Q,而且也可以向q些JavaBeans通过setҎ实现数据赋倹{?/P>
一旦Bean Factoryq行时刻掌管q些Ȁzȝ对象QSpring通过AOP方式Q从一个横切面些JavaBeans提供了权限访问、事务锁{通用功能的实玎ͼq种实现是基于动态代理模式,而动态代理是AOP实现的一U方式?/P>
前面提到QJive中用代理模式实现权限访问,比代理模式更加简z和抽象的是动态代理,使用动态代理将使得调用者无需指定被调用者的代理c,q是动态代理区别代理模式的本质?/P>
动态代理这一优势Q又可以体现在另外一句话语上Q动态代理拦截了调用者对被调用者的调用Q正是这一功能W合了AOP的拦截器功能QؓAOP实现提供了可能?/P>
Spring框架使用了动态代理实现的AOPQ正是通过动态代理机制拦截了外界对Bean Factory理下的对象的调用。如下图Q?/P>
以上只是大体解构了Spring的架构,Spring框架在这个架构下Q还带了很多其它功能,如Web MVC?DAO JDBC?DAO ORM 、以及remoteQ后者类似我设计的EJBҎ调用框架?/P>
MQSpring实是Ioc和AOP的完应用,Ioc用来装蝲JavaBeansQ创些对象;AOP用来拦截q些对象的用,q才是框架设计的必然l典方式?/P>
ZT:
http://www.zahui.com/html/6/40477.htm
java代码: |
public interface Person { public int getAge() throws Throwable; public String getName() throws Throwable; } |
java代码: |
public class PersonServer implements Person { int age; String name; public PersonServer(String name, int age) { this.age = age; this.name = name; } public int getAge() { return age; } public String getName() { return name; } } |
java代码: |
import java.io.ObjectOutputStream; import java.io.ObjectInputStream; import java.net.Socket; public class Person_Stub implements Person { Socket socket; public Person_Stub() throws Throwable { // connect to skeleton socket = new Socket("computer_name", 9000); } public int getAge() throws Throwable { // pass method name to skeleton ObjectOutputStream outStream = new ObjectOutputStream(socket.getOutputStream()); outStream.writeObject("age"); outStream.flush(); ObjectInputStream inStream = new ObjectInputStream(socket.getInputStream()); return inStream.readInt(); } public String getName() throws Throwable { // pass method name to skeleton ObjectOutputStream outStream = new ObjectOutputStream(socket.getOutputStream()); outStream.writeObject("name"); outStream.flush(); ObjectInputStream inStream = new ObjectInputStream(socket.getInputStream()); return (String)inStream.readObject(); } } |
java代码: |
import java.io.ObjectOutputStream; import java.io.ObjectInputStream; import java.net.Socket; import java.net.ServerSocket; public class Person_Skeleton extends Thread { PersonServer myServer; public Person_Skeleton(PersonServer server) { // get reference of object server this.myServer = server; } public void run() { try { // new socket at port 9000 ServerSocket serverSocket = new ServerSocket(9000); // accept stub's request Socket socket = serverSocket.accept(); while (socket != null) { // get stub's request ObjectInputStream inStream = new ObjectInputStream(socket.getInputStream()); String method = (String)inStream.readObject(); // check method name if (method.equals("age")) { // execute object server's business method int age = myServer.getAge(); ObjectOutputStream outStream = new ObjectOutputStream(socket.getOutputStream()); // return result to stub outStream.writeInt(age); outStream.flush(); } if(method.equals("name")) { // execute object server's business method String name = myServer.getName(); ObjectOutputStream outStream = new ObjectOutputStream(socket.getOutputStream()); // return result to stub outStream.writeObject(name); outStream.flush(); } } } catch(Throwable t) { t.printStackTrace(); System.exit(0); } } public static void main(String args []) { // new object server PersonServer person = new PersonServer("Richard", 34); Person_Skeleton skel = new Person_Skeleton(person); skel.start(); } } |
java代码: |
public class PersonClient { public static void main(String [] args) { try { Person person = new Person_Stub(); int age = person.getAge(); String name = person.getName(); System.out.println(name + " is " + age + " years old"); } catch(Throwable t) { t.printStackTrace(); } } } |
java代码: |
try { InitialContext ctx = new InitialContext(); //W一?/SPAN> UserServiceHome home = (UserServiceHome) PortableRemoteObject.narrow( ctx.lookup(JNDIString), UserServiceHome.class); //home: _UserServiceHome_Stub System.out.println(home.toString()); //W二?/SPAN> UserService object = home.create(); //ojbect: _UserService_Stub System.out.println(object.toString()); //W三?/SPAN> int userId = 1; UserInfo ui = object.getUserInfo(userId); } |
java代码: |
UserServiceHome home; UserService obj = home.create(); |
java代码: |
org.omg.CORBA.portable.OutputStream out = _request("create", true); in = (org.omg.CORBA_2_3.portable.InputStream)_invoke(out); |
java代码: |
_EJSRemoteStatelessUserServiceHome_a940aa04_Tie._invoke() { ...... switch (method.length()) { case 6: if (method.equals("create")) { return create(in, reply); } ...... } } |
java代码: |
_EJSRemoteStatelessUserServiceHome_a940aa04_Tie.create() { EJSRemoteStatelessUserServiceHome_a940aa04 target = null; result = target.create(); org.omg.CORBA.portable.OutputStream out = reply.createReply(); Util.writeRemoteObject(out,result); return out; } |
java代码: |
EJSRemoteStatelessUserServiceHome_a940aa04.create() { UserService _EJS_result; _EJS_result = EJSStatelessUserServiceHomeBean_a940aa04.create(); } |
java代码: |
UserService result = super.createWrapper(new BeanId(this, null)); |
java代码: |
UserService object; object.getUserInfo(userId); |
java代码: |
org.omg.CORBA.portable.OutputStream out = _request("getUserInfo", true); out.write_long(arg0); in = (org.omg.CORBA_2_3.portable.InputStream)_invoke(out); |
java代码: |
_EJSRemoteStatelessUserService_a940aa04_Tie._invoke() { switch (method.charAt(5)) { case 83: if (method.equals("getUserInfo")) { return getUserInfo(in, reply); } ...... } } _EJSRemoteStatelessUserService_a940aa04_Tie.getUserInfo() { EJSRemoteStatelessUserService_a940aa04 target = null; int arg0 = in.read_long(); UserDTO result = target.getUserInfo(arg0); org.omg.CORBA_2_3.portable.OutputStream out = reply.createReply(); out.write_value(result,UserDTO.class); return out; } |
java代码: |
EJSRemoteStatelessUserService_a940aa04.getUserInfo() { UserServiceBean _EJS_beanRef = container.preInvoke(this, 0, _EJS_s); _EJS_result = _EJS_beanRef.getUserInfo(id); } |