JAVAWEB开发之Struts2详解(四)——ognl与valueStack(重点)、Struts常用标签、防止表单重复提交、Struts2中内置json插件

ognl

ognl中有一个OgnlContext,它可以设置root与非root,root中获取数据时,不需要加#,而非root数据获取时需要加#号。
简单示例如下:
OgnlDemo1
package cn.itcast.ognl;

import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;

public class OgnlDemo1 {

	public static void main(String[] args) throws OgnlException {
		// ognl可以通过对象调用方法

		// System.out.println("aaa".length());

		// 使用ognl来完成上面操作

		// 1.创建一个ognl上下文
		OgnlContext context = new OgnlContext();

		Object obj1 = Ognl.getValue("'aaa'.length()", context.getRoot());

		System.out.println(obj1);
	}
}


OgnlDemo2

package cn.itcast.ognl;

import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;

public class OgnlDemo2 {

	public static void main(String[] args) throws OgnlException {
		// ognl可以通过类调用静态方法

		System.out.println(Math.max(10, 20));
		System.out.println(Math.PI);
		// 使用ognl来完成上面操作

		// 1.创建一个ognl上下文
		OgnlContext context = new OgnlContext();

		Object obj1 = Ognl.getValue("@java.lang.Math@max(10,20)",
				context.getRoot());

		System.out.println(obj1);

		Object obj2 = Ognl.getValue("@java.lang.Math@PI", context.getRoot());

		System.out.println(obj2);
	}

}

关于存取根与非根数据如下所示:
Person
package cn.itcast.ognl;

public class Person {

	private String name;
	private Dog dog;

	public String getName() {
		return name;
	}

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

	public Dog getDog() {
		return dog;
	}

	public void setDog(Dog dog) {
		this.dog = dog;
	}

}

Dog

package cn.itcast.ognl;

public class Dog {

	private String name;

	private Person p;

	public String getName() {
		return name;
	}

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

	public Person getP() {
		return p;
	}

	public void setP(Person p) {
		this.p = p;
	}

}

OgnlDemo3
package cn.itcast.ognl;

import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;

public class OgnlDemo3 {

	public static void main(String[] args) throws OgnlException {

		// 创建一个ognl上下文
		OgnlContext context = new OgnlContext();// 本质上是一个Map集合

		Person p = new Person();
		p.setName("张三");

		Dog dog = new Dog();
		dog.setName("lucy");

		p.setDog(dog); // 张三有条狗叫lucy

		context.setRoot(p);

		Dog dog1 = new Dog();
		dog1.setName("豆豆");

		Person pp = new Person();
		pp.setName("jams");
		dog1.setP(pp);

		context.put("dog", dog1);

		context.put("name", "tom");

		// 使用ognl来获取根中数据,不需要加#
		Object name1 = Ognl.getValue("name", context, context.getRoot());

		System.out.println(name1);

		// 使用ognl来获取非根中的数据,获取非根中的数据 需要使用#
		Object name2 = Ognl.getValue("#name", context, context.getRoot());

		System.out.println(name2);

		// 获取张三的狗的名称
		Object name3 = Ognl.getValue("dog.name", context, context.getRoot());

		System.out.println(name3);

		// 获取豆豆的主人名称
		Object name4 = Ognl.getValue("#dog.p.name", context, context.getRoot());

		System.out.println(name4);

	}
}

ognl介绍

ognl是Object Graphic Navigation Language(对象导航图语言)的缩写,它是一个开源项目。Struts2框架使用ognl作为默认的表达式语言。
ognl是一种比EL强大很多倍的语言。
ognl相对其它表达式语言具有下面五大优势:
1、支持对象方法调用,如xxx.doSomeSpecial();
2、支持类静态方法的调用和值访问,表达式的格式:@[类全名(包括包路径)]@[方法名| 值名],例如:@java.lang.String@format("foo %s","bar");或@tutorial.MyConstant@APP_NAME;
设置:struts.ognl.allowStaticMethodAccess=true;
3、访问ognl上下文(OGNL context)和ActionContext;(重点:操作valueStack值栈)
4、支持赋值操作和表达式串联,如price=100,discount=0.8,caculatePrice(),这个表达式会返回80;
5、操作集合对象。
示例:
<h1>实例方法调用</h1>
<s:property value="'abcdef'.length()"/>
<h2>静态方法调用</h2>
<s:property value="@java.lang.String@format('你好, %s','小明')"/>
演示:在struts2中使用ognl表达式
需要结合struts2的标签使用<s:property value="ognl表达式">
<s:property value="'abc'.length()"/>  演示对象调用方法
<s:property value="@java.lang.Math@max(10,20)"/> 演示静态成员访问.
注意:在struts2中使用静态成员访问,必须设置一个常量:
struts.ognl.allowStaticMethodAccess=false
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>演示:使用ognl来通过对象调用方法</title>
</head>

<body>
	<s:property value="'abc'.length()" />
	<hr>

	<s:property value="@java.lang.Math@max(10,20)" />
</body>
</html>

Struts2中的valueStack

valueStack概述:
ValueStack实际上是一个接口com.opensymphony.xwork2.util.ValueStack,在Struts2中利用ognl时,实际上使用的是实现了该接口的OgnlValueStack类,这个类是Struts2利用OGNL的基础
  • ValueStack(值栈):贯穿Action的生命周期(每个Action类的对象实例都拥有一个ValueStack对象)相当于一个数据中的中转站.在其中保存当前Action对象和其他相关对象。
  • Struts框架把ValueStack对象保存在名为"struts.valueStack"的请求属性中,request中。
在ValueStack对象内部有两个逻辑部分:
  • ObjectStack:Struts把动作和相关对象压入ObjectStack中—(List)
  • ContextMap:Struts把各种各样的映射关系(一些Map类型的对象)压入ContextMap中

Struts会把下面这些映射压入ContextMap中

  • parameters:该Map中包含当前请求的请求参数
  • request:该Map中包含当前request对象中的所有属性
  • session:该Map中包含当前session对象中的所有属性
  • application:该Map中包含当前application对象中的所有属性
  • attr:该Map按如下顺序来检索某个属性:request、session、application
理解Struts2中的ValueStack
断点执行如下代码:
Object ctx=ServletActionContext.getRequest().getAttribute("struts.valueStack");

______________________________________________________________________________

理解OGNL Context
OGNL Context是Struts2的数据中心,结构示意图如下:

当Struts2接受一个请求时,会迅速创建ActionContext,ValueStack,action,然后将action存放进ValueStack,所以action的实例变量可以被OGNL访问
注意:Struts2中,OGNL表达式需要配合Struts标签才可以使用,如:<s:property value="name" />

问题1:什么是ValueStack?

valueStack主要是将action数据携带到页面上,通过ognl获取数据
1、ValueStack有一个实现类叫OgnlValueStack。
2、每一个action都有一个ValueStack(一个请求,一个request,一个action,一个ValueStack)valueStack生命周期就是request生命周期。
3、valueStack中存储了当前action对象以及其它常用web对象(request,session,application,parameters)
4、Struts2框架将valueStack以"struts.valueStack"为名存储到request域中

ValueStack内部结构图如下:


问题2:valueStack结构?

ValueStack中存在root属性(CompoundRoot)、context属性(OgnlContext)
* CompoundRoot 就是ArrayList
* OgnlContext 就是Map
list 集合中存储的是action相关信息
map集合中存储的是相关映射信息,包含 parameters、request、session,application,attr等
想要从list中获取数据,可以不使用#号(它就是ognl的root)
如果从map中获取数据,需要使用#(其实在Struts2中的map—context其实就是OgnlContext)
结论:
ValueStack有两部分List   Map
在Struts2中List就是root,Map就是OgnlContext
默认情况下,在Struts2中从ValueStack中获取数据从root中获取

问题3:值栈对象的创建,ValueStack和ActionContext是什么关系?

ActionContext ctx = ActionContext.getContext();
if (ctx != null) {
stack = ctx.getValueStack();
}
ValueStack是每一次请求时,都会创建
在ActionContext中持有了ValueStack的引用

ValueStack对象的创建过程
StrutsPrepareAndExecuteFilter
doFilter方法
prepare.createActionContext(request, response); 
创建ActionContext和ValueStack
ctx = new ActionContext(stack.getContext());
ActionContext引用ValueStack对象 
Dispatcher——serviceAction方法
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
将ValueStack对象 保存到request 范围


问题4:如何获得值栈对象?

对于ValueStack获取有两种方式:
1、通过request获取
ValueStack vs=(ValueStack)ServletActionContext.getRequest().getAttribute(ServletActionContext.STATUS_VALUESTACK_KEY);
2、通过ActionContext获取
ValueStack vs=ActionContext.getContext().getValueStack();


问题5:向值栈中保存数据(主要针对root)

主要有两个方法
push(Object obj)----->底层就是root.add(0,obj) 将数据存储到栈顶。
set(String name,Object obj)------->底层是将数据封装到HashMap中,在将这个HashMap通过push存储。
在JSP通过<s:debug />查看值栈内容
ActionContext提供了对ognl上下文对象中数据操作的方法
ServletActionContext.getRequest().setAttribute("username", "username_request");
ServletActionContext.getServletContext().setAttribute("username", "username_application");
ServletActionContext.getContext().getSession().put("username", "username_session");
 // 获取值栈对象
ValueStack valueStack=ServletActionContext.getContext().getValueStack();
System.out.println("valueStack       "+valueStack);
 // 向值栈保存数据
valueStack.set("username", "username_valueStack");
valueStach.push("www.baidu.com");

问题6:如何在JSP中获取值栈的数据?

获取root中数据不需要#,而context中数据需要#
1、如果栈顶是一个Map集合,获取时,可以直接通过Map集合的key来获取value
<s:property value="username" />
2、如果栈顶数据不是一个Map,没有key值,可以通过序号来获取
<s:property value="[0]"> 从0的位置向下查找所有
<s:property value="[0].top"> 只查找0位置上数据(栈顶数据)
3、获取OgnlContext中的数据
request:<s:property value="#request.username"/>
session:<s:property value="#session.username"/>
application:<s:property value="#application.username"/>
attr:<s:property value="#attr.username"/>
parameters:<s:property value="#parameters.cid[0]"/>

ValueStack主流应用:就是解决将action数据携带到jsp页面

 问题:action向jsp携带数据,都是什么样的数据?

1、文本(字符串)
fieldError  校验数据错误信息提示
actionError  关于逻辑操作时错误信息(例如登录失败)
message  就是一个信息提示
this.addFieldError("msg", "字段错误信息");
this.addActionError("Action全局错误信息");
this.addActionMessage("Action的消息信息");
fieldError 针对某一个字段错误信息(常用于表单校验)、actionError(普通错误信息,不针对某个字段 如登录失败)、actionMessage 通用消息
在jsp中使用 struts2提供标签 显示消息信息
<s:fielderror fieldName="msg"/>
<s:actionerror/>
<s:actionmessage/>
2、复杂数据
 可以使用valueStack存储
在action中存储数据
 List<User> users = new ArrayList<User>();
users.add(new User("tom", "123", 20, "男"));
users.add(new User("james", "456", 21, "男"));
users.add(new User("fox", "789", 26, "男"));
vs.push(users);

在页面上获取数据:
使用了<s:iterator>标签来迭代集合。
<s:iterator value="[0].top" var="user"> 这是将集合中迭代出来每一个元素起个名称叫user,而user是存储在context中,不在root中.l
<s:iterator value="[0].top" var="user">
username:<s:property value="#user.username"/><br>
password:<s:property value="#user.password"/>
<hr>
</s:iterator>
注意:如果我们在使用<s:iterator>进行迭代时,没有给迭代出的元素起名.
<s:iterator value="[0].top">
username:<s:property value="username"/><br>
password:<s:property value="password"/>
<hr>
</s:iterator>


关于默认压入到valueStack中的数据

1、访问的action对象会被压入到valueStack中。
DefaultActionInvocation 的init方法 stack.push(action);
Action如果想传递数据给JSP,只有将数据保存成成员变量,并且提供get方法就可以了。
2.ModelDriveInterceptor会执行下面操作
ModelDriven modelDriven = (ModelDriven) action;
ValueStack stack = invocation.getStack();
Object model = modelDriven.getModel();
if (model !=  null) {
stack.push(model);
}
将实现了ModelDrive接口的action中getModel方法的返回值,也就是我们所说的model对象压入到了valueStack.

问题7:为什么EL表达式可以访问valueStack中的数据?

Struts2框架中所使用的request对象,是增强后的request对象。
${ username }--------->request.getAttribute("username");
增强后的request,会首先在request范围查找,如果查找不到,会在valueStack中查找。
StrutsPreparedAndExecuteFilter的doFilter代码中 request = prepare.wrapRequest(request);
* 对Request对象进行了包装 ,StrutsRequestWrapper 
* 重写request的 getAttribute 
Object attribute = super.getAttribute(s);
if (attribute == null) {
   attribute = stack.findValue(s);
}
访问request范围的数据时,如果数据找不到,去值栈中找
request对象 具备访问值栈数据的能力(查找root的数据)

OGNL表达式常见用法($ % #)

#号的用法

用法一: 访问OGNL上下文和Action上下文,#相当于ActionContext.getContext()
  <s:property value="#request.name" />  ------------>  ActionContext().getContext().getRequest().get("name");
如果访问OgnlContext中的除了被抽取后的root外的其他对象,由于它们不是根对象,所以在访问时,需要添加#前缀

也可以写为#request['username'] 或#session['username']或#application['username']
Action中代码: 
 ServletActionContext.getRequest().setAttribute("username", "username_request");
 ServletActionContext.getServletContext().setAttribute("username", "username_application");
 ServletActionContext.getContext().getSession().put("username", "username_session");
 ValueStack valueStack=ServletActionContext.getContext().getValueStack();
 valueStack.set("username", "username_valueStack");
Jsp页面:
    使用ognl表达式取值*****************************<br>
    request:<s:property value="#request.username"/><br>
    session:<s:property value="#session.username"/><br>
    application:<s:property value="#application.username"/><br>
    attr:<s:property value="#attr.username"/><br>
    valueStack:<s:property value="username"/><br>
    parameters:<s:property value="#parameters.cid[0]"/><br>
用法二:不写#号 默认在值栈root中进行查找

在OgnlValueStack类中有一个List类型的root变量,它存放了一组对象。
处于第一位的对象叫栈顶对象。
通常我们在ognl表达式里直接写上属性的名称即可访问root变量里对象的属性,搜索顺序是从栈顶元素开始寻找,如果栈顶对象不存在该属性,就会从第二个对象开始寻找,如果没有找到就会从第三个对象开始寻找,依次向下访问直到找到为止。代码示例剖析如下图所示:

<s:property value="name" /> 在root中查找name属性 
* 查询元素时,从root的栈顶元素 开始查找, 如果访问指定栈中元素   
<s:property value="[1].name" />  访问栈中第二个元素name属性 
* 访问第二个元素对象 <s:property value="[1].top" />
用法三:进行投影映射(过滤)
1、集合的投影(只输出部分属性)
collocationName.{ expression }

<h1>遍历集合只要name属性</h1>
<s:iterator value="products.{name}" var="pname"> 
<s:property value="#pname"/>
</s:iterator>
2、遍历时对数据设置条件
例如过滤年龄大于19 的用户
集合的过滤有以下三种方式:
方式一:"?#":过滤所有符合条件的集合,如:users.{?#this.age>19};
方式二:"^#":过滤第一个符合条件的元素,如:users.{^#this.age>19};
方式三:"$#":过滤最后一个符合条件的元素,如:users.{$#this.age>19};
 this:表示集合中的每个元素。
<h1>遍历集合只要price大于1500商品</h1>
<s:iterator value="products.{?#this.price>1500}" var="product"> 
<s:property value="#product.name"/> --- <s:property value="#product.price"/>
</s:iterator>

3、投影综合使用
投影(过滤)操作返回的是一个集合,可以使用索引取得集合中指定的元素,如:users.{?#this.age>19}[0]

<s:iterator value="allList.{?#this.age>25}.{name}" var="person">
        <s:property/><br>
</s:iterator> 
<s:iterator value="allList.{?#this.age>25}[0]" var="person">
        <s:property/><br>
 </s:iterator> 

<h1>只显示价格大于1500 商品名称</h1>
<s:iterator value="products.{?#this.price>1500}.{name}" var="pname"> 
<s:property value="#pname"/>
</s:iterator>  
用法四:使用#号构造Map,如#{‘foo1’:‘bar1’, ‘foo2’:‘bar2’}
经常结合Struts2标签用来生成select、checkbox、radio



<h1>使用#构造map集合 遍历</h1>
<s:iterator value="#{'name':'aaa','age':'20', 'hobby':'sport' }" var="entry">
key : <s:property value="#entry.key"/> , value:  <s:property value="#entry.value"/> <br/>
</s:iterator>

%号的使用

%号的用途是在标签的属性值被理解为字符串类型时,告诉执行环境%{}里的OGNL表达式。
%{表达式}  当前表达式会被作为ognl解析。
%{'表达式'} 当前表达式不会被作为ognl解析。
<s:property value="表达式"> 对于s:property标签,他的value属性会被默认作为ognl。以后,所有表达式如果想要让其是ognl  %{表达式}


$号用法

$作用:就是在配置文件中使用ognl表达式来获取valueStack中的数据
有两个主要用途:
  • 用于在国际化资源文件中,引用ognl表达式。
  • 在struts2配置文件中,引用ognl表达式


1.struts.xml
<result type="stream">
<param name="contentType">${contentType}</param>
</result>
2.在校验文件中使用
${min}  ${max}
${minLength} ${maxLength}
3.在国际化文件中使用
在properties文件中
  username=${#request.username}
在jsp页面
  <s:text name="username">
总结:#就是用于获取数据  %就是用于设置是否是ognl表达式  $就是在配置文件中使用ognl

Struts常用逻辑标签(property、set、iterator、if/elseif/else、url)

property标签

property标签用于输出指定值:
<s:property value="#name"  default="a default value" />
* default:可选属性,如果需要输出的属性值为null,则显示该属性的指定值。
* escape:可选属性,指定是否格式化HTML代码。
* value:可选属性,指定需要输出的属性值,如果没有指定该属性值,则默认输出ValueStack栈顶的值。

set标签

set标签用于将某个值放入指定范围。
var:变量的名字,name,id和var表达的含义是一样的,name,id被var替代。
scope:指定变量被放置的范围,该属性可以接收application、session、request、page或action。如果没有设置该属性,则默认放置在值栈的context中。
value:赋给变量的值,如果没有设置该属性,则将ValueStack栈顶的值赋给变量。

iterator标签

Iterator:标签用于对集合进行迭代,这里的集合包含List、set和数组。
value:可选属性,指定被迭代的集合,如果没有设置该属性,则使用ValueStack栈顶的集合。
var:可选属性,引用变量的名称。
status:可选属性,该属性指定迭代时IteratorStatus实例。该实例包含如下几个方法:
    int getCount(),返回当前迭代了几个元素
    int getIndex(),返回当前迭代元素的索引
    boolean isEvent(),返回当前被迭代元素的索引是否是偶数
    boolean  isOdd(),返回当前被迭代元素的索引是否是奇数
    boolean  isFirst(),返回当前被迭代元素是否是第一个元素
    boolean isLast(),返回当前被迭代元素是否是最后一个元素


st下的属性在:org.apache.struts2.views.jsp.IteratorStatus类下

if/elseif/else标签

if/elseif/else 基本的流程控制:if 标签可单独使用也可以和elseif标签以及else标签一起使用

url标签

url: 该标签用于创建url,可以通过"param"标签提供request参数
value:如果不提供就使用当前的action,使用value后缀必须加.action
action:用来生成url的action,如果没有则使用value
namespace:命名空间
var:引用变量的名称

ognl操作集合

使用ognl操作list和数组



ognl也可以直接创建集合对象,利用下拉列表框


使用ognl操作Map

    ognl用多种方式使用#号,每种是不同的.动态map对于动态单选按扭组很有用.
    创建map与创建list语法很相似,不同的是map前需要加"#"号.

操作示例:


代码示例演示ognl如下:

 
Product
package cn.test.domain;

public class Product {
	private String name;
	private double price;
	private int count;

	public String getName() {
		return name;
	}

	public Product() {
		super();
	}

	public Product(String name, double price, int count) {
		super();
		this.name = name;
		this.price = price;
		this.count = count;
	}

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

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	public int getCount() {
		return count;
	}

	public void setCount(int count) {
		this.count = count;
	}

}

User
package cn.test.domain;

public class User {

	public User() {
		super();
	}

	public User(String username, String password, int age, String sex) {
		super();
		this.username = username;
		this.password = password;
		this.age = age;
		this.sex = sex;
	}

	private String username;
	private String password;
	private int age;
	private String sex;

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

}
struts.xml
<?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>
	<constant name="struts.ognl.allowStaticMethodAccess" value="true" />
	<package name="default" namespace="/" extends="struts-default">

		<action name="ognlDemo1" class="cn.test.action.OgnlDemo1Action"></action>
		<action name="ognlDemo2" class="cn.test.action.OgnlDemo2Action">
			<result>/ognl2.jsp</result>
		</action>
		<action name="ognlDemo3" class="cn.test.action.OgnlDemo3Action">
			<result>/ognl3.jsp</result>
		</action>
		<action name="ognlDemo4" class="cn.test.action.OgnlDemo4Action">
			<result>/ognl4.jsp</result>
		</action>
		<action name="ognlDemo5" class="cn.test.action.OgnlDemo5Action">
			<result>/ognl5.jsp</result>
		</action>
		<action name="ognlDemo6" class="cn.test.action.OgnlDemo6Action">
			<result>/ognl6.jsp</result>
		</action>
	</package>
</struts>
my.properties


OgnlDemo1Action
package cn.test.action;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.ValueStack;

public class OgnlDemo1Action extends ActionSupport {
	@Override
	public String execute() throws Exception {
		// 获取ValueStack

		// 1.通过request获取
		ValueStack vs = (ValueStack) ServletActionContext.getRequest()
				.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
		System.out.println(vs);

		// 2.通过ActionContext获取
		ValueStack vs2 = ActionContext.getContext().getValueStack();

		System.out.println(vs2);

		return null;
	}

}

OgnlDemo2Action
package cn.test.action;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.ValueStack;

public class OgnlDemo2Action extends ActionSupport {
	@Override
	public String execute() throws Exception {

		// 向valueStack中存入数据
		ValueStack vs=ActionContext.getContext().getValueStack();
		
		vs.set("username", "tom");
		
		vs.push("hello world");
		
		return SUCCESS;
	}

}
ognl2.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>演示:使用ognl来获取valueStack数据</title>
</head>

<body>
	1.获取栈顶的map
	<br>
	<s:property value="username" />

	<hr>
	2.获得栈顶非Map集合数据
	<br>
	<s:property value="[1].top" />

	<hr>
	3.获得OgnlContext中数据
	<br>
	<%
		request.setAttribute("rname", "rvalue");
		session.setAttribute("sname", "svalue");
		application.setAttribute("aname", "avalue");
	%>

	<s:property value="#request.rname" />
	<br>
	<s:property value="#session.sname" />
	<br>
	<s:property value="#application.aname" />
	<br>

	<s:property value="#attr.sname" /><br>
	<s:property value="#parameters.username[0]" />

	<s:debug />
</body>
</html>

OgnlDemo3Action
package cn.test.action;

import java.util.ArrayList;
import java.util.List;

import cn.test.domain.User;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.ValueStack;

public class OgnlDemo3Action extends ActionSupport {
	@Override
	public String execute() throws Exception {

		// 向valueStack中存入数据(root)

		ValueStack vs = ActionContext.getContext().getValueStack();

		List<User> users = new ArrayList<User>();

		users.add(new User("tom", "123", 20, "男"));
		users.add(new User("jams", "456", 21, "男"));
		users.add(new User("fox", "789", 26, "男"));

//		vs.push(users);

		vs.set("users", users);
		return SUCCESS;
	}

}
ognl3.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>演示:使用ognl来获取valueStack中复杂数据</title>
</head>

<body>
	1.使用push存储数据存取
	<br>
	<s:property value="[0].top.users" />
	<br>

	<s:iterator value="[0].top.users" var="user">
    username:<s:property value="#user.username" />
		<br>
     password:<s:property value="#user.password" />
		<hr>
	</s:iterator>
	<hr>

	<s:iterator value="[0].top.users">
	username:<s:property value="username" />
		<br>
	password:<s:property value="password" />
		<hr>
	</s:iterator>
	<hr>
	2.使用set存储数据
	<hr>
	<s:property value="users" />
	<br>

	<s:iterator value="users" var="user">
	 username:<s:property value="#user.username" />
		<br>
	 password:<s:property value="#user.password" />
		<hr>
	</s:iterator>

	<hr>

	<s:iterator value="users">
	 username:<s:property value="username" />
		<br>
	 password:<s:property value="password" />
		<hr>
	</s:iterator>
	<s:debug />
</body>
</html>

OgnlDemo4Action
package cn.test.action;

import java.util.ArrayList;
import java.util.List;

import cn.test.domain.User;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.util.ValueStack;

public class OgnlDemo4Action extends ActionSupport implements ModelDriven<User> {
	private List<User> users;
	private User user = new User("tom", "123", 20, "男");

	public User getModel() {
		return user;
	}

	public List<User> getUsers() {
		return users;
	}

	public void setUsers(List<User> users) {
		this.users = users;
	}

	public String getHello() {
		return "hello world";
	}

	@Override
	public String execute() throws Exception {

		ValueStack vs = ActionContext.getContext().getValueStack();
		users = new ArrayList<User>();
		users.add(new User("tom", "123", 20, "男"));
		users.add(new User("jams", "456", 21, "男"));
		users.add(new User("fox", "789", 26, "男"));

		user = new User("fox", "789", 26, "男");

		return SUCCESS;
	}

}
ognl4.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>演示:使用ognl来获取valueStack中复杂数据</title>
</head>

<body>
	<s:property value="hello" />
	<hr>
	<s:property value="username" />
	<s:property value="age" />
	<hr>
	<s:property value="model.username"/>
	<s:property value="model.age"/>
	<hr>
	<s:iterator value="users" var="u">
		<s:property value="#u.username" />
		<br>
	</s:iterator>

	<s:debug />
</body>
</html>

OgnlDemo5Action
package cn.test.action;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.ValueStack;

public class OgnlDemo5Action extends ActionSupport {

	@Override
	public String execute() throws Exception {
		ValueStack vs = ActionContext.getContext().getValueStack();

		vs.set("username", "张三"); // 向ValueStack压入数据
		return SUCCESS;
	}

}
ognl5.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>演示:使用el获取ValueStack中数据</title>
</head>

<body>
	Ognl获取:<s:property value="username"/><br>
	el获取:${username }
	<s:debug />
</body>
</html>

OgnlDemo6Action
package cn.test.action;

import java.util.ArrayList;
import java.util.List;

import cn.test.domain.Product;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.ValueStack;

public class OgnlDemo6Action extends ActionSupport {
	private List<Product> ps;

	public List<Product> getPs() {
		return ps;
	}

	public void setPs(List<Product> ps) {
		this.ps = ps;
	}

	@Override
	public String execute() throws Exception {

		// 对ps进行赋值
		ps = new ArrayList<Product>();
		ps.add(new Product("电视机", 1800, 100));
		ps.add(new Product("洗衣机", 800, 10));
		ps.add(new Product("空调", 3800, 100));

		return SUCCESS;
	}

}
ognl6.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>演示:进行投影操作</title>
</head>

<body>
	<s:property value="ps" />
	<br>1.使用iterator进行遍历
	<br>
	<s:iterator value="ps" var="p">
        名称:<s:property value="#p.name" />
		<br>
        价格:<s:property value="#p.price" />
		<br>
         数量:<s:property value="#p.count" />
		<br>
		<hr>
	</s:iterator>

	<hr>
	2.对集合进行投影,只得到指定的属性
	<br>

	<s:iterator value="ps.{name}" var="pname">
		<s:property value="#pname" />
	</s:iterator>

	<hr>
	3.将ps中价格大于1000的商品得到
	<br>
	<s:iterator value="ps.{?#this.price>1000}" var="p">
	 名称:<s:property value="#p.name" />
		<br>
	  价格:<s:property value="#p.price" />
		<br>
	   数量:<s:property value="#p.count" />
		<br>
	</s:iterator>

	<hr>
	4.将ps中价格大于1000的商品名称得到
	<br>
	<s:iterator value="ps.{?#this.price>1000}.{name}" var="pname">
		<s:property value="#pname" />
		<br>
		<hr>
	</s:iterator>

	<s:debug />
</body>
</html>

ognl7.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>演示:进行投影操作</title>
</head>

<body>
	1.可以使用#来构建一个Map集合
	<br>

	<s:iterator value="#{'name':'tom','age':20}" var="entry">
		<s:property value="#entry.key" />----<s:property value="#entry.value" />
		<br>
	</s:iterator>

	<hr>
	2.可以构建List集合
	<br>
	<s:iterator value="{'aa','bb','cc'}" var="v">
		<s:property value="#v" />
	</s:iterator>

	<hr>
	3.手动创建一个集合,在Struts2中是结合表单标签使用的
	<br>
	<s:form>
		<s:radio list="{'男','女'}" name="sex"></s:radio>

		<s:radio list="#{'男':'male','女':'female'}" name="sex"></s:radio>

		<s:select list="{'a','b','c'}" name="aa"></s:select>

		<s:select list="#{'a':'aaa','b':'bbb','c':'ccc' }" name="aa"></s:select>
	</s:form>
	<s:debug />
</body>
</html>


ognl8.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>演示:%号的使用</title>
</head>

<body>
	<%
		request.setAttribute("username", "tom");
	%>
	<s:property value="#request.username" default="hello" />
	<br>

	<s:property value="%{#request.username}" />
	<br>

	<s:property value="%{'#request.username'}" />
	<br>

	<hr>

	<s:textfield name="abc" value="%{#request.username}" />
	<s:debug />
</body>
</html>

ognl9.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>演示:$用法</title>
</head>

<body>
	<%
		request.setAttribute("username", "张三");
	%>

	在国际化文件中使用:
	<br>
	<s:i18n name="cn.test.resource.my">
		<s:text name="username" />
	</s:i18n>
	<s:debug />
</body>
</html>


Struts2中的表单标签

 概述:
表单标签将在HTML文档里被呈现为一个表单元素
使用表单标签的优点:
  • 表单回显
  • 对页面进行布局和排版
标签的属性可以被赋值为一个静态的值或一个OGNL表达式,如果在赋值时使用了一个OGNL表达式并把它用%{}括起来,这个表达式将会被求值。
表单标签的共同属性

 *  表示该属性只在没有使用theme=simple 主题时才可以使用

form标签

form标签用来呈现HTML语言中的表单元素

默认情况下,form标签将被呈现为一个表格形式的HTML表单。嵌套在form标签里的输入字段将被呈现为一个表格行。每个表格行由两个字段组成,一个对应着行标,一个对应着输入元素。提交按钮将被呈现为一个横跨两列单元格的行。<s:form action="" method="post"  namespace="/ui">

textfield, password, hidden 标签

extfield 标签将被呈现为一个输入文本字段, password 标签将被呈现为一个口令字段, hidden 标签将被呈现为一个不可见字段. 


password标签扩展自textfield标签,多了一个showPassword属性  该属性是布尔类型,默认值是false,它决定着在表单回显时是否显示输入的密码,true显示密码

submit标签

submit 标签将呈现为一个提交按钮. 根据其 type 属性的值. 这个标签可以提供 3 种呈现效果:
  • input: <input type=“submit” value=“提交”…/>
  • button: <input type=“button” value=“确定” …/>
  • image: <input type=“image” value=“图片” src=“XX.jpg” …/>

reset标签

reset 标签将呈现为一个重置按钮. 根据其 type 属性的值. 
这个标签可以提供 2 种呈现效果:
input: <input type=“reset” value=“重置”…/>
button: <input type=“button” value=“重置按键” …/>

label标签

label 标签将呈现一个 HTML 行标元素:


textarea标签

textarea 标签将呈现为一个 HTML 文本域元素

checkboxlist标签

checkboxlist 标签将呈现一组多选框.

checkboxlist标签被映射到一个字符串数组或是一个基本类型的数组。若它提供的多选框一个也没有被选中,相应的属性将被赋值为一个空数组而不是空值
示例1:

示例2:

radio标签

radio标签将呈现为一组单选按钮,单选按钮的个数与程序员通过该标签的list属性提供的选项的个数相同。
一般的,使用后radio标签实现多选一,对于真假 则该使用checkbox标签

示例如下:

select标签

select标签将呈现一个select元素

示例代码:

示例代码2:

主题

主题:为了让所有的UI标签能够产生同样的视觉效果而归集到一起的一组模板,即风格相近的模板被打包成为一个主题
1、simple:把UI标签翻译成最简单的HTML对应元素,而且会忽视行标属性
2、xhtml:xhtml是默认的主题,这个主题的模板通过使用一个布局表格提供了一种自动化排版机制(默认值)
3、css_xhtml:这个主题里的模板与xhtml主题里的模板很相似,但他们将使用css来进行布局和排版
4、ajax:这个主题类的模板以xhtml主题里的模板为基础,但增加了一些ajax的功能
修改主题:
A、通过UI标签的theme属性(只试用于当前的标签)
  <s:textfield name="username" label="用户名" theme="simple"></s:textfield>
B、在一个表单里,若没有给出某个UI标签的theme属性,它将使用这个表单的主题(适用于整个form标签)
  <s:form action="" method="post" namespace="/ui"  theme="simple"> 
C、修改struts.properties文件中的struts.ui.theme属性.(适用于整个环境)
  <!--设置ui标签的主题 -->
  <constant name="struts.ui.theme"  value="simple"></constant>
优先级:A>B>C

 struts2标签自动回显


<s:textfield name="username"/>  <input type="text" name="username" value="zhang">
*当Struts2解析该标签时,获取name属性的值username
*以username为条件,到对象栈中查找PropertyName="username"的属性
*如果找到了,获取该属性的值,该属性的值就是  <s:textfield name="username"/> 的值
* 如果找到了,获取该属性的值,该属性的值(是“”)就是<s:textfield name="username"/>的值
* 如果没有找到了,<s:textfield name="username"/>的值=" "

防止表单重复提交

问题:什么是表单重复提交?
regist.jsp----->RegistServlet
表单重复提交 危害: 刷票、 重复注册、带来服务器访问压力(拒绝服务)
解决方案:
在页面上生成一个令牌(就是一个随机字符串),将其存储到session中,并在表单中携带.
在服务器端,获取数据时,也将令牌获取,将它与session中存储的token对比,没问题,
将session中令牌删除。
struts2中怎样解决表单重复提交:
在struts2中解决表单重复提交,可以使用它定义的一个interceptor。
 <interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
 1、定义一个JSP页面,在表单中增加一个隐藏域

2、定义struts_token.xml配置文件



问题:token拦截器只拦截save方法
<!-- 在默认栈中增加token拦截器 -->
<interceptors>
     <interceptor-stack name="tokenStack">
         <interceptor-ref name="defaultStack"></interceptor-ref>
         <interceptor-ref name="token">
             <!-- 配置token拦截器拦截哪些方法 -->
             <param name="includeMethods">save</param>
         </interceptor-ref>
     </interceptor-stack>
</interceptors>

error.jsp页面打印错误信息
error.jsp页面如下:使用<s:actionerror/>打印错误信息
<%@ page language="java" pageEncoding="utf-8" contentType="text/html; charset=utf-8"%>
<%@ taglib uri="/struts-tags"   prefix="s"%>
<html>
  <head>
    <title>My JSP 'index.jsp' starting page</title>
    </head>
  <body>
    <s:actionerror/>
  </body>
</html>
修改error.jsp页面打印错误信息为中文
1、在与action同级目录新建token.properties资源文件
2、在该文件中增加如下内容
struts.messages.invalid.token=您已经重复提交表单,请刷新后重试
该信息所在位置struts2-core-2.3.3.jar包下\org\apache\struts2\struts-messages.properties文件
3、在struts.xml文件中加载该资源文件
<constant name="struts.custom.i18n.resources" value="cn.itcast.model.token">
</constant>

<s:token />标签防止重复提交
在debug状态,控制台出现下面信息,是因为Action中并没有struts.token和struts.token.name属性,我们不用关心这个错误:
严重: ParametersInterceptor - [setParameters]: Unexpected Exception caught setting 'struts.token' on 'class xxx: Error setting expression 'struts.token' with value '[Ljava.lang.String;@39f16f'
严重: ParametersInterceptor - [setParameters]: Unexpected Exception caught setting 'struts.token.name'

代码示例如下:
  
RegisterServlet
package cn.itcast.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class RegistServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		String username = request.getParameter("username");
		String password = request.getParameter("password");

		String token = request.getParameter("token");

		String _token = (String) request.getSession().getAttribute("token");
		request.getSession().removeAttribute("token");

		if (token.equals(_token)) {

			System.out.println("将" + username + " 与" + password
					+ "存储到数据库中,完成注册");
		} else {
			response.getWriter().write("不允许表单重复提交");
		}
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}
register.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    
    <title>My JSP 'index.jsp' starting page</title>
	
  </head>
  
  <body>
  	<%
  		//生成一个令牌
  		String token=UUID.randomUUID().toString();
  	
  		session.setAttribute("token", token);
  	%>
  
  	<form action="${pageContext.request.contextPath}/regist" method="get">
  		<input type="hidden" name="token" value="<%=token%>">
  		username:<input type="text" name="username"><br>
  		password:<input type="password" name="password"><br>
  		<input type="submit" value="注册">
  	</form>
  </body>
</html>

Struts2中的防止表单重复刷新如下:
struts.xml
<?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="default" namespace="/" extends="struts-default">
		<action name="regist" class="cn.itcast.action.RegistAction">
			<result name="invalid.token">/token.jsp</result>
			<interceptor-ref name="token" />
			<interceptor-ref name="defaultStack" />
		</action>
	</package>
</struts>
RegistAction
package cn.itcast.action;

import com.opensymphony.xwork2.ActionSupport;

public class RegistAction extends ActionSupport {

	private String username;
	private String password;

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	@Override
	public String execute() throws Exception {
		System.out.println("将" + username + " 与" + password + "存储到数据库中,完成注册");
		return null;
	}
}


struts_regist.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>

<title>My JSP 'index.jsp' starting page</title>

</head>

<body>


	<form action="${pageContext.request.contextPath}/regist.action"
		method="get">
		<s:token/>
		username:<input type="text" name="username"><br>
		password:<input type="password" name="password"><br> <input
			type="submit" value="注册">
	</form>
</body>
</html>
token.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>

<title>My JSP 'index.jsp' starting page</title>

</head>

<body>
	<s:actionerror/>
</body>
</html>


Struts2中json插件的使用

Struts2中怎样处理异步提交(ajax)
原始:
HttpServletResponse response=ServletActionContext.getRequest();
response.getWriter().write("hello "+msg);
respoonse.getWriter().close();
还可以使用Struts2中提供的json插件(步骤如下):
1、导入json插件包
在Struts2的lib包下  struts2-json-plugin-2.3.15.1.jar
2、在struts.xml文件中配置
<package extends="json-default">
设置视图<result type="json">

这样设置后,会将ValueStack栈顶数据变为json。
对于Struts中,也就是会将action对象转为json。

<param name="root">p</param>如果没有设置,可以理解成将整个action都转换为json数据。也就是说在action中提供的getXxx方法,就是json中国的一个属性。
如果设置了root,那么只将指定数据转换成json

怎样设置转换成json的对象中不包含特定的属性?
1、@json(serialize=false)  在getXxx方法上进行设置
2、还可以通过json插件的interceptor完成
<param name="includeProperties">ps\[\d+\]\.name,ps\[\d+\]\.price,ps\[\d+\]\.count</param>
代码示例如下:

Product
package cn.test.domain;

import org.apache.struts2.json.annotations.JSON;

public class Product {
	private int id;
	private String name;
	private double price;
	private int count;

	public Product() {
		super();
	}

	public Product(int id, String name, double price, int count) {
		super();
		this.id = id;
		this.name = name;
		this.price = price;
		this.count = count;
	}

	// @JSON(serialize=false)
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

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

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	public int getCount() {
		return count;
	}

	public void setCount(int count) {
		this.count = count;
	}

}
Ajax1Action
package cn.test.action;

import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

public class Ajax1Action extends ActionSupport {
	private String msg;

	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}

	@Override
	public String execute() throws Exception {
		HttpServletResponse response = ServletActionContext.getResponse();
		response.getWriter().write("hello " + msg);
		response.getWriter().close();
		return null;
	}
}
Ajax2Action
 package cn.test.action;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.ServletActionContext;

import cn.test.domain.Product;

import com.opensymphony.xwork2.ActionSupport;

public class Ajax2Action extends ActionSupport {
	private List<Product> ps;

	private Product p;

	public Product getP() {
		return p;
	}

	public void setP(Product p) {
		this.p = p;
	}

	public List<Product> getPs() {
		return ps;
	}

	public void setPs(List<Product> ps) {
		this.ps = ps;
	}

	@Override
	public String execute() throws Exception {

		ps = new ArrayList<Product>();
		ps.add(new Product(1, "洗衣机", 1800, 10));

		ps.add(new Product(2, "电视机", 2800, 20));
		ps.add(new Product(3, "缝纫机", 800, 50));

		p = new Product(3, "缝纫机", 800, 50);

		return SUCCESS;
	}
}
my.js
function getXmlHttpRequest() {
	var xmlhttp=null;
	if (window.XMLHttpRequest) {
		xmlhttp=new XMLHttpRequest(); //针对于现在的浏览器包括IE7以上的版本
	} else if(window.ActiveXObject){
		// 针对于IE5,IE6版本
		xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
	}
	return xmlhttp;
}
struts.xml
<?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="default" namespace="/" extends="json-default">
		<action name="ajax1" class="cn.test.action.Ajax1Action"></action>

		<action name="ajax2" class="cn.test.action.Ajax2Action">
			<result type="json">
				<param name="includeProperties">ps\[\d+\]\.name,ps\[d+\]\.price,ps\[\d+\]\.count</param>
			</result>
		</action>
	</package>
</struts>
ajax1.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>第一种Struts2处理异步请求</title>
<script type="text/javascript"
	src="${pageContext.request.contextPath}/my.js"></script>
<script type="text/javascript">
	function hello() {
		//1.得到XMLHttpRequest对象
		var xmlhttp = getXmlHttpRequest();

		//2.设置回调函数
		xmlhttp.onreadystatechange = function() {

			if (xmlhttp.status == 200 && xmlhttp.readyState == 4) {
				alert(xmlhttp.responseText);
			}
		};
		//3.open
		xmlhttp.open("GET", "${pageContext.request.contextPath}/ajax1?msg="
				+ document.getElementById("t").value);

		//4.send
		xmlhttp.send(null);
	}
</script>
</head>
<body>
	<input type="text" id="t">
	<input type="button" value="提交" onclick="hello();">
</body>
</html>

ajax2.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>第一种Struts2处理异步请求</title>
<script type="text/javascript"
	src="${pageContext.request.contextPath}/my.js"></script>
<script type="text/javascript">
	function showProduct() {
		//1.得到XMLHttpRequest对象
		var xmlhttp = getXmlHttpRequest();

		//2.设置回调函数
		xmlhttp.onreadystatechange = function() {

			if (xmlhttp.status == 200 && xmlhttp.readyState == 4) {
				alert(xmlhttp.responseText);
				//	var jsonObj = eval("(" + xmlhttp.responseText + ")");
			}
		};
		//3.open
		xmlhttp.open("GET", "${pageContext.request.contextPath}/ajax2?msg="
				+ document.getElementById("t").value);

		//4.send
		xmlhttp.send(null);
	}
</script>
</head>
<body>
	<input type="text" id="t">
	<input type="button" value="提交" onclick="showProduct();">
</body>
</html>

运行结果如下:



你可能感兴趣的:(JAVAWEB开发之Struts2详解(四)——ognl与valueStack(重点)、Struts常用标签、防止表单重复提交、Struts2中内置json插件)