- 浏览: 1208544 次
- 性别:
- 来自: 广州
文章分类
- 全部博客 (353)
- java基础 (40)
- tapestry (16)
- gwt (14)
- ajax (7)
- linux (8)
- ubuntu (18)
- eclipse (6)
- dojo (2)
- javascript (7)
- maven (4)
- 日常生活 (29)
- web2.0 (2)
- jsonrpc (1)
- compass (1)
- lucene (0)
- spring (10)
- cluster (3)
- 数据结构 (2)
- sqlserver (1)
- tomcat (2)
- swing (1)
- servlet (1)
- hibernate (1)
- firefox (1)
- Java-Puzzlers (1)
- Wicket (2)
- mysql (10)
- windows (5)
- Webwork (1)
- struts2 (1)
- Seam (2)
- jboss (1)
- idea (6)
- 分布计算 (3)
- Python-Django (7)
- Hadoop (1)
- 工具 (3)
- Tokyo Tyrant (2)
- Comet (1)
- android (115)
- 音乐 (6)
- cxf (1)
- mqtt (1)
最新评论
-
hesai_vip:
学习了,感谢
gradlew wrapper使用下载到本地的gradle.zip文件安装。 -
imknown:
姚瑶大坏蛋 写道我也遇到了这个,用你这个方法,导致下拉刷新不起 ...
解决android-Ultra-Pull-To-Refresh下拉刷新组件中嵌套ViewPager的一个bug -
姚瑶大坏蛋:
我也遇到了这个,用你这个方法,导致下拉刷新不起作用了,你遇到过 ...
解决android-Ultra-Pull-To-Refresh下拉刷新组件中嵌套ViewPager的一个bug -
寐语者:
LeaderElection(String zookeeper ...
使用Zookeeper来为你的程序加上Leader Election的功能。 -
fyc0109:
博主, 安装了一部分还是报这个错误!FAILURE: Buil ...
gradlew wrapper使用下载到本地的gradle.zip文件安装。
有许多页面的一部分或者这个页面是很少更新的,他们通常是由外部文件来生成这个部分。所以我们可以把这部分内容cache住,当有新的请求时,我们就response cache,这样可以减少服务器的负担,还可以提高性能。其中oscache已经可以实现页面的cache和页面部分cache。oscache使用jsp tags来实现局部cache的。拿到Tapestry中肯定是行不通的。在同事的提醒下,想到写这个Tapestry的cache组件来达到重用的目的。
说干就干,先在头脑中想好要怎样使用cache(页面上的布局)。ok。 我想好了。
这里有2个参数,updateCondition 当为true时,我们就绕过cache, cacheProvider 我把他定义为一个接口,这样用户可以把cache存在任何地方。而且提供这样的一个接口,用户可以更好的操作cache。先看看jwc对cache组件的定义。
下面的是ICacheProvider接口:
ok。 再来看看Cache组件的代码。
在使用中你可以把CacheProvider放到Global或者Visit对象中。注意要使用同一个CacheProvider。
本来我是打算用oscache来实现了。 其实oscache自己带了filter来处理cache。 我想尽量把他做简单点。 容易理解。 其实你可以看到 我的这个组件需要提供个CacheProvider。 这个是个接口。 所以这样的话, 你想使用任何cache都是可以的。 只要用你现在用的cache实现CacheProvider就行了。 这样岂不是更灵活???
这里说说我的想法, 这个Cache主要是cache页面的,你想到的比较多,可能你忘了Cache组件中有个updateCondition 属性, 其实我是不太赞成ICacheProvider的removeCache这个方法的,这也是我开始想到使用idpath作为cacheKey的原因,用户不需要知道太多的东西。他仅仅需要知道什么时候我需要让tapestry重新生成一下Body的内容就行。 他也就需要实现updateConditon这个component方法。争对你说的这种场景, 我在updateCondition这个方法里面去判断数据库里面的最新帖子的时间和你生成cache时最新帖子的时间来比较(你可以保存在一个singtlon对象里面),如果时间更新了,return true就ok了。 其实我现在这个项目中也是这种情况,首页内容部分是由管理员upload的一个文件(owl file)生成的内容。这时候我在MiscUtils类里面有个checkOWLFileUpdated()方法去判断owl时候发生了变化, 也是使用file的lastmodfy time来判断的。 我在Cache组件中仅仅是非常方便的委派MiscUtils的那个方法而已。
你在上面也提到了主动的方式,就是在发表玩帖子的时候去设置updateCondition为true。其实你只要把这个值set到一个singlton类属性里面就ok了。 updateCondition方法就去check那个值吧。 我不是很赞成这种做法,因为他把一些非业务相关的逻辑加了进来,可能你会说我可以用aop方便的搞定这个。 但是我还是觉得判断cache是否要更新就让Cache组件来作罢(updateCondition)。
开始时我觉得这个cacheKey其实可以对用户不见的,用户不用关心cache的内容。其实这里的cache的内容也就是cache组件的body render之后的html source。但是ICacheProvider提供了removeCache这个方法。假如用idPath的对用户来说确实是不友好的。 指定cacheKey值的话,可读性也很高。这个想法不错。我会加入这个功能,多加个cacheKey属性,假如用户关心的话就指定, 不指定的话默认就是idpath。
<span cacheProvider="ognl:cacheProvider" cacheKey="literal:Home:news" updateCondition="ognl:needUpdate">
//body ....
</span>
@InjectCache("Home:news")
public CacheContent getHomeNewsCache();
你这个annotation的意思是获得cache的内容么? 我这里可能有多个cacheProvider, 而且我想用户可以方便的通过cacheProvider去拿到cache content。 再者我想用户肯定不会想去自己updateCache的内容,因为这个body是tapestry解析后的内容,我想用户关系的只是现在cache中的内容是不是stale的。我现在需不需要更新这个cache。 获得cache的内容交给tapestry来处理。 其实这个组件的目的也是主要是想cache页面的html source而已。
现在想要更新cache中的内容的话, 你只需要让updateCondition为true, 或者让对应的cache 内容为null 即可。
非常谢谢tapestry提供的建议,欢迎一起研究。
说干就干,先在头脑中想好要怎样使用cache(页面上的布局)。ok。 我想好了。
xml 代码
- <span jwcid="@Cache" cacheProvider="ognl:cacheProvider" updateCondition="ognl:needUpdate">
- //Cache body, which is the content you want to cache.
- <!---->span>
这里有2个参数,updateCondition 当为true时,我们就绕过cache, cacheProvider 我把他定义为一个接口,这样用户可以把cache存在任何地方。而且提供这样的一个接口,用户可以更好的操作cache。先看看jwc对cache组件的定义。
xml 代码
- xml version="1.0" encoding="UTF-8"?>
- "-//Apache Software Foundation//Tapestry Specification 4.0//EN"
- "http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd">
- <component-specification allow-body="yes" allow-informal-parameters="no" class="com.live.spaces.dengyin2000.tapestry.tfancomponents.components.Cache">
- <description>
- Cache component, this component can inclue any content as its body, and cache its body.
- This is useful in rarely updated content.
- <!---->description>
- <parameter name="updateCondition" required="no" default-value="false">
- <description>
- The flag that need to refresh cache, it would casue tapestry render not use the cache.
- <!---->description>
- <!---->parameter>
- <parameter name="cacheProvider" required="yes">
- <description>
- You need to provider an cache provider to store its body content. for some simply use.
- Please see @com.live.spaces.dengyin2000.tapestry.tfancomponents.components.SimpleHtmlSourceCacheProvider
- <!---->description>
- <!---->parameter>
- <!---->component-specification>
下面的是ICacheProvider接口:
java 代码
- package com.live.spaces.dengyin2000.tapestry.tfancomponents.components;
- /**
- * @author Denny - deng.yin@gmail.com
- * @since 2006-12-21
- */
- public interface ICacheProvider {
- /**
- *
- * @param cacheKey
- * @param cacheContent
- */
- public void storeCache(String cacheKey, String cacheContent);
- /**
- *
- * @param cacheKey
- * @return
- */
- public String getCacheContent(String cacheKey);
- /**
- * This method provider to user, so that user can controll cache manaully.
- * @param cacheKey
- */
- public void removeCache(String cacheKey);
- /**
- * This method provider to user, so that user can controll cache manaully.
- * Clear all caches
- *
- */
- public void reset();
- }
ok。 再来看看Cache组件的代码。
java 代码
- package com.live.spaces.dengyin2000.tapestry.tfancomponents.components;
- import java.io.PrintWriter;
- import java.io.StringWriter;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.apache.tapestry.AbstractComponent;
- import org.apache.tapestry.IMarkupWriter;
- import org.apache.tapestry.IRequestCycle;
- import org.apache.tapestry.util.ContentType;
- /**
- * @author Denny deng
- *
- */
- public abstract class Cache extends AbstractComponent {
- protected static final Log logger = LogFactory.getLog(Cache.class);
- public abstract boolean getUpdateCondition();
- public abstract ICacheProvider getCacheProvider();
- @Override
- protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle) {
- if (getUpdateCondition()){
- renderComponentWithCache(writer, cycle);
- }else{
- if (getCacheProvider().getCacheContent(this.getIdPath()) != null){
- //response cache html content.
- writer.printRaw(getCacheProvider().getCacheContent(this.getIdPath()));
- }else{
- renderComponentWithCache(writer, cycle);
- }
- }
- }
- private void renderComponentWithCache(IMarkupWriter writer, IRequestCycle cycle) {
- logger.debug("We need to refresh cache now.");
- CacheWriterWrapper cacheWrapper = new CacheWriterWrapper();
- super.renderBody(buildCacheMarkupWriter(cacheWrapper.getPrintWriter(), writer), cycle);
- String cacheContent = cacheWrapper.getCacheContent();
- logger.debug("fetched cache content, ready to put it into cache.");
- getCacheProvider().storeCache(this.getIdPath(), cacheContent);
- // response html content.
- writer.printRaw(cacheContent);
- }
- private IMarkupWriter buildCacheMarkupWriter(PrintWriter writer, IMarkupWriter sourceWriter){
- return this.getPage().getRequestCycle().getInfrastructure().getMarkupWriterSource().newMarkupWriter(writer, new ContentType(sourceWriter.getContentType()));
- }
- class CacheWriterWrapper{
- private StringWriter sw;
- private PrintWriter pw;
- public CacheWriterWrapper() {
- sw = new StringWriter();
- pw = new PrintWriter(sw);
- }
- public String getCacheContent(){
- return sw.getBuffer().toString();
- }
- public PrintWriter getPrintWriter(){
- return pw;
- }
- }
- }
主要是得到cache组件body的内容,然后把body的内容cache住,下次的话就response Cache的内容。 其实也是满简单的。
我自己还写了一个简单CacheProvider。
java 代码
- package com.live.spaces.dengyin2000.tapestry.tfancomponents.components;
- import java.util.HashMap;
- import java.util.Map;
- /**
- * @author Denny - deng.yin@gmail.com
- * @since 2006-12-21
- */
- public class SimpleHtmlSourceCacheProvider implements ICacheProvider {
- private Mapnew HashMap
- public String getCacheContent(String cacheKey) {
- return cache.get(cacheKey);
- }
- public void storeCache(String cacheKey, String cacheContent) {
- cache.put(cacheKey, cacheContent);
- }
- public void removeCache(String cacheKey) {
- cache.remove(cacheKey);
- }
- public void reset() {
- cache.clear();
- }
- }
我在google code host上面建了一个probject地址是http://code.google.com/p/tfancomponents/ 有兴趣的同学可以看看, 这是一个maven项目。
评论
7 楼
dengyin2000
2007-08-10
koda 写道
不错!我想知道你为什么不直接使用oschache呢?
本来我是打算用oscache来实现了。 其实oscache自己带了filter来处理cache。 我想尽量把他做简单点。 容易理解。 其实你可以看到 我的这个组件需要提供个CacheProvider。 这个是个接口。 所以这样的话, 你想使用任何cache都是可以的。 只要用你现在用的cache实现CacheProvider就行了。 这样岂不是更灵活???
6 楼
koda
2007-08-10
不错!我想知道你为什么不直接使用oschache呢?
5 楼
dengyin2000
2006-12-22
tapestry 写道
我的CacheContent意思是封装一个对象,里边有个开关变量,设定是否需要update,当然还有cache的内容(这个才是你的cacheContent的意思),里边有个update方法,因为总感觉update应该是cache自己的事情,但实验了一下概念还是比较乱,先暂时放放。
使用起来应该有两种情况,一种是设置页面的update开关,一种是cacheProvider的removeCache。试想这样一个场景,ShowBlogs页面,你cache住了,然后用户添加了blog,除非他添加完后直接需要到ShowBlogs页面,可以调用ShowBlogs.setNeedUpdate(true),然后显示ShowBlogs页面来刷cache,但一般情况很可能不是跳到ShowBlogs页面,可能是用户自己的ManageBlogs页面,这个时候更新的唯一方法就是调用cacheProvider.removeCache了。
cacheProvider里加个updateCache方法吧,方法里调用removeCache,这样api清楚点。
使用起来应该有两种情况,一种是设置页面的update开关,一种是cacheProvider的removeCache。试想这样一个场景,ShowBlogs页面,你cache住了,然后用户添加了blog,除非他添加完后直接需要到ShowBlogs页面,可以调用ShowBlogs.setNeedUpdate(true),然后显示ShowBlogs页面来刷cache,但一般情况很可能不是跳到ShowBlogs页面,可能是用户自己的ManageBlogs页面,这个时候更新的唯一方法就是调用cacheProvider.removeCache了。
cacheProvider里加个updateCache方法吧,方法里调用removeCache,这样api清楚点。
这里说说我的想法, 这个Cache主要是cache页面的,你想到的比较多,可能你忘了Cache组件中有个updateCondition 属性, 其实我是不太赞成ICacheProvider的removeCache这个方法的,这也是我开始想到使用idpath作为cacheKey的原因,用户不需要知道太多的东西。他仅仅需要知道什么时候我需要让tapestry重新生成一下Body的内容就行。 他也就需要实现updateConditon这个component方法。争对你说的这种场景, 我在updateCondition这个方法里面去判断数据库里面的最新帖子的时间和你生成cache时最新帖子的时间来比较(你可以保存在一个singtlon对象里面),如果时间更新了,return true就ok了。 其实我现在这个项目中也是这种情况,首页内容部分是由管理员upload的一个文件(owl file)生成的内容。这时候我在MiscUtils类里面有个checkOWLFileUpdated()方法去判断owl时候发生了变化, 也是使用file的lastmodfy time来判断的。 我在Cache组件中仅仅是非常方便的委派MiscUtils的那个方法而已。
你在上面也提到了主动的方式,就是在发表玩帖子的时候去设置updateCondition为true。其实你只要把这个值set到一个singlton类属性里面就ok了。 updateCondition方法就去check那个值吧。 我不是很赞成这种做法,因为他把一些非业务相关的逻辑加了进来,可能你会说我可以用aop方便的搞定这个。 但是我还是觉得判断cache是否要更新就让Cache组件来作罢(updateCondition)。
4 楼
tapestry
2006-12-22
还有几点疑问,一个是tapestry本身就cache住了静态的模版文档,只需要动态内容添加进去然后生成页面,这个cache应该说是想将静态和动态内容cache住,不需要再生成了,既然是动态的必须是可被更新的,所以要给出个key来,好让人更新,老是调用页面去设置开关然后再显示好像不大方便,现在设置key的话就存在key的管理问题了,今天设定为news了,明天改了成newses了,好多地方就会更新不到了,设为enum或者常量都可以,一个数据字典的概念了,比如Home页面有3个cache了,分别是news,tags,links,后台更新数据的时候来看看哪里用了news了,更新下。这个扯远了,不过老是感觉还有改进的可能,但又暂时想不到。
3 楼
tapestry
2006-12-22
我的CacheContent意思是封装一个对象,里边有个开关变量,设定是否需要update,当然还有cache的内容(这个才是你的cacheContent的意思),里边有个update方法,因为总感觉update应该是cache自己的事情,但实验了一下概念还是比较乱,先暂时放放。
使用起来应该有两种情况,一种是设置页面的update开关,一种是cacheProvider的removeCache。试想这样一个场景,ShowBlogs页面,你cache住了,然后用户添加了blog,除非他添加完后直接需要到ShowBlogs页面,可以调用ShowBlogs.setNeedUpdate(true),然后显示ShowBlogs页面来刷cache,但一般情况很可能不是跳到ShowBlogs页面,可能是用户自己的ManageBlogs页面,这个时候更新的唯一方法就是调用cacheProvider.removeCache了。
cacheProvider里加个updateCache方法吧,方法里调用removeCache,这样api清楚点。
使用起来应该有两种情况,一种是设置页面的update开关,一种是cacheProvider的removeCache。试想这样一个场景,ShowBlogs页面,你cache住了,然后用户添加了blog,除非他添加完后直接需要到ShowBlogs页面,可以调用ShowBlogs.setNeedUpdate(true),然后显示ShowBlogs页面来刷cache,但一般情况很可能不是跳到ShowBlogs页面,可能是用户自己的ManageBlogs页面,这个时候更新的唯一方法就是调用cacheProvider.removeCache了。
cacheProvider里加个updateCache方法吧,方法里调用removeCache,这样api清楚点。
2 楼
dengyin2000
2006-12-22
tapestry 写道
这个idea不错,还有扩展的余地,保存的key最好不要用idPath,自己可以定义,例如定义一个cache名字为news,key应该为Home:news,这样我可以使用cacheProvider.update("Home:news")来更新,还可以写个annotation,例如我新建了个news,
@InjectCache("Home:news")
public CacheContent getHomeNewsCache();
public void save(){
getNewsService().save(getNews());
getHomeNewsCache().update();
}
这样可用性比较好,有兴趣的话,一起研究一下。
@InjectCache("Home:news")
public CacheContent getHomeNewsCache();
public void save(){
getNewsService().save(getNews());
getHomeNewsCache().update();
}
这样可用性比较好,有兴趣的话,一起研究一下。
开始时我觉得这个cacheKey其实可以对用户不见的,用户不用关心cache的内容。其实这里的cache的内容也就是cache组件的body render之后的html source。但是ICacheProvider提供了removeCache这个方法。假如用idPath的对用户来说确实是不友好的。 指定cacheKey值的话,可读性也很高。这个想法不错。我会加入这个功能,多加个cacheKey属性,假如用户关心的话就指定, 不指定的话默认就是idpath。
<span cacheProvider="ognl:cacheProvider" cacheKey="literal:Home:news" updateCondition="ognl:needUpdate">
//body ....
</span>
@InjectCache("Home:news")
public CacheContent getHomeNewsCache();
你这个annotation的意思是获得cache的内容么? 我这里可能有多个cacheProvider, 而且我想用户可以方便的通过cacheProvider去拿到cache content。 再者我想用户肯定不会想去自己updateCache的内容,因为这个body是tapestry解析后的内容,我想用户关系的只是现在cache中的内容是不是stale的。我现在需不需要更新这个cache。 获得cache的内容交给tapestry来处理。 其实这个组件的目的也是主要是想cache页面的html source而已。
现在想要更新cache中的内容的话, 你只需要让updateCondition为true, 或者让对应的cache 内容为null 即可。
非常谢谢tapestry提供的建议,欢迎一起研究。
1 楼
tapestry
2006-12-22
这个idea不错,还有扩展的余地,保存的key最好不要用idPath,自己可以定义,例如定义一个cache名字为news,key应该为Home:news,这样我可以使用cacheProvider.update("Home:news")来更新,还可以写个annotation,例如我新建了个news,
@InjectCache("Home:news")
public CacheContent getHomeNewsCache();
public void save(){
getNewsService().save(getNews());
getHomeNewsCache().update();
}
这样可用性比较好,有兴趣的话,一起研究一下。
@InjectCache("Home:news")
public CacheContent getHomeNewsCache();
public void save(){
getNewsService().save(getNews());
getHomeNewsCache().update();
}
这样可用性比较好,有兴趣的话,一起研究一下。
发表评论
-
解决用run-jetty-run锁住css,js文件的问题。
2008-09-25 17:46 6585开发中用run-jetty-run插件启动jetty调式tap ... -
打造Tapestry5中的智能的错误页面。
2008-09-18 15:59 1776我们一般需要为生产和开发环境准备两套error page。 t ... -
T5这么多的Page Lifecycle method, 应该怎样使用?
2008-09-04 18:18 2368Tapestry5种大概有以下Page ... -
扔掉T5复杂的Grid组件,打造自己灵活的支持分页排序组件。
2008-01-03 13:12 2826Grid算是比较T5中较复杂的一个组件,我也有篇介绍Grid怎 ... -
对Tapestry的一点思考。
2007-12-27 23:33 4064Tapestry5已经开发了蛮久了。 听说最近要发布T5.0. ... -
Tapestry 5.0.5 bug, TAPESTRY-1648
2007-08-26 12:20 2600有一个domian object, 其中有个property的 ... -
T5 技巧 3:使用“t::body”进行布局。
2007-08-25 00:08 2897现在正在使用T5开发一个小项目。 因为现在T5还正处于发展中。 ... -
T5 技巧 2:为Grid组件的每一行增加“删除/修改”链接。
2007-08-21 12:35 8965现在正在使用T5开发一个小项目。 因为现在T5还正处于发展中。 ... -
T5 技巧 1:解决Form的提交乱码问题。
2007-08-21 10:58 8303现在正在使用T5开发一个小项目。 因为现在T5还正处于发展中。 ... -
T5 developing with WTP and TOMCAT
2007-08-16 09:50 2708以下是我发给tapestry右键列表的问题。 现在还没有人回复 ... -
Wicket Vs Tapestry
2007-05-11 14:41 7447我是一个tapestry的老用户。从学校毕业就开始使用tape ... -
Tapestry5中 page template不能reload。
2007-05-09 13:50 5854上午看了下tapestry5的文档,然后自己写了个简单的页面。 ... -
Tapestry Table 组件的强大(分页查询时只fetch当前页的数据)。
2006-03-01 16:00 4311导入的blog格式乱了,大 ... -
Tapestry 显示图片
2006-03-06 16:00 2745导入的blog格式乱了,请看我的msn spaces blog ... -
@Persist 解释
2006-03-08 16:00 3119a) @Persist("client") ...
相关推荐
介绍Tapestry组件的使用和功能。内容还行,使用初学者入门。
自定义的邮件组件!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
tapestry部分组件绑定参数的列表!
tapestry页面编辑组件,可以实现文本框,单选框,多选框和下拉框等的自动生成,并返回改变后的数据。
tapestry4.02中封装ext的GridPanel组件
tapestry5组件说明使用及登陆修改等简单实例
来自:http://tapestry.apache.org/tapestry5.1/tapestry-core/ref
tapestry hibernate Spring应用及组件的使用的一个简单完整例子,包含form组件、table组件的一个增删改查。其中数据库创建用户和表在docs里,数据库使用oracle
Tapestry简单入门介绍,包含Tapestry入门、tapestry组件介绍
2)Tapestry 各种核心组件的使用 3)自带验证,自定义验证,验证码的生成 4)Tree组件的使用,Grid的各种使用(修改样式,排序,隔行换色等等),Loop组件的使用 5)集合Spring4.0.5实现的增删改查 等等 如果你是新...
Tapestry是一个开源的基于servlet的应用程序框架,它使用组件对象模型来创建动态的,交互的web应用。一个组件就是任意一个带有jwcid属性的html标记。其中jwc的意思是Java Web Component。Tapestry使得java代码与html...
Tapestry5最新中文教程.doc 作者 Renat Zubairov & Igor Drobiazko译者 沙晓兰 发布于 2008年7月2日 下午9时30分 社区 Java 主题 Web框架 ----------------------------------------- Tapestry5.1实例教程.pdf ...
Tapestry是一个开源的基于servlet的应用程序框架,它使用组件对象模型来创建动态的,交互的web应用。一个组件就是任意一个带有jwcid属性的html标记。其中jwc的意思是Java Web Component。Tapestry使得java代码与html...
tapestry5组件说明使用等简单实例。Apache Tapestry是一个使用Java语言创建web应用的面向组件的开发框架。Tapestry应用建立在根据组件构建的页面的基础上。这个框架能够提供输入验证(input validation)、本地化/...
资源名称:深入浅出Tapestry内容简介:本书以循序渐进的方式,从Tapestry框架技术的基本概念入手,讲解Tapestry框架在J2EE Web应用程序中的整体架构实现。使读者在学习如何使用Tapestry框架技术的同时,还能够获得在...
本文介绍Tapestry框架版本5。本文利用Tapestry 5开发一个简单的具有创建/读/更新/删除功能的应用,在创建这个应用的过程中,本文体会到Tapestry...还将了解如何应用Tapestry中内嵌的Ajax功能来创建支持Ajax的组件。
Tapestry 4 官方文档中文版本,现在中文资料比较少,和大家共享一下
Tapestry是一个基于控件的框架以致于用它开发Web应用类似开发传统的GUI应用。你用Tapestry开发Web应用时你无需关注以操作为中心的(Operation-centric) Servlet API.引用Tapestry网站上的一句话:"Tapestry用对象...
tapestry 实例tapestry 实例tapestry 实例tapestry 实例
Tapestry5.0.16文档和大家一起学习