第三章时我们介绍了Struts2从前端获取数据,封装到后端,在第四章时做了两个小项目来说明从前端获取数据,然而在获取数据时,
用的是ServletActionContext.getRequest().setAttribute(String key,Object value) ,
即用的的Servlet中的HttpServletRequest类进行相应的封装,耦合度太高。
Struts2 既然提供了自己的方法来获取数据,那么相应的也会提供自己的方法来展示数据。
最常用的技术就是OGNL表达式和值栈。 在显示数据时,用到了struts2的标签和OGNL表达式,其中el表达式增强了Request的底层getAttribute()方法,所以el表达式也可以访问后端封装的数据。
OGNL 中获取的数据,是从 Stack Context 中获取数据。 其中,值栈 Value Stack 也属于 Stack Context, 只不过是 Stack Context 最上面的一层。 即Struts2 把所有的数据,都放置到 Stack Context里面,其中 Stack Context最上面的一块区域叫做 Value Stack, Value Stack 里面的数据,可以直接取出, Stack Context 里面的数据,不能直接取出, 必须通过 # 号才可以取出。
一. 封装数据
一.一 封装基本数据类型用setter(从前端–>后端)和getter(从后端到前端)方法
Struts2中常用的单个类型有String类型(String不属于8种基本数据类型)和Integer (最好使用包装类Integer)类型
一.一.一 创建Action ,为 SingleAction
新建一个SingleAction,放置基本的数据类型
package com.yjl.web.action; import com.opensymphony.xwork2.ActionSupport; import org.apache.log4j.Logger; /** * @author 两个蝴蝶飞 * @version 创建时间:2018年8月24日 上午9:15:50 * @description 单个的数据类型的封装,如Integer 和String */ public class SingleAction extends ActionSupport{ private static final long serialVersionUID = -6264461713221609298L; private Logger logger=Logger.getLogger(SingleAction.class); private Integer age; private String name; //定义一个属性后,最好setter和getter方法均实现 public Integer getAge() { return age; } public String getName() { return name; } public String getData() { age=24; name="两个蝴蝶飞"; return SUCCESS; } }
一.一.二 配置 struts.xml
<package name="data" extends="struts-default" namespace="/"> <action name="Single_*" class="com.yjl.web.action.SingleAction" method="{1}"> <result name="success">/WEB-INF/content/showData.jsp</result> </action> </package>
一.一.三 编写 /content/showData.jsp 页面
前端显示的时候,showData.jsp页面的代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!--需要引入struts的标签库,默认都添加过了--> <%@ taglib uri="/struts-tags" prefix="s"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <!--struts2 提供的标签--> 姓名: <s:property value="name"/> <br/> 年龄: <s:property value="age"/> </body> </html>
在输入请求: http://localhost:8080/Struts_Data/Single_getData.action 后,
会显示出结果:
这是 struts2 标签库,通过 getter() 方法,来获取数据的。
一.二 封装数据到 request,session,application 域里面
有的时候,这个属性并不是表单中或者实体中的数据,只是一个单纯的提示信息,如message,主要用于提示登录信息。
这个时候就不用麻烦的实现它的setter和getter方法了,可以直接用ActionContext类将其放在类似于request,session的map集合里面。
一.二.一 放置数据
在后端Action 的getData()方法中:
String message="用户名或者密码错误"; //放在request域中 ActionContext.getContext().put("message",message); //放在application域中 //ActionContext.getContext().getApplication().put("message",message); //放在session域中 //ActionContext.getContext().getSession().put("message",message);
运用的是第一种方式, ActionContext() 来获取 Servlet API ,用于存储数据。
一.二.二 前端通过 EL 获取数据
在前端获取时,用el表达式获取
显示错误的信息,取出时EL时用: ${message} <br/>
一.三 封装List让其显示到前端
一.三.一 放置数据
public String getData() { List<String> allList=new ArrayList<String>(); allList.add("两个蝴蝶飞"); allList.add("慧芳"); allList.add("正伟"); //放置时用值栈里面 ActionContext.getContext().getValueStack().set("allList",allList); return SUCCESS; }
放在栈顶的用getValueStack().push(Object) 方法,这个常用于放置单个对象。
getValueStack().set(key,Object) 常常用于放置集合。
一.三.二 获取数据
如果不是放在栈顶,只是一个普通的变量,可以用set方法,进行设置属性。
<!--设置标签库--> <%@ taglib uri="/struts-tags" prefix="s"%> <s:iterator value="allList" var="name"> <s:property value="#name"/><br/> </s:iterator>
一.四 封装Map集合到前端(如入学年份)
一.四.一 放置数据
public String getData() { Map<Integer,String> yearMap=new HashMap<Integer,String>(); yearMap.put(2014,"2014级学生"); yearMap.put(2015,"2015级学生"); yearMap.put(2016,"2016级学生"); yearMap.put(2017,"2017级学生"); //放置时用值栈 在一次性传递数据到前端时,会有很多的数据,不要都放在栈顶ValueStack中. ActionContext.getContext().getValueStack().set("yearMap",yearMap); return SUCCESS; }
一.四.二 获取数据
在前端时,显示时只需要key,value即可,会自动解析。
<s:iterator value="yearMap"> <s:property value="key"/>-------><s:property value="value"/> <br/> </s:iterator>
一.五 封装单个 java Bean 对象到前端(用Push方法放在栈顶)
一.五.一 放置数据
public String getData() { User user=new User(); user.setName("莉莉"); user.setAge(25); user.setSex("女"); user.setRelation("二姐"); ActionContext.getContext().getValueStack().push(user); return SUCCESS; }
一.五.二 获取数据
姓名:<s:property value="name"/> 年龄:<s:property value="age"/> 性别:<s:property value="sex"/> 关系:<s:property value="relation"/>
有时,为了简便属性,常用EL表达式取出
姓名:${name} 年龄:${age} 性别:${sex} 关系:${relation}
用 EL 表达式取出时,准确地来说,是从 StackContext 里面取出的数据。
一.五.二 获取对象属性数据
在实际的开发项目中,实体与实体之间是有一定的关联的,如User 中会存在Class对象,表示这个用户属于哪一个班级,
那么在取出属性数据的时候,如取出Class中的name值,可以用.(点)的方式取出
在user 对象里面,可以通过
<s:property value=“class.name”/> 或者 ${class.name} 来获取数据。
可以进行一直的连续点击 如 user.class.speciality.name; 学生的班级的专业的名称
一.六 封装List 对象到前端
最常用的操作还是查询,查询出所有符合条件的对象,这是非常常用。(用第四章项目的UserService中的静态模拟数据)
一.六.一 设置数据
public String getData() { UserService userService=new UserService(); List<User> userList=userService.findAll(); ActionContext.getContext().getValueStack().set("userList",userList); return SUCCESS; }
一.六.二 获取数据
在前端页面中,
可以用${user.name} el 表达式
<tbody> <s:iterator value="userList" var="user"> <tr> <td>${user.name}</td> <td>${user.sex}</td> <td>${user.age}</td> <td>${user.relation}</td> <td> <a href="#">查看详情</a> <a href="#">修改</a> <a href="#">删除</a> </tr> </s:iterator> </tbody>
也可以用 struts2提供的 property 属性标签:
<td><s:property value="#user.name"/></td>
形式。
有时候为了简化方便,也会省略 var=“user” (只放置在Value Stack 里面,用完就删除)
<tbody> <s:iterator value="userList"> <tr> <td>${name}</td> <td>${sex}</td> <td>${age}</td> <td>${relation}</td> <td> <a href="#">查看详情</a> <a href="#">修改</a> <a href="#">删除</a> </tr> </s:iterator> </tbody>
建议不要省略var=“user” .
虽然在开发中多写这一个var="user"麻烦了一些,但是规范性和可读性高了一些。
在显示user时,var=“user”,在显示class时,var=“class”,
这样在u s e r . n a m e , {user.name} ,user.name,{class.name} 时会增加可读性, ${name}就不明所以了。
重启服务器,显示:
常用的基本的类型就这些了, Map<String,List>等形式是不常用的,就不讲解了。
二. OGNL表达式的强大之处
二.一 直接调用字符串中的方法
<div class="row"> ognl显示字符串的长度:<s:property value="'两个蝴蝶飞'.length()"/><br/> ognl字符串转换成大写显示:<s:property value="'hello world'.toUpperCase()"/> </div>
二.二 OGNL访问系统包下的静态属性和方法
如访问 math包下的 PI静态属性 和 abs() 静态方法
<div class="row"> Math中的PI静态属性:<s:property value="@java.lang.Math@PI"/><br/> Math中的abs静态方法:<s:property value="@java.lang.Math@abs(-3)"/><br/> </div>
访问后展示结果:
二.三 访问自定义的静态属性和方法
如果stuts2内置的方法不够使用时,用户可以自己定义相应的属性和方法。
二.三.一 创建标签类
在pojo包下新建一个MyOgnl类,里面有静态属性,静态无参方法,静态有参方法
package com.yjl.pojo; /** * @author 两个蝴蝶飞 * @version 创建时间:2018年8月24日 上午10:44:37 * @description ongl执行静态方法 */ public class MyOgnl { public static String NAME="两个蝴蝶飞"; public static String defaultMethod1() { return "我是一个Java程序员"; } public static String defaultMethod2(String str) { if(str!=null&&!"".equals(str)) { return str+"长度是:"+str.length(); }else { return "字符串为空,长度是:0"; } } }
二.三.二 struts2.xml 配置 struts.ognl.allowStaticMethodAccess 属性。
需要在struts.xml配置struts.ognl.allowStaticMethodAccess的值为true,允许访问. 默认为false
<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
二.三.三 前端页面展示
在showData.jsp页面上
<div class="row"> 访问静态属性: <s:property value="@com.yjl.pojo.MyOgnl@NAME"/> <br/> 访问静态无参方法: <s:property value="@com.yjl.pojo.MyOgnl@defaultMethod1()"/> <br/> 访问静态有参方法: <s:property value="@com.yjl.pojo.MyOgnl@defaultMethod2('两个蝴蝶飞')"/> <br/> </div>
访问静态属性,形式为: @类全限定名称@静态属性,
访问静态方法,形式为: @类全限定名称@方法(), @类全限定名称@方法(参数1,参数2)
展示页面如下所示:
三. 检测每个Action对象里面只有一个值栈对象
在访问Action时,每一次访问,都会创建一个Action对象。 它是多实例的。 与Servlet不一样,Servlet只是在第一次访问时进行实例化。 每一个Action对象都只有一个ValueStack值栈。
public String getData() { ActionContext ac=ActionContext.getContext(); ValueStack v1=ac.getValueStack(); ValueStack v2=ac.getValueStack(); logger.info(v1==v2); //true return SUCCESS; }
谢谢您的观看!!!