- 说明:struts2中前端页面传递各种参数(简单参数,数组,List,Set,Map 及复合结构)至后端。
- 建议:如果你需要了解如何传递数组的,先看页面再看对应的Action,再看里面的注释(如果想了解传参的具体细节或底层思想)。演示输出结果,请看控制台。
- 环境:tomcat+struts2+Ognl
- 主代码如下:
**************************1视图层CODE*****************************
findUser.jsp>>>>>>>>>>>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String basePath = request.getScheme()+"://"
+ request.getServerName() +":"
+request.getServerPort() +"/"
+ request.getContextPath()+"/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<!-- 重写href,作为相对路径 -->
<base href="<%=basePath%>">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>findUser.jsp</title>
</head>
<body>
<h1>前端提交到服务器的数据的数据结构</h1>
<p>
http://localhost:8080/应用名/findUser.action?
user.id=1688&pnames=tom&pnames=anie&pnames=maniy&names%5B0%5D=%E6%9D%8E%E4%B8%89&names%5B1%5D=%E6%9D%8E%E5%9B%9B
&names%5B2%5D=%E7%8E%8B%E4%BA%94&user.ids%5B0%5D=10086&user.ids%5B1%5D=10082&user.ids%5B2%5D=10085
&user.orders%5B0%5D.orderId=order1688&user.orders%5B0%5D.orderName=AJ%E9%A3%9E%E4%BA%BA&user.orders%5B0%5D.productPrice=1500
&user.orders%5B1%5D.orderId=order1699&user.orders%5B1%5D.orderName=Ads%E4%B8%89%E5%8F%B6&user.orders%5B1%5D.productPrice=800
&orderSet.makeNew%5B0%5D.orderName=hi&orderSet.makeNew%5B1%5D.orderName=hello&userMap.user.id=2600
&userMap.user.name=jack&userMap%5B%27mu2%27%5D.id=2700&userMap%5B%27mu2%27%5D.name=jack2
<br/>
<span>
<blockquote>前端(视图层)映射到后端时的数据结构。可以看出都是弱类型(文本类型String)来表示前端的所有数据。
也就是说:不论你是float,int,String,Date,object在前端都视为弱类型,那为映射到java中,必须要进行数据类型转换。
转换的具体思路或过程,在UserAction.java文件中搜索:"前端的弱类型数据转换成java强类型思路或过程"有说明。</blockquote>
</span><br/>
{<br/> <blockquote>
用户id:<br/>
user.id=[Ljava.lang.String;@1504a84, <br/>
用户名数组,方式一<br/>
pnames=[Ljava.lang.String;@1644c9, <br/>
用户名数组,方式二(Ognl)<br/>
names[0]=[Ljava.lang.String;@3da671, names[1]=[Ljava.lang.String;@13aa7d4, names[2]=[Ljava.lang.String;@49968b,<br/>
对象中数组:<br/>
user.ids[0]=[Ljava.lang.String;@28ad5a, user.ids[1]=[Ljava.lang.String;@13864d9, user.ids[2]=[Ljava.lang.String;@1c66091,<br/>
List传参:List<Order> <br/>
user.orders[0].orderId=[Ljava.lang.String;@a87a8, <br/>
user.orders[0].orderName=[Ljava.lang.String;@164e850, user.orders[0].productPrice=[Ljava.lang.String;@eeda37,<br/>
user.orders[1].orderId=[Ljava.lang.String;@17a8369,<br/>
user.orders[1].orderName=[Ljava.lang.String;@1fdf894, user.orders[1].productPrice=[Ljava.lang.String;@4c4ff8,<br/>
Set传参:Set<Order><br/>
orderSet.makeNew[0].orderName=[Ljava.lang.String;@1e070c0, <br/>
orderSet.makeNew[1].orderName=[Ljava.lang.String;@edfb95, <br/>
Map传参:Map<User><br/>
userMap.user.id=[Ljava.lang.String;@201dbc, userMap.user.name=[Ljava.lang.String;@8024c8,<br/>
userMap['mu2'].id=[Ljava.lang.String;@8d241b, userMap['mu2'].name=[Ljava.lang.String;@1cfee57<br/>
</blockquote>
}
</p><hr>
<h1>开发中实用传参方式及原理说明(实验时建议选中所有数据再提交)</h1>
<form action="findUser.action" method="get">
<div>
<span>1.根据用户id查询用户</span><br/>
<input type="text" name="user.id" value="1688"/><br/>
</div>
<div>
<span>2.简单数组传参1(原始方式,但后端设值还是用到Ognl)</span><br/>
<!-- 获取user,再获取ids,运用Array.set(array, index, value)设值<br/> -->
tom<input type="checkbox" name="pnames" value="tom"><br/>
anie<input type="checkbox" name="pnames" value="anie"><br/>
maniy<input type="checkbox" name="pnames" value="maniy"><br/><br/>
</div>
<!-- 以下全是ognl方式传参 -->
<div>
<span>3.简单数组传参2(这以下皆为Ognl方式传递参数)</span><br/>
<!-- 获取user,再获取ids,运用Array.set(array, index, value)设值<br/> -->
李三<input type="checkbox" name="names[0]" value="李三"><br/>
李四<input type="checkbox" name="names[1]" value="李四"><br/>
王五<input type="checkbox" name="names[2]" value="王五"><br/>
</div>
<div>
<span>4.对象中的数组传参</span><br/>
<!-- 获取user,再获取ids,运用Array.set(array, index, value)设值<br/> -->
10086<input type="checkbox" name="user.ids[0]" value="10086"><br/>
10082<input type="checkbox" name="user.ids[1]" value="10082"><br/>
10085<input type="checkbox" name="user.ids[2]" value="10085"><br/>
</div>
<div>
<span>5.List传参(List<Order>)</span><br/>
<span>第一个订单</span><br/>
order1688<input type="checkbox" name="user.orders[0].orderId" value="order1688"><br/>
AJ飞人<input type="checkbox" name="user.orders[0].orderName" value="AJ飞人"><br/>
1500<input type="checkbox" name="user.orders[0].productPrice" value="1500"><br/><br/>
<!-- 第二个订单 :重复异常user.orders[0].productPrice-->
<span>第二个订单</span><br/>
order1699<input type="checkbox" name="user.orders[1].orderId" value="order1699"><br/>
Ads三叶<input type="checkbox" name="user.orders[1].orderName" value="Ads三叶"><br/>
800<input type="checkbox" name="user.orders[1].productPrice" value="800"><br/><br/>
</div>
<div>6.Set传参<br/>
hi<input type="checkbox" name="orderSet.makeNew[0].orderName" value="hi"><br/>
hello<input type="checkbox" name="orderSet.makeNew[1].orderName" value="hello"><br/><br/>
</div>
<div>7.Map接收参数<br/>
<span>第一个Entry(指定Map的key为user)</span><br/>
2600<input type="checkbox" name="userMap.user.id" value="2600"><br/>
jack<input type="checkbox" name="userMap.user.name" value="jack"><br/><br/>
<span>第二个Entry(指定Map的key为mu2,若作用相同的key则进行"追加赋值")</span><br/>
2700<input type="checkbox" name="userMap['mu2'].id" value="2700"><br/>
jack2<input type="checkbox" name="userMap['mu2'].name" value="jack2"><br/>
</div>
<input type="submit" value="提交数据" /><br/>
</form>
</body>
</html>
showFindUser.jsp >>>>>>>>>>>>>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
import="java.util.*"
import="com.opensymphony.xwork2.ognl.OgnlValueStack"
import="com.opensymphony.xwork2.util.CompoundRoot"
import="org.yl.action.UserAction"
import="org.yl.domain.User"
%>
<!-- 引入struts2标签库 -->
<%@ taglib uri="/struts-tags" prefix="s" %>
<%
String basePath = request.getScheme()+"://"
+ request.getServerName() +":"
+request.getServerPort() +"/"
+ request.getContextPath()+"/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<base href="<%=basePath%>">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>视图层:JSP,从ValueStack中的CompoundRoot中取值</h1>
<div>
<span>用户信息:</span><br/>
<!-- 1.java直接取值 -->
<%
OgnlValueStack vs = (OgnlValueStack)request.getAttribute("struts.valueStack");
//值栈的上下文
Map<String,Object> vsContext = vs.getContext();
for(Map.Entry<String, Object> entry: vsContext.entrySet()){
//System.out.println("key:" + entry.getKey() + "--value:" + entry.getValue() + "\n");
}
//值栈的根(CompoundRoot数据结构为栈,使用ArrayList实现的)
CompoundRoot root = vs.getRoot();
Object obj = root.peek();//从root栈中取出一个数据
UserAction userAction = null;
User user = null;
String name = null;
if(obj instanceof UserAction){
userAction = (UserAction)obj;
user = userAction.getUser();
System.out.println("************showFindUser.jsp页面展示信息*************");
System.out.println("Action中的成员变量信息:" +"\n"
+ "1.user信息 ======"
+ "id:" + user.getId() + "\n"
+ "name:" + user.getName() + "\n"
+ "sex:" + user.getSex() + "\n"
+ "deposit:" + user.getDeposit()+ "\n"
+ "telephone:" + user.getTelephone() + "\n"
+"");
name = user.getName();//供页面使用,与html标签进行整合
}
%>
java直接取值:<input type="text" value="<%=name %>" readonly="readonly" /><br/>
<!-- 2.标签库解药or毒药 -->
<!-- el表达式 -->
el表达式取值:<input type="text" value="${user.name }" readonly="readonly" /><br/>
<!-- 使用struts2标签库中的标签
<s:property value="user.telephone"/><br/>-->
struts2标签取值:<input type="text" value="<s:property value="user.telephone"/>" readonly="readonly" /><br/>
</div>
</body>
</html>
**************************2控制层CODE*****************************
UserAction.java >>>>>>>
package org.yl.action;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.yl.domain.Order;
import org.yl.domain.User;
import com.opensymphony.xwork2.util.Element;
import com.opensymphony.xwork2.util.KeyProperty;
/**
* 演示:显示层从ValueStack中取值
* (1)视图层传递参数
* (2)el+jstl
* (3)struts2标签库+Ognl
*
* @author 拈花为何不一笑
*
* 此UserAction对应的页面:findUser.jsp
*/
public class UserAction {//何时何地创建Action?服务Action时创建ActionProxy,
//而在创建代理时ObjectFactory创建Action并且把Action放入至值栈中(实际是放入CompoundRoot中)
//何地?DefaultActionInvocation作为场地
//初始化
private User user = new User();
//普通数组(原始方式接收数组)
private String pnames[];
//普通数组(Ognl方式:names[0])
private String names[] = new String[6];
//Xwork2重写Ognl中的SetPropertyAccessor等Accessor
//Set中不支持存放基本数据类型和String类型(即使String被实例化为"",也不能当作类对象操作String中的属性或方法),可以存放javaBean
//private Set<String> sts = new HashSet<String>();
//Set集合接收参数
/**
* 表达式:orderSet.makeNew[0].orderName
* 问题一:如何把新创建了的Order作为元素被添加到orderSet中的?怎么辨别或区分新创建的Order的?引入了一个包装类:SurrugeList
* 且它的成员变量surrugate存放orderSet(HashSet)
* 简要而关键的流程:
* 1.把orderSet(HashSet类型)包装成一个SurrugateList用于对应下标[0][1]……
* (因为Set中取值是用iterator,而没有get(index)。为了与表达式中的下标关联List类型,用到了SurrugateList)
* 2.ATS Node:makeNew获取Property时创建SurrugateList
* 3.后面逻辑就按List Accessor进行处理
*
* 4.ATS Nod:[0]获取Property时,使用XWorkListPropertyAccessor
* 对象工厂创建bean,用@Element注解(orderSet属性上的注解)获取bean的Class
* 来创建bean(Order):
* objectFactory.buildBean(beanClass, context)
* 并把这个创建的Order元素放到SurrugateList的的成员变量surrugate(存放的是orderSet)中:
* orderSet.add(Order);
*
* 5.再然后,通过Ognl给Order.setOrderName("前端的参数值"),就OK了。
*
* 问题二:这个过程中用到了两个注解:@KeyProperty和@Element,它们的作用是什么呢?
* 注解:@KeyProperty 作为后面逻辑,进行数据类型转换的Class参数
* (不设置会报异常:Error getting property descriptor影响整个过程。对当前的参数映射到Set中并无逻辑关系)
* 注解:@Element 创建Set<T>中的T时,使用到的beanClass
*
* 以上过程总结起来就是一句话:Ognl解析Set类型的表达式时,是披着ListAccessor的外衣把Set当作List来处理的。(当然这是Xwork2对Ognl的扩展了)
*
* 建议:由于Set逻辑处理繁琐且复杂,昼量用List替代Set接收参数。(Set食之无味,弃之可惜!)
*/
@KeyProperty(value="orderId")
@Element(value=org.yl.domain.Order.class )
private Set<Order> orderSet = new HashSet<Order>();//若不初始化,默认创建一个ArrayList,显然不正确
//Map接收参数
private Map<String,User> userMap = new HashMap<String,User>();
//业务方法(struts.xml的UserAction配置中不指定具体方法时,excute或doExecute作为默认方法)
public String doExecute(){//执行action阶段调用
System.out.println("findUser...");
/**
* 下面逻辑发生在拦截器阶段
* 1.xwork2的InstantiatingNullHandler类调用对象工厂objectFactory.buildBean(clazz, context);
* 来创建了UserAction中为空的成员属性User:user。
* 2.当UserAction中的成员属性是类对象时且开发人员没有初始化时,
* 由Ognl+CompoundRootAccessor+InstantiatingNullHandler经过一系列逻辑创建了该成员属性
* 创建User实例后,再通过Ognl把前端传递过来的参数值:user.id="m-p6"赋给User对象中的成员变量id。
* 3.由于步骤2开销不少,建议开发中先初始化Action中的成员变量(类对象作为Action的成员变量),避免程序执行步骤2
*/
if(this.user != null){//UserAction中的User实例也被框架创建了。(谁创建的?在哪创建的?)
System.out.println("user.id:" + this.user.getId());
//模拟从DB或企业信息系统中获取到的数据
if(user.getId() != null && user.getId().equals("1688")){
this.user.setName("张天见");
this.user.setSex("男");
this.user.setTelephone("13638885606");
this.user.setDeposit(73000);
}
/**
* 原始方式接收参数
*
*/
//数组接收参数:接收前端传递的多个pnames
String[] mypnames = this.pnames;
if(mypnames != null && mypnames.length > 0){
System.out.println("***数组接收参数1:前端参数pnames映射到UserActoin中的成员变量pnames***");
for(String pn:mypnames){
System.out.println(pn);
}
}
/**
* 以下都是ognl方式接收参数,顺便说一说前端的弱类型数据转换成java强类型思路或过程
* Ongl设值过程序,前端传递过来的参数被xwork+ognl进行了文本弱类型转换成java强类型
* 比如:前端传递一个文本类型(弱类型)name=user.orders[0].productPrice" value="1500"
* 1500是个文本类型,如何转换成java强类型float?
* 简要说下过程:拿到setProductPrice(float)方法,再拿到这个方法的参数类型float。
* 知道了是对float进行设值,那么xwork+ognl就把弱类型1500转换成float类型。
*
* 说明:xwork对ognl数据类型转换进行了扩展。
*/
//数组来接收参数:前端参数ids映射到UserActoin中的成员变量User中的ids
String ids[] = this.user.getIds();
if(ids !=null && ids.length > 0){
System.out.println("***数组接收参数2:前端参数ids映射到UserActoin中的成员变量User中的ids***");
for(String e:ids){
System.out.println(e);
}
}
//数组来接收参数:前端参数names映射到UserActoin中的成员变量names
String names[] = this.names;
if(names != null && names.length > 0){
System.out.println("***数组接收参数:前端参数names映射到UserActoin中的成员变量names***");
for(String n:names){
try {
if(n!= null)
n = new String(n.getBytes("ISO-8859-1"),"UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
System.out.println(n);
}
}
//List接收数据List<Order> orders
List<Order> orders = this.user.getOrders();
if(orders != null && orders.size() > 0){
System.out.println("***List接收数据:前端参数orders映射到UserActoin中的成员变量User中的orders***");
for(Order order:orders){
if(order!= null){
String orderName = null;
try {
orderName = new String(order.getOrderName().getBytes("ISO-8859-1"),"UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
System.out.println("订单号:" + order.getOrderId() +"\n"
+ "订单名称:" + orderName +"\n"
+ "产品单价:" + order.getProductPrice() + "\n"
);
System.out.println("\n\n");
}
}
}//
//set接收数据,与list逻辑相似只是多了一个披外衣的过程
System.out.println("************Set接收数据*******************");
if(this.orderSet != null && this.orderSet.size() > 0){
for(Order or: orderSet){
System.out.println(or.getOrderName());
}
}//
//Map接收参数
System.out.println("************Map接收数据*******************");
Map<String,User> uMap = this.userMap;
if(uMap != null && !uMap.isEmpty()){
for(Map.Entry<String, User> entry:uMap.entrySet()){
String key = entry.getKey();
User u = entry.getValue();
//使用userMap.user.id的user作为key
System.out.println("key-String:" + key);
System.out.println("value-User如下:");
if(u!=null){
System.out.println("用户Id:"+u.getId()+", 用户名:"+u.getName());
}
}
}
}
//struts2中提供与Web容器直接交互的类:ServletActionContext
//获取服务器路径
/*HttpServletRequest request =ServletActionContext.getRequest();
String serverPath = request.getSession().getServletContext().getRealPath("/");
System.out.println("serverPath: " + serverPath);*/
return "showFindUser";
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public void setNames(String names[]) {
this.names = names;
}
public String[] getNames() {
return names;
}
public void setOrderSet(Set<Order> orderSet) {
this.orderSet = orderSet;
}
public Set<Order> getOrderSet() {
return orderSet;
}
public void setUserMap(Map<String,User> userMap) {
this.userMap = userMap;
}
public Map<String,User> getUserMap() {
return userMap;
}
public void setPnames(String pnames[]) {
this.pnames = pnames;
}
public String[] getPnames() {
return pnames;
}
}
**************************3配置文件E*****************************
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>
<!-- 常量bean配置 -->
<constant name="struts.devMode" value="true" />
<!-- action事件映射 -->
<package name="default" namespace="/" extends="struts-default">
<action name="reg" class="org.yl.action.Register">
<result name="success">/success.jsp</result>
</action>
<action name="findUser" class="org.yl.action.UserAction">
<result name="showFindUser">/showFindUser.jsp</result>
</action>
</package>
</struts>
=123向左向右向前向后。///******