<!-- /* Font Definitions */ @font-face {font-family:Wingdings; panose-1:5 0 0 0 0 0 0 0 0 0; mso-font-charset:2; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:0 268435456 0 0 -2147483648 0;} @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"/@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:宋体; mso-font-kerning:1.0pt;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:595.3pt 841.9pt; margin:72.0pt 89.85pt 72.0pt 89.85pt; mso-header-margin:42.55pt; mso-footer-margin:49.6pt; mso-paper-source:0; layout-grid:15.6pt;} div.Section1 {page:Section1;} /* List Definitions */ @list l0 {mso-list-id:2041084062; mso-list-type:hybrid; mso-list-template-ids:835123252 -575355162 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;} @list l0:level1 {mso-level-tab-stop:18.0pt; mso-level-number-position:left; margin-left:18.0pt; text-indent:-18.0pt;} @list l0:level2 {mso-level-legal-format:yes; mso-level-text:"%1/.%2"; mso-level-tab-stop:19.5pt; mso-level-number-position:left; margin-left:19.5pt; text-indent:-19.5pt;} @list l0:level3 {mso-level-legal-format:yes; mso-level-text:"%1/.%2/.%3"; mso-level-tab-stop:36.0pt; mso-level-number-position:left; margin-left:36.0pt; text-indent:-36.0pt;} @list l0:level4 {mso-level-legal-format:yes; mso-level-text:"%1/.%2/.%3/.%4"; mso-level-tab-stop:36.0pt; mso-level-number-position:left; margin-left:36.0pt; text-indent:-36.0pt;} @list l0:level5 {mso-level-legal-format:yes; mso-level-text:"%1/.%2/.%3/.%4/.%5"; mso-level-tab-stop:54.0pt; mso-level-number-position:left; margin-left:54.0pt; text-indent:-54.0pt;} @list l0:level6 {mso-level-legal-format:yes; mso-level-text:"%1/.%2/.%3/.%4/.%5/.%6"; mso-level-tab-stop:54.0pt; mso-level-number-position:left; margin-left:54.0pt; text-indent:-54.0pt;} @list l0:level7 {mso-level-legal-format:yes; mso-level-text:"%1/.%2/.%3/.%4/.%5/.%6/.%7"; mso-level-tab-stop:54.0pt; mso-level-number-position:left; margin-left:54.0pt; text-indent:-54.0pt;} @list l0:level8 {mso-level-legal-format:yes; mso-level-text:"%1/.%2/.%3/.%4/.%5/.%6/.%7/.%8"; mso-level-tab-stop:72.0pt; mso-level-number-position:left; margin-left:72.0pt; text-indent:-72.0pt;} @list l0:level9 {mso-level-legal-format:yes; mso-level-text:"%1/.%2/.%3/.%4/.%5/.%6/.%7/.%8/.%9"; mso-level-tab-stop:72.0pt; mso-level-number-position:left; margin-left:72.0pt; text-indent:-72.0pt;} ol {margin-bottom:0cm;} ul {margin-bottom:0cm;} -->
Struts2总结
总体流程:-------------
容器加载web.xml,struts2.xml--->HttpServletRequest--->(ActionContextCleanUp)--->
FilterDispatcher--->ActionMapper-->是否有对应的Action--->有则把请求的处理交给ActionProxy--->通过Configuration Manager询问框架的配置文件,找到需要调用的Action类,创建一个ActionInvocation的实例。--->ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用。-->Action处理分完后,返回一个result-->根据struts.xml中的配置找到对应的返回结果。
Action处理的流程:-----------------
经过defalutStack拦截器,再经过一些自定义的拦截器。(先后顺序得看在struts.xml中的配置的先后)--->进行类型转换--->调用属性的对应的setter方法-->类型不匹配就会报错,终止执行(如果有相应出错的页面就跳转到该页面)---->匹配后,进行相应的属性校验(如果有)--->不成功终止执行(如果有相应出错的页面就跳转到该页面)--->进行相应的方法调用---> Action处理分完后,返回一个result-->经过defalutStack拦截器,再经过一些自定义的拦截器-->根据struts.xml中的配置找到对应的返回结果。--->根据相应的properties文件读取国际化信息(如果有)。
------------------------------------------以下为北大的PPT上的内容----------------------------------------
类型转换---------------------
实现TypeCoverter接口,或者继承DefaultTypeConverter实现类(该类实现了TypeCoverter接口),通过继承该实现类来实现自己的类型转换器。重写convertValue方法即可。
为了简化类型转换器的实现,Struts2提供了一个StrutsTypeConverter抽象类,这个抽象类是DefaultConverter的子类。实现了方法,并提供了2个不同转换方向的方法:Object
convertToString(Map context,String[] values,Class toClass)和String convertFromString(Map context,Object o)。
实现了自定义类型转换器之后,将该类型转换器注册在Web应用中,Struts2框架才可以正常使用该类型转换器
1、局部类型转换器
文件名: ActionName-conversion.properties
内容:多个propertyName(属性名)=类型转换器类(含包名),如 date=com.aumy.DateConverter
存放位置:和ActionName类相同路径。
2、全局类型转换器
文件名: xwork-conversion.properties
内容: 多个“复合类型=对应类型转换器”项组成,如 java.Util.Date=com.aumy.DateConverter
存放位置:src目录下。
国际化--------------------
Properties文件查找顺序
假设我们在某个ChildAction中调用了getText("user.title"),Struts 2.0的将会执行以下的操作:
查找ChildAction_xx_XX.properties文件或ChildAction.properties;
查找ChildAction实现的接口,查找与接口同名的资源文件MyInterface.properties;
查找ChildAction的父类ParentAction的properties文件,文件名为ParentAction.properties;
判断当前ChildAction是否实现接口ModelDriven。如果是,调用getModel()获得对象,查找与其同名的资源文件;
查找当前包下的package.properties文件;
查找当前包的父包,直到最顶层包;
在值栈(Value Stack)中,查找名为user的属性,转到user类型同名的资源文件,查找键为title的资源;
查找在struts.properties配置的默认的资源文件
输出user.title。
快捷地选择或切换语言----------------------------
开发国际化的应用程序时,有一个功能是必不可少的——让用户快捷地选择或切换语言。在Struts 2.0中,通过ActionContext.getContext().setLocale(Locale arg)可以设置用户的默认语言。不过,由于这是一个比较普遍的应用场景(Scenario),所以Struts 2.0为您提供了一个名i18n的拦截器(Interceptor),并在默认情况下将其注册到拦截器链(Interceptor chain)中。它的原理为在执行Action方法前,i18n拦截器查找请求中的一个名为"request_locale"的参数。如果其存在,拦截器就将其作为参数实例化Locale对象,并将其设为用户默认的区域(Locale),最后,将此Locale对象保存在session的名为“WW_TRANS_I18N_LOCALE”的属性中。
下面,我将提供一完整示例演示它的使用方法。
package tutorial;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Map;
publicclass Locales {
public Map<String, Locale> getLocales() {
Map<String, Locale> locales =new Hashtable<String, Locale>(2);
locales.put("American English", Locale.US);
locales.put("Simplified Chinese", Locale.CHINA);
return locales;
}
}
<%@taglib prefix="s" uri="/struts-tags"%>
<script type="text/javascript">
<!--
function langSelecter_onChanged() {
document.langForm.submit();
}
//-->
</script>
<s:set name="SESSION_LOCALE" value="#session['WW_TRANS_I18N_LOCALE']"/>
<s:bean id="locales" name="tutorial.Locales"/>
<form action="<s:url includeParams="get" encode="true"/>" name="langForm"
style="background-color: powderblue; padding-top: 4px; padding-bottom: 4px;">
Language: <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>
上述代码的原理为,LangSelector.jsp先实例化一个Locales对象,并把对象的Map类型的属性locales赋予下拉列表(select) 。如此一来,下拉列表就获得可用语言的列表。大家看到LangSelector有<s:form>标志和一段Javascript脚本,它们的作用就是在用户在下拉列表中选择了后,提交包含“reqeust_locale”变量的表单到Action。在打开页面时,为了下拉列表的选中的当前区域,我们需要到session取得当前区域(键为“WW_TRANS_I18N_LOCALE”的属性),而该属性在没有设置语言前是为空的,所以通过值栈中locale属性来取得当前区域(用户浏览器所设置的语言)。
你可以把LangSelector.jsp作为一个控件使用,方法是在JSP页面中把它包含进来,代码如下所示: <s:include value="/LangSelector.jsp"/>
在例1中的HellloWorld.jsp中<body>后加入上述代码,并在struts.xml中新建Action,代码如下:
<action name="HelloWorld">
<result>/HelloWorld.jsp</result>
</action>
数据校验-------------------------------
1. 自定义校验:
1.1 validate()方法校验,这个方法是会校验action中所有请求方法(当然不包括getter/setter方法)。它是在具体的validateXxx()方法这后执行。
1.2 validateXxx()方法就是对Xxx()方法进行校验。
2. 校验框架
校验框架是通过validation拦截器实现,该拦载被注册到默认的拦截器链中。它在conversionError拦截器之后,在validateXxx()之前被调用。这里又出现了一个选择的问题:到底是应该在action中通过validateXxx()或validate()实现校验,还是使用validation拦截器?绝大多数情况,我建议大家使用校验框架,只有当框架满足不了您的要求才自已编写代码实现。
Invalid field value for field的错误信息被定义在默认的
xwork.jar 的包里 com.opensymphony.xwork2.xwork-messages.properties文件中
-----国际化的资源文件相同
自定义类型转换错误信息分为两种(这里的定义其实就是在定义国际化的资源文件properties)
1)全局性
struts.custom.i18n.resources=globalMessages
xwork.default.invalid.fieldvalue= "{0}" 为无效的数据.
2)局部性
局部性错误校验的优先级高于全局性错误验证的优先级
与要进行验证的类位于相同目录下,类名_zh_CN.properties
invalid.fieldvalue.age=年龄为无效的数据!
说明:age为要进行校验的字段