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表达式注意事项

 
 
 
 
 
 
 
 
 




![[2023] NAND闪存及控制器的市场趋势](https://img-blog.csdnimg.cn/img_convert/74451631d2ff5c81ba79ba8d4f300e41.jpeg)













