以下内容是基于导入struts2-2.3.32.jar包来讲的
1.OGNL
OGNL是Object-Graph Navigation Language的缩写,全称为对象图导航语言,是一种功能强大的表达式语言,它通过简单一致的语法,可以任意存取对象的属性或者调用对象的方法,能够遍历整个对象的结构图,实现对象属性类型的转换等功能。它是一个开源项目。 Struts2框架使用OGNL作为默认的表达式语言。
OGNL 有一个上下文(Context)概念,说白了上下文就是一个MAP结构,它实现了 java.utils.Map 的接口。
作用:
1、支持对象方法调用,如xxx.doSomeSpecial();
2、支持类静态的方法调用和值访问,表达式的格式:
@[类全名(包括包路径)]@[方法名 | 值名],例如:
@java.lang.String@format('foo %s', 'bar')
或@tutorial.MyConstant@APP_NAME;
3、支持赋值操作和表达式串联,如price=100, discount=0.8,
calculatePrice(),这个表达式会返回80;
4、访问OGNL上下文(OGNL context)和ActionContext;
5、操作集合对象。
ognl表达式取值,如果是根元素取值不用带#符号, 非根元素取值要带#号!
知识点:
OGNL中重要的3个符号:#、%、$:
#符号的用途一般有三种。
— 访问非根对象属性,例如#session.msg表达式,由于Struts 2中值栈被视为根对象,所以访问其他非根对象时,需要加#前缀。实际上,#相当于ActionContext. getContext();#session.msg表达式相当于ActionContext.getContext().getSession(). getAttribute("msg") 。
— 用于过滤和投影(projecting)集合,如persons.{?#this.age>25},persons.{?#this.name=='pla1'}.{age}[0]。
— 用来构造Map,例如示例中的#{'foo1':'bar1', 'foo2':'bar2'}。
2.%符号
3.$符号
$符号主要有两个方面的用途。
— 在国际化资源文件中,引用OGNL表达式,例如国际化资源文件中的代码:reg.agerange=国际化资源信息:年龄必须在${min}同${max}之间。
— 在Struts 2框架的配置文件中引用OGNL表达式。
2.基本使用
A.往根元素设置并获取值:
1 package com.rong.web.test;
2
3 import com.rong.web.entity.User;
4
5 import ognl.Ognl;
6 import ognl.OgnlContext;
7
8 public class OGNLTest {
9
10 public static void main(String[] args) throws Exception{
11 //Ognl上下文OgnlContext实现了 java.util.Map 的接口,具有Map的功能
12 OgnlContext ognlContext = new OgnlContext();
13 ognlContext.put("username", "huge");
14 System.out.println(ognlContext.get("username"));
15
16 User user=new User();
17 user.setId(57);
18 user.setName("rjl");
19 user.setAge(18);
20 //设置上下文根对象
21 ognlContext.setRoot(user);
22 //表达式
23 Object expression1 = Ognl.parseExpression("name");
24 Object expression2 = Ognl.parseExpression("id");
25 Object expression3 = Ognl.parseExpression("age");
26 Object value1 = Ognl.getValue(expression1, ognlContext, ognlContext.getRoot());
27 Object value2 = Ognl.getValue(expression2, ognlContext, ognlContext.getRoot());
28 Object value3 = Ognl.getValue(expression3, ognlContext, ognlContext.getRoot());
29
30 System.out.println(value1.toString()+value2.toString()+value3.toString());
31 }
32 }
B.往非根元素设置并获取值:
1 package com.rong.web.test;
2
3 import com.rong.web.entity.Student;
4
5 import ognl.Ognl;
6 import ognl.OgnlContext;
7
8 public class OGNLTest {
9
10 public static void main(String[] args) throws Exception{
11 //Ognl上下文OgnlContext实现了 java.utils.Map 的接口,具有Map的功能
12 OgnlContext ognlContext = new OgnlContext();
13 //往非根元素设置值;非根元素取值要带#号
14 Student student = new Student(24,"kobe",38);
15 ognlContext.put("stu", student);
16 Object expression = Ognl.parseExpression("#stu.sid");
17 Object value = Ognl.getValue(expression, ognlContext, ognlContext.getRoot());
18 System.out.println(value);
19 }
20 }
3.值栈(ValueStack)
ValueStack实际是一个接口,在Struts2中利用OGNL时,实际上使用的是实现了该接口的OgnlValueStack类,这个类是Struts2利用OGNL的基础。
ValueStack贯穿整个 Action 的生命周期
(每个 Action 类的对象实例都拥有一个ValueStack 对象).
相当于一个数据的中转站. 在其中保存当前Action 对象和其他相关对象.
Struts2框架把 ValueStack 对象保存在名为 “struts.valueStack” 的request请求属性中。
Action中获取值栈对象的两种方式:
1 package com.rong.web.action;
2
3 import javax.servlet.http.HttpServletRequest;
4
5 import org.apache.struts2.ServletActionContext;
6
7 import com.opensymphony.xwork2.ActionContext;
8 import com.opensymphony.xwork2.ActionSupport;
9 import com.opensymphony.xwork2.util.ValueStack;
10
11 public class MyAction extends ActionSupport {
12 private static final long serialVersionUID = -351587239525292420L;
13
14 @Override
15 public String execute() throws Exception {
16 ActionContext actionContext = ActionContext.getContext();
17 //ValueStack是执行Ognl表达式的基础。也是从OgnlContext中去获取值、设置值的基础
18 //ValueStack值栈
19 ValueStack valueStack = actionContext.getValueStack();
20 //com.opensymphony.xwork2.ognl.OgnlValueStack@55195240
21 System.out.println(valueStack);
22
23
24 //Struts2框架把 ValueStack 对象保存在名为 “struts.valueStack” 的request请求属性中。
25 HttpServletRequest request = ServletActionContext.getRequest();
26 Object object = request.getAttribute("struts.valueStack");
27 //com.opensymphony.xwork2.ognl.OgnlValueStack@55195240
28 System.out.println(object);
29 return SUCCESS;
30 }
31 }
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
值栈中有根元素 和 非根元素。
非根元素就是OgnlContext
OgnlContext中引用了值栈的根元素数据
Struts每次访问action的时候:
1. 创建一个ActionContext对象
2. 创建值栈对象
把域中存放的数据、以及Action对象,放到值栈中!
这时候,值栈就有了struts运行时期的数据!
3. 把值栈的数据,拷贝一份给ActionContext!
4. 最后,把值栈放到request的请求中!
操作根元素数据:
1 ActionContext actionContext = ActionContext.getContext();
2 //ValueStack是执行Ognl表达式的基础。也是从OgnlContext中去获取值、设置值的基础
3 //ValueStack值栈
4 ValueStack valueStack = actionContext.getValueStack();
5 //com.opensymphony.xwork2.ognl.OgnlValueStack@55195240
6 System.out.println(valueStack);
7 Student student = new Student(24,"kobe",38);
8 valueStack.pop();//移出根元素
9 valueStack.getRoot().push(student);//设置根元素
10
11 boolean empty = valueStack.getRoot().isEmpty();
12 System.out.println("根元素是否为空:"+empty);
13 Student pop = (Student) valueStack.getRoot().pop();//移出根元素,并返回该元素
14 System.out.println(pop.getSname());
操作非根元素数据:
1 package com.rong.web.action;
2
3 import java.util.Map;
4
5 import com.opensymphony.xwork2.ActionContext;
6 import com.opensymphony.xwork2.ActionSupport;
7 import com.rong.web.entity.Student;
8
9 public class MyAction extends ActionSupport {
10 private static final long serialVersionUID = -351587239525292420L;
11
12 @Override
13 public String execute() throws Exception {
14 ActionContext actionContext = ActionContext.getContext();
15 Student student = new Student(24,"kobe",38);
16 Map<String, Object> request = actionContext.getContextMap();
17 request.put("one", "ONE");
18 Map<String, Object> session = actionContext.getSession();
19 session.put("two", student);
20 Map<String, Object> application = actionContext.getApplication();
21 application.put("three", "Three");
22 System.out.println(request.get("one"));
23 System.out.println(((Student)session.get("two")).getSname());
24 System.out.println(application.get("three"));
25
26 return SUCCESS;
27 }
28 }
4.struts标签(实际开发很少用,用jstl较多)
标签防止重复提交
<s:token />标签防止重复提交,用法如下:第一步:在表单中加入<s:token />
<s:form action="helloworld_other" method="post" namespace="/test">
<s:textfield name="person.name"/><s:token/><s:submit/>
</s:form>
第二步:
<action name="helloworld_*" class="com.rong.web.action.HelloWorldAction" method="{1}">
<interceptor-ref name="defaultStack"/>
<!-- 增加令牌拦截器 -->
<interceptor-ref name="token">
<!-- 哪些方法被令牌拦截器拦截 -->
<param name=“includeMethods">save</param>
</interceptor-ref>
<!-- 当表单重复提交转向的页面 -->
<result name="invalid.token">/WEB-INF/page/message.jsp</result>
</action>
以上配置加入了“token”拦截器和“invalid.token”结果,因为“token”拦截器在会话的token与请求的token不一致时,将会直接返回“invalid.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'
$符号配置文件取值用:
1 package com.rong.web.action; 2 3 import com.opensymphony.xwork2.ActionSupport; 4 5 public class MyAction extends ActionSupport { 6 private static final long serialVersionUID = -351587239525292420L; 7 private String username; 8 public String getUsername() { 9 return username; 10 } 11 public void setUsername(String username) { 12 this.username = username; 13 } 14 @Override 15 public String execute() throws Exception { 16 username="rjl"; 17 return SUCCESS; 18 } 19 }
<struts>
<package name="default" namespace="/" extends="struts-default" >
<action name="test" class="com.rong.web.action.MyAction">
<result type="redirect">/one.jsp?username=${username}</result>
</action>
</package>
</struts>
#号%号略。
struts标签使用:
导入标签库:<%@ taglib uri="/struts-tags" prefix="s"%>
1、条件标签 if…elseif…else
1 package com.rong.web.action; 2 3 import java.util.Map; 4 5 import com.opensymphony.xwork2.ActionContext; 6 import com.opensymphony.xwork2.ActionSupport; 7 8 public class MyAction extends ActionSupport { 9 private static final long serialVersionUID = -351587239525292420L; 10 @Override 11 public String execute() throws Exception { 12 ActionContext actionContext = ActionContext.getContext(); 13 Map<String, Object> session = actionContext.getSession(); 14 session.put("number", 57); 15 return SUCCESS; 16 } 17 }
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="/struts-tags" prefix="s"%>
<c:set var="basePath" value="${pageContext.request.contextPath }"></c:set>
<!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>
one.jsp!
<s:debug></s:debug>
<s:if test="#session.number>57">great!</s:if>
<s:elseif test="#session.number<57">less!</s:elseif>
<s:else>equal!</s:else>
</body>
</html>
2、迭代标签 iterator
用于循环数组,集合和Map
属性:
value:数组,集合或Map
var:当前元素
status:当前元素的状态index,count,even,odd,first,last
其余的标签略。
5.Action中验证(代码验证)
后台向前台返回校验信息,数据校验由后台进行(较少用,一般前台做数据校验)
A.验证所有方法
<struts>
<package name="default" namespace="/" extends="struts-default" >
<action name="check" class="com.rong.web.action.MyAction">
<result>/one.jsp</result>
<!-- 验证信息错误时,框架固定返回input视图 -->
<result name="input">/index.jsp</result>
</action>
</package>
</struts>
index.jsp
<body>
<form action="${pageContext.request.contextPath }/check" method="post">
<input type="text" name="student.sname"/>
<!-- 获取后台返回的校验信息 -->
<s:fielderror key="#student.sname"></s:fielderror>
<input type="submit" value="登录"/>
</form>
</body>
MyAction.java
1 package com.rong.web.action;
2
3 import com.opensymphony.xwork2.ActionSupport;
4 import com.rong.web.entity.Student;
5
6 public class MyAction extends ActionSupport {
7 private static final long serialVersionUID = -351587239525292420L;
8 private Student student;
9 public Student getStudent() {
10 return student;
11 }
12 public void setStudent(Student student) {
13 this.student = student;
14 }
15 //重写validate方法校验前台信息,在执行execute方法之前执行。此Action里所有的方法都会走这个验证。
16 @Override
17 public void validate() {
18 if(student.getSname().trim().length()==0){
19 //向前台返回校验信息
20 this.addFieldError("student.sname", "学生名字不能为空!");
21 }
22 }
23 @Override
24 public String execute() throws Exception {
25 System.out.println("execute!!!");
26 return SUCCESS;
27 }
28 }
B.验证某个方法
public void validate方法名(){
//方法名首字母需要大写!!!
}
1 package com.rong.web.action;
2
3 import com.opensymphony.xwork2.ActionSupport;
4 import com.rong.web.entity.Student;
5
6 public class MyAction extends ActionSupport {
7 private static final long serialVersionUID = -351587239525292420L;
8 private Student student;
9 public Student getStudent() {
10 return student;
11 }
12 public void setStudent(Student student) {
13 this.student = student;
14 }
15 //针对某一个方法做验证:validate方法名,其中方法名首字母要大写
16 public void validateExecute(){
17 if(student.getSname().trim().length()==0){
18 //向前台返回校验信息
19 this.addFieldError("student.sname", "学生名字不能为空!");
20 }
21 }
22 @Override
23 public String execute() throws Exception {
24 System.out.println("execute!!!");
25 return SUCCESS;
26 }
27 }
C.添加/显示错误
添加:
@Override public void validate() { if(student.getSname().trim().length()==0){ //向前台返回校验信息 this.addFieldError("student.sname", "学生名字不能为空!"); } }
显示:
<body>
<form action="${pageContext.request.contextPath }/check" method="post">
<input type="text" name="student.sname"/>
<!-- 获取后台返回的校验信息 -->
<!-- 显示指定错误信息 -->
<s:fielderror key="#student.sname"></s:fielderror>
<!-- 显示指定错误信息 -->
<s:fielderror fieldName="student.sname"></s:fielderror>
<!-- 可以显示所有的错误信息 -->
<s:fielderror></s:fielderror>
<input type="submit" value="登录"/>
</form>
</body>
fielderror标签样式问题:
struts默认添加额外的ul-li样式,去除这种效果便于显示!
解决方式:
1.新建src\template\simple包
2.拷贝一个fielderror.ftl
3.修改fielderror.ftl文件,把ul和li去掉即可