[ SSH框架 ] Struts2框架学习之一

一、Struts2框架的概述

  Struts2是一种基于MVC模式的轻量级Web框架,它自问世以来,就受到了广大Web开发者的关注,并广泛应用于各种企业系统的开发中。目前掌握 Struts2框架几乎成为Wcb开发者的必备技能之一。

  接下来将针对 Struts2的特点、安装以及执行流程等内容进行详细的讲解。

1.1 什么是Struts2

  在介绍 Struts2之前,先来认识一下 Struts1。Struts1是最早的基于MVC模式的轻量级Web框架,它能够合理的划分代码结构,并包含验证框架、国际化框架等多种实用工具框架。但是随着技术的进步,Struts1的局限性也越来越多的暴露出来。为了符合更加灵活、高效的开发需求,Struts2框架应运而生。
  Struts2是 Struts1的下一代产品,是在 Struts1和 WebWork技术的基础上进行合并后的全新框架( WebWork是由 OpenSymphony组织开发的,致力力于组件化和代码重用的J2 EE Web框架,它也是一个MVC框架)。虽然 Struts2的名字与 Struts1相似,但其设计思想却有很大不同。实质上,Struts2是以 WebWork为核心的,它采用拦截器的机制来处理用户的请求。这样的设计也使得业务逻辑控制器能够与 ServletAPI完全脱离开,所以 Struts2可以理解为 WebWork的更新产品。
Struts2拥有优良的设计和功能,其优势具体如下:
  ●  项目开源,使用及拓展方便,天生优势。
  ●  提供 Exception处理机制。
  ●  Result方式的页面导航,通过 Result标签很方便的实现重定向和页面跳转。
  ●  通过简单、集中的配置来调度业务类,使得配置和修改都非常容易。
  ●  提供简单、统一的表达式语言来访问所有可供访问的数据。
  ●  提供标准、强大的验证框架和国际化框架。
  ●  提提供强大的、可以有效减少页面代码的标签。
  ●  提供良好的Ajax支持。
  ●  拥有简单的插件,只需放入相应的JAR包,任何人都可以扩展 Struts2框架,比如自定义拦截器。
  ●  自定义结果类型、自定义标签等,为 Struts2定制制需要的功能,不需要什么特殊配置,并且可以发布给其他人使用。
  ●  拥有智能的默认设置,不需要另外进行繁琐的设置。使用默认设置就可以完成大多数项目程序开发所需要的功能。
  上面列举的就是 Struts2的一系列技术优势,只需对它们简单了解即可,在学习了后面的知识后,会慢慢对这些技术优势有更好的理解和体会。
  那么除了 Struts2之外,还有那些优秀的WEB层框架呢?

1.2 常见的WEB层框架
  ●  Struts2
  ●  Struts1
  ●  WebWork
  ●  SpringMVC
  WEB层框架都有一个特点:基于前端控制器模式实现。
 
1.3 WEB层框架都会基于前端控制器的模式
  什么是前端控制器模式呢?我们来看下图,在图中传统方式的开发,有一次请求就会对应一个Servlet。这样会导致出现很多 Servlet。而 Struts2将所有的请求都先经过一个前端控制器,在前端控制器中实现框架的部分功能,剩下具体操作要提交到具体的 Action中。那么所有的请求都会经过前端控制器,那用什么来实现前端控制器呢?过滤器就是最好的一个实现方式,因为需要所有的请求都可以被过滤器拦截,然后在过滤器中实现部分的功能。所以 Struts2的前端控制器也是有过滤器来实现的。
   

  了解了这些之后,让我们通过一个Struts2的快速入门,来感受一下Struts2。

二、Struts2快速入门

2.1 下载Struts2的开发包:

百度网盘链接:https://pan.baidu.com/s/1HeQLGcDaXdskUayFI-vGWw   密码:qyxp

2.2 解压Struts2的开发包

解压后的目录结构如下图:

  

从图中可以看出,展示的是解压后的 Struts2.3.24 的目录结构,为了让大家对每个目录的内容和作用有一定的了解,接下来针对这些目录进行简单介绍,具体如下:
  ●  apps:该文件夹存用于存放官方提供的 Struts2示例程序,这些程序可以作为学习者的学习资料,可为学习者提供很好的参照。各示例均为war文件,可以通过zip方式进行解压。
  ●  docs:该文件夹用于存放官方提供的 Struts2文档,包括 Struts2的快速入门、 Struts2的文档,以及API文档等内容
  ●  lib:该文件夹用于存放 Struts2的核心类库,以及 Struts2的第三方插件类库。
  ●  src:该文件夹用于存放该版本 Struts2框架对应的源代码
有了 Struts2的开发环境,接下来我们亻可以进行 Struts2的开发了。
 
2.3 创建一个web工程引入jar包
  首先,需要我们创建一个WEB工程,引入相关的jar包文件。引入哪些jar包呢?将 struts-2.3.24框架目录中的lib文件夹打开,得到 Struts2开发中可能用到的所有JAR包(此版本有107个JAR包)。实际的开发中,我们们根本不用引入这么多的jar包。因此要进行 struts2的基本的开发,可以参考 struts-2.3.24中的aps下的一些示例代码,其中 struts2-blank.war 是一个 struts2的空的工程。我们只需要将 struts2-blank.war 解压后进入到WEB-INF下的的lib中査看。 如下图:
  

  以上这些就是struts2基本的开发包了,那么这些包都有什么含义呢?说明如下图:

   

  从表可以看出,此版本的 Struts2项目所依赖的基础JAR包共13个。 Struts2根据据版本的不同所依赖的基础JAR包可能不完全相同,不过基本上变化不大,读者可以视情况而定。
  需要注意的是,通通常使用 Struts2的Web项目并不需要利用到 Struts2的全部JAR包,因此没有必要一次将 Struts2的lib目录下的全部JAR包复制到Web项目的WEB-INF/ib路径下,而是根据需要,再添加加相应的JAR包。
  那么 Struts2的基本jar包已经引入完成了,我们使用用 Struts2都是是从页面发起请求到服务器,再由服务器处理请求,响应到页面的这个过程。接下来我们就从页面开发进行 Struts2的开发吧。

2.4 创建一个页面,放置一个连接

 首先在WebContent下创建一个jsp文件,在jsp文件中编写一个Action的访问路径。如下图

    <<h1>Struts2的入门案例</h1>
    <a herf="${pageContext.request.contextPath }/HelloAction.action">访问Struts2的Action</a> 

2.5 编写一个Action

  在src下创建一个包 com.Kevin.action,在该包下新建一个 HelloAction 的类。在这个类中编写一个公有的,返回值为 String类型的方法,这个方法的名称叫做 execute,且该方法没有任何参数。(因为这个方法最终要被反射执行) 如下图:
package com.Kevin.action;

public class HelloAction {
    
    /**
     * 提供一个默认的执行的方法:execute
     * @return
     */
    public String execute(){
        System.out.println("HelloAction中的execute方法执行了------");
        return null;
    }
}

  Action类编写好了以后,Struts2框架是如何识别它就是一个Action呢,我们需要对Action类进行配置。

2.6 完成Action配置

   这个时候,我们还需要观察apps中的示例代码,在WEB-INF的 classes中,有一个名称为 struts.xml 的文件,这个文件就是 struts2的配置文件。

  我们在开发中需要将 struts xml文件引入到工程的src下,因为src下内内容发布到web服务器中就是WEB-INF下的 classes中。将 struts.xml中的原有的内容删除掉,然后配置上自己编写的 Action类就可以了。

  配置内容如下:里面的具体的标签,会在后面的地方详细介绍。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">
    
<struts>
    <package name="hellodemo" extends="struts-default" namespace="/">
        <!-- name:访问名称 class:action位置 -->
        <action name="HelloAction" class="com.Kevin.action.HelloAction">

        </action>
    </package>

</struts>    

   Action类已经配置好了,配置好了以后大家考虑一下,现在是否可以执行呢?其实现在还不行,因为之前我们介绍过,WEB层的框架都有一个特点就是基于前端控制器的模式,这个前端控制器是由过滤器实现的,所所以我们需要配置 Struts2的核心过滤器。这个过滤器的名称称是 StrutsPrepareAndExecuteFilter 。


2.7 配置核心过滤器
  Struts2框架要想执行,所有的请求都需要经过这个前端控制器(核心过滤器),所以需要配置这个核心过滤器。因为这个过滤器完成了框架的部分的功能。那么我们接下来对过滤器进行配置。我们打开web.xml,在web.xml中进行如下配置。
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

</web-app>

  那么到这,我们程序就可以执行了,但是到了 Action以后,页面并没有跳转,只是会在控制台输出 Action中的内容,往往我们在实际的开发中,处理了请求以后,还需要进行页面的跳转,如何完成 Struts2的页面的跳转呢?
  这个时候我们需要修改改 Action类中的 execute方法法的返回值了,这个方法返回了一个 String类型,这个 String类型的值就是一个逻辑视图(逻辑视图:相相当于对一个真实的页面,取了一个别名)。那么我们来修改一个 Action类。

2.8 修改Action,将方法设置一个返回值

  修改Action中的execute方法的返回值,我们先任意给其返回一个字符串,比如返回一个 ok 的字符串。这个字符串就作为一个逻辑视图的名称。

package com.Kevin.action;

public class HelloAction {
    
    /**
     * 提供一个默认的执行的方法:execute
     * @return
     */
    public String execute(){
        System.out.println("HelloAction中的execute方法执行了------");
        return "ok";
    }
}

  返回一个 ok 的字符串了,这个字符串如何代表一个页面呢?我们就需要对struts2进行配置了。这个时候需要修改struts.xml,对Action的配置进行完善。

2.9 修改struts.xml

  打开struts.xml 文件,对action标签进行完善,在action标签中配置一个result标签,这个标签中的name属性就是之前方法返回的那个字符串的逻辑视图名称ok 。标签内部就是跳转的页面。 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">
    
<struts>
    <package name="hellodemo" extends="struts-default" namespace="/">
        <!-- name:访问名称 class:action位置 -->
        <action name="HelloAction" class="com.Kevin.action.HelloAction">
            <!-- 配置方法的返回值到页面 -->
            <result name="ok">/hello.jsp</result>
        </action>
    </package>

</struts>    

  到这里,我们的整个程序就执行完毕了,可以启动服务器并且测试项目。

打开页面:

页面跳转:

 

 

三、Struts2开发流程分析

3.1 Struts2的执行流程

  从客户端发送请求过来先经过前端控制器(核心过滤器 StrutsPreparedAndExecuteFilter )过滤器中执行一组拦截器(一组拦截器就会完成部分功能代码码),到底哪些拦截器执行了呢,在 Struts2中定义很多拦截器,在其默认栈中的拦截器会得到执行,这个我们可以通过断点调试的方式测试,拦截器执行完成以后,就会执行目标 Action,在 Action中返回一个结果视图,根据 Result的配置进行页面的跳转。

 

 四、Struts2的常见配置

4.1 Action的配置

   Struts2框架的核心配置文件是 struts.xml文件,该文件主要用来配置 Action和请求的对应关系。
【< package>的配置】
  Struts2框架架的核心组件是 Action和拦截器,它使用包来管理 Action和拦截器。每个包就是多个Action、多个拦截器、多个拦截器引用的集合。在 struts.xml文件中,package元素用于定义包配置每个 package元素定义了一个包配置。 package元素的常用属性,如表所示。
  
  表中就是 package元素的常用属性,其中,在配置包时,必须指定name属性,就是包的标识。除此之外,还可以指定一个可选的 extends属性,extends属性值必须是另一个包的name属性值,但该属性值通常都设置为 struts-default,这样该包中的 Action就具有了 Struts2框架默认的拦截器等功能了。除此之外外,Struts2还提供了一种所谓的抽象包,抽象包不能包含 Action定义。为为了显式指定个包是抽象包,可以为该 package元素增增加 abstract="true"属性。
  在 package中还有 namespace的配置,namespace属性与 action标签的name属性共同决定了访问路径。namespace有如下三种配置:
  ●  默认名称空间:默认的名称空间就是 namespace=""
  ●  跟名称空间:跟名称空间就是 namespace="/"
  ●  带名称的名称空间:带名称的名称空间就是 namespace="/demo1"
【 Action的配置】
  Action映射是框架中的基本“工作单元”。 Action映射就是将一个请求的URL映射到一个 Action类,当一个请求匹配某个 Action名称时,框架就使用这个映射来确定如何处理请求。在 struts.xml文件中,通过< action>元素对请求的 Action和 Action类进行配置< action>元素中共有4个属性,这4个属性的说明如表所示。
  
  其中name属性和 namespace属性共同决定了访问路径,class对应的是 Action类的全路径。Method指定了执行 Action的那个方法,默认是 execute方法。
  基本的 Struts2的配置我们己经了解了,在实际的开发中我们需要大量的用到到 Struts2的常量,那么我们接下来学习一下 Struts2的常量。

4.2 模块开发的配置
  在实际开发中,我们通常很多人都需要修改同一个配置文件就是 struts.xml。因为这个文件是Struts2的核心配置文件。而且这个文件一且改错了一点,那么会导致整个项目都会出现问题,所以Struts2提供了< include>标签解决这个问题。
  < include>元素用来在一个 struts.xml 配置文件中包含其他的配置文件,包含配置体现的是软件工程中的“分而治之”原则。 Struts2允许将一个配置文件分解成多个配置文件,从而提高配置文件的可读性。 Struts2默认只加载WEB-INF/ classes下的 struts.xml文件,但一且通过多个xml文件来配置Action,就必须通过 struts.xml文件来包含其他配置文件
  为了让大家更直观地理解如何在 struts.xml文件中进行包含配置,接下来通过一段示例代码来说明,具体如下
<struts>    
        <!-- 包含了4个配置文件 -->
    <!-- 不指定路径,默认路径在src下的方式 -->
    <include file="struts-user.xml"></include>
    <include file="struts-customer.xml"></include>
    <include file="struts-book.xml"></include>
    <!-- 配置文件在具体包中时的方式 -->
    <include file="com.Kevin.action.hello.xml"></include>
</struts>    
  在上述代码片段中,struts.xml文件包含了4个配置文件,这4个配置文件都包含在 <include>元素中。配置< include>元素时,指定了一个必需的file属性,该属性指定了被包含配置文件的文件名。上述 include元素的file属性中,前3个没有指定文件所在路径时,表示该文件在项目的src路径下,如果配置文件在具体的包中,那么引入配置文件时,需要包含文件所在包的路径。
  需要注意的是,每一个被包含的配置文件都是标准的 Struts2配置文件,一样包含DTD信息Struts2配置文件的根元素等信息。通过将 Struts2的所有配置文件都放在Web项目的WEB- INF/classes路径下, struts.xml文件包含了其他的配置文件,在 Struts2框架自动加载 struts.xml文件时,完成加载所有的配置信息。
  Action的基本配置以及熟悉了,那么通过配置 Struts2框架就可以找到具体的 Action类了,那么Action类又要如何编写呢?接下来学习 Action类的编写的方式。

五、Struts2的Action访问
  在 Struts2的应用开发中,Action作为框架的核心类,实现对用户请求的处理,Action类被称为业务逻辑控制器。一个 Action类代表一次请求或调用,每个请求的动作都对应于一个相应的 Action类,一个 Action类是一个独立的工作单元。也就是说,用户的每次请求,都会转到一个相应的 Action类里面,由这个 Action类来进行处理。简而而言之,,Action就是用来处理一次用户请求的对象。
  实现 Action控制类共有3种方式,接下来,分别别对它们进行讲解,具体如下:

5.1 Action的编写方式
【 Action的是一个POJO的类】
  在 Struts2中,Action可以不继承特殊的类或不实现任何特殊的接口,仅仅是一个POJO。POJO全称 Plain Ordinary Java Object(简单的Java对象),只要具有一部分 getter/ setter方法的那种类,就可以称作POJO。一般在这个POJO类中,要有一个公共的无参的构造方法(采用默认的构造方法就可以)和一个 execute方法。定义格式如下:
package com.Kevin.action;

public class HelloAction {
    
    /**
     * 提供一个默认的执行的方法:execute
     * @return
     */
    public String execute(){
        System.out.println("HelloAction中的execute方法执行了------");
        return "ok";
    }
}
execute( )方法的要求如下:
  ●  方法的权限修饰符为 public。
  ●  返回一个字符串,就是指示的下一个页面的 Result。
  ●  方法没有参数。
也就是说,满足上述要求的POJO都可算作是 Struts2的 Action实现。
通常会让开发者自己编写 Action类或者者实现 Action接口或者继承 Actionsupport类。
【 Action类实现一个 Action的接口】
  为了让用户开发的 Action类更规范,Struts2提供一个 Action接口,用户在实现 Action控制制类时,可以实现 Struts2提提供的这个 Action接口。
Action接口定义了 Struts的的 Action处理理类应该实现的规范,Action接口中的具体代码如下所示。
package com.Kevin.action;
import com.opensymphony.xwork2.Action;
public class UserAction implements Action{ @Override public String execute() throws Exception { System.out.println("实现了Action接口----------"); return NONE; } }
  从上述代码中可以看出,Action接接口位于 com.opensymphony.xwork2包中。这个接口里只定义了一个execute( )方法,该接口的规范规定了 Action处理类应该包含一个 execute方法,该方法返返回一个字符串。除此之外,该接口还定义了5个字符串常量,它们的作用是统一 execute( )方法的返回值。
Action接口中提供了5个已经定义的常量如下:
  ●  SUCCESS:success,代表成功。
  ●  NONE:none,代表页面不跳转。
  ●  ERROR:error,代表跳转到到错误页面。
  ●  INPUT:input,数据校验的时候跳转的路径。
  ●  LOGIN:login,用来跳转到登录页面。
由于 Xwork的 Action接口简单,为开发者提供的帮助较小,所以在实际开发过程中,Action类很少直接实现Action接口,通常都是从ActionSupport类继承。
【Action类继承ActionSupport类】(推荐)
package com.Kevin.action;

import com.opensymphony.xwork2.ActionSupport;

public class PersonAction extends ActionSupport{
    
    public String execute(){
        System.out.println("继承ActionSupport类----------");
        return NONE;
    }

}
  ActionSupport 类本身实现了 Action接口,是 Struts2中默认的 Action接口的实现类,所以继承ActionSupport 就相当于实现了 Action接口。 ActionSupport 类还实现了 Validateable、ValidationawareTextprovider、Localeprovider、和 Serializable等接口,来为用户提供更多的功能。
  ActionSupport 类中提供了许多默认方法,这些默认方法包括获取国际化信息的方法、数据校验的方法、默认的处理用户请求的方法等。实际上,ActionSupport 类是 Struts2默认的 Action处理类。如果让开发者的 Action类继承该 ActionSupport 类,则会大大简化 Action的开发。
  Action的类已经会编写了,如果要执行这个 Action,可以通过前面的配置来完成,但是之前的方式有一个缺点,就是多次请求不能对应同一个 Action,因为实际的开发中,一个模块的请求通常由一个 Action类处理就好了,否则则会造成 Action类过多。那么接下来我们讲一下 Action访问的一些细节。
 
5.2 Action的访问
  Action的访问不是难题,因为之前已经访问过了,但是出现一个问题。一次请求现在对应一个Action,那么如果请求很多对应很多个 Action。现在要处理的问题就是要让一个模块的操作提交到一个 Action中。
  其实我们学过在< action>的标签中有一个属性 method,通通过 method的配置来指定 Action中的某个方法执行。
【解决 Action的访问的问题的方式一:通通过配置 method属性完成】

编写测试代码如下:

BookAction类:

package com.Kevin.method;

import com.opensymphony.xwork2.ActionSupport;

public class BookAction extends ActionSupport{
    
    public String add(){
        System.out.println("add----");
        return NONE;
        
    }
    
    public String update(){
        System.out.println("update-----");
        return NONE;
    }

}
struts.xml中配置:
    <!-- 配置method方法访问 -->
    <package name="methoddemo" extends="struts-default" namespace="/">
        <action name="addAction" class="com.Kevin.method.BookAction" method="add"></action>
        <action name="updateAction" class="com.Kevin.method.BookAction" method="update"></action>
    </package>
但是这种方式我们会发现,同一个 Action类就被配置了很多次,只是修改了后面的 method的值。那么能不能配置简单化呢?也就是一个 Action类,只配置一次就好了?这个时候我们就需要使用通配符的配置方式了。
【解决 Action的访问的问题的方式二:通过通配符的配置完成】
编写测试代码如下:
BookAction类:
package com.Kevin.method;

import com.opensymphony.xwork2.ActionSupport;

public class BookAction extends ActionSupport{
    
    public String add(){
        System.out.println("add----");
        return NONE;
        
    }
    
    public String update(){
        System.out.println("update-----");
        return NONE;
    }

}
struts.xml中配置:
    <!-- 通配符方式实现 -->
    <package name="methoddemo2" extends="struts-default" namespace="/">
        <!-- 
            name属性值里加符号 *
            1.执行action中的add方法,访问book_add
            2.执行actoin中的update方法,访问book_update
            上述两个路径使用book_* 就可匹配到
         -->
        <action name="book_*" class="com.Kevin.method.BookAction" method="{1}"></action>
    </package>
【解决 Action的访问的问题的方式三:动态方法访问】(一般不用)
  动态方法访问在 Struts2中默认是不开启的,如果想要使用需要先去开启一个常量。
<constant name="struts.enable.DynamicMethodInvocation" value=true"></constant>
  动态方法访问主要的控制是在页面端,所以编写 Action和和配置 Action都很简单,关键是访问路径的编写。 由于不经常使用,笔者在这里就不做过多介绍,有兴趣的朋友可自行查阅。
 

六、简单区别Struts1和Struts2

1.从 action类上分析
  ●  Struts1要求 Action类继承一个抽象基类。Struts1的一个普遍问题是使用抽象类编程而不是接口。
  ●  Struts2 Action类可以实现一个 Action接口,也可实现其他接口,使可选和定制的服务成为可能。 Struts2提供一个 Actionsupport基类去实现常用的接接口。 Action接口不是必须的,任何有 execute标识的POJO对象都可以用作 Struts2的 Action对象。
 
2.从 Servlet依赖分析
  ●  Struts1 Action依赖于 Servlet Apl,因为当个 Action被调用时 Http Servletrequest和Http Servletresponse被传递给 execute方法
  ●  Struts2 Action不依赖于容容器,允许Action脱离容器单独被测试。如如果需要Struts2 Action仍仍然可以访问初始的 request和 response。但是,其他的元素减少或者消除了直接访问 Http Servetrequest和HttpServletresponsel的必要性。
3.从 action线程模式分析
  ●  Struts1 Action是单例模式并且必须是线程安全的,因为仅有 Action的一个实例来处理所有的请求。单例策略限制了 Struts1 Actior能作的事,并且要在开发时特别小心。Action资源必须是线程安全的或同步的。
  ●  Struts2 Action对象为每一个请求产生一个实例,因此没有线程安全问题。(实际上servlet容器给每个请求产生许多可丢弃的对象,并且不会导致性能和垃圾回收问题)
posted @ 2018-05-08 21:29  Kevin.ZhangCG  阅读(832)  评论(0编辑  收藏  举报