概述
- OGNL表达式:
OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。Struts2 框架使用OGNL作为默认的表达式语言。 - OGNL优势
- 支持对象方法调用,如xxx.doSomeSpecial();
- 支持类静态的方法调用和值访问,表达式的格式:
@[类全名(包括路径名)]@[方法名|值名],例如:
@java.lang.String@format(‘foo%s’,‘bar’)
或@tutorial.MyConstant@APP_NAME; - 支持赋值操作和表达式串联,如price=100,discount=0.8
calculatePrice(),这个表达式会返回80. - 访问OGNL上下文(OGNL context)和ActionContext;
- 操作集合对象
- 总结
OGNL有一个上下文(context)的概念,上下文也就是一个MAP结构,它实现了java.util.Map的接口。
分析:
- Struts框架默认支持ognl表达式语言(struts框架默认必须引入的包:ognl.jar)
- 作用:
- 页面取值使用。
- EL表达式语言,用于页面取值,jsp页面取值标准,(默认直接可以使用)
- ognl表达式语言,struts标签默认支持的表达式语言。必须配置struts标签用,不能离开struts标签直接使用。
OgnkContext对象
OgnkContext对象是Ognl表达式语言的核心。
源码类:public class OgnlContext implements Map {…}
//OgnlContext用法
public class OgmlDemo1{
/**
* 1.使用ognl表达式语言取值,取非根元素的值,必须要用#
* @throws OgnlException
*/
@Test
public void testOgnl1() throws OgnlException {
//创建一个Ognl上下文对象
OgnlContext context = new OgnlContext();
//存放数据
context.put("cn","china");
User user = new User();
user.setId(1);
user.setName("jack");
//往非根元素放入数据,取值的时候表达式要用"#"
context.put("user",user);
//获取数据(map)
String value = (String) context.get("cn");
System.out.println(value);
//构建一个ognl表达式,再解析表达式
Object ognl = Ognl.parseExpression("#user.adress.province");
Object value1 = Ognl.getValue(ognl,context,context.getRoot());
System.out.println(value1);
}
/**
* 2.使用ognl表达式语言取值,取根元素的值,不用带#
* @throws OgnlException
*/
@Test
public void testOgnl2() throws OgnlException {
//创建一个Ognl上下文对象
OgnlContext context = new OgnlContext();
User user = new User();
user.setId(1);
user.setName("jack");
//往根元素放入数据,取值的时候表达式 不要用 "#"
context.setRoot(user);
//构建一个ognl表达式,再解析表达式
Object ognl = Ognl.parseExpression("adress.province");
Object value = Ognl.getValue(ognl,context,context.getRoot());
System.out.println(value);
}
/**
* 3.Ognl对静态方法调用的支持
* @throws OgnlException
*/
@Test
public void testOgnl3() throws OgnlException {
//创建一个Ognl上下文对象
OgnlContext context = new OgnlContext();
//Ognl表达式语言,调用类的静态方法
// Object ognl = Ognl.parseExpression("@Math@floor(10.9)");
//由于Math类在开发中比较常用,所以也可以这样使用
Object ognl = Ognl.parseExpression("@@floor(10.9)");
Object value = Ognl.getValue(ognl,context,context.getRoot());
System.out.println(value);
}
}
ValueStack
ValueStack,即值栈对象
是整个struts数据存储的核心,即中转站。
用户每次访问struts的action,都会创建一个action对象、值栈对象、ActionContext对象。
然后把Action对象放入到值栈中。最后再把值栈对象放到request中,传入jsp页面。
(key:struts.valueStack);开发者只需要通过ActionContext对象就可以访问struts的其他的
关键对象。(ActionContext是给开发者使用的,便于学习与使用)
问题:
- OgnlContext与ValueStack的关系
Struts标签
struts标签取值,就使用了ognl表达式语言。
<body>
<h1>1.迭代list</h1><br/>
<table border="1">
<tr>
<td>编号</td>
<td>名称</td>
</tr>
<s:iterator var="user" value="#request.list" status="st">
<tr class="<s:property value="#st.even?'even':'odd'"/> ">
<td><s:property value="#user.id"/></td>
<td><s:property value="#user.name"/></td>
</tr>
<%--<s:property value="#st.even"/><br/>--%>
</s:iterator>
</table><br/>
<h1>2.迭代map</h1><br/>
<table border="1">
<tr>
<td>编号</td>
<td>名称</td>
</tr>
<s:iterator var="en" value="#request.map" status="st">
<tr class="<s:property value="#st.even?'even':'odd'"/> ">
<td><s:property value="#en.key"/></td>
<td><s:property value="#en.value.name"/></td>
</tr>
<%--<s:property value="#st.even"/><br/>--%>
</s:iterator>
</table>
<h1>1.构建list集合</h1><br/>
<%--ognl表达式可以取值,也可以动态构建集合--%>
<s:iterator var="str" value="{'a','b'}">
<s:property value="#str"></s:property>
</s:iterator>
<h1>2.构建map集合</h1><br/>
<s:iterator var="en" value="#{'cn':'China','usa':'American'}">
<s:property value="#en.key"/>
<s:property value="#en.value"/>
</s:iterator>
//struts的数据流转
public class OgnlDemo3 extends ActionSupport {
@Override
public String execute() throws Exception {
//测试迭代标签
List<User> list = new ArrayList<User>();
Map<Integer,User> map = new HashMap<Integer,User>();
//初始化
for(int i=1;i<11;i++){
User user = new User(i,"jack"+i);
list.add(user);
map.put(user.getId(),user);
}
//保存非根
ActionContext.getContext().getContextMap().put("list",list);
ActionContext.getContext().getContextMap().put("map",map);
//保存根
// ActionContext.getContext().getValueStack().getRoot().push(list);
return super.execute();
}
}
struts ognl 中几个特殊符号
- #:获取非根元素值,动态创建map集合
- $:配置文件提取
- %:提供一个ognl表达式运行环境
<h1>获取request域中的数据</h1><br/>
<%--property标签是对象类型的标签,默认支持ognl表达式,会从根元素取China名称对应的值--%>
<s:property value="China"/><br/>
<%--从费根元素取值--%>
<s:property value="#request.cn"/><br/>
<s:property value="%{#request.cn}"/><br/>
<%--如果直接赋值需要用单引号--%>
<s:property value="'China'"/>
<%--值类型的标签,value值默认就是值类型,不支持ognl表达式--%>
国家:<s:textfield name="txtCountry" value="%{#request.cn}"/>
Struts中常用的几个技术
数据回显
数据回显必须要用struts标签
//Action代码:
/**************数据回显******************/
//获取值栈
ValueStack vs = ac.getValueStack();
//移除栈顶元素
vs.pop();
//入栈
vs.push(user);
//jsp代码:
<!--数据回显技术:s:textfield 会自动查找根元素数据(Ognl表达式语言取值)-->
<s:form action="#">
用户名:<s:textfield name="name"/><br/>
邮箱:<s:textfield name="email"/><br/>
</s:form>
模型驱动
Struts运行时候,会执行默认的拦截器栈,其中有一个拦截器,模型驱动拦截器:
<interceptor
name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
@Override
public String intercept(ActionInvocation invocation) throws Exception {
Object action = invocation.getAction();
if (action instanceof ModelDriven) {
ModelDriven modelDriven = (ModelDriven) action;
ValueStack stack = invocation.getStack();
Object model = modelDriven.getModel();
if (model != null) {
stack.push(model);
}
if (refreshModelBeforeResult) {
invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));
}
}
return invocation.invoke();
}
- 引入
prams拦截器,可以把请求数据自动填充的action的属性中
举例1:
JSP
<input type=text name=userName />
<input type=text name=pwd />
Action
class UserAction{
// 封装请求数据
private String userName;
private String pwd;
//.. set方法
}
举例2:
JSP
<input type=text name=user.userName />
<input type=text name=user.pwd />
Action
class UserAction{
// 封装请求数据
private User user;
..
}
举例3:(模型驱动)
JSP
<input type=text name=userName />
<input type=text name=pwd />
Action
class UserAction{
// 封装请求数据
private User user;
..
}
-
步骤及原理
步骤:- 实现ModelDriver接口
- 实现接口方法: 接口方法返回的就是要封装的对象
- 对象一定要实例化。
分析:
/**
* 1. 数据回显
* 2. 模型驱动
*/
public class UserAction extends ActionSupport implements ModelDriven<User> {
// 封装请求数据
private User user = new User();
public void setUser(User user) {
this.user = user;
}
public User getUser() {
return user;
}
// 实现模型驱动接口方法
@Override
public User getModel() {
return user;
}
public String add() {
// 测试: 使用了模型驱动,是否数据正常? Ok
System.out.println(user);
return "success";
}
防止表单重复提交
Struts提供了防止表单重复提交拦截器:
<interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
案例:
- 建库建表
-- 删除数据库
DROP DATABASE hib_demo;
-- 创建数据库
CREATE DATABASE hib_demo DEFAULT CHARACTER SET utf8;
-- 建表
CREATE TABLE employee (
id INT PRIMARY KEY AUTO_INCREMENT,
empName VARCHAR(20),
workDate DATE -- 入职时间
);
- 搭建环境
- 搭建struts环境
- 组件:c3p0/dbutils/驱动