??xml version="1.0" encoding="utf-8" standalone="yes"?>
OGNLQObject-Graph Navigation LanguageQ,大概可以理解为:(x)对象囑Ş化导航语a。是一U可以方便地操作对象属性的开源表辑ּ语言。OGNL有如下特点:(x)
1、支持对象方法调用,形式如:(x)objName.methodName()Q?br />
2、支持类静态的Ҏ(gu)调用和D问,表达式的格式为@[cd名(包括包\Q]@[Ҏ(gu)?| 值名]Q例如:(x)
@java.lang.String@format('foo %s', 'bar')或@tutorial.MyConstant@APP_NAMEQ?br />
3、支持赋值操作和表达式串联,例如Q?br />
price=100, discount=0.8, calculatePrice()Q这个表辑ּ?x)返?0Q?br />
4、访问OGNL上下文(OGNL contextQ和ActionContextQ?br />
5、操作集合对象?br />
二、用OGNL表达?br />
OGNL要结合struts标签来用。由于比较灵z,也容易把人给弄晕Q尤其是“%”?#8220;#”?#8220;$”q三个符L(fng)使用。由?q泛应用于EL中,q里重点??W号的用法?br />
1?#8220;#”W号有三U用途:(x)
(1)、访问非根对象(struts中值栈为根对象Q如OGNL上下文和Action上下文,#相当于ActionContext.getContext()Q下表有几个ActionContext中有用的属性:(x)
parameters
包含当前HTTPh参数的Map
#parameters.id[0]作用相当于request.getParameter("id")
request
包含当前HttpServletRequest的属性(attribute)的Map
#request.userName相当于request.getAttribute("userName")
session
包含当前HttpSession的属性(attributeQ的Map
#session.userName相当于session.getAttribute("userName")
application
包含当前应用的ServletContext的属性(attributeQ的Map
#application.userName相当于application.getAttribute("userName")
注:(x)attr 用于按request > session > application序讉K其属性(attributeQ,#attr.userName相当于按序在以上三个范_(d)scopeQ内d userName属性,直到扑ֈ为止。用于过滤和投媄(jing)Qprojecting)集合Q如books.{?#this.price<100}Q构?MapQ如#{'foo1':'bar1', 'foo2':'bar2'}?br />
(2)、用于过滤和投媄(jing)Qprojecting)集合Q如: books.{?#this.price>35}
books.{?#this.price>35}
(3)、构造MapQ如: #{'foo1':'bar1', 'foo2':'bar2'}
#{'foo1':'bar1', 'foo2':'bar2'}q种方式常用在给radio或select、checkbox{标{赋g。如果要在页面中取一个map的值可以这样写Q?br />
<s:property value="#myMap['foo1']"/>
<s:property value="#myMap['foo1']"/>
2?#8220;%”W号的用途是在标{属性D理解为字W串cdӞ告诉执行环境%{}里的是OGNL表达式。很有点cMjavascript里面的eval_r()功能Q例如:(x)
var oDiv = eval_r("document.all.div"+index)
var oDiv = eval_r("document.all.div"+index)
当index变量?Ӟ语句׃(x)被当作var oDiv = document.all.div1
var oDiv = document.all.div1来执行?{}是赯个作用。D例:(x)
<s:set name="myMap" value="#{'key1':'value1','key2':'value2'}"/> W??br />
<s:property value="#myMap['key1']"/> W??br />
<s:url value="#myMap['key1']" /> W??br />
<s:set name="myMap" value="#{'key1':'value1','key2':'value2'}"/> W??br />
<s:property value="#myMap['key1']"/> W??br />
<s:url value="#myMap['key1']"/> W??br />
上面的代码第2行会(x)在页面上输出“value1”Q而第3行则?x)输?#myMap['key1']"q么一个字W串。如果将W?行改写成q样Q?br />
<s:url value="%{#myMap['key1']}"/>
<s:url value="%{#myMap['key1']}"/>
则输Zؓ(f)“value1”?br />
q说明struts2里不同的标签对ognl的表辑ּ的理解是不一L(fng)。如果当有的标签“看不?#8221;cM“#myMap['key1']”的语句时Q就要用%{}来把q括q去Q?#8220;译”一下了?br />
3?#8220;$”有两U用?br />
(1)、在国际化资源文件中Q引用OGNL表达式?br />
(2)、在Struts 2配置文g中,引用OGNL表达式:(x)
<action name="saveUser" class="userAction" method="save">
<result type="redirect">listUser.action?msg=${msg}</result>
</action>
<action name="saveUser" class="userAction" method="save">
<result type="redirect">listUser.action?msg=${msg}</result>
</action>
资源文g的命名:(x)basename_language_country.properties
JAVA国际?br />如果pȝ同时存在资源文g、类文gQ系l将以类文gZQ而不?x)调用资源文件?br />对于体中文的LocaleQResourceBundle搜烦(ch)资源的顺序是Q?br />(1)baseName_zh_CN.class
(2)baseName_zh_CN.properties
(3)baseName_zh.class
(4)baseName_zh.properties
(5)baseName.class
(6)baseName.properties
Struts2的国际化入门
Struts2国际化是建立在Java国际化的基础上的Q一h通过提供不同国家/语言环境的消息资源,然后通过ResourceBundle
加蝲指定Locale对应的资源文Ӟ再取得该资源文g中指定key对应的消?-整个q程与JAVAE序的国家化完全相同Q只?br />Struts2框架对JAVAE序国际化进行了q一步封装,从而简化了应用E序的国际化?br />Struts2需要国际化的部?br />cd转换:
数据校验:
验证框架xml配置文g的国际化QRegisterAction-validation.xml文g<message key="username.xml.invalid"/>
JSP面的国际化Q?lt;s:text name="addUser"/>
Action的国际化:利用ActionSupportcL供的getText()Ҏ(gu).
Struts2中加载全局资源文g
struts.xml
<constant name="struts.custom.i18n.resources" value="baseName"/>
?br />struts.properties
struts.custom.i18n.resources=baseName
讉K国际化消?/p>
Struts2讉K国际化消息主要有如下三种方式Q?br />(1)JSP面Q?lt;s:text name="key"/>
(2)ActioncMQ用ActionSupportcȝgetTextҎ(gu)?br />(3)表单元素的Label里:(x)单元素指定一个key属?/p>
输出带占位符的国际化消息
Struts2中提供了如下两种方式来填充消息字W串中的占位W?/p>
(1)JSP面Q在<s:text.../>标签中用多?lt;s:param.../>标签来填充消息中的占位符?br />(2)Action中,在调用getTextҎ(gu)时用getText(String aTextName,List args)或getText(String key, String[] args)Ҏ(gu)来填充占位符?br />除此之外QStruts2q提供了对占位符的一U替代方式,q种方式允许在国际化消息资源文g中用表辑ּQ对于这U方式,则可避免在用国际化消息时还需要ؓ(f)占位W传入参?/p>
倹{?/p>
如下在消息资源中使用表达?br />succTip=${username}, Ƣ迎, (zhn)已l登?
在上面的消息资源中,通过使用表达式,可以从ValueStack中取username属性|自动填充到该消息资源中?/p>
加蝲资源文g的方?br />(1)加蝲全局资源文gQ?<constant name="struts.custom.i18n.resources" value="baseName"/>
(2)包范围资源文?Qؓ(f)Struts2指定包范围资源文件的Ҏ(gu)?在包的根路径下徏立多个文件名为package_language_country.properties的文Ӟ一旦徏立了
q个pd的国际化资源文gQ应用中处于该包下的所有Action都可以访问该资源文g。需要注意的是上面的包范围资源文件的baseName是packageQ不是Action所在的包名?br />(3)Action范围资源文gQ在ActioncL件所在的路径建立多个文g名ؓ(f)ActionName_language_country.properties的文件?br />(4)临时指定资源文gQ?lt;s:i18n.../>标签的name属性指定(f)时的国际化资源文?/p>
加蝲资源文g的顺?br />Action中加载资源文Ӟ假设我们在某个ChildAction中调用了getText("user.title")QStruts 2.0的将?x)执行以下的操作Q?br />(1)优先加蝲pȝ中保存在ChildAction的类文g相同位置Q且baseName为ChildAction的系列资源文件?br />(2)如果?1)中找不到指定key对应的消息,且ChildAction有父cParentActionQ则加蝲pȝ中保存在ParentAction的类文g相同位置Q且
baseName为ParentAction的系列资源文件?br />(3)如果?2)中找不到指定key对应的消息,且ChildAction有实现接口IChildActionQ则加蝲pȝ中保存在IChildAction的类文g相同位置Q且
baseName为IChildAction的系列资源文件?br />(4)如果?3)中找不到指定key对应的消息,且ChildAction有实现接口ModelDriven(即用模型驱动模?Q则对于getModel()Ҏ(gu)q回的model对象Q?br /> 重新执行W?1)步操作?br />(5)如果?4)中找不到指定key对应的消息,则查扑ֽ前包下baseName为package的系列资源文件?br />(6)如果?5)中找不到指定key对应的消息,则沿着当前包上溯,直到最层包来查找baseName为package的系列资源文件?br />(7)如果?6)中找不到指定key对应的消息,则查找struts.custom.i18n.resources帔R指定baseName的系列资源文件?br />(8)如果l过上面的步骤一直找不到key对应的消息,直接输key的字W串倹{?/p>
对于在JSP中访问国际化消息Q则单的多,他们又可以分ZUŞ式:(x)
(1)对于使用<s:i18n.../>标签作ؓ(f)父标{<s:text.../>标签、表单标{形式Q?br /> a、将?lt;s:i18n.../>标签指定的国际化资源文g中加载指定key对应的消息?br /> b、如果在a中找不到指定key对应的消息,则查找struts.custom.i18n.resources帔R指定baseName的系列资源文件?br /> c、如果经q上面步骤一直找不到该key对应的消息,直接输key的字W串倹{?/p>
(2)如果<s:text.../>标签、表单标{没有?lt;s:i18n.../>标签作ؓ(f)父标{:(x)
直接加蝲struts.custom.i18n.resources帔R指定baseName的系列资源文件。如果找不到该key对应的消息,直接输key的字W串倹{?/p>
允许用户自行选择E序语言
Struts2国际化的q行机制
在Struts2中,可以通过ActionContext.getContext().setLocale(Locale arg)讄用户的默认语a?br />Z化设|用户默认语a环境QStruts2提供了一个名为i18n的拦截器(Interceptor),q且其注册在默认的拦截器中(defaultStack)?br /> i18n拦截器在执行ActionҎ(gu)前,自动查找h中一个名为request_locale的参数。如果该参数存在Q拦截器将其作为参敎ͼ转换成Locale对象Q?br />q将其设为用户默认的Locale(代表国家/语言环境)?br /> 除此之外Qi18n拦截器还?x)将上面生成的Locale对象保存在用户Session的名为WW_TRANS_I18N_LOCALE的属性中。一旦用户Session中存在一个名?br />WW_TRANS_I18N_LOCALE的属性,则该属性指定的Locale会(x)作ؓ(f)览者的默认Locale?br /><%@ page language="java" contentType="text/html; charset=GBK"%>
<%@taglib prefix="s" uri="/struts-tags"%>
<script. type="text/javascript">
function langSelecter_onChanged()
{
document.getElementById("langForm").submit();
}
</script>
<%-- 讄SESSION_LOCALE为用户session中的WW_TRANS_I18N_LOCALE属性?--%>
<s:set name="SESSION_LOCALE" value="#session['WW_TRANS_I18N_LOCALE']"/>
<%-- 使用lee.Locales创徏locales实例 --%>
<s:bean id="locales" name="lee.Locales">
<%-- 为locales实例传入current参数|如果SESSION_LOCALE为空Q则q回ValueStack中locale属性?即用h览器讄的Locale) --%>
<s:param name="current" value="#SESSION_LOCALE == null ? locale : #SESSION_LOCALE"/>
</s:bean>
<%-- 让用户选择语言的表?--%>
<form. action="<s:url/>" id="langForm"
style="background-color:#bbbbbb; padding-top: 4px; padding-bottom: 4px;">
<s:text name="languag"/>
<s:select label="Language" list="#locales.locales" listKey="value" listValue="key"
value="#SESSION_LOCALE == null ? locale : #SESSION_LOCALE"
name="request_locale" id="langSelecter"
nchange="langSelecter_onChanged()" theme="simple"/>
</form>
在其他页面中包含该页?
<s:include value="selectlanguage.jsp"/>
在struts.xml文g中增加Action通配W的配置Q?br /><?xml version="1.0" encoding="GBK"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.custom.i18n.resources" value="messageResource"/>
<constant name="struts.i18n.encoding" value="GBK"/>
<package name="lee" extends="struts-default">
<!-- 使用通配W定义Action的name -->
<action name="*">
<!-- 请求{发给/WEB-INF/jsp/路径下同名的JSP面 -->
<result>/WEB-INF/jsp/{1}.jsp</result>
</action>
</package>
</struts>
版本Qstruts2.1.6
此实例实现功能:(x)用户需要指定用户名登陆Q登陆成功进入相应页面执行操作,否则q回到登陆页面进行登陆,当直接访问操作页面(登陆后才能访问的面Q时则不允许Q须q回登陆面?/p>
代码如下Q?/p>
一、页?/p>
login.jsp
welcome.jsp
show.jsp
二、Action
LoginFormAction
LoginAction
ShowAction
三、拦截器
?struts.xml
Struts的配|文Ӟ(x)
input.jsp
当提交input.jsp 的时?Validate (g)查没有通过Q这时我需要回到input.jspQ此时应该下拉列表框的CreditType应该被保?只需要在example.CreditCardAction 实现 Preparable接口Qƈ实现prepare Ҏ(gu)Q然后在add?action中加?/span>
q样Q在验证前将首先调用 prepareҎ(gu)Q即使失败了回到input.jsp面creditCardType选择框的g然存在?/p>
<interceptor-ref name="defaultStack"/> 中的 defaultStack 是我们在struts.xml 中配|的Q其中我们注释掉?<interceptor-ref name="prepare"/> q样在example.CreditCardAction中的其他Action׃?x)首先执行prepareҎ(gu)Q只有加上了 <interceptor-ref name="prepare"/> 的才?x)去首先执?prepareҎ(gu)?/span>
首先Q我们需要了解Struts2是将Action中的属性全部封装在一个叫做struts.valueStack的请求属性中Q然后我们就可以通过下面的代码来获取q些gQ?/p>
someThing是Action中属性值的名称?/span>
Struts2的属性驱动指的是在action中JSP面的每一个form中的name都对应在action中有一个属性与之对应。看下面代码片段:
<form action="register.do" name="RegisterForm" method="post">
Username:<input type="text" name="uname"><br>
Password:<input type="password" name="upass"><br>
Confirm: <input type="password" name="rpass"><br>
<input type="submit" value="Submit">
</form>
q是一个最基本的用h册的表单,它有三个数据要提? uname、upass、rpassQ那么对应的Action也要有三个属性(其实是三个属性的setterQ,看register.do实际的Action定义c:(x)
package org.abu.csdn.action.user;
import com.opensymphony.xwork2.ActionSupport;
/**
* Struts2属性驱动演C用的Action
* @author 阿布
*
*/
public class RegisterAction extends ActionSupport {
private String uname;
private String upass;
private String rpass;
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getUpass() {
return upass;
}
public void setUpass(String upass) {
this.upass = upass;
}
public String getRpass() {
return rpass;
}
public void setRpass(String rpass) {
this.rpass = rpass;
}
@Override
public String execute() throws Exception {
return ActionSupport.SUCCESS;
}
}
你会(x)看到RegisterAction中的三个属性和RegisterForm表单中的name属性名字一模一P没错Q这是Struts2的属性驱动,当表单提交到RegisterAction后,Struts2会(x)自动根据表单的name属性调用Action中相应的属性setterQ去自动赋倹{?
2.Struts2的模型驱?
Struts2的模型驱动其实和Struts1.x中的ActionForm有点cMQ在Struts1.x中每一个Action都必L一个ActionForm与之对应Q而Struts2.0中,每一个Action同样需要提供一个POJO对象Q用来封装表单属性,看代码:(x)
<form action="register.do" name="RegisterForm" method="post">
Username:<input type="text" name="uname"><br>
Password:<input type="password" name="upass"><br>
Confirm: <input type="password" name="rpass"><br>
<input type="submit" value="Submit">
</form>
q段表单的代码和上面的一模一P׃赘述了。接下来看POJO的代码,其实是普通的Java BeanQ?
package org.abu.csdn.action.user;
import com.opensymphony.xwork2.ActionSupport;
/**
* Struts2属性驱动演C用的Java Bean
* @author 阿布
*
*/
public class User {
private String uname;
private String upass;
private String rpass;
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getUpass() {
return upass;
}
public void setUpass(String upass) {
this.upass = upass;
}
public String getRpass() {
return rpass;
}
public void setRpass(String rpass) {
this.rpass = rpass;
}
}
对不P也是和属性驱动中的例子一P很简单,因ؓ(f)演示的都是同一个例子,只是Ҏ(gu)不同而已Q但是接下来׃一样了Q看RegisterAction代码Q?
package org.abu.csdn.action.user;
import org.abu.csdn.dto.User;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
/**
* Struts2模型驱动演示用的Action
*
* @author 阿布
*
*/
public class RegisterAction extends ActionSupport implements ModelDriven<User> {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String execute() throws Exception {
return ActionSupport.SUCCESS;
}
// 模型驱动必须实现的方法,也是ModelDriven接口中唯一的方?
public User getModel() {
return user;
}
}
看到没有Q和属性驱动的Action有很大的区别Q下面一一列DQ?
Q?Q模型驱动的Action必须实现ModelDriven接口Q而且要提供相应的泛型Q这里当然就是具体用的Java Bean了?
Q?Q实现ModelDriven的getModelҎ(gu)Q其实就是简单的q回泛型的一个对象?
Q?Q在Action提供一个泛型的U有对象Q这里就是定义一个User的user对象Qƈ提供相应的getter与setter?
好了Q上面的三g事做完之后,Action׃(x)去自动调用User的setter表单中的name属性的DlUser中的属性。而Action的后l处理的Jsp面后者是Servlet可以用user对象了?
3.到底是用属性驱动和是模型驱动呢Q?
q个问题困扰了很多Struts2的初学者,我这里提供一些徏议:(x)
Q?Q请你统一整个pȝ中的Action使用的驱动模型,卌么都是用属性驱动,要么都是用模型驱动?
Q?Q如果你的DB中的持久层的对象与表单中的属性都是一一对应的话Q那么就使用模型驱动吧,毕竟看v来代码要整洁得多?
Q?Q如果表单的属性不是一一对应的话Q那么就应该使用属性驱动,否则Q你的系l就必须提供两个BeanQ一个对应表单提交的数据Q另一个用与持久层?
看上面的例子Q其实密码确认rpass是不需要放到DB中去的,而仅仅是用于校验密码的,不是吗?那么如果使用模型驱动的话Q就存在q个问题了,而用属性驱动的话又有些J琐Q现在我们就来调整一个看我的解决Ҏ(gu)Q?
4.完整的例?
Q?Q表单提交的JSP面index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<base href="<%=basePath%>">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>CSDN首页</title>
</head>
<body>
<s:a href="userManager/userRegister.jsp">用户注册</s:a>
<form action="register.do" name="SampleForm" method="post">
Username:<input type="text" name="uname"><br>
Password:<input type="password" name="upass"><br>
Confirm: <input type="password" name="rpass"><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
(2)User的定?
package org.abu.csdn.action.user;
import com.opensymphony.xwork2.ActionSupport;
/**
* Struts2属性驱动演C用的Java Bean
* @author 阿布
*
*/
public class User {
private String uname;
private String upass;
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getUpass() {
return upass;
}
public void setUpass(String upass) {
this.upass = upass;
}
}
Q?QRegisterAction的定?
package org.abu.csdn.action.user;
import com.opensymphony.xwork2.ActionSupport;
/**
* Struts2属性驱动演C用的Action
* @author 阿布
*
*/
public class RegisterAction extends ActionSupport {
// 用来lspring注入Q及(qing)属性拷?
private User user;
private String uname;
private String upass;
private String rpass;
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getUpass() {
return upass;
}
public void setUpass(String upass) {
this.upass = upass;
}
public String getRpass() {
return rpass;
}
public void setRpass(String rpass) {
this.rpass = rpass;
}
@Override
public String execute() throws Exception {
// 调用Ҏ(gu)属性copy到user中去Q便于后l的serviceҎ(gu)
copyAttribute();
// TODOQ编写自quser业务代码
return ActionSupport.SUCCESS;
}
/**
* 注意q是一个action全局的校?br />
*/
@Override
public void validate() {
// q行密码的校?
if (!(upass.trim()).equals((rpass.trim()))) {
// 注意q里addFieldError的fieldName参数必须用引号引h,
// 不能q样使用addFieldError(rpass,"XXXXXX"),而必LaddFieldError("rpass","XXXXX")
this.addFieldError("rpass", this
.getText("csdn.action.user.register.validate.verify"));
}
}
/**
* 表单属性中需要持久化的属性拷贝到user中去
* @author 阿布
*
*/
private void copyAttributes () {
user.setUname(uname);
user.setUpass(upass);
}
}
Q?QStruts.xml配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
"http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<package name="root" extends="struts-default" namespace="/userManager">
<action name="userRegister" class="org.abu.csdn.action.user.RegisterAction">
<result name="success">/index.jsp</result>
<result name="input">/userManager/userRegister.jsp</result>
</action>
</package>
</struts>
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/csuliky/archive/2009/05/30/4226917.aspx