`
朱嘉华
  • 浏览: 238363 次
  • 性别: Icon_minigender_2
  • 来自: 北京
社区版块
存档分类
最新评论

WebWork深入浅出

阅读更多

前言

本篇文章并没有太多WebWork 的实战代码细节。本人非常希望能充当一名导游的角色,带领读者逐步游览WebWork的功能特性和原理。在第一章,我们将提出基于三层架构的Web层需要解决的10个问题,这是本文的纵轴。围绕着纵轴,我们按照横轴的顺序逐步描述讲解:WebWork简介、WebWork入门、WebWork原理、WebWork实战和技巧、展望WebWork未来、最后是本文的总结。

基于三层架构的 Web 层需要解决的问题

我们这里讨论的Web层,是基于典型的三层架构:Web层,业务层,数据层。故,我们将不讨论任何涉及业务(业务逻辑)层和数据层功能的实现。

Web层需要解决的问题:

1、  数据的输入。如何获得基于无状态HTTP的请求数据?如何将请求的字符数据转换为对应的模型对象?

2、  输入数据的验证。如何验证输入数据的合法性并给出明确的错误消息提示

3、  数据的输出。如何展现复杂的对象结构?如何处理复杂的展现逻辑?

4、  数据的传递和共享。如何在不同的请求或页面之间传递和共享数据?

5、  页面的流程管理。如何管理Web应用中的页面流程?

6、  模块化的管理。如何将复杂的Web应用以模块化的方式管理?

7、  灵活可扩展的架构。如何支持各种不同的展现层技术?如何与业务层或数据层的各种框架整合?

8、  安全和访问控制的管理。如何提供基于Web的安全机制和资源访问控制的管理?

9、  代码实现的简洁和高效。如何让开发步骤和代码维护变得简单?如何尽量减少开发的中间环节?如何将公共的功能剥离出来,并可以灵活的组装应用?

10、                      其它问题。异步调用、国际化支持、文件上传、防止重复提交等等。

下面,让我们来一起看看WebWork是如何解决上面的这些问题。

 

WebWork 简介

 

WebWork是由OpenSymphony组织开发的,致力于组件化和代码重用的J2EE Web框架。WebWork目前最新版本是2.2.2,现在的WebWork2.x前身是Rickard Oberg开发的WebWork,但现在WebWork已经被拆分成了Xwork1WebWork2两个项目,如下示意图所示:

 


archit.gif


 work简洁、灵活功能强大,它是一个标准的Command模式框架实现,并且完全从web层脱离出来。Xwork提供了很多核心功能:前端拦截机(interceptor),运行时表单属性验证,类型转换,强大的表达式语言(OGNL – the Object Graph Notation Language),IoCInversion of Control依赖倒转控制)容器等。

WebWork2建立在Xwork之上,处理HTTP的请求和响应。所有的请求都会被它的前端控制器(ServletDispatcher,最新版本是FilterDispatcher)截获。前端控制器对请求的数据进行包装,初始化上下文数据,根据配置文件查找请求URL对应的Action类,执行Action,将执行结果转发到相应的展现页面。WebWork2支持多视图表示,视图部分可以使用JSP, Velocity, FreeMarker, JasperReportsXML等。

下面我们提到的WebWork将为WebWork2,使用的版本是WebWork2.2.2

 

WebWork 入门

WebWork 安装

如果只是搭建一个WebWork开发环境,那将非常简单:

1、  去网站http://www.opensymphony.com/webwork下载最新的WebWork2.2.2项目。

2、  搭建一个Web应用(这个不难吧);并拷贝WebWork框架运行需要的所有Jar文件到Web应用的WEB-INF\lib中。这些Jar文件,可以在WebWork项目中lib\default目录找到,即那个目录里面的所有文件。当然,别忘记今天的“主角”,在WebWork跟目录下的webwork-2.2.2.jar文件。

3、  Web.xml文件中配置WebWork的前端控制器FilterDispatcher,也就是一个普通的Servlet Filter(过滤器)而已。代码如下:

    < filter >

        < filter-name > webwork </ filter-name >

        < filter-class > com.opensymphony.webwork.dispatcher.FilterDispatcher </ filter-class >

    </ filter >

 

    < filter-mapping >

        < filter-name > webwork </ filter-name >

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

  </ filter-mapping >

 

不过如果是在实际项目中使用,安装过程中还是有一些问题需要注意的:

1、  关于前端控制器。在以前WebWork2版本里面,前端控制器是ServeltDispatcher,它是一个JavaServlet。而现在是一个Filter(过滤器),会导致无法在页面中使用Jspinclude来包含一个WebWorkAction请求的URL。如果真的需要这样做,可以使用WebWorkaction标签库。

2、  关于Action请求URL的后缀。我们知道,在一般的Web框架中,前端控制器会将特定后缀的请求URL映射到对应的Action请求中。而我们这里的前端控制器会接受任意的请求,但它默认是将.action结尾的URL映射为WebWorkAction请求。我们可以在webwork.properties文件中,设置我们自己的后缀名,多个后缀名可以用逗号隔开。例如:webwork.action.extension=action,do

3、  Jsp 页面中, WebWork 的标签库不需要在 web.xml 中定义,在页面中通过如下的代码直接引用: <%@ taglib prefix = "ww" uri = "/webwork" %>

4、  Jsp页面中,默认“altSyntax”是开启的。它是用来解决标签库中的字符串和表达式语言混淆的问题。所以,作为变量的表达式语言应该放在%{}中,否则WebWork会把它当作字符串处理。

5、  如果展现层技术使用FreemarkerWebWork官方的推荐,也是我个人的推荐),如果在页面中需要使用标签库,必须在web.xml中配置JspSupportServlet,代码如下:

      < servlet >

      < servlet-name > JspSupportServlet </ servlet-name >

      < servlet-class > com.opensymphony.webwork.views.JspSupportServlet </ servlet-class >

      < load-on-startup > 1 </ load-on-startup >

   </ servlet >

6、  还有一些其它的定制,比如:编码,标签的模板文件等等,都可以在webwork.properties文件中配置。如果在ClassPath中没有这个文件,WebWork会自动读取WebWorkJar包里面的default.properties文件。

WebWork 核心概念

WebWork的三个关键部分

1、  Actions。一般一个Action代表一次请求或调用。在WebWork中,一般Action类需要实现Action接口,或者直接继承基础类ActionSupport。这是,它要实现默认的execute方法,并返回一个在配置文件中定义的Result(也就是一个自定义的字符串而已)。当然,Action也可以只是一个POJO(普通Java对象),不用继承任何类也不用实现任何接口。Action是一次请求的控制器,同时也充当数据模型的角色,我们强烈建议不要将业务逻辑放在Action中。

2、  Results。它是一个结果页面的定义。它用来指示Action执行之后,如何显示执行的结果。Result Type表示如何以及用哪种视图技术展现结果。通过Result TypeWebWork可以方便的支持多种视图技术;而且这些视图技术可以互相切换,Action部分不需做任何改动。

3、  InterceptorsWebWork的拦截器,WebWork截获Action请求,在Action执行之前或之后调用拦截器方法。这样,可以用插拔的方式将功能注入到Action中。WebWork框架的很多功能都是以拦截器的形式提供出来。例如:参数组装,验证,国际化,文件上传等等。

第一个例子: Welcome

 

入门,我们从简单的Welcome开始吧!需求如下:一个页面,有一个用户名输入框;输入自己的名字,例如Moxie,提交按钮返回一个欢迎的页面,并显示前面输入的用户名和一句欢迎信息,例如:Moxie, Welcome!页面操作流程图如下:


login.gif

WelcomeAcion.java

 

welcomeResult.jsp

 

welcome.jsp

 

开发步骤如下:

1、  输入页面。Welcome.jsp是一个非常简单输入页面,代码如下:

 

< form name = "register" action = "welcome.action" method = "POST" >

      Name: < input name = "username" > Please input your name.

</ form >

2、  WebWorkAction类。它实现了Action接口,获得welcome.jsp页面传入的数据即输入的用户名,根据这个用户名生成了一条欢迎信息,并在结果页面中打印出来。WelcomeAction.java代码如下:

 

public class WelcomeAction implements Action{

      private String username;

      private String welcomeMessage;

 

      public String execute() throws Exception {

            welcomeMessage = username +",Welcome!";

            return SUCCESS;

      }

     

      public void setUsername(String username) {

            this.username = username;

      }

     

      public String getWelcomeMessage() {

            return welcomeMessage;

      }

}

看了上面的代码,也许你都不敢相信这就是 Web 编程。没有调用任何一个 JavaServlet API ,它是如何获得请求的数据并将执行结果暴露给输入页面的呢?它是通过值堆栈和表达式语言来实现(后面会有详细介绍)。我们先看看 Action 是如何获得请求的数据。输入框的名字“ username ”,即请求的参数的名字,它就是一个表达式语言。 WebWork 遇到这个表达式语言,就会执行相应的 setUsername 方法,而 username 参数的值就是执行这个方法的参数。这些是在 Action 执行 execute 方法之前完成,这样 Action 就可以获得请求的数据对象。类似的原理, WebWork 也是通过表达式语言将 getWelcomeMessage 方法暴露给结果页面。

3、  结果页面。welcomeResult.jsp页面,将通过表达式语言,取得Action执行之后暴露出来的数据对象。代码如下:

<%@ taglib prefix = "ww" uri = "/webwork" %>

< ww:property value = "%{welcomeMessage}" />

我们在结果页面中使用了 WebWork 标签库。我们用到的是 property 标签,它通过表达式语言,打印 Action 暴露出的数据对象。

4、  定义配置文件xwork.xml。代码如下:

< xwork >

    < include file = "webwork-default.xml" />

    < package name = "default" extends = "webwork-default" >

  < action name = "welcome" class = "com.noname.web.action.WelcomeAction" >

            < result name = "success" type = "dispatcher" > /welcomeResult.jsp </ result >

              < interceptor-ref name = "params" />

      </ action >

</package>

</xwork>

name ”参数用于请求的 URL 。例如: http://localhost/welcome.action ,这样通过请求的 url ,我们就可以在配置文件中找到对应的 action 。“ class ”即实现 Action 的类。一个 Action 中可以定义多个 Result Result 的“ name ”对应 Action 方法返回的字符串。在我们的 WelcomeAction 方法中,执行成功之后返回字符串“ success ”。即我们在这个 Action 里定义的那个 result 。“ interceptor-ref ”定义这个 action 所使用到的拦截器。我们这里使用了 WebWork 提供的 params 拦截器,它能自动的帮我们将请求的参数组装成 Action 中需要的数据对象。通过这个拦截器,它会调用 Action setUsername 方法,取得 username 参数的值,这样 Action 就可以获得用户输入的 username 数据。也许你会奇怪, params 这个拦截器是从哪里变出来的?这个 xwork.xml 文件包含了 WebWork 提供的默认配置文件 webwork-default.xml,可以在webwork-2.2.2.jar文件中找到。我们定义的这个package继承了它里面的packagewebwork-default”,这样就可以共享“webwork-defaultpackage里面定义的所有拦截器。

 

 

WebWork 原理

通过上面的例子,我们已经了解WebWork开发、运行的基本流程(一定要亲自安装,并开发这个Welcome的例子哦)。如果要在实际项目中使用WebWork,我们必须要了解下面的概念和WebWork的原理。

 

ValueStack( 值堆栈 ) EL( 表达式语言 )

关于ValueStack的描述:

1、  ValueStack其实就是一个放置Java对象的堆栈而已,唯一特别的是可以使用EL来获得值堆栈中对象属性的数据,并可以为值堆栈的对象属性赋值。

2、  EL,全称Express Language,即表达式语言。不要被语言吓倒,它是简单的对象导航语言。有字符串(例如:方法名)和特殊字符组成(例如用.表示调用对应的属性方法)。通过EL,我们可以存、取对象数据,而且还可以直接访问类的静态数据,调用静态方法。

3、  WebWorkValueStack底层有第三方开源项目OGNL实现。所以EL也都遵循OGNL的规范。我们在开发中,几乎不需要知道OGNL的细节。

4、  WebWork为每一次请求构建一个ValueStack,并将所有相关的数据对象(例如:Action对象、Model对象等)放到ValueStack中。再将ValueStack暴露给视图页面,这样页面就可以直接访问后台处理生成的数据。

下面我们用一个雇员类为例,使用Junit框架(单元测试框架)来展示ValueStack的功能。

我们有一个Employee类,它有两个属性:姓名,地址。姓名是一个字符串,地址是一个对象,地址类有国家、城市、街道三个属性。代码如下:

Employee.java代码如下:

public class Employee {

      private String name;

     

      private Address address;

     

      public Employee() {

      }

     

      public String getName() {

            return name;

      }

 

      public void setName(String name) {

            this.name = name;

      }

 

      public Address getAddress() {

            if(address == null)

                  address = new Address();

            return address;

      }

     

      public void setAddress(Address address) {

            this.address = address;

      }

}

 

Address.java代码如下:

public class Address {

            private String country;

            private String city;

            private String street;

           

            ……

            //默认的GetSet方法,省略

           

}

下面出场的是OgnlValueStackTest,它有两个测试方法。分别测试使用ELValueStack中取值和存值。代码如下:

import com.opensymphony.xwork.util.OgnlValueStack;

import junit.framework.TestCase;

 

public class OgnlValueStackTest extends TestCase {

            private OgnlValueStack valueStack;

            private Employee employee;

           

            @Override

            protected void setUp() throws Exception {

                        valueStack = new OgnlValueStack();

                        employee = new Employee();

                        valueStack.push(employee);

            }

 

            public void testCouldGetDataFromObjectInOgnlValueStackByEL() throws Exception{

                        employee.setName("Moxie");

                        Address address = new Address();

                        address.setCountry("China");

                        employee.setAddress(address);

                       

                        assertEquals("Moxie",valueStack.findValue("name"));

                        assertEquals("China",valueStack.findValue("address.country"));

            }

           

            public void testCouldSetDataForObjectInOgnlValueStackByEL() throws Exception{

                        valueStack.setValue("name","Moxie");

                        valueStack.setValue("address.country","China");

                       

                        assertEquals("Moxie",employee.getName());

                        assertEquals("China",employee.getAddress().getCountry());

            }

}

这是一个Junit Test,关于Junit的使用不是本篇文章的范畴。作为一个Java开发者,熟悉这样的测试框架是最基本的要求。setUp方法在每个测试方法调用之前都会执行,它用来初始化每个测试方法都需要的对象和数据。我们的setUp方法首先创建两个对象:valueStack对象和employee对象,然后将employee对象入栈。这样,emloyee对象就在值堆栈的最上端。

第一个测试方法testCouldGetDataFromObjectInOgnlValueStackByEL测试可以用表达式语言取得值堆栈里的对象数据。我们首先为值堆栈里的employee对象设置数据,设置了用户名和用户地址所在的国家。

第一个验证断言             assertEquals("Moxie",valueStack.findValue("name"))解释为:我们期望使用表达式语言“name”去ValueStack中查找得到的对象是”Moxie”。即期望valueStack.findValue("name")语句执行返回的数据是”Moxie”对象。再深入下去,这条语句会调用ValueStack里对象的getName方法(即employee对象的getName方法),并返回这个方法返回的数据。

第二个断言assertEquals("China",valueStack.findValue("address.country"))。它期望表达式语言“address.country”取得的数据是对象的address属性对象的country属性,即取得雇员对象的地址所在的国家。深入下去,它也就是调用对象employeegetAddress().getCountry()方法。  第二个测试方法testCouldSetDataForObjectInOgnlValueStackByEL测试通过表达式语言为ValueStack中的对象设置数据。

第一个设值语句valueStack.setValue("name","Moxie"),它通过表达式语言“name”将“”Moxie””赋值给ValueStack里的对象,即调用值堆栈中的对象的setName方法,并把后面的值作为方法的参数。同理,第二个设置语句会调用值堆栈中的对象的getAddress().setCountry()方法,把后面的数据作为setCountry方法的参数。

 

看了这个例子,我们就会知道如何通过ValueStack进行数据的存取。在我们使用ValueStack时需要注意:

1、  所有存取操作的目标对象都是已放入ValueStack中的对象。所以在使用之前,必须要先将对象入栈。例如我们在setup方法中的语句:valueStack.push(employee)

2、  每一次WebWork请求,在创建Action对象之前都会先生成一个ValueStack对象,再将Action对象入栈。这样我们就可以通过表达式语言来直接存取action对象的数据,所以在WebWork中,action具有数据模型的功能。

3、  在对ValueStack进行存取操作时,我们的操作指令(表达式语言)并不知道它是对哪个对象进行操作。例如,我们在获取员工姓名时,我们给的操作指令是”name”,这时,并不知道ValueStack里面的对象一定就是employeeValueStack会从上而下,遍历栈里面的对象,并试图调用当前遍历对象的getName方法,当它找到了这个方法,并执行之后,就会将执行得到的数据返回。这就是那神秘的ValueStack

4、  关于值堆栈的context map,它是一个放置值堆栈上下文数据的对象。通过符号“#“再加上对象的名称,可以访问这些数据(只可以访问)。一些JavaServlet相关的数据都放在这个容器中。这个对webwork的标签库特别有用,这样我们可以直接通过表达式语言去访问requestattributesessionapplication里的数据。例如:用property标签库打印出所有请求参数的数据,代码如下:<ww:property value="%{#request}"/>

5、  其它。“top”是ValueStack里面的关键字,通过它可以找到ValueStack中最上面的那个对象。可以试着打印一下valueStack.findValue("top"))看看。表达式语言除了可以调用基于JavaBean规范的getset方法之外,还可以调用一般的Java方法(这是需要使用方法的全名,并传入需要的参数),也可以直接访问Java类的静态字段和静态方法。具体的使用,可以查看WebWork的官方文档。

 

Interceptor( 拦截器 )

拦截器在前面的“WebWork核心概念章节做了简单介绍,这里我们将对它进行更进一步的探讨。关于拦截器的描述:

1、  一个拦截器就是在xwork.xml文件中定义的一个无状态Java类,它至少要实现XWorkcom.opensymphony.xwork.interceptor.Interceptor接口。代码如下:

public interface Interceptor extends Serializable {

    void destroy();

 

    void init();

 

    String intercept(ActionInvocation invocation) throws Exception;

}

2、  实现Interceptor接口的拦截器,代码部分在intercept方法中实现。在intercept方法中,可以直接返回一个Result字符串,这样整个执行直接“短路”,这时Actionexecute方法也不会执行(一般很少会这么用)。所以,一般都会在这个方法里调用参数对象invocationinvoke方法,并返回这个方法执行的结果。这样会持续执行后面的拦截器方法以及Actionexecute方法等。

3、  大部分的时候,拦截器直接继承WebWork的抽象类com.opensymphony.xwork.interceptor.AroundInterceptor就可以了。这时,需要实现它的beforeafter方法。Before方法会在Action执行之前调用,after方法在Action执行之后调用。

4、  拦截器的执行顺序。我们可将多个拦截器放一起组装成一个拦截器栈。这样拦截器会按照栈的顺序由上而下执行before方法,所有before方法执行结束,再执行Action的方法,执行Result的方法,再返回执行结果,最后再从下而上执行拦截器的after方法。</

分享到:
评论

相关推荐

    webwork深入浅出

    ### WebWork深入浅出 #### 一、引言 随着互联网技术的发展,Web应用程序的复杂度日益增加。为了更好地管理这种复杂性,开发者们引入了多种框架和技术来简化开发过程。其中,WebWork框架作为一款优秀的Java Web开发...

    WebWork深入浅出.rar

    WebWork深入浅出教程旨在帮助开发者全面理解并熟练掌握WebWork的核心概念和技术。 一、WebWork概述 WebWork的核心理念是提供一种更加灵活和强大的MVC架构,它强调代码的可重用性、可维护性和可测试性。相比Struts,...

    webwork深入浅出学习资料

    《WebWork深入浅出学习资料》一书由钱安川撰写,旨在为初学者及进阶者提供一份详实的学习指南,通过系统性的介绍WebWork的核心概念、设计原理以及实战技巧,帮助读者快速掌握该框架的运用。 ### WebWork框架概览 ...

    Webwork2 开发指南

    为了深入了解Webwork2,阅读《Webwork2 开发指南》和《webwork深入浅出.pdf》是非常有帮助的。这两份文档会详细解释Webwork2的关键概念、配置方法、最佳实践以及常见问题的解决方案。通过学习这些资料,开发者可以更...

    深入浅出struts2

    │深入浅出STRUTS 2 Struts Ti却发现了二者在技术与开发人员这两个层面上的共同之处,不久之后,两个项目就在WebWork的技术基础上进行了合并2。 当我们说起WebWork的时候,我们实际上说的是两个项目——XWork和...

    深入浅出Hibernate源码

    增加webwork实现的GUI。 加入中文支持。 步骤4: 升级到Hibernate 3。 环境说明 --------- 程序包中的程序经过测试的运行环境为: 1, Tomcat 5.0.25 2, Hibernate 2.1.7 3, Hibernate 3.0.2 4, Eclipse 3.0.1 ...

    晾晾多年珍藏 深入浅出Struts 2.pdf

    《深入浅出Struts 2》是一本针对Java Web开发框架Struts 2的专业指南,旨在帮助开发者深入了解和熟练运用这一强大的MVC框架。Struts 2是Apache软件基金会下的一个开源项目,它继承了Struts 1的优点,并且吸取了其他...

    wework深入浅出

    ### WebWork:深入浅出解析 #### WebWork概述与架构 WebWork是OpenSymphony组织开发的一款基于J2EE框架的Web应用开发框架,目前最新版本为2.2.2,由Rickard Oberg创立。WebWork框架的核心优势在于其灵活的Command...

    Struts2-Webwork2-DWR

    深入浅出Struts2 的开发指南通常会涵盖以下主题:MVC 模式,Action 和 Result,配置管理,拦截器,国际化,异常处理,以及与第三方库如 Spring 的集成。Webwork2 Guide 则会讲解 Webwork2 的核心概念,如动作映射、...

    深入浅出Strust2 原书扫描版及完整实例代码

    本资源包含了《深入浅出Struts2》的原书扫描版以及与之配套的完整实例代码,旨在帮助开发者全面理解和掌握Struts2框架的精髓。 《深入浅出Struts2》这本书详细介绍了Struts2的基础概念、核心组件以及高级特性的使用...

    Struts2.0深入浅出

    如果没有Webwork、XWork和Struts2 所有开发人员不懈的努力,这本书将永远无法面世。在我从一个开源项目的使用者变成一个开源项目的开发人员的过程中,Patrick Lightbody 和Jason Carreira对我的帮助将永远铭刻我心。...

    深入浅出Hibernate

    本下载包说明 ------------- &lt;br/&gt;本下载包是《深入浅出Hibernate》(http://www.redsaga.com/hibernate_book.html)一书的配套教程程序,目前版本为1.0. &lt;br/&gt;本下载包与书籍的实战篇紧密结合. &lt;br...

    深入浅出struts2中文版

    ### 深入浅出Struts2中文版关键知识点概览 #### 1. Struts2框架概述 - **框架定位**:Struts2作为Java Web应用开发中的一个重要框架,继承了Struts1的设计思想,并在此基础上进行了大量优化和扩展。它通过一系列的...

    WebWork2.2入门

    本文将深入浅出地介绍如何开始使用 WebWork 2.2,以及在实际开发中可能会遇到的问题,如调试方法。 ### 1. WebWork 框架基础 WebWork 2.2 是 WebWork 框架的一个版本,它提供了一种灵活的方式来组织和控制 Web ...

    struts深入浅出

    Struts2是Java Web开发中的一个强大框架,它基于...通过深入理解和熟练运用,开发者可以构建出高效、易维护的企业级应用。然而,随着Spring Boot等现代框架的崛起,开发者在选择技术栈时也应考虑其适应性和长远发展。

Global site tag (gtag.js) - Google Analytics