Struts2

Struts2 简介

Struts2 是一种流行的 Java模型 - 视图 - 控制器(MVC)框架。成功地结合了 WebWork和Struts1.x 两种 web 框架。Struts2是以WebWork为核心,采用拦截器机制对用户的请求进行处理。

从一个高水平角度看,Struts2 是一个MVC拉动的(或MVC2)框架,Struts2 的模型-视图-控制器模式是通过以下五个核心部分进行实现的:

  • 操作(Actions)
  • 拦截器(Interceptors)
  • 值栈(Value Stack)/OGNL
  • 结果(Result)/结果类型
  • 视图技术

而Struts2 与传统的MVC框架略有不同,因为它由Action扮演模型的角色,而不是控制器,虽然这样会有一些重叠。

Struts 2çæ¶æ

 

Struts2 配置文件

web.xml文件

这个文件为每个web应用程序提供接入点。在部署描述符(web.xml)中,Struts2 应用程序的接入点将会定义为一个过滤器。因此我们将在web.xml里定义一个FilterDispatcher类的接入点。

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

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

 struts.xml文件

struts.xml中主要配置Struts项目的一些全局的属性,用户请求和响应Action之间的对应关系,以及配置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>
    <!-- 配置struts可以受理的请求的扩展名 -->
    <constant name="struts.action.extension" value="action,do,"></constant>
    <!--
        package:包,struts2使用package来组织模块
        name属性:必须,用于其他的包应用当前包
        extends:当前包继承哪个包,继承的,即可以继承其中的所有的配置,
                 通常情况下继承struts-default
        namespace:可选,如果它没有给出,则以“/”为默认值,若namespace有一个非默认值,
                   则要想调用这个包里的Action,就必须
                   把这个属性所定义的命名空间添加到有关的URI字符串里
    -->
	<package name="helloworld" extends="struts-default">
    <!--
            配置一个action:一个struts2的请求就是一个action
            name:对应一个struts2的请求的名字(或对一个servletPath,但去除/和扩展名),
                  不包含扩展名
            class:默认值为com.opensymphony.xwork2.ActionSupport
            method:默认值为execute
            result:结果,表示action方法执行后可能返回的一个结果,
                    代表action方法执行后,可能去的一个目的地,
                    所以一个action节点可能会有多个result子节点。
                    多个result子节点使用name来区分。
            name:标识一个result,和action方法的返回值对应,默认值为success
            type:表示结果的类型。默认值为dispatcher(转发到结果)。redirect(重定向),
                  但是重定向不能跳转到WEB-INF目录下。
        -->
    <!--
        ActionSupport是默认的Action类:若某个action节点没有配置class属性,则ActionSupport即为            
        待执行的Action类,而execute方法即为默认执行的action方法(该方法返回success字符串)
    --> 
	<action name="product-input">
		<result>/WEB-INF/pages/input.jsp</result> 
	</action>
		<!-- product-save请求调用Product类的save方法,方法返回值对应result的name-->
	<action name="product-save" class="com.struts2.helloworld.Product" method="test">
		<result name="details">/WEB-INF/pages/details.jsp</result>
	</action>
	</package>
</struts>

通配符匹配

<body>
    <a href="product-input.action">Product Input</a>
			
    <!-- 通配符匹配 -->
    <a href="UserAction-save?name=save">User Save</a>

    <a href="UserAction-update?name=update">User Update</a>

    <a href="UserAction-delete?name=delete">User Delete</a>

    <a href="UserAction-query?name=query">User Query</a>

</body>
    <!-- 利用通配符匹配 -->
    <action name="UserAciton-*" class="com.struts2.action.UserAciton" method="{1}">
        <result name="{1}-success">/success.jsp</result>
    </action>

struts提供了一种模块化struts.xml文件的方法,你可以将文件拆分为多个xml文件,并用以下方式导入它们。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
     <include file="my-struts1.xml"/>
     <include file="my-struts2.xml"/>
</struts>

struts-config.xml文件

struts-config.xml配置文件是Web Client中View和Model组件之间的链接,但在你99.99%的项目里你不必使用这些设置。 struts-config.xml配置文件包含以下主要元素:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.0//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_0.dtd">

<struts-config> <!-- 这是配置文件的根节点 -->

   <!-- 这是你将ActionForm子类映射到name的位置,你可以在struts-config.xml文件的其余部分,甚至 
        在JSP页面上,将这个name用作ActionForm的别名 -->
   <form-beans>
      <form-bean name="login" type="test.struts.LoginForm" />
   </form-beans>

   <!-- 此部分将你在webapp上的页面映射到name,你可以使用这个name来引用实际页面。这避免了对你网 
        页上的URL进行硬编码 -->
   <global-forwards>
   </global-forwards>

   <!-- 这是你声明表单处理程序的地方,也被称为操作映射(action mappings) -->
   <action-mappings>
      <action
         path="/login"
         type="test.struts.LoginAction" >

         <forward name="valid" path="/jsp/MainMenu.jsp" />
         <forward name="invalid" path="/jsp/LoginView.jsp" />
      </action>
   </action-mappings>

   <!-- 这部分是配置Struts的内部,在实际情况中很少使用 -->
   <controller 
      contentType="text/html;charset=UTF-8"
      debug="3"
      maxFileSize="1.618M"
      locale="true"
      nocache="true"/>

</struts-config>

struts.properties文件

这个配置文件提供了一种机制来改变框架的默认行为。实际上,struts.properties配置文件中包含的所有属性也可以在web.xml中配置使用init-param,以及在struts.xml配置文件中使用constant标签。

struts.properties文件中配置的值将覆盖default.properties中配置的默认值,这些值包含在struts2-core-x.y.z.jar分布中。有一些属性,你可以考虑改为使用struts.properties。

### When set to true, Struts will act much more friendly for developers
struts.devMode = true

### Enables reloading of internationalization files
struts.i18n.reload = true

### Enables reloading of XML configuration files
struts.configuration.xml.reload = true

### Sets the port that the server is run on
struts.url.http.port = 8080

 

Struts2 Actions动作

Actions是Struts2框架的核心,因为它们适用于任何MVC(Model View Controller)框架。 每个URL映射到特定的action,其提供处理来自用户的请求所需的处理逻辑。
但action还有另外两个重要的功能。 首先,action在将数据从请求传递到视图(无论是JSP还是其他类型的结果)方面起着重要作用。 第二,action必须协助框架确定哪个结果应该呈现在响应请求的视图中。

创建Action

Struts2中actions的唯一要求是必须有一个无参数方法返回String或Result对象,并且必须是POJO。如果没有指定no-argument方法,则默认是使用execute()方法。

ActionSupport类是默认的Action类,若某个action节点没有配置class属性,则ActionSupport类即为待执行的Action类,而类中的execute方法即为要默认执行的action方法。

在这个类中还默认封装了一些静态变量(同Action接口一样)

	* SUCCESS       -- 成功.
	* INPUT         -- 用于数据表单校验.如果校验失败,跳转INPUT视图.
	* LOGIN         -- 登录.
	* ERROR         -- 错误.
	* NONE          -- 页面不转向.

 这个类中的默认执行方法

public String input() throws Exception {
    return "input";
}

public String doDefault() throws Exception {
    return "success";
}

public String execute() throws Exception {
    return "success";
}

让我们来看看在Hello World示例中的action方法: 

public class UserAciton {
	
	public String test() {
		System.out.println("details...");
		return "details";
	}

    public String execute() throws Exception {
        return "success";
   }

	public String save() {
		System.out.println("save...");
		return "save-success";
	}
	
	public String update() {
		System.out.println("update...");
		return "update-success";
	}
	
	public String delete() {
		System.out.println("delete...");
		return "delete-success";
	}
	
	public String query() {
		System.out.println("query...");
		return "query-success";
	}
	
	
}

为了说明action方法控制视图的要点,让我们对execute方法进行以下更改,并扩展ActionSupport类如下:

public class HelloWorldAction extends ActionSupport{
   private String name;

   public String execute() throws Exception {
      if ("SECRET".equals(name))
      {
         return SUCCESS;
      }else{
         return ERROR;  
      }
   }
   
   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }
}

在这个例子中,我们在execute方法中使用一些逻辑来查看name属性。如果属性等于字符串“SECRET”,我们返回SUCCESS作为结果,否则我们返回ERROR作为结果。因为我们已经扩展了ActionSupport,所以我们可以使用String常量、SUCCESS和ERROR。 现在,让我们修改struts.xml文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
   "http://struts.apache.org/dtds/struts-2.0.dtd">
   <struts>
      <constant name="struts.devMode" value="true" />
      <package name="helloworld" extends="struts-default">
         <action name="hello" 
            class="cn.w3cschool.struts2.HelloWorldAction"
            method="execute">
            <result name="success">/HelloWorld.jsp</result>
            <result name="error">/AccessDenied.jsp</result>
         </action>
      </package>
</struts>

如果返回结果是SUCCESS将调用HelloWorld.jsp文件,如果action的结果是ERROR,即字符串常量为“error”,AccessDenied.jsp将被框架调用。

 

Struts2 拦截器

拦截器在概念上与servlet过滤器或JDK代理类相同。拦截器允许横切功能,把action以及框架分开实现。你可以使用拦截器实现以下操作:

  • 在调用action之前提供预处理逻辑。

  • 在调用action后提供后处理逻辑。

  • 捕获异常,以便可以执行备用处理。

Struts2框架中提供的许多功能都是使用拦截器实现的,包括异常处理,文件上传,生命周期回调和验证等。事实上,由于Struts2将其大部分功能基于拦截器,因此不太可能为每个action分配7个或8个拦截器。

Struts 2框架提供了一个良好的开箱即用的拦截器列表,这些拦截器预先配置好并可以使用。 下面列出了几个重要的拦截器:

序号拦截器和说明
1alias

允许参数在请求之间使用不同的别名。

2checkbox

通过为未检查的复选框添加参数值false,以辅助管理复选框。

3conversionError

将字符串转换为参数类型的错误信息放置到action的错误字段中。

4createSession

自动创建HTTP会话(如果尚不存在)。

5debugging

为开发人员提供一些不同的调试屏幕。

6execAndWait

当action在后台执行时,将用户发送到中间的等待页面。

7exception

映射从action到结果抛出的异常,允许通过重定向自动处理异常。

8fileUpload

便于文件上传。

9

i18n

在用户会话期间跟踪选定的区域。

10logger

通过输出正在执行的action的名称提供简单的日志记录。

11params

设置action上的请求参数。

12prepare

这通常用于执行预处理工作,例如设置数据库连接。

13profile

允许记录action的简单分析信息。

14scope

在会话或应用程序范围内存储和检索action的状态。

15ServletConfig

提供可访问各种基于servlet信息的action。

16timer

以action执行时间的形式提供简单的分析信息。

17token

检查action的有效性,以防止重复提交表单。

18validation

提供action的验证支持。

如下图,我们首先使用timer拦截器,目的是测量执行action方法所需的时间。同时我们使用params拦截器,目的是将请求参数发送给action。 

<struts>
   <constant name="struts.devMode" value="true" />
   <package name="helloworld" extends="struts-default">
      <action name="hello" 
         class="cn.w3cschool.struts2.HelloWorldAction"
         method="execute">
         <interceptor-ref name="params"/>
         <interceptor-ref name="timer" />
         <result name="success">/HelloWorld.jsp</result>
      </action>
   </package>
</struts>

 

Struts2 结果类型

如前面所述,<results>标签在Struts2 MVC框架中扮演视图的角色。Action负责执行业务逻辑,下一步就是使用<results>标签显示视图。
通常有一些导航规则附加的结果。例如,如果action是进行验证用户,则有三种可能的结果:(a)成功登录(b)登录失败:用户名或密码不正确(c)帐户锁定。
在这种情况下,action将配置三个可能的结果字符串和三个不同的视图来渲染结果,这在我们前面的例子中已经看到过了。
但是,Struts2不绑定使用JSP作为视图技术。毕竟,MVC范例的目的是保持图层分离和高度可配置。例如,对于Web2.0客户端,你可能希望返回XML或JSON作为输出。在这种情况下,你可以为XML或JSON创建一个新的结果类型并实现这一点。
Struts提供了许多预定义的结果类型,我们已经看到的是默认的结果类型dispatcher,它用于分发到JSP页面。Struts允许你使用其他标记语言为视图技术呈现结果,较常选用的包括VelocityFreemakerXSLTTiles

dispatcher结果类型

dispatcher结果类型是默认的类型,如果未指定其他结果类型,则使用此类型。它用于转发到服务器上的servlet,JSP,HTML等页面。它使用RequestDispatcher.forward()方法。
如下面这个“简写”的版本,里面我们用一个JSP路径作为结果标签的主体。

①转发到一个JSP:

<result name="success">
   ${basePath}/HelloWorld.jsp  //struts.xml中可以使用EL表达式
</result>

我们还可以使用<result>元素中的<param name="location">标签来指定JSP文件

<result name="success" type="dispatcher">
   <param name="location">
      /HelloWorld.jsp
   </param >
</result>

②转发到一个Action:

<action name="testResult" class="com.struts2.action.TestResultAction">
    <!--参数之间必须使用&amp;。&amp;是&在xml中转义字符。需要在对应的Action类中定义参数的变量及其get和set方法。-->
    <result name="success" type="chain"><!-- 转发到一个Action并携带请求参数 -->
        <param name="actionName">testAction</param>
        <param name="namespace">/atguigu</param>
        <param name="errorcode">${errorcode}&amp;error=1</param> 
    </result>			
</action>

 

redirect结果类型

redirect结果类型调用标准的response.sendRedirect()方法,使得浏览器向给定的位置创建一个新请求。
我们可以在<result...>元素的主体中或作为<param name="location">的元素中给定位置。

①重定向到一个JSP

<action name="hello" 
   class="com.tutorialspoint.struts2.HelloWorldAction"
   method="execute">
   <result name="success" type="redirect">
       <param name="location">
         /NewWorld.jsp
      </param >
   </result>
</action>

②重定向到一个Action

<action name="testResult" class="com.struts2.action.TestResultAction">															
    <result name="index" type="redirectAction">
        <!-- 下面两个参数和底下新建的package相关参数对应 -->
        <param name="actionName">testAction</param>	<!-- 对应要跳转到的Action -->
        <param name="namespace">/atguigu</param>  <!-- 指定目标Action所在的命名空间 -->
    </result>	 
</package>
	
<package name="testPackage" namespace="/atguigu" extends="struts-default">
    <action name="testAction" class="com.struts2.action.TestAction">
        <result>/success.jsp</result>
    </action>
</package>

我们还可以通过redirect的响应类型便捷的实现redirectAction功能,但是转发不能通过这种写法实现

<result name="index" type="redirect">
    ${basePath}/atguigu/testAction.do
</result> 

 

Struts2 值栈/OGNL

Struts2使用OGNL将请求Action的参数封装为对象存储到值栈中,并通过OGNL表达式读取值栈中的对象属性值。

每次访问action时候,都会创建action对象,在每个action对象里面都会有一个值栈对象。

在ValueStack对象的内部有两个逻辑部分:

①ObjectStack(对象栈):struts把Action和相关对象压入ObjectStack中。实际上是CompoundRoot类型,是一个使用ArrayList定义的栈。里边保存各种和当前Action实例相关的对象,是一个数据结构意义上的栈。

②ContextMap(Map栈):struts把各种各样的映射关系(一些Map类型的对象)压入ContextMap中,实际上是OgnlContext类型,是个Map,也是对ActionContext的一个引用。里边保存着各种Map:request、session、application、parameters,attr。


你可以在Action中获取值栈对象,如下所示:

ActionContext.getContext().getValueStack()

一旦你有一个值栈对象,你可以使用以下方法来操纵该对象:

序号值栈方法和说明
1Object findValue(String expr)

通过在默认搜索顺序中对值栈评估所给定的表达式来查找值。

2CompoundRoot getRoot()

获取将对象推入值栈的CompoundRoot。

3Object peek()

获取值栈顶部的对象而不改变值栈。

4Object pop()

获取值栈顶部的对象,并将其从值栈中删除。

5void push(Object o)

将对象放在值栈的顶部。

6void set(String key,Object o)

使用给定的key在值栈上设置一个对象,使其可通过findValue(key,...)检索。

7void setDefaultType(Class defaultType)

设置在获取值时要转换的默认类型。

8void setValue(String expr,Object value)

尝试使用由默认搜索顺序给定的表达式在值栈的bean上设置属性。

9int size()

获取值栈中的对象数。

OGNL(Object-Graph Navigation Language,对象图导航语言)是一种强大的表达式语言,用于引用和操作值栈上的数据,还可用于数据传输和类型转换。
OGNL非常类似于JSP表达式语言。OGNL基于上下文中存有根对象或默认对象的理念,使用标记符号(即#号)来引用默认或根对象的属性。
如前面所述,OGNL是基于上下文的,而Struts构建了一个ActionContext映射以供OGNL使用。 ActionContext映射包含以下内容:

  • 应用程序 - 应用程序作用域变量

  • 会话 - 会话作用域变量

  • 根/值栈 - 所有的action变量都存储在这里

  • 请求 - 请求作用域变量

  • 参数 - 请求参数

  • 属性 - 存储在页面,请求,会话和应用程序作用域中的属性

访问对象栈中的属性

若想访问ObjectStack里的某个对象的属性,可以使用以下几种形式之一(OGNL写在value中): 

<s:property value="object.propertyName">
<s:property value="object.['propertyName']">
<s:property value="object.["propertyName"]">

ObjectStack里的对象可以通过一个从零开始的下标来引用。

ObjectStack里的栈顶对象可以用[0]来引用,它下面的那个对象可以用[1]引用。若希望返回栈顶对象的message属性值:[0].message或[0]['message']或[0]["message"]

若在指定的对象里没有找到指定的属性,则到指定对象的下一个对象里继续搜索,即[n]的含义是从第n个开始搜索,而不是只搜索第n个对象。若从栈顶对象开始搜索,则可以省略下标部分。

示例

创建用于访问值栈的action类,然后在details.JSP视图页面设置使用OGNL进行访问的几个key。

public class HelloWorldAction extends ActionSupport{
   private String name;
   
   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }
   
   public String execute() throws Exception {
      //获取值栈对象
      ValueStack stack = ActionContext.getContext().getValueStack();
      Map<String, Object> context = new HashMap<String, Object>();
      //把对象压入到值栈的栈顶
      context.put("key1", new String("This is key1")); 
      context.put("key2", new String("This is key2"));
      stack.push(context);
      System.out.println("Size of the valueStack: " + stack.size());
      return "success";
   }  
}

实际上,Struts 2在执行时会将action添加到值栈的顶部。所以,通常放置东西在值栈的方法是添加getters/setters的值到Action类,然后使用<s:property>标签访问值(property标签用来输出值栈中的一个属性值)。

创建index.jsp文件:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
   pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<title>Hello World</title>
</head>
<body>
   <h1>Hello World From Struts2</h1>
   <form action="hello">
      <label for="name">请输入用户名</label><br/>
      <input type="text" name="username"/>
      <input type="submit" value="Say Hello"/>
   </form>
</body>
</html>

创建视图details.jsp文件:

<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %> <!-- 切记不要忘记引入这个 -->
<html>
<head>
<title>Hello World</title>
</head>
<body>
   Entered value : <s:property value="username"/>或者${username}<br/>
   Value of key 1 : <s:property value="key1" /><br/>
   Value of key 2 : <s:property value="key2" /> <br/>
</body>
</html>

现在,在index.jsp的文本框中输入任意单词,然后单击“Say Hello”按钮执行定义的action。可以在控制台看到以下输出:

Size of the valueStack: 3

这意味着它将显示你输入的任何值和我们放在值栈上的key1和key2的值。

页面最终跳转到details.jsp,显示效果如下:

this is key1
this is key2
fyj

注意:处于栈顶的分别是 key1 和 key2,其次才是我们提交的 username 值。

 

访问Map栈中的属性

 若想访问ContextMap里的某个对象的属性,可以使用以下几种形式之一: 

<s:property value="#object.propertyName">
<s:property value="#object.['propertyName']">
<s:property value="#object.["propertyName"]">

示例

创建Action类:

public class Product {
	private Integer productId;
	private String productName;
	private String productDesc;
	public Integer getProductId() {return productId;}
	public void setProductId(Integer productId) {this.productId = productId;}
	public String getProductName() {return productName;}
	public void setProductName(String productName) {this.productName = productName;}
	public String getProductDesc() {return productDesc;}
	public void setProductDesc(String productDesc) {this.productDesc = productDesc;}
    public String save(){
        System.out.println("save:"+this);
        //获取值栈对象
        ValueStack stack = ActionContext.getContext().getValueStack();
        Test test = new Test();
        test.setProductDesc("AABBCC");
        test.setProductName("ABCD");
        stack.push(test);
        sessionMap.put("product",this);
        requestMap.put("test",test);
        return "success";
    }
    private Map<String,Object> sessionMap;
    private Map<String,Object> requestMap;

}

在视图details.jsp访问Map栈中的属性值

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %><html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
    ProductName:<s:property value="#session.product.productName"/>

    ProductName:<s:property value="#request.test.productName"/>

    <!-- 我们还可以调用对象栈的方法为一个属性赋值 -->
    <s:property value="setProductName('fyj')"/>
</body>
</html>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mephisto180502

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值