您的位置:首页 > 其它

浏览项目文件

2016-03-19 14:42 344 查看
项目结构遵循Maven的标准:

Java 源文件在
src/main/java 下

Web应用文件在
src/main/webapp
(包含
src/main/webapp/WEB-INF
)下
Java 测试文件在
src/test/java 下

非编码文件 (包含 Tapestry 页面 and 组件 模板) 在
src/main/resources
and
src/test/resources 下


打开web.xml配置文件,看看Maven为我们做了什么:

src/main/webapp/WEB-INF/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>tutorial1 Tapestry 5 Application</display-name>
<context-param>
<!-- The only significant configuration for Tapestry 5, this informs Tapestry
of where to look for pages, components and mixins. -->
<param-name>tapestry.app-package</param-name>
<param-value>com.example.tutorial1</param-value>
</context-param>
<!--
Specify some additional Modules for two different execution
modes: development and qa.
Remember that the default execution mode is production
-->
<context-param>
<param-name>tapestry.development-modules</param-name>
<param-value>
com.example.tutorial1.services.DevelopmentModule
</param-value>
</context-param>
<context-param>
<param-name>tapestry.qa-modules</param-name>
<param-value>
com.example.tutorial1.services.QaModule
</param-value>
</context-param>
<filter>
<filter-name>app</filter-name>
<filter-class>org.apache.tapestry5.TapestryFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>app</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>


这里很简洁: 你可以看到作为tapestry.app-package的上下文参数是你早些提供的; TapestryFilter 实例会使用这些信息来指定Java类和组件的位置。

Tapestry 操作是Servlet 过滤器而不是传统的Servlet. 在这种模式下, Tapestry 才能拦截所有的请求,来决定展现哪一个Tapestry 页面(或其它资源).在网络环境下,你不需要配置Tapestry的操作 ,尽管你添加了N多的页面或组件到你的应所有。

web.xml 的其余配置是用来匹配模式类的Tapestry 执行模式,执行模式决定了应用如何运行:默认为 'production', 但是web.xml 定义了其它两种模式:'development' 和 'qa' ("Quality Assurance"的简写) 。模式类会隐式加载这些执行模式,当然你也可以改变这些配置。我们将会在稍后讨论这个问题。

Tapestry 页面 仅仅是由Java 类加上一个组件模板组成。

在你的web应用的根目录,Index页面将会使用任意不需要添加上下文目录的请求。


Index Java 类

Tapestry 对于放置Java 类的位置拥有非常明确的规则。 Tapestry 在应用根包里(com.xxxx.tutorial1)添加了一个子包 "pages",Java 类都在这里放置。因此,Java 类的全名叫
com.xxxx.
tutorial
1.pages.Index
.

src/main/java/com/example/tutorial/pages/Index.java

package com.example.tutorial1.pages;

import org.apache.tapestry5.Block;
import org.apache.tapestry5.EventContext;
import org.apache.tapestry5.SymbolConstants;
import org.apache.tapestry5.annotations.InjectPage;
import org.apache.tapestry5.annotations.Log;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.ioc.annotations.Symbol;
import org.apache.tapestry5.services.HttpError;
import org.apache.tapestry5.services.ajax.AjaxResponseRenderer;
import org.slf4j.Logger;

import java.util.Date;

/**
* Start page of application tutorial1.
*/
public class Index
{
@Inject
private Logger logger;

@Inject
private AjaxResponseRenderer ajaxResponseRenderer;

@Property
@Inject
@Symbol(SymbolConstants.TAPESTRY_VERSION)
private String tapestryVersion;

@InjectPage
private About about;

@Inject
private Block block;

// Handle call with an unwanted context
Object onActivate(EventContext eventContext)
{
return eventContext.getCount() > 0 ? new HttpError(404, "Resource not found") : null;
}

Object onActionFromLearnMore()
{
about.setLearn("LearnMore");

return about;
}

@Log
void onComplete()
{
logger.info("Complete call on Index page");
}

@Log
void onAjax()
{
logger.info("Ajax call on Index page");

ajaxResponseRenderer.addRender("middlezone", block);
}

public Date getCurrentTime()
{
return new Date();
}
}


由于Index页尝试解释一系列不同的Tapestry 用法,使得这个类有点长。尽管如此,这个类还是很简单:没有继承基类,没有实现接口,只是一个有了属性和方法的纯POJO。

你肯定对Tapestry有了大致的了解:

必须把Java 类放在指定包位置,这里是 com.example.tutorial1.pages
类必须是 public
确保有一个 public 并且无参的构造器 (本例中,Java 编译器已经隐式为我们提供了--个人观点:继承了Object)
所有非静态属性必须是 private

当运行应用式,我们看到页面显示了当前日期和时间,以及其它一些链接。当前时间就是从Java类里属性来的,(稍后我们来讲一下这个值是怎么应用到模板的)因此,属性可以在页面和类中交互.

Tapestry 中,一个页面类匹配一个模板,实际上,页面内组件也是这样(除非这个组件没有模板引用).

你应该经常听到
模型-视图-控制器(MVC) 模式. 在 Tapestry 里,页面类扮演着模型 (数据源)和控制器(用户的操作和逻辑响应).页面模板就是MVC里的视图 。作为一个模型,页面类开放java属性给页面引用。

让我们看看页面组件模板在Java类提供的用户交互里是如何构建的。


组件模板

Tapestry 页面由POJO Java 类和Tapestry 组件模板组成。模板拥有和Java类一样的名字,但后缀是.tml. 所以 这里的Java 类叫做 com.example.tutorial.pages.Index, 模板文件将会也必须出现在 src/main/resource/com/example/tutorial/pages/Index.tml. 最后,经过打包部署WAR文件后,Java类和模板文件都会存在同一个文件夹下。

Tapestry 组件模板遵循XML文件规范. 也就是说你可以使用任意的xml编辑器。 模板可以拥有一个 DOCTYPE 或 XML schema(大纲?) 来规范当前内容.

注意:Tapestry 解析组件模板时使用的是不通过式解析,它会校验合法的格式性诸如标点,节点平衡,属性有""等,所以需要你来把这些基本的错误解决,Tapestry才能编译通过。

大多数来说,一个Tapestry 组件模板和XHTML差不多。

src/main/resources/com/example/tutorial1/pages/Index.tml

<html t:type="layout" title="tutorial1 Index"
xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd"
xmlns:p="tapestry:parameter">

<div class="hero-unit">
<p>
<img src="${asset:context:images/tapestry.png}"
alt="${message:greeting}" title="${message:greeting}"/>
</p>
<h3>${message:greeting}</h3>
<p>The current time is: <strong>${currentTime}</strong></p>
<p>
This is a template for a simple marketing or informational website. It includes a large callout called
the hero unit and three supporting pieces of content. Use it as a starting point to create something
more unique.
</p>
<p><t:actionlink t:id="learnmore" class="btn btn-primary btn-large">Learn more »</t:actionlink></p>
</div>

<div class="row">
<div class="span4">
<h2>Normal link</h2>
<p>Clink the bottom link and the page refresh with event <code>complete</code></p>
<p><t:eventlink event="complete" class="btn btn-default">Complete»</t:eventlink></p>
</div>
<t:zone t:id="middlezone" class="span4">

</t:zone>
<div class="span4">
<h2>Ajax link</h2>
<p>Click the bottom link to update just the middle column with Ajax call with event <code>ajax</code></p>
<p><t:eventlink event="ajax" zone="middlezone" class="btn btn-default">Ajax»</t:eventlink></p>
</div>
</div>

<t:block t:id="block">
<h2>Ajax updated</h2>
<p>I'v been updated through AJAX call</p>
<p>The current time is: <strong>${currentTime}</strong></p>
</t:block>

</html>


你必须为你的模板文件命名为 Index.tml, 而且必须和类名的大小写一致。如果写错了,也行会在一部分系统中运行正常(比如Mac Windows),但是在其它系统却不能运行(比如Linux和大部分其它系统)。由于普通情况下我们都是在Windows开发,发布在Linux或者Solaris,这样的错误会令我们抓狂。因此,小心对待这个问题。

Tapestry 的模板如 Index.tml 的目标是看起来和普通静态页面一样(静态是只不变的意思,对应动态的Tapestry 页面)

实际上, 许多情况下我们期望模板类似静态HTML文件开头,由美工开发,然后用作Tapestry 动态页面。

Tapestry 隐藏了XML里非标准元素以及属性。为了方便使用,t: 被用于命名前缀,但这不是必须的,你可以指定任意你想使用的前缀。

此模板解释了一些Tapestry的特性。

快速开始部分介绍了许多不同的特性,方法,普通模式在Tapestry中的使用,我们来看一下:

首先,有两个普通的XML命名空间定义:

xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd"
xmlns:p="tapestry:parameter"


第一个 "t:", 用于标记Tapestry 的特殊元素和属性。虽然以经有了XSD(一种XML语法定义),但是不方便使用(稍后我们来说一下原因)

第二个 "p:", 引入其它模板块的一种方式,稍后我们将会展开说明

一个Tapestry 组件模板由大部分的标准XHTML组成,大部分会直接传递到客户浏览器,模板的动态部分由组件和扩展来完成。


Templates里的扩展

让我们从扩展开始. 当动态渲染页面时,扩展是输出的一种简单方式,默认情况下,一个扩展属性指向当前页面java类的属性。

<p>The current time is: ${currentTime}</p>


大括号里面是属性表达式。 Tapestry 使用自己直观,快捷,类型安全的属性表达式。

Tapestry 不会使用反射来实现属性表达式


更多高级属性表达式可以使用点属性 (比如
user.address.city
), 甚至可以调用方法.这里的扩展仅仅读取了当前页面的
currentTime属性
.

Tapestry 遵循Sun公司置顶的JavaBean规范:
currentTime属性映射到两个方法:
getCurrentTime()
setCurrentTime()
. 如果省略不写,代表你不需要使用。这里就只有getCurrentTime()方法,所以 currentTime 是只读的(或者只写另外一种setter,只写属性). (要对JavaBean属性保持清醒,方法名称起着重要作用,实例变量是否存在不是必要的)

Tapestry 可以走的更远: 当为页面匹配内在扩展时,它是不区分大小写的。在模板中,无论你写成
${currenttime} 或 ${CurrentTime}亦或其它大小写情况,Tapestry 依然会调用
getCurrentTime()
方法.

Tapestry中没有必要说明 哪个对象拥有
currentTime
属性; 模板和页面通常互相结合使用;表达式通常在页面实例中,本例中是Index 类的实例.

Index.tml 模板包含了另一中表达式:

<p>${message:greeting}</p>


这里
greeting 不是页面的属性,它实际上是一个本地化的Key值。每一个Tapestry页面和组件允许拥有自己的消息目录。(这里当然存在一个消息目录,我们待会再讲)


src/main/resources/com/example/tutorial/pages/Index.properties

greeting=Welcome to Tapestry 5!  We hope that this project template will get you going in style.


在代码外部存放一些重复的字符串,消息目录十分有用,它的设计初衷是使应用本地化(稍后的章节会详细讲解)消息存放在全局消息目录:src/main/webapp/WEB-INF/app.properties下,可以在任意页面使用。

这里的 "message:" 前缀没有什么特殊,只是一些Tapestry中的具有特殊意义的固有前缀。实际上,在扩展中省略前缀和使用固有"prop:"前缀一样,可以看成属性表达式。

扩展在抽取信息和渲染到客户端页面方面十分有用,但它在组件中更加有用。


模板中的组件

组件在组件模板中的作用体现在两个方面 :

作为普通元素,但是以 t:type 属性来定义说明这是组件类型.

作为Tapestry命名空间元素,决定了元素的类型.

这里我们使用 <html>元素来代表应用布局组件.

<html t:type="layout" ...>
...
</html>


但是 EventLink 组件, 我们使用 Tapestry 命名空间元素:

<t:eventlink page="Index">refresh page</t:eventlink>


选择使用哪一种由你来决定。大多数情况下,他们是相同的。

上面我们说大小写是不敏感的,这里使用的类型(layout和eventlink)都是小写的;实际上类名都是大写的:Layout和EventLink。在核心库里,Tapestry混合了应用组件定义,因此, "layout"类型映射到了组件类com.example.tutorial.components.Layout, 但 "event link"映射到了 Tapestry's 构建类 org.apache.tapestry5.corelib.components.EventLink.

Tapestry 组件通常作为参数来配置,对于每个组件来说,都有一系列自己的参数,和本身特殊的类型和作用。有些参数是必须的,有些是可选的。元素属性通常用户绑定特殊文本值或是页面属性。Tapestry 也很灵活:你可以一直使用Tapestry的命名空间( "t:" 前缀),但不是必须的。

<html t:type="layout" title="tutorial1 Index"
p:sidebarTitle="Framework Version" ...


这里绑定了两个参数,
title
sidebarTitle
, 代表了Layout 组件的名字 "tutorial1 Index" 和 "Framework Version".

布局组件实际上提供了向浏览器发送的空白HTML,我们在稍后章节讲解。页面模板嵌入了组件布局模板,下表为你说明参数如何传递到布局模板,然后渲染到最终页面



这里有趣的是(Tapestry里的高级概念,稍后讲解 )我们可以使用布局组件作为参数放入Index.tml模板里,这就是tapestry:parameter的命名空间 (p:前缀),元素的名称匹配到组件参数,然后整个模板块传到布局组件里...这就决定了内在模板块也被渲染。

<t:eventlink event="complete" class="btn btn-default">Complete»</t:eventlink>


此时,页面组件PageLink被绑定到Index页面,这里将会作为URL输出到页面链接,所以当前时间才会更新。你也可以创建到应用其它页面的链接,我们在稍后的章节讲解。


魔法效应

是时候看点魔法的东西了,编辑Index.java 修改
getCurrentTime()
为 :

Index.java (partial)

public String getCurrentTime()
{
return "A great day to learn Tapestry";
}


确保你保存文件后,点击浏览器的刷新按钮:



如果 Live Class Reloading 没生效,检查问题章节 Class
Reloading.

这是Tapestry一个早期令人惊奇的特性:修改你的组件模板,效果即使生效。 (称之为 Live Class Reloading 特性). 不需要重新启动,不需要重新部署。改变代码,立即查看。没有什么会减缓你的速度或增加完成工作时间。

但是 ... 如果你犯了错会怎样?如果你在模板里写错了名字?试一下;在模板里,修改 ${currentTime} 为 ${currenTime}, 看一下你会得到什么



这里是Tapestry 异常报告页面,非常的详细。它明确展示了Tapestry要做什么,遇到了模板中直接定位到上下文的问题,Tapestry 通常展示了整个栈的异常信息,因为异常一般都是被抛出,捕获,或者被其它异常再度抛出。实际上,如果我们往下滚动一点,我们会看到该异常的详细信息,外带一点提示:



这就是Tapestry的风格: 不仅指出在做什么时遇到了什么问题,还会提示你解决方案。这里提示你可用的属性名称。

信息的详细程度可以在应用里配置:以开发模式运行应用而不是上线模式。在上线模式中,异常报告只会输出最顶级的异常信息.实际上,大部分的上线应用都会处理好异常的。

Tapestry 展示了更深的栈异常信息,并伴随着应用运行环境的异常:当前请求,Session(如果存在)甚至JVM的详细信息。继续滚动可以查看。

接下来:
实现HI-LO猜游戏
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: