分享
 
 
 

Tapestry入门及进阶一

王朝java/jsp·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

要Tapestry开发一个Web Application,对一个新手来说有点困难的,Tapestry由于不同于

以前的Web Presentation Framework,所以不可讳言,学习曲线比较长这是事实。

我先讲讲一个Web Application的大体结构:

以JBuider9为开发工具,你要先建立一个工程,例如是名称是TapestryExmaple,它的

workspace是F:\myproject\TapestryExmaple.它下面的子目录和文件有

bak--这是Jbuider自建的backup目录。

build--我的ant的工作目录,我的ant会利用这个目录编译打包。

classes--JBuilder编译时放class的目录

configs--我的一些配置文件放置的地方

lib-- 我的要用到的库文件放置的目录

context--我的Web application的context目录

doc--我的文档目录

src-- 我的java source的目录

build.properties--ant工作的属性设置文件

build.xml--ant工作的定义文件

你建立好这个工程以后,你好需要建立Web Application, 点击File-->New-->Web-->Web

Application,因为我们需要在JBuilder里利用Tomcat4.1调试,用Jboss3.x也可以,不过你

要去下载一个插件叫EntWizard_JBoss3x_JB9_v3-1-5.zip的插件,JBuiderx提供对JB

oss的支持,不过Jbuiderx经常有些莫名其妙的怪毛病,而且比较慢,我是不用的。

你建立Web Application的时候你要输入Name和Directory两项值,Name比如是

patientrecord,注意你在这里输入的name,会在你将来测试时的URL里出现:

你的URL就可能像这样:http://localhost:8080/patientrecord/app

后面那个app是在web.xml里配置的,下面再说。

你的Web Application的Directory值要跟我们上面预定的一致,就是那个context目录,

在这里就是F:\myproject\TapestryExmaple\context,这个context目录是web applicatio

n

的核心目录,下面要详细的讲讲。

例如像我的context目录下面有这三个目录

home -- 我的web applicattion的子模块home的context

下面有子目录 css--放置本子模块用到的css文件

images--放置本子模块用到的image(图标)

文件:Home.html,Register.xml ...

这些是我字模块中的页面对应的HTMLtemplate(模版)

patientrecord--我的web applicattion的子模块patientrecord的context

目录结构跟home子模块相同

WEB-INF--最核心的目录

下面的子目录和文件有

classes--你的java classes会在这里有一份拷贝

lib--你的工程引用的lib在这里用一份拷贝

patientrecord.application--你的Tapestry核心配置文件

web.xml--web application的核心配置文件

下面我们来研究一下patientrecord.application和web.xml这两个文件,我的范例文

件如下:

web.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd>

<web-app>

<display-name>Patient Record System</display-name>

<filter>

<filter-name>redirect</filter-name>

<filter-class>org.apache.tapestry.RedirectFilter</filter-class>

</filter>

<filter-mapping>

<filter-name>redirect</filter-name>

<url-pattern>/</url-pattern>

</filter-mapping>

<servlet>

<servlet-name>patientrecord</servlet-name>

<servlet-class>com.ht.web.PatientRecordServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>patientrecord</servlet-name>

<url-pattern>/app</url-pattern>

</servlet-mapping>

<session-config>

<session-timeout>15</session-timeout>

</session-config>

</web-app>

这个里面属性有

display-name--不重要,只是显示名称

filter和filter-mapping配置--不要动,使用默认配置,

servlet配置--这个是很重要的,我的servle name是patientrecord,对应的class为

com.ht.web.PatientRecordServlet,这是我自己开发的一个类:

这个类看上去很简单:

package com.ht.web;

import org.apache.tapestry.ApplicationServlet;

/**

* @version $Id: SimpleServlet.java,v 1.9 2002/05/04 12:43:31 hship Exp $

* @author Howard Lewis Ship

*

*/

public class PatientRecordServlet extends ApplicationServlet

{

}

你一般就是定义一个类extends org.apache.tapestry.ApplicationServlet就行了

当然,如果你还有什么特别要求,你可对这个类进行强化。

我再来谈谈这个核心类的作用:这其实是个Dispatcher(分发者),它接受外界传来的

http request请求,然后把请求处理后派发给Tapestry Engine处理.

图例:

http://bbs1.nju.edu.cn/file/high-level-component-request.p

servlet-mapping--这是URL映射的设置,一般设为app

<session-config>

<session-timeout>15</session-timeout>

</session-config>

这段是对HTTP Session的timeout的配置,这里是15分钟。

下面再来研究一下patientrecord.application文件,这也是一个XML文件:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE application PUBLIC

"-//Apache Software Foundation//Tapestry Specification 3.0//EN"

"http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd>

<application name="Patient Record System" engine-class="com.ht.web.PatientRecordEngine">

<property name="org.apache.tapestry.visit-class" value="com.ht.web.VisitorState"/>

<property name="com.ht.home-page" value="home:Home"/>

<!--<property name="com.ht.exception-page" value="home:PaitentRecordException"/>-->

<property name="com.ht.security-exception-page" value="home:SecurityExceptionPage"/>

<!--Overrided the Home Service to let us to decide which page will be the home page-->

<service name="home" class="com.ht.web.HomeService"/>

<library id="home" specification-path="/com/ht/home/Home.library"/>

<library id="patientrecord" specification-path="/com/ht/patientrecord/PatientRecord.library"/>

</application>

由这个文档我们可以看出

我的application name="Patient Record System"

我的engine-class为com.ht.web.PatientRecordEngine

我的org.apache.tapestry.visit-class为com.ht.web.VisitorState

以上两项是override Tapestry的默认实现

<property name="com.ht.home-page" value="home:Home"/>

这是我配置我的home-page页指向我的web application的子模块home里Home页

<!--<property name="com.ht.exception-page" value="home:PaitentRecordException"/>-->

<property name="com.ht.security-exception-page" value="home:SecurityExceptionPage"/>

这两项是我设定出错处理页

其中的com.ht.exception-page是处理普通的org.apache.tapestry.ApplicationException,

现在被注释掉,因为目前在开发阶段,我要察看详细的出错情况,不需处理。

com.ht.security-exception-page是处理java.lang.SecurityException,

因为对于一个需要登录的网站,一个为登录的用户是不可以访问大多数资源,

如果他访问了不可访问的资源,我就抛出SecurityException交给engine处理。

<!--Overrided the Home Service to let us to decide which page will be the home page-->

<service name="home" class="com.ht.web.HomeService"/>

Tapestry engine 可以定义一些service提供服务,我在这里定义一个home service就是

要我自己决定我的home page页,而不是Tapestry的默认配置页。

<library id="home" specification-path="/com/ht/home/Home.library"/>

<library id="patientrecord" specification-path="/com/ht/patientrecord/PatientRecord.library"/>

这两项是说明我的application包含两个library,这其实是一个Web application切分

子模块的手段,比如/com/ht/home/Home.library"/ 对应着我的home子模块,

而/com/ht/patientrecord/PatientRecord.library则对应着我的patientrecord子模块

下面说说Tapestry engine,例如我的engine实现如下:

package com.ht.web;

import java.io.*;

import java.net.URLEncoder;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

import org.apache.tapestry.*;

import org.apache.tapestry.engine.BaseEngine;

import org.apache.tapestry.engine.IPropertySource;

import org.apache.tapestry.request.ResponseOutputStream;

import org.apache.commons.lang.StringUtils;

/**

* @author Hery Tang

*

* Creation Date 2003-9-18

* Version 1.0

*/

public class PatientRecordEngine extends BaseEngine {

public static final String HOME_PAGE_NAME = "com.ht.home-page";

public static final String EXCEPTION_PAGE_NAME= "com.ht.exception-page";

public static final String SECURITY_EXCEPTION_PAGE_NAME = "com.ht.security-exception-page";

private transient boolean killSession;

protected void cleanupAfterRequest(IRequestCycle cycle)

{

super.cleanupAfterRequest(cycle);

if (killSession)

{

try

{

HttpSession session = cycle.getRequestContext().getSession();

if (session != null)

{

session.invalidate();

}

}

catch (IllegalStateException ex)

{

// Ignore.

}

}

}

public void logout()

{

VisitorState visit = (VisitorState) getVisit();

if (visit != null)

{

visit.setUser(null);

visit = null;

}

killSession = true;

}

/**

* This methods read the home page name which defined by the user by using

* propetry com.ht.home-page in application specification

*

* @return The name of home page.

*/

public String getHomePageName() {

return getPropertySource().getPropertyValue(HOME_PAGE_NAME);

}

/**

* Return the security exception page name. If user does not defined this

* page name, the normal exception page will be return.

* @return The name of the security exception page.

*/

public String getSecurityExceptionPageName() {

String result =

getPropertySource().getPropertyValue(

SECURITY_EXCEPTION_PAGE_NAME);

if (StringUtils.isEmpty(result)) {

result = getExceptionPageName();

}

return result;

}

/**

* Return the exception page name. If user does not defined this page name,

* the default exception page will be return.

* @return The name of the normal exception page.

*/

public String getExceptionPageName() {

String result =

getPropertySource().getPropertyValue(EXCEPTION_PAGE_NAME);

if (StringUtils.isEmpty(result)) {

result = super.getExceptionPageName();

}

return result;

}

/**

* Overide the method to support security Exception.

*/

protected void activateExceptionPage(

IRequestCycle cycle,

ResponseOutputStream output,

Throwable cause)

throws ServletException {

//Print it to console first

printExceptions(cause);

try {

String exceptionPageName;

Throwable throwable = cause;

Throwable securityException = null;

boolean isSecurityException = false;

if (throwable

instanceof org.apache.tapestry.ApplicationRuntimeException) {

ApplicationRuntimeException exception =

(ApplicationRuntimeException) throwable;

if (exception.getRootCause() instanceof SecurityException) {

securityException = exception.getCause();

isSecurityException = true;

}

}

if (isSecurityException) {

exceptionPageName = getSecurityExceptionPageName();

} else {

exceptionPageName = getExceptionPageName();

}

IPage exceptionPage = cycle.getPage(exceptionPageName);

if (securityException == null) {

exceptionPage.setProperty("exception", cause);

} else {

exceptionPage.setProperty("exception", securityException);

}

cycle.activate(exceptionPage);

renderResponse(cycle, output);

} catch (Throwable ex) {

// Worst case scenario. The exception page itself is broken, leaving

// us with no option but to write the cause to the output.

reportException(

Tapestry.getMessage(

"AbstractEngine.unable-to-process-client-request"),

cause);

// Also, write the exception thrown when redendering the exception

// page, so that can get fixed as well.

reportException(

Tapestry.getMessage(

"AbstractEngine.unable-to-present-exception-page"),

ex);

// And throw the exception.

throw new ServletException(ex.getMessage(), ex);

}

}

private void printExceptions(Throwable throwable) {

if (throwable == null) {

return;

}

throwable.printStackTrace();

printExceptions(throwable.getCause());

}

}

public void logout()说明

一个用户登出,则将一个代表用户状态的VisitorState对象里的状态清空,同时置

killSession标志量为true

protected void cleanupAfterRequest(IRequestCycle cycle)

overrride父类BaseEngine实现,先调用父类实现然后再察看killSession标志量,如果为true,则invalidate session.

public String getHomePageName()

public String getSecurityExceptionPageName()

public String getExceptionPageName()

都是为了取出我在在patientrecord.application的配置。

protected void activateExceptionPage(

IRequestCycle cycle,

ResponseOutputStream output,

Throwable cause)

override AbstractEngine的是实现,用我自己的方式处理各种Exception.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有