Struts2之OGNL表达式
- 1、什么是OGNL表达式
- 2、OGNL表达式的作用
- 3、值栈与OGNL
- 3.1、值栈
- 3.2、OGNL访问值栈
- 4、类型转换
- 4.1、类型转换的意义
- 4.2、内置的类型转换器
- 4.3、自定义类型转换器
- 4.3.1、创建日期转换器
- 4.3.2、配置转换器
- 4.3.3、页面
- 4.3.4、实体类和Action控制器
- 4.3.5、struts.xml配置
- 4.3.6、测试
- 4.4、处理类型转换错误
- 5、OGNL表达式注意事项
1、什么是OGNL表达式
全称Object Graph Navigation Language,对象导航语言。属于开源项目,其目的是为了取代页面中的Java脚本,简化数据的访问。和EL表达式同属于表达式语言,其功能强大。
2、OGNL表达式的作用
主要用作表达式语言和进行类型转换。如下:
- 表达式语言:将表单或Struts2标签与特定的Java数据绑定起来,用来将数据移入、移出框架。
- 类型转换:数据进入和流出框架,在页面数据的字符串类型和Java数据类型之间进行转换。
以下用图示说明:
3、值栈与OGNL
3.1、值栈
值栈,英文为ValueStack,是由Struts2框架创建的存储区域,具有栈的特点,并且所有的Action实例都会被存放在值栈中。
3.2、OGNL访问值栈
需要注意以下两点:
- 按照从上到下的顺序访问。
- 靠近栈顶的同名属性会被读取。
图示如下:
4、类型转换
4.1、类型转换的意义
在基于HTTP协议的Web应用中,客户端请求的所有内容都是以文本编码方式传输到服务端。服务器端的编程语言却有着丰富的数据类型。比如在Servlet中,接收到的参数类型都是String类型,需要开发者根据需要的类型进行自行转换,如下:
String ageStr = request.getParameter("age");
Integer age = Integer.parseInt(ageStr);
如果每个接收到的参数都需要手动转换,就会很不方便,而类型转换则很好的解决了这一问题。
4.2、内置的类型转换器
Struts2提供了多种内置类型转换器,自动对客户端传来的数据进行类型转换。如下图示:
4.3、自定义类型转换器
有时Struts2自带的内置转换器不能很好的满足需求,需要自定义类型转换器。自定义的转换器需要继承org.apache.struts2.util.StrutsTypeConverter类,该类的源码如下:
public abstract class StrutsTypeConverter extends DefaultTypeConverter {
public Object convertValue(Map context, Object o, Class toClass) {
if (toClass.equals(String.class)) {
return convertToString(context, o);
} else if (o instanceof String[]) {
return convertFromString(context, (String[]) o, toClass);
} else if (o instanceof String) {
return convertFromString(context, new String[]{(String) o}, toClass);
} else {
return performFallbackConversion(context, o, toClass);
}
}
/**
* Hook to perform a fallback conversion if every default options failed. By default
* this will ask Ognl's DefaultTypeConverter (of which this class extends) to
* perform the conversion.
*
* @param context the action context
* @param o object to be converted
* @param toClass the class to convert to
* @return The fallback conversion
*/
protected Object performFallbackConversion(Map context, Object o, Class toClass) {
return super.convertValue(context, o, toClass);
}
/**
* Converts one or more String values to the specified class.
*
* @param context the action context
* @param values the String values to be converted, such as those submitted from an HTML form
* @param toClass the class to convert to
* @return the converted object
*/
public abstract Object convertFromString(Map context, String[] values, Class toClass);
/**
* Converts the specified object to a String.
*
* @param context the action context
* @param o the object to be converted
* @return the converted String
*/
public abstract String convertToString(Map context, Object o);
}
一般需要重写convertFromString(Map context, String[] values, Class toClass)方法或convertToString(Map context, Object o)方法,在对象和字符串之间进行转换。
以下将自定义一个日期类型转换器,对日期格式进行自动转换。
4.3.1、创建日期转换器
/**
* @ClassName: DateConverter
* @Description:自定义日期类型转换器
* @author: yanchengzhi
* @date: 2023年1月9日 下午3:25:01
* @Copyright:
*/
public class DateConverter extends StrutsTypeConverter {
private final DateFormat [] dfs = {
new SimpleDateFormat("yyyy年MM月dd日"),
new SimpleDateFormat("yyyy-MM-dd"),
new SimpleDateFormat("MM/dd/yy"),
new SimpleDateFormat("yyyy.MM.dd"),
new SimpleDateFormat("yyMMdd"),
new SimpleDateFormat("yyyy/MM/dd")
};
/**
* 字符串转为日期格式
*/
@Override
public Object convertFromString(Map context, String[] values, Class toClass) {
String dateStr = values[0];
for(int i=0;i<dfs.length;i++) {
try {
return dfs[i].parse(dateStr);
} catch (Exception e) {
continue;
}
}
throw new TypeConversionException("转换错误");
}
/**
* 日期转换为字符串格式
*/
@Override
public String convertToString(Map context, Object o) {
Date date = (Date)o;
return dfs[1].format(date);
}
}
4.3.2、配置转换器
如果是应用于全局范围内的类型转换器,则需要在resources目录下创建一个xwork-conversion.properties属性文件,如下:
如果是用于特定类的类型转换器,则需要在同级目录下创建一个名为ClassName-conversion.properties的属性文件,配置与上相同。
4.3.3、页面
person.jsp页面:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="person/person.action" method="post">
<div>
<label>姓名:</label>
<input type="text" name="person.name" />
</div>
<div>
<label>年龄:</label>
<input type="text" name="person.age" />
</div>
<div>
<label>出生日期:</label>
<input type="text" name="person.birth" />
</div>
<div>
<input type="submit" value="提交" />
</div>
</form>
</body>
</html>
personMess.jsp页面:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>姓名:<s:property value="person.name" /> </h1>
<h1>年龄:<s:property value="person.age" /> </h1>
<h1>出生日期:<s:property value="person.birth" /> </h1>
<h1>出生日期:<s:date name="person.birth" /> </h1>
</body>
</html>
4.3.4、实体类和Action控制器
Person类如下:
@Data
public class Person {
private String name;
private Integer age;
private Date birth;
}
PersonAction控制器如下:
public class PersonAction extends ActionSupport {
private static final long serialVersionUID = 1L;
private Person person;
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public String test() {
System.out.println(person.toString());
return SUCCESS;
}
}
4.3.5、struts.xml配置
<package name="person" extends="default" namespace="/person">
<action name="person" class="com.ycz.struts01.action.PersonAction" method="test">
<result>/personMess.jsp</result>
</action>
</package>
4.3.6、测试
启动项目,访问http://localhost:8081/struts01/person.jsp:
填写表单,这里的出生日期是手动输入的字符串,只要满足自定义类型转换器里的一种格式即可:
提交表单,页面跳转:
控制台输出:
可以看到,控制台输出的是日期格式,而表单中填写的是字符串格式,格式自动由字符串转换成了日期,而该转换由类型转换器自动完成。注意页面中用到了一个特殊标签:
<s:date>
标签用于向页面中输出格式化的日期,该标签有三个属性,name,format和nice。当nice属性为false时(不指定默认为false),可通过format属性自定义日期的格式,如果为true,format设置将不生效。
4.4、处理类型转换错误
在resources目录下创建message.properties属性文件,内容如下:
xwork.default.invalid.fieldvalue=字段"{0}"的值无效
然后在sturts.xml中进行配置:
页面中添加相应的错误输出标签:
启动项目,访问页面:
日期里输入一个错误格式,提交:
错误提示消息正确回显了。
5、OGNL表达式注意事项