一、简介
Stripes是一个开源的,基于Action的Java web框架。传统型Java web开发强调通过松耦合的设计达到灵活开发之目的,这导致了产生多种配置文件,额外对象以及其它零碎的资源。显然,这些问题提升了众多开发人员的学习曲线,从而降低了开发效率。基于这些原因,一些Java开发者求助于另外的非Java开发框架—例如Ruby on Rails或者Django。而象Stripes这样的新型Java web开发框架,从支持流线式开发框架的成功中获取了大量现成的经验。本文中,我们将通过一个具体的案例来探讨Stripes是如何区别于其它基于Action的Java web框架(例如Struts),而同时又实现了例如Ruby on Rails框架所具备的简单性。
下图1展示了基于Stripes框架开发的典型应用程序中事件及组件间的通常流程。
图1:典型的Stripes流程 |
如你所见,这也正是我们从一个典型的MVC框架下所想得到的东西。在Stripes及其它基于行为的框架之间的一个主要区别在于,它没有提供外部配置文件。很快我们将会看到,在配置方面,Stripes借助于注解和约定(convention)等技术进一步简化了开发过程。
二、构建你的第一个Stripes行为
下面,让我们通过创建一个“Hello World”示例来理解Stripes框架是如何把诸多内容结合到一起的。其中,HelloWorldAction类负责提示用户输入自己的姓名,然后把它们显示于一个单独的视图中。首先,我们来编写控制器Java类。
public class HelloWorldAction implements ActionBean { |
在此,这个控制器类十分类似于一个实现了一个称为ActionBean的Stripes特定接口的POJO(普通Java对象)。注意,所有的Stripes行为都需要实现这个接口,以便允许StripesDispatcher servlet把一个ActionBeanContext对象注入到当前提供服务的行为中。该ActionBeanContext对象允许你存取servlet API对象—例如请求,响应和servlet上下文。大多数情况下,在一个Stripes应用程序中没有必要存取这些低级别的API对象。该ActionBeanContext类还允许你取得关于当前行为的状态信息,而且还可以从当前行为中添加参考消息和错误消息。注意,ActionBeanContext域及其存取器(accessor)可以存储在一个基类中,因为所有的Stripes行为都会要求这样的实现。
对于该控制器类的其它内容,我相信任何一位Java开发者都应该熟悉。Person对象及相应的存取器将用于把所有人的姓名信息读写到我们的视图中。尽管这是一个简单的嵌套对象,但是Stripes还允许使用Java集合,泛型和index属性等实现更为复杂的数据绑定。既然Stripes可以处理复杂的数据绑定,那么,你的域(domain)对象也可以重用于需要它们的其它层中。例如,我们可以很容易地实现经由Stripes收集一个域(domain)对象中的信息,并且使用其它POJO框架(例如Hibernate或EJB 3)进行永久性存储。
另外,还应注意,在此,一个简单的Stripes校验注解已被添加到person域中以确保当调用hello方法时用户输入了姓名信息。如果该用户没有输入这些要求的域,那么他们将被返回到源页面并且显示出一个与这个校验相关的错误消息。仅当要求hello事件时才检查这个校验—这是通过注解属性(on={"hello"})指定的。Stripes还将基于校验类型和域名友好地生成一个缺省的错误消息。例如,如果当提交表单时没有提供要求的Person对象的firstName域,那么用户将看到下列结果:
Person First Name is a required field. |
这条消息是系统通过把对象图形组件当作Person.firstName而构建的,从而使之更具可读性。如果必要的话,可以重载这些校验错误消息以便提供更多的定制。
#p#
还有一个称为age的整型(integer)域,这是Person对象的一个属性。Stripes将根据请求参数值首先针对Person.age整数域执行类型转换,并绑定Person对象中的相应值。在把该值绑定到Person对象的age域上后,Stripes将进行校验以保证该Integer值小于13。如果用户输入了一个字符串而不是一个整数,那么该用户将看到如下的这条消息:
The value (Mark) entered in field Person Age must be a valid number. |
如果用户输入了一个整数但是该值小于13,那么用户将看到这条消息:
The minimum allowed value for Age is 13. |
在此,我们仍然不需要对于这些错误消息提供任何外部配置。提供这一校验功能的注解是内联于你的域的,这使得开发者能够容易地定位校验,理解校验将会怎样发生,以及对该校验进行维护性修改。
在这个Stripes行为中,还存在两个可以调用的方法(称为“事件”)。一个事件是通过一个ActionBean类中的一个方法使用下列签名形式加以描述的:
public Resolution eventName |
注意,相应的index方法被加上了@DefaultHandler注解标记。因为在这个行为中存在多个事件,所以需要把它们其中之一指定为缺省的事件。如果调用这个行为的URL没有指定一个事件,那么Stripes将查找一个标记有@DefaultHandler注解的事件并执行它。
三、构建视图
现在,让我们在“Hello World”示例中添加我们的视图逻辑部分。默认情况下,Stripes支持JSP作为标准视图技术,然而,你还可以使用其它视图技术—例如FreeMarker。在此,基本没有什么要介绍的新内容—除了Stripes标签库外。初始的视图,称为Hello.jsp,允许用户输入并提交他们的名字。
<%@ taglib prefix="stripes" |
这个JSP相当简单—只负责读取和维护。其中表单及输入域中使用的Stripes标签非常类似于它们的HTML对应物。其中,stripes:form标签包含一个称为beanclass的属性—这是我们以前定义的控制器类的全称限定名。我们可以使用beanclass属性来代替该stripes:form标签中的action属性。然而,如果你需要重构一个Stripes行为的话,使用beanclass属性将会更为容易些。下面是如果你使用action属性的话,该stripes:form标签看起来的样子:
<stripes:form action="/example/HelloWorld.action"> |
其中,一个stripes:input标签用于指定Person.firstName的一个name属性—它将用于把输入域存储到控制器中的Person对象的firstName域的值中。最后,stripes:submit标签用于指定一个name属性—该属性将用于指示Stripes HelloWorldAction类使用hello事件。
现在,我们开始把姓名值提交到HelloWorldAction。为此,我们仅需要将它回显于一个单独的视图中。
<%@ taglib prefix="stripes" |
#p#
这个JSP将显示用户的姓名域中的信息—通过访问一个对行为本身的引用来实现。为此,Stripes自动地包括了一个actionBean请求属性,这可以使用JSTL加以存取。最后,我们使用一个stripes:link标签来创建一个到HelloWorldAction类的往回的链接,以便我们可以输入另一个不同的名字。我们还能够像下面这样通过显式地引用index事件来创建该stripes:link标签:
<stripes:link |
既然我们已经使用@DefaultHandler注解了该index方法,所以,Stripes能够知道要执行哪个方法—即使不使用事件属性。
四、使用convention(约定)进行配置
现在,既然我们已经成功地创建了我们的Java组件,那么接下来,我们将把行为映射配置到一个URL,并且把它链接到我们以前创建的两个视图上。请等一下—我们是在使用Stripes框架进行开发,所以在此我们根本不需要任何外部配置!
尽管这听起来可能有点不太真实,但的确如此—这正是Stripes框架带给我们的最具生产效率的众多特征之一。在配置问题上,Stripes使用convention把Action映射到URL。我们也不需要使用一个外部配置文件来把一个符号名映射到实际的视图上。这意味着,开发者不必在配置文件之间来回切换以决定如何在众多的符号名(例如SUCCESS)中加以选择并最终把它们导航到视图的实际路径。根本不需要通过外部来配置Java和视图组件。显然,这提高了系统开发的可维护性,并进一步提高了软件生产效率。
那么,在没有以外部方式配置每一个行为或另一个注解的情况下,Stripes是如何提供到Java行为类的隐式的URL映射呢?这可以通过在web.xml文件中配置Stripes和该文件使用智能的缺省设置来创建URL映射方面得到解释。首先,我们需要讨论一个称为StripesFilter的Servlet过滤器。下面是在web.xml文件中的StripesFilter过滤器的缺省配置:
<filter> |
当启动Servlet容器时,StripesFilter执行其init-param元素的初始化。其中,最重要的一个init-param元素是ActionResolver.UrlFilters参数。这个参数告诉Stripes到哪里寻找Stripes相关的类。在本文示例中,Stripes将在缺省的/WEB-INF/classes路径下查找所有实现了ActionBean接口的类。所找到的每一个ActionBean类,连同该类缺省的绑定URL,都被添加到一个映射中。
现在,让我们通过一个示例来实际分析一下Stripes对我们的Hello世界示例类做了些什么。既然该HelloWorldAction类位于/WEB-INF/classes路径下并且实现了ActionBean,那么,它将被识别为一个Stripes servlet。在我们的示例中,该类的全称限定名为com.myco.web.stripes.action.example.HelloWorldAction。然后,这个全称限定的名字通过实现下面这些规则被翻译成一个URL绑定:
1.把每次出现的四个子串之一(www,web,stripes或action)连接成全称限定类名。在我们的示例中,我们在包名中使用了这四个匹配中的三个。没有使用此匹配的一个是“example.HelloWorldAction”。
2.从类名的最后删除字符串“Action”和“Bean”—如果它们存在的话。于是,这产生了“example.HelloWorld”,因为我们的类以“Action”结束。
3.现在,我们使用“/”符号代替“.”符号,结果是“example/HelloWorld"”。
4.最后,我们在结尾添加上绑定后缀(默认情况下是“.action”),至此最终完成URL绑定。最终结果是“example/HelloWorld.action”。
现在,既然Stripes已经找到了ActionBean类并且为它创建了一个URL绑定,那么,接下来将对它们通过java.util.Map<string,class<?extendsactionbean>>(其中,键是URL绑定,而值为实现ActionBean的类)进行缓冲。下面是我们的示例在映射中看起来的样子:
URL绑定 | ActionBean类 |
/example/HelloWorld.action | com.myco.web.stripes.action.example.HelloWorldAction |
接下来,我们要讨论的第二个问题是,Stripes怎么把URL绑定翻译回你要使用的ActionBean类呢?这个任务由Stripes调度器(dispatcher)Servlet来完成—此调度器在web.xml文件中配置,如下所示:
<servlet> |
#p#
StripesDispatcher的一个任务就是解析一个到一个Stripes ActionBean类的URL。当用户调用URL http://host/uri/example/HelloWorld.action时,该Stripes调度器servlet将认真检查此URL绑定映射以发现com.myco.web.stripes.action.example.HelloWorldAction类,并且创建它的一个实例。最后,调用index方法,因为它被定义为(注解为)缺省的处理器并且该URL中没有指定一个事件。
如果我们想直接执行HelloWorldAction类中的hello方法会怎么样呢?如果这样的话,URL中需要包括事件名—作为一个请求参数形式提供:http://host/uri/example/HelloWorld.action?hello=&firstName=Mark&age=13
【注意】在此,我们并没有为该hello请求参数指定一个值。在本文示例中,StripesDispatcher负责识别匹配hello请求参数名和一个方法名(该方法名位于HelloWorldAction类中,并且方法签名为“public Resolution hello()”)。为了提高性能,方法名在初始化时通过一个单独的Map进行缓冲。
现在,我们已经了解了Stripes的基本知识以及如何创建简单的Action。其实,还有许多关于此框架操作的细节。通过在web.xml中进行一些初始的配置,我们可以成功地避免再引入一个单独的XML配置文件来绑定我们的描述组件。这是很重要的,因为:第一,你可以查找一个URL并且立即知道要查找什么类—如果你需要进行任何修改的话;第二,当配置文件变得相当巨大和不可管理时,我们不需要使用一个单独的工具来帮助我们。通过消除了这个配置文件,我们不必再浪费大量的元数据来填充框架。最后,我们不需要继续维护一个单独的文件来描述我们的组件彼此之间的关系。
五、 基于Prototype JavaScript库集成Ajax技术
从现在开始,让我们来探讨Stripes是如何处理Ajax相关问题的。我们将使用一个更新适当内容的Ajax调用来修改上面的Hello世界示例。这个示例将展示如何使用Prototype以便为Stripes行为提供Ajax调用。这个示例的完整源码可以从本文提供的下载源码中获取。首先,让我们修改该Hello.jsp以便包括对Prototype JavaScript库的参考。我们还将添加一个相应于该Ajax调用的JavaScript函数,并且把原先的提交按钮改变为绑定了一个onclick事件的新按钮:
<stripes:button <stripes:button <%@ taglib prefix="stripes" |
在此,stripes:button拥有一个onclick事件,该事件将调用HelloWorldAction类中的sayHelloAjax方法并且把相应的结果返回到称为hello的div标签中。接下来,我们来看一下要在HelloWorldAction类中引入的另一个新的方法:
public Resolution sayHelloAjax(){ |
这个方法没有做多少工作,因为其涉及的前后绑定工作都由Stripes负责实现了。因此,这个方法的唯一责任就是把当前控制转发到一个称为SayHelloAjax.jsp的页面。下面是此SayHelloAjax.jsp的内容:
<h2>Hello ${actionBean.person.firstName} your age is ${actionBean.person.age}!</h2> |
六、与Spring框架的集成
Stripes还提供了与Spring框架的内置集成。你可以把Spring beans或服务自动地注入到你的行为中。在Stripes框架中,实现这一点并不要求外部配置—除了你的Spring上下文配置之外。例如,如果我们在我们的Spring配置中存在一个如下所定义的bean:
<bean id="personService" parent="abstractTxDefinition"> |
那么,为了实现把此personService注入到一个Stripes行为中,需要添加一个属性和匹配该Spring bean名字的setter。Stripes提供了@SpringBean注解来定位合适的Spring bean以注入到行为类中。下面是一个需要包括到Stripes行为中的示例:
private PersonService personService; |
请注意:仅靠本文是无法涉及Stripes所有高级特征的;然而,Stripes参考文档中已经提供了比较综合性的相应资料。Stripes框架中还包括一个类似于Tiles的省略了外部配置的布局管理器。另外,Stripes框架中引入的拦截器(interceptor)还可以用于跨生命周期事件,文件上传,以及更多的内容上。
七、结论
从本文中我们可以看到,Stripes的确是一种强有力然而却十分简单的Java web框架。这个框架充分利用了Java 5中注解和泛型等特征,从而使Java开发者不必维护外部配置文件而提高了生产效率。
相关推荐
### Stripes 入门 Stripes 是一款专为简化 Java Web 开发流程而设计的开源框架,它以提高开发效率为目标,力求使开发者能够轻松快速地构建 Web 应用程序。与传统 Java Web 框架相比,Stripes 采用了更为简洁的方法...
### Stripes框架简介 ...以上内容涵盖了Stripes框架的基本介绍、快速入门指南以及一些核心特性的详细解释。希望这些知识点能够帮助开发者更好地理解和使用Stripes框架,以构建高效、可维护的Java Web应用。
不错的stripes教程,分享一下…… 和我们熟悉 Struts 1 和 Struts 2 类似,Stripes 同样是一种展示层框架,用于快速构建web程序。在使 用Struts 1,WebWork 和 Struts 2 等框架的时候,通常需要大量额外的 XML 配置...
Stripes框架的快速入门部分主要介绍了一些基础概念和入门步骤。首先提到的是如何安装Sun JDK以及使用Maven创建Stripes项目。Maven是一个项目管理工具,可以简化项目构建过程,它通过一个中央仓库来管理项目依赖。...
- **《Stripes and Java Web Development Is Fun Again》**:这本书被许多读者认为是学习Stripes的最佳入门书籍之一。作者不仅详细介绍了Stripes的基本概念和技术细节,还通过实际案例展示了如何利用Stripes构建真实...
背景-Stripes框架包的简要概述-指导条纹设计的概念-与条带有关的事物的术语条纹显影入门和新环境设置-更详细的概述 World-使用Stripes CLI为FOLIO创建一个hello world应用程序开发和测试指南-如何将现有应用程序迁移...
初级入门吉他谱 guitar tab
待办事项:修改此自述文件以替换有关入门的这些部分。先决条件为了查看和登录正在提供服务的平台,需要运行合适的Okapi后端。 如果您的应用还没有自己的后端模块,则可以使用“Vagrant”框。运行您的新应用从ui-...
- **文档完善**:提供了易于理解的官方文档,便于新手快速入门。 - **社区活跃**:尽管规模较小,但社区成员热情且乐于分享。 **缺点**: - **社区规模**:相比其他框架,Stripes的社区规模较小,资源相对有限。 - ...
入门 从 Hackage 安装它。 cabal update && cabal install pocket-dns 用法 设置 conf.yml 这是后端设置。 当后端为zookeeper时,conf.yml的格式如下。 backend: zookeeper coord: localhost:2181/ timeout: ...
《云端代码:利用Google AppEngine编程》是一本实用而全面的指南,不仅适合初学者快速入门,也适合有一定经验的开发者进一步提升自己的技能。通过本书的学习,读者将能够掌握Google AppEngine的核心技术和最佳实践,...
- **Frederic Daoud**,《Stripes: And Java Web Development Is Fun Again》和《Getting Started with Apache Click》的作者,认为这本书写得引人入胜、实用、重要且独特,他立即应用了书中的技巧,改善了自己的...
- **Mike Naberezny**(Maintainable Software 合伙人)认为尽管这不是一本入门书籍,但对于有一定SQL经验的开发者来说,它是一本非常有价值且内容丰富的参考书。 - **Liz Neely**(资深数据库程序员)认为这是一本...
通过深入浅出的方式介绍了Ruby、Io、Prolog、Scala、Erlang、Clojure和Haskell等七种语言的关键概念和技术,本书不仅适合希望快速入门这些语言的初学者,也适用于希望通过比较学习来提升自己的资深程序员。...