Struts2学习-3 : OGNL表达式详解
OGNL表达式详解
1,OGNL:Object Graph Navigation Language
2,OGNL不仅可以调用属性,还可以调用普通方法
<!-- 表达式可以调get和set,可以调方法,可以按索引取数组内容 (打印a)-->
<s:property value='"abcdefg".toCharArray()[0]'/><br/>
<!-- ognl表达式中:context代表contextMap (打印对应的value)-->
<s:property value="#context['com.opensymphony.xwork2.ActionContext.locale']"/>
<!-- 打印11111111111111111,直接量,直接写的值,H表示大数据? -->
<s:property value="11111111111111111H"/><br/>
|
111B 表示BigDecimal类型 1111H表示BigInteger
3:OGNL获取属性等
<%
request.setAttribute("str", new String[]{"a","b","c"});
%>
<s:debug></s:debug>
<!-- OGNL中可以使用伪属性 .length(以下打印3) -->
<s:property value="#request.str.length"/><br/>
<s:property value="#request.str['length']"/><br/>
<s:property value="#request.str['len'+'gth']"/><br/>
|
4.1链式表达式(Chained Subexpressions):
<!-- 链式表达式,#this表示前面的110H.intValue() -->
<s:property value="110H.intValue().(#this<112?#this*2:#this/2)"/><br/>
|
*4.2访问静态资源:
取得静态常量,用@进行间隔,加小括号表示静态方法,不加小括号就是代表取get方法
<!-- 使用静态资源,需要打开静态常量开关struts.ognl.allowStaticMethodAccess -->
<!-- 表示Integer中的MAX_VALUE常量 -->
<s:property value="@[email protected]_VALUE"/><br/>
<!-- 表示使用System类中的currentTimeMillis()静态方法 -->
<s:property value="@[email protected]()"/><hr/>
|
*4.3集合对象的操作
创建集合并迭代:
a、表达式:{'a','b','c'}用于创建List集合
<!--{'a','b','c'} 创建了一个List集合 -->
<s:iterator value="{'a','b','c'}">
<s:property/><br/><!-- value省略,打印a b c -->
</s:iterator>
<!-- 打印class java.util.ArrayList -->
<s:property value="{'a','b','c'}.class"/><br/>
|
b、表达式:#{'a':'aa','b':'bb','c':'cc'}用于创建Map集合
<s:iterator value="#{'a':'aa','b':'bb'}">
<!-- 打印a:aa b:bb -->
<s:property value="key"/>:<s:property value="value"/><br/>
</s:iterator>
|
c、in表达式:注意复杂程度
选项有eat,sleep,study,key包含(in表达式)其中的sleep,study。
<!-- EL表达式在Struts2中已经被改写了:原有功能保持不变。只是在四大域范围内找不到的话,EL表达式就变成了OGNL表达式 -->
<s:iterator value="#{'eat':'吃饭','sleep':'睡觉','study':'学习'}">
<input type="checkbox" name="hobby" <s:property value="key in {'java','sleep','study'}?'checked=\"checked\"':''"/> value="${key}"/>${value}
</s:iterator><br/>
|
4.4投影查询:Projecting Across Collections PPT第27页
<!-- 打印fengjie=fengjie -->
${name}=<s:property value="name"/><br/>
<!-- 打印[10, 6, 4, 0] -->
<s:property value="{5,3,2,0}.{#this*2}"/>
<!-- 打印[5, 3, 2] -->
<s:property value="{5,3,2,0}.{?#this*2}"/>
<!-- 打印 [5] -->
<s:property value="{5,3,2,0}.{^#this*2}"/>
<!-- 打印 [2] -->
<s:property value="{5,3,2,0}.{$#this*2}"/><br/>
|
5:类型的转换
<s:property value=”(5).{#this*2}”/>--->[0, 2, 4, 6, 8]
<!-- 打印[0, 2, 4, 6, 8] -->
<s:property value="(5).{#this*2}"/><br/>
|
<s:property value=”#{'name':'wzt','age':30,'gender':'male'}.{#key}”/>发现什么都没有输出
<s:property value="#{'name':'wzt','age':30,'gender':'male'}.{#this}"/>有输出。把Map转为了Value
<!-- 打印 [wzt, 30, male]-->
<s:property value="#{'name':'wzt','age':30,'gender':'male'}.{#this}"/><br/>
<!-- 打印当前日期 -->
<s:property value="new java.util.Date()"/>
|
ONGL国际化
2.1、配置全局的国际消息资源包,并在JSP中进行获取
2.1在类路径或包中建立一个资源包:msg_zh_CN.properties msg_en_US.properties
2.2在struts.xml中配置全局资源包:
<!-- 配置全局国际化消息资源包,value写资源包的基名,多个资源包之间用逗号,分隔-->
<constant name="struts.custom.i18n.resources" value="com.itheima.resources.msg"></constant>
|
2.3在JSP中使用<s:text value=”key”/>的形式进行访问
<s:text name="hello"></s:text><br/> <!-- 下面这个也能访问,是调用根栈中DefaultTextProvider的方法,第一种方法其实就是调用这个方法 -->
<s:property value="getText('hello')"/><br/>
<!-- 没有hello1,则直接打印hello1 -->
<s:text name="hello1"></s:text><br/>
|
3.1、配置动作类的资源消息报,并在JSP中进行获取
动作类名_zh_CN.properties,放在与动作类相同的包中。
注意:如果动作类没有继承ActionSupport,则会从全局资源包中读取消息;如果继承了ActionSupport,则动作消息资源包的优先级要高。
原理就是在根栈中动作类在TextProvider的前面,因此先调用动作类的getText方法,如果动作类没有继承ActionSupport,就没有getText方法了。
4.1、配置包级别的资源消息,并在JSP中进行获取
package_zh_CN.properties package是固定写法
5.1、其他知识因时间关系不在深究,具体参考官方文档:Guides-->Localization的说明
V2.1.8:..\struts-2.1.8.1\docs\docs\localization.html
V2.3.14:..\Users\wzhting\Desktop\struts-2.3.14.2\docs\WW\localization.html
包级别的资源包(在动作类继承actionsupport)
action动作消息资源包优先级最高
package消息资源包级别优先级次之
(package无论在哪里,优先级仍旧是次之)
全局优先级最低
原理:
a先自己的包,再找所有的父类的,一层层往上找
例如如下,就找到Int1的资源包
b找所有的包中,包级别的资源包
c找全局的资源文件
d打印本身(在这个列子里打印Hello1)
动作属性的设置
1、演示给动作类的属性赋值的三种方式(在执行动作的时候,会把当前这个动作类压入栈顶)
2.1在动作类中直接给字段赋初始值,并提供getter和setter方法。
private String name = "fengjie"; |
2.2(静态参数值)在struts.xml
<action name="test1" class="com.itheima.action.HelloAction1" method="test1">
<param name="name">任敏</param><!-- 给动作类属性设置值:setter -->
<result>/1.jsp</result>
</action>
|
2.3(动态参数值)在请求动作时以get方式传递参数name=什么,就显示什么
动作属性的设置,2.1 2.2 2.3 优先级逐步增高,就是说2.3动态参数值优先级最高。
Tips:
静态参数值的获取是由staticParams拦截器实现的。
动态参数值的获取是由params拦截器实现的。
动态参数值优先值最高,因为先进行静态拦截staticParams拦截器实现,再进行动态拦截params拦截器实现,动态拦截把静态覆盖了
中文也支持,因为struts的编码常量设置默认为UTF-8
2、查阅staticParams和params拦截器的源代码帮助理解
用户注册案例
1、先分析页面的请求再下手做。由动作开始。
2、编写配置文件(user.xml,包含到struts.xml中),动作类,JSP页面(使用UI标签)
<!-- 更改strutsUI标签的显示样式模板,参考struts2-core-*.jar中的template -->
<constant name="struts.ui.theme" value="xhtml"></constant>
<package name="p1" namespace="/user" extends="struts-default">
<action name="RegUserUI" class="com.itheima.action.UserAction" method="RegUserUI">
<result type="dispatcher" name="success">/WEB-INF/pages/regist.jsp</result>
</action>
<action name="RegUser" class="com.itheima.action.UserAction" method="RegUser">
<result type="dispatcher" name="success">/WEB-INF/pages/main.jsp</result>
<result type="dispatcher" name="error">/WEB-INF/pages/commons/error.jsp</result>
</action>
</package>
|
写一个User的JavaBean,有username,nick和password三个变量
写动作类UserAction,继承ActionSupport。
public class UserAction extends ActionSupport{
private User user = new User();
public User getUser() {
System.out.println("getUser");
return user;
}
public void setUser(User user) {
System.out.println("setUser");
this.user = user;
}
public String RegUserUI(){
return SUCCESS;
}
public String RegUser(){
try{
System.out.println(user);
//调用service,保存数据
System.out.println("调用后台service,保存数据到数据库中");
return SUCCESS;
}catch(Exception e){
e.printStackTrace();
return ERROR;
}
}
}
|
写一个注册页面regist.jsp(注意name应该为user.nick这个格式)
注意,在第一个form表单中,submit不要加 name=”submit“ 因为动作类里面没有getsubmit,后台会报错.(struts-2.3.15.1已解决这个问题);
使用OGNL表达式后,只需要写action=”RegUser“就可以了。会自动得到访问地址。
此时action里面的RegUser根据struts里的常量值来,例如设置为do,那这个值自动在后面加do
不需要加冒号,会自己加,如果没有label,那么key就会使用国际化的资源包,如果有label,那么就使用label的值
<!--
<form action="${pageContext.request.contextPath}/user/RegUser.action" method="post">
用户名:<input type="text" name="user.username"/><br/>
昵称:<input type="text" name="user.nick"/><br/>
密码:<input type="password" name="user.password"/><br/>
<input type="submit" value="注册"/>
</form>
-->
<s:form action="RegUser" namespace="/user">
<s:textfield key="hello" label="用户名" name="user.username" ></s:textfield>
<s:textfield label="昵称" name="user.nick"></s:textfield>
<s:password label="密码" name="user.password"></s:password>
<s:submit value="注册"></s:submit>
</s:form>
|
建立index.jsp(注意要设置escapeAmp="false",否则&会转义)
要使用s:a不要使用html的<a>好处是:动作的扩展名不定;支持中文参数值URL编码
还有一个s:url是同理的,功能类似JSTL中的c:url
s:param的value属性是一个OGNL表达式,因此字符串直接量要使用value=”'你好'”
注意,这里的地址会被重写,防止用户禁用cookie;
<s:a namespace="/user" action="RegUserUI" escapeAmp="false">注册
<s:param name="p1">p1value</s:param>
<s:param name="p2">你好</s:param>
</s:a><br/>
<s:url action="RegUserUI" namespace="/user" var="url" escapeAmp="false">
<s:param name="p1" >p1value</s:param>
<s:param name="p2">你好</s:param>
</s:url>
<a href="${url}">注册</a>
|
技巧:如果不确定是不是OGNL表达式,那么加上%{abc},那么abc就是一个OGNL表达式而不是字符串了
ModelDriver模型驱动。 其实就是一个拦截器
其实实现了ModelDriven接口的时,会调用getModel()方法,并把该方法返回的对象压入栈顶。是modelDriven拦截器干的。
所以必须先实例化User这个类,否则压入栈顶的时候会空指针,user必须先new出来。可以把User这个类的get和set方法删掉,因为ModelDriver这个类已经把这个实例压入栈顶了。
public class UserAction extends ActionSupport implements ModelDriven<User> {
private User user = new User();
public User getModel() {
return user;
}
private Map<String, String> hobbies = new HashMap<String, String>();
public Map<String, String> getHobbies() {
hobbies.put("eat", "吃饭");
hobbies.put("sleep", "睡觉");
hobbies.put("study", "学java");
return hobbies;
}
public void setHobbies(Map<String, String> hobbies) {
this.hobbies = hobbies;
}
public String RegUserUI() {
return SUCCESS;
}
public String RegUser() {
try {
System.out.println(user);
// 调用service,保存数据
System.out.println("调用后台service,保存数据到数据库中");
return SUCCESS;
} catch (Exception e) {
e.printStackTrace();
return ERROR;
}
}
}
|
写jsp页面(注意用iterator标签和checkboxlist标签都能达到一样的效果)
<s:form action="RegUser" namespace="/user">
<s:textfield key="hello" label="用户名" name="username" ></s:textfield>
<s:textfield label="昵称" name="nick"></s:textfield>
<s:password label="密码" name="password"></s:password>
爱好:
<s:iterator value="hobbies" var="me">
<!-- 如果要把一个字符串当做OGNL表达式对待,请使用%{}包括起来 -->
<s:checkbox name="hobby" fieldValue="%{key}" label="%{value}"></s:checkbox>
</s:iterator>
<hr/>
<s:checkboxlist list="hobbies" name="hobby" listKey="key" listValue="value" label="新爱好"></s:checkboxlist>
<s:radio list="#{'male':'男','female':'女'}" name="gender" label="性别"></s:radio>
<s:submit value="注册"></s:submit>
</s:form>
|
控制逻辑的value,90%都是OGNL表达式。而UI标签里面的东西,90%都不是OGNL表达式。