【JavaWeb-18】ActionContext存取数据、ValueStack存取值、EL新查找顺序、iterator、OGNL投影、其他标签、UI主题、防重复提交
来源:互联网 发布:求购湖南快乐十分源码 编辑:程序博客网 时间:2024/04/30 15:49
1、我们之前说过,OGNL上下文包含ActionContext和ValueStack。我们先来说说ActionContext,它是一个大Map,里面装有4个小Map,分别是application、session、request和attr。我们做个测试时往里面存数据然后再取数据。
——我们部署好struts2之后,在index.jsp中使用struts标签库。在正文中写<s:debug></s:debug>
,它相当于一个a标签,点击前往可以查看整个OGNL上下文里面的数据。
——我们在动作类的方法中存入数据,存数据有多重方法,总之是获得对应的Map,然后往里面存数据。
public String data(){ //往大Map里面,也就是ActionContext里存数据 ActionContext context=ActionContext.getContext(); context.put("actionContextKey", "actionContextValue"); //第1种方式:往小Map里面存数据,比如ActionContext里的小Mapsession Map<String,Object> s1=context.getSession(); s1.put("sessionKey1", "sessionValue1"); //第2种方式:往小Map里面存数据,比如ActionContext里的小Mapsession HttpSession s2=ServletActionContext.getRequest().getSession(); s2.setAttribute("sessionKey2", "sessionValue2"); //第1种方式,往application里存 Map<String,Object> a1=context.getApplication(); a1.put("applicationKey1", "applicationValue1"); //第2种方式,往application里存 ServletContext a2=ServletActionContext.getServletContext(); a2.setAttribute("applicationKey2", "applicationValue2"); return SUCCESS; }
——然后在index.jsp页面里面获取数据:
<!-- 取ActionContext大Map里面的值,用#+key --><s:property value="#actionContextKey"/><br><!-- 取小Map里的值,需要先取到对应的session和application等。而这些都是大Map的key,所以操作如下 --><s:property value="#session.sessionKey1"/><br><s:property value="#session.sessionKey2"/><br><s:property value="#application.applicationKey1"/><br><s:property value="#application.applicationKey2"/><br>
源代码:JavaEE ActionContext存取数据示例
2、ValueStack存取数据。
——和上述案例类似,我们在动作类的方法中写如下代码,用于获取ValueStack的引用,有3种方式,很明显用第三种ActionContext直接获取更方便。而且我们打印出他们3个引用的hashcode发现是同一个,这就是线程安全的体现。
public String data(){ //第1种方式:获取ValueStack的引用,通过request间接获取 HttpServletRequest request1=ServletActionContext.getRequest(); ValueStack vs1=(ValueStack)request1.getAttribute("struts.valueStack"); System.out.println(vs1.hashCode()); //第2种方式:获取ValueStack的引用,通过request间接获取 ActionContext context=ActionContext.getContext(); Map<String,Object> request2=(Map<String,Object>)context.get("request"); ValueStack vs2=(ValueStack)request2.get("struts.valueStack"); System.out.println(vs2.hashCode()); //第3种方式:获取ValueStack的引用,通过actionContext直接获取 ValueStack vs3=context.getValueStack(); System.out.println(vs3.hashCode()); return SUCCESS; }
——获取ValueStack的引用后,我们采用压栈操作存数据。
//压栈操作vs3.push(new User("Andy",22));vs3.push(new User("eric",23));
——我们可以看到后push的在栈顶。
——我们在jsp中运用的时候,操作如下,默认取第一个,当然可以指定索引。
<!-- 取ValueStack值,不需要#,它从最上面栈顶依次找,找到就行 --><s:property value="username"/><br> //结果是eric// 这里有一个索引是[1],其实意思是把第一个栈顶的元素pop出去,如果是[2]那么就把最上面2个元素pop出去再取值,下方我们重新做试验<s:property value="[1].username" /> //结果是Andy
——采用setValue存数据,第一个参数是表达式,加#表示存在ActionContext里,不加#表示存在ValueStack里面,存在ValueStack里面其实是给里面对应的变量赋值,也就是说如下面代码所示,如果ValueStack里面没有username变量,那么就会报错。紧接着上面的代码,我们发现我们存在ValueStack里面的test2其实是覆盖了原先有的eric(因为它是从栈顶开始的第一个username属性对应的值,被setValue覆盖了)。
vs3.setValue("#username", "test1");vs3.setValue("username", "test2");
上面第一句代码产生的效果就是存在了ActionContext里面:
——采用set方法设置数据。
//set方法,如果栈顶是Map元素,直接key和value赋值过去,如果栈顶不是,那么就创建一个放在栈顶vs3.set("s1", new User("tom",30));
然后在jsp中取值的时候,操作:
<!-- 取栈顶Map里面的数据 --><s:property value="s1.username" />
注意:如果s:property
不指定的话默认取栈顶元素(或元素对应的地址)。
——我们来验证ValueStack取值时候的索引是把元素pop出去,而不是取第几个值的意思。
//压栈操作vs3.push(new User("Andy",22));vs3.push(new User("eric",23));//setValuevs3.setValue("#username", "test1");vs3.setValue("username", "test2");//set方法,如果栈顶是Map元素,直接key和value赋值过去,如果栈顶不是,那么就创建一个放在栈顶vs3.set("s1", new User("tom",30));
——经过上面的代码操作,我们的ValueStack的从栈顶往下应该是Map、User(test2)、User(Andy)。如下图。
——接着,我们在jsp中取值,按照道理好像是我们先从栈顶向下取了test2,然后下标为1也就是第二个是Andy,然后下标为2也就是第三个是空的没有值
。
<s:property value="username"/><br> <s:property value="[1].username" /><br> <s:property value="[2].username" /><br>
但是,事实上我们得到的值是:
test2test2Andy
——原理就在于,我们第一句话取值,表示从栈顶向下取第一个遇到的值,就是test2。第二句话取值,有个下标1,表示把栈顶第1个元素pop掉,然后生成一个新的ValueStack的List,从上向下取值,发现还是test2。第三句话取值,有个下标2,表示把栈顶最上面两个元素pop掉,也就是一个HashMap和User都pop掉了,然后取值,发现取到的是Andy。这里面起作用的函数就是cutStack,它根据下标的数字cut掉栈顶几个元素然后生成一个新的栈。
——另外,我们上面使用的struts标签s:property
,其实本质上都是调用了findValue方法,这个寻找顺序和以前讲过的类似,就是page、request、session、application。
3、Struts2对EL表达式查找顺序的改变。核心意思就是:一般情况下,我们写${name}
这样一个EL表达式,程序会先去pageScope中找,然后依次是requestScope、sessionScope和applicationScope。但是在Struts2种,查找顺序就不是这样了,而是pageScope、requestScope、ValueStack、ContextMap(ActionContext)、sessionScope和applicationScope。也就是说,我们在动作类中如果不把数据放入4个域中,一样可以通过EL表达式获取到数据,因为它会被放到ValueStack里。
——我们在动作类中写:
public class MyAction extends ActionSupport { private String name="动作类中的name"; public String getName() { return name; } public void setName(String name) { this.name = name; } ……}
——然后,我们刷新页面发现会自动添加到ValueStack里面了。
——我们在jsp页面使用EL表达式${name }
获取数据,就能获取到动作类中的name
。核心是因为Struts2对原来的request进行了包装。
4、iterator操作符。
——现在动作类里面整一个List。
public class MyAction extends ActionSupport { private List<User> users; public List<User> getUsers() { return users; } public void setUsers(List<User> users) { this.users = users; } public String data(){ users=new ArrayList<User>(); users.add(new User("Eric",20)); users.add(new User("Andy",21)); users.add(new User("Tom",22)); return SUCCESS; }}
——然后,在jsp中直接使用,我们说这个List没有放在4个域中,但是被放到了ValueStack里,所有在jsp中使用是可以取到值的。下面有两种方法,第一种是没有var属性的,那么每次遍历的元素都会被压到ValueStack里面,所以我们就直接用属性名username等取值。如果有var属性,那么会将它们放到ActionContext中,其中var的值作为Key,元素内容作为Value,所以我们取值需要用#
,而且是#key+属性
的形式取值。
<table> <tr> <td>序号</td> <td>姓名</td> <td>年龄</td> </tr> <s:iterator value="users" status="stat"> <tr> <td><s:property value="#stat.count" /></td> <td><s:property value="username" /></td> <td><s:property value="age" /></td> </tr> </s:iterator> </table> <table> <tr> <td>序号</td> <td>姓名</td> <td>年龄</td> </tr> <s:iterator value="users" var="u" status="stat"> <tr> <td>${stat.count }</td> <td><s:property value="#u.username" /></td> <td><s:property value="#u.age" /></td> </tr> </s:iterator> </table>
5、OGNL的投影:添加过滤条件。很少用到,做个了解即可。
——比如上面迭代的例子,我们做如下修改,也就是获取所有age>21的元素。这里面有3种,?#
表示全部,^#
表示匹配第一个,$#
表示匹配最后一个。
<s:iterator value="users.{?#this.age>21}" status="stat">
——下面表示只提取username属性的值。
<s:iterator value="users.{username}" status="stat">
6、struts2的其他标签。
——set标签。作用是var当做key,value里面数据当做值存到ActionContext里去。但是写成如下的样子,虽然在ActionContext里能找到,但是值是null。因为value里面是一个OGNL表达式,需要转成字符串。
<s:set var="name1" value="test1"></s:set>
正确写法:
<s:set var="name1" value="'test1'"></s:set>
可以看到ActionContext李:
——action标签。指定动作类名称,并不会执行,取值默认是false。
<s:action name="action1" executeResult="true"></s:action>
——if/else标签。
<s:set var="score" value="'C'"></s:set><s:if test="#score=='A'">优秀</s:if><s:elseif test="#score=='B'">良好</s:elseif><s:else>不妙</s:else>
——url标签。
// 页面上直接输出i-am-value<s:url value="i-am-value"></s:url>//把action全路径输出来,显示的是/Day01_ValueStack/data.action,不存储<s:url action="data"></s:url>//不显示,只存储,存在ActionContext里,key就是customUrl<s:url action="data" var="customUrl"></s:url>
有的时候我们存储了action的全路径后,就使用<a href='<s:property value="#customUrl" />'>点我到action去</a>
’。而不直接使用硬编码的<a href='${pageContext.request.contextPath}/data.action'>点我到action去</a>
。因为我们时候要做伪静态页面,也就是把网址最后修改成html结尾。那么这个时候我们使用#customUrl
就自动转换了,而采用硬编码的方式就会出错。
伪静态的设置在struts.xml里:
<constant name="struts.action.extensions" value="html" ></constant>
——我们还可以添加get参数:
<s:url action="actionData" var="customUrl"> <s:param name="username" value="'andy'"></s:param> </s:url>
然后我们在使用这个#customUrl
链接的地方就会发现,这个链接后面自动添加了一个参数。
7、几种符号的使用。
——#。去contextMap里面的值用。还有在OGNL创建Map对象时用,如<s:radio list="#{'0':'男','1':'女'}" />
。
——$。jsp的EL表达式用。还有在struts.xml配置文件中也用,比如配置下载文件的那地方${@java.net.URLEncoder.encode(filename)}
。这里的filename是我们在动作类里面定义的,我们知道动作类是默认在ValueStack的栈顶的,所以里面的变量也在ValueStack里面,所以我们才能取到值。
——%。用的地方是把字符串强制当做OGNL表达式。我们知道反过来把OGNL表达式转成字符串就是加一对单引号,反过来操作的话就是用这里的%{}。比如<s:textfield value="%{username}" />
。
8、结合ModelDriver、struts表单的源代码。
——在struts2-core-2.3.15.3.jar核心包里面有一个xhtml的包,里面就是UI主题,还有一个simple的主题。
——我们可以针对某一个表单或者全部表单进行设置。但是需要注意的是如果设置成simple主题的话,前面label名称没有了需要自己写,而且每个表单都不换行了需要自己换行。我们在struts.xml文件中设置常量效果是一样的,只不过设置常量就意味着整个项目的表单都会生效:<constant name="struts.ui.theme" value="simple"></constant>
。
<s:form action="registerAction" theme="simple">……</s:form>
源代码:JavaEE struts表单和ModelDriver以及主题
9、防止表单重复提交。我们防止重复提交的话,一般是通过验证码,第一次生成的时候,放一份验证码在Session里面,然后提交后比较了就删除session里面的验证码,这样再提交就没有比较就判断出错了,防止重复提交。
——在struts2里面,我们可以用tokenSession来防止重复提交,它的原理就是只处理第一次的提交,后面的直接忽略掉。我们先在表单中增加一个token的标签表单,是隐藏的。
<s:form action="loginAction"> <s:token></s:token> <s:textfield name="username" label="用户名"></s:textfield> <s:submit value="提交"></s:submit> </s:form>
然后,在struts.xml对应的action里面配置这个拦截器。
<package name="p_name_1" extends="struts-default"> <action name="loginAction" class="com.hello.web.action.MyAction" method="login"> <interceptor-ref name="defaultStack"></interceptor-ref> <interceptor-ref name="tokenSession"></interceptor-ref> <result>/success.jsp</result> </action> </package>
我们在动作类的方法中写的一个输出语句,每次提交都会经过动作类打印这条语句,但是配置了以上代码之后,我们提交成功后,后退浏览器再提交的时候,语句就不打印了,也就是说只打印一次,动作类的方法只执行1次,这就是防止重复提交的内容。
源代码:JavaEE Struts2利用tokenSession防止重复提交
- 【JavaWeb-18】ActionContext存取数据、ValueStack存取值、EL新查找顺序、iterator、OGNL投影、其他标签、UI主题、防重复提交
- Struts标签-OGNL-EL-ValueStack-ActionContext之间的区别
- OGNL表达式存取值
- OGNL ValueStack ActionContext
- ActionContext、ValueStack、OGNL
- ActionContext、ValueStack、OGNL
- ActionContext、ValueStack、OGNL
- JAVAWEB开发之Struts2详解(四)——ognl与valueStack(重点)、Struts常用标签、防止表单重复提交、Struts2中内置json插件
- list map Iterator 存取值
- Struts2 ValueStack & ActionContext & OGNL 关系
- 简单理解OGNL、ActionContext、ValueStack
- Struts2-day02 获取Servlet API OGNL表达式 ValueStack ActionContext ValueStack存数据 取数据 Interceptor
- 三大框架之----struts2之ValueStack存取数据
- 自定义防重复提交标签
- Struts2小结-ValueStack-OGNL-EL
- 数据存取
- 存取数据
- 数据存取
- 图
- 初学ACM之路(训练大纲)
- 85MaximalRectangle
- Linux使用之一安装安装scim中文输入法
- Design Thinking | 创新设计流程的7个模式
- 【JavaWeb-18】ActionContext存取数据、ValueStack存取值、EL新查找顺序、iterator、OGNL投影、其他标签、UI主题、防重复提交
- Mobius函数计算 定义+代码模板
- 2016年9月英语学习总结
- 常规new和布局new
- 类模板1——基本概念
- Spring中@ModelAttribute注解用法小结
- HDU 1272 小希的迷宫 并查集判断回路和连通
- XPATH 注入的介绍与代码防御
- Win32 程序基础知识