读书人

struts2框架自带项目struts2-mailread

发布时间: 2012-11-21 08:23:25 作者: rapoo

struts2框架自带项目struts2-mailreader学习笔记
struts2框架自带项目struts2-mailreader学习笔记


我们依照使用该项目的步骤来说。
第一、一个网页请求转到welcome.do的网页,我们去查看web.xml中的配置,发现要调用StrutsPrepareAndExecuteFilte这个过滤器。而这个过滤器是干什么用的呢?
查看源代码我们发现:
1.StrutsPrepareAndExecuteFilte 实现了Filter接口。
服务器启动调用StrutsPrepareAndExecuteFilter .init()初始化来初始化几个重要的类,比如Dispatcher,FilterHostConfig。
2.当前台有请求发来,StrutsPrepareAndExecuteFilter 的doFilter()被调用,这个doFilter实现了封装request,查找 ActionMapper,以确定这个请求是否需要调用某个 Action。
那么,为什么使用StrutsPrepareAndExecuteFilter而不是用FilterDispatcher呢?可参见http://wellfrog.iteye.com/blog/773482
在这里,还要注意,项目源码为:

execute.executeAction(request, response, mapping);

而这个execute是ExecuteOperations的一个实例,这个execute调用的这个方法executeAction实际上是通过调用Dispatcher类的serviceAction方法来实现的:
public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {        dispatcher.serviceAction(request, response, servletContext, mapping);    }

再查看Dispatcher的源码,发现
:Configuration config = configurationManager.getConfiguration();            ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(                    namespace, name, method, extraContext, true, false);            request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());            // if the ActionMapping says to go straight to a result, do it!            if (mapping.getResult() != null) {                Result result = mapping.getResult();                result.execute(proxy.getInvocation());            } else {                proxy.execute();            }

这也就验证了struts2工作流程中的把控制权交给 ActionProxy,然后ActionProxy 依照框架的配置文件(struts.xml),找到需要调用的 Action 类。即
<action name="Welcome" name="code"><include file="mailreader-default.xml"/><include file="mailreader-support.xml"/>

<action name="Welcome" name="code"><interceptor-stack name="guest" >                <interceptor-ref name="defaultStack"/>            </interceptor-stack>
代表这个guest拦截器是一个拦截器栈,使用的是defaultStack这个拦截器栈,在struts2-core-xxx.jar包下找到struts-default.xml,再在其中找到如下代码:
<interceptor-stack name="defaultStack">                <interceptor-ref name="exception"/>                <interceptor-ref name="alias"/>                <interceptor-ref name="servletConfig"/>                <interceptor-ref name="i18n"/>                <interceptor-ref name="prepare"/>                <interceptor-ref name="chain"/>                <interceptor-ref name="scopedModelDriven"/>                <interceptor-ref name="modelDriven"/>                <interceptor-ref name="fileUpload"/>                <interceptor-ref name="checkbox"/>                <interceptor-ref name="multiselect"/>                <interceptor-ref name="staticParams"/>                <interceptor-ref name="actionMappingParams"/>                <interceptor-ref name="params">                    <param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</param>                </interceptor-ref>                <interceptor-ref name="conversionError"/>                <interceptor-ref name="validation">                    <param name="excludeMethods">input,back,cancel,browse</param>                </interceptor-ref>                <interceptor-ref name="workflow">                    <param name="excludeMethods">input,back,cancel,browse</param>                </interceptor-ref>                <interceptor-ref name="debugging"/>            </interceptor-stack>            <!-- The completeStack is here for backwards compatibility for                 applications that still refer to the defaultStack by the                 old name -->            <interceptor-stack name="completeStack">                <interceptor-ref name="defaultStack"/>            </interceptor-stack>

各拦截器的作用详见http://blog.csdn.net/jadyer/article/details/5887529

第三、我们查看返回的页面Welcome.jsp。1.如下国际化代码需要注意:
<s:url id="en" action="Welcome">            <s:param name="request_locale">en</s:param>        </s:url><s:a href="%{en}">English</s:a>

查看struts2参考手册的关于Generic Tags的内容,我们发现struts2的url标签的用法是这样的:http://localhost:8080/MyStrutsTest3/Welcome.do?request_locale=en这里就要说下国际化的实现过程:该国际化是通过Struts2的I18nInterceptor拦截器会拦截所有的Action而实现的,它主要做的事情为:1.从客户端发送过来的请求参数中寻找是否存在名为request_locale的参数。2.若有,则将request_locale的value转化为locale保存起来
该locale是保存在以WW_TRANS_I18N_LOCALE所命名的session里面的。查看拦截器源码,发现:session.put(attributeName, locale)其中attributeName即为protected String attributeName = DEFAULT_SESSION_ATTRIBUTE
和public static final String DEFAULT_SESSION_ATTRIBUTE = "WW_TRANS_I18N_LOCALE"
于是便可通过这种方式实现一个选择页面所显示的语言环境的功能。
而这个
<s:url id="en" action="Welcome">
的id,现在应该使用var属性取代,它的作用是:<s:text name="index.title"/>
查看参考手册得知:
如果还找不到,则在值栈中搜索,参考http://txyly998.iteye.com/blog/336357
所以我们这里是查找相应的父类MailReaderSupport的资源文件MailReaderSupport.properties.
3.我们再看如下代码
<li><a href="<s:url action="Registration_input"/>"><s:text            name="index.registration"/></a></li>

这里就要注意我们上面提到的url的用法,即<action name="Registration_*" method="{1}" name="code"><s:if test="task=='Create'"> <title><s:text name="registration.title.create"/></title> </s:if> <s:if test="task=='Edit'"> <title><s:text name="registration.title.edit"/></title> </s:if>
这里的<s:if test="">是struts2的控制标签,其中的task为Registration这个Action的属性。这里是使用OGNL表达式从值栈中取出的。这个Task属性的值如果是Create就代表在session中没有这个用户名,所以就在该注册页面中显示注册信息,而不显示注册以后显示的信息,而这个注册以后的信息是否显示则是通过判断task是否为Edit来得到。
再往下看,
<s:actionerror/><s:form action="Registration_save" validate="false">    <s:token />    <s:hidden name="task"/>    <s:if test="task == 'Create'">        <s:textfield key="username"/>    </s:if>    <s:else>        <s:label key="username"/>        <s:hidden name="username"/>    </s:else>    <s:password key="password" showPassword="true"/>    <s:password key="password2"/>    <s:textfield key="user.fullName"/>    <s:textfield key="user.fromAddress"/>    <s:textfield key="user.replyToAddress"/>    <s:if test="task == 'Create'">        <s:submit key="button.save" action="Registration_save"/>        <s:reset key="button.reset"/>        <s:submit action="Welcome" key="button.cancel"                    onclick="form.onsubmit=null"/>    </s:if>    <s:else>        <s:submit key="button.save" action="Registration"/>        <s:reset key="button.reset"/>        <s:submit action="MainMenu" key="button.cancel"                    onclick="form.onsubmit=null"/>    </s:else></s:form>

<s:form>是表单用法,<s:token/>用法如下
此外,这些标签的name属性代表这些元素的名称,而key属性则用于访问国际化文件内容,
这里我们要介绍下几种调用国际化资源的方式:
1、jsp页面的国际化,a.使用标签
<s:text name ="资源文件中中定义的key">
输出国际化b.使用struts2标签的key属性,此时一定要注意theme不能设置为simple,否则不能成功引用国家化文件,如<s:textfield name =“name”key ="资源化文件中的key">。c.使用<s:i18n></s:i18n>在对应资源文件中查找如
<s:i18n name = "globalMessages">                                 <s:text name ="username"></s:text>                              </s:i18n>

2、getText(String key)可在所有需要使用的地方使用,如a.
<s:textfield label ="%{getText("username")}" name = "username">
其中%{}是取出值栈中的Action对象 然后我们直接调用它的相应方法取出这个username属性。或者说我们对这个值栈中的action对象我们调用它相应的方法。
b.action中的validate方法中增加错误信息的国际化
this.addFieldError(username,this.getText("username.invalid"));this.addActionError(this.getText("username.invalid"));

c.xml验证框架中的错误信息国际化
<message key = "name.invalid"></message>
或<message>${getText("name.invalid")}</message>
而<s:hidden>是addActionError(getText("error.username.unique"));这个代码意思是出错后就在相应jsp页面的<s:actionerror>中显示信息,而这个信息通过getText这个方法从国际化文件中得到。

第五、我们回到welcome.jsp,看他的第二个链接
<action name="Login_*" method="{1}" type="redirectAction">Welcome</result> <result type="redirectAction">MainMenu</result> <result name="expired" type="chain">ChangePassword</result> <exception-mapping exception="org.apache.struts.apps.mailreader.dao.ExpiredPasswordException" result="expired"/> <interceptor-ref name="guest"/> </action>
这里虽然Login没有定义input方法,但是他的父类ActionSupport定义了input方法,它直接返回input字符串。这个结果集就要我们返回login.jsp页面。再来看这个Login.jsp页面。它的action就为Login,那么我们对于这个action映射可以看到它的method实际上应该调用的是LoginAction的execute(),我们可以理解其为:不写method,其默认值就是execute()。完成相应的execute()中的操作后,其返回SUCCESS,这个对应的result为MainMenu,因为
<result type="redirectAction">MainMenu</result>
默认的name为SUCCESS。得到这个主页面,然后也有两个链接,
1.一个是编辑自己的信息,这个返回到刚刚我们提到的Registration页面,和上面的不同在于,由于
<s:if test ="task=='Edit'">
这里就显示相应的编辑信息。
2.另一个就是注销当前用户,返回到welcome.jsp。由于代码差不多,这里就不在赘述了。
第六、我们看客户端的校验框架,
<validators>    <field name="username">        <field-validator type="requiredstring">            <message key="error.username.required"/>        </field-validator>    </field>    <field name="user.fullName">        <field-validator type="requiredstring">            <message key="error.fullName.required"/>        </field-validator>    </field>    <field name="user.fromAddress">        <field-validator type="requiredstring">            <message key="error.fromAddress.required"/>        </field-validator>        <field-validator type="email">            <message key="errors.email"/>        </field-validator>    </field>    <field name="user.replyToAddress">        <field-validator type="email">            <message key="errors.email"/>        </field-validator>    </field></validators>
如果我们要使用上述客户端校验框架,我们必须在所检验的字段的这个页面的form标签中将<s:form validate="true">的validate属性设置为TRUE,并且不能将<s:form theme="">的theme属性设置为simple,我的理解是,我们使用simple主题,排版中就不会有错误信息显示的地方了。设置<s:form validate = "true">属性之后,表单的onsubmit="return validateForm_register();"即在源码中多出了一段函数名为validateForm_register()的JavaScript代码,调用完成后再提交到相关页面。

这里还要注意一点,被校验的Action类要继承ActionSupport类,并要在action配置中指定名为input的jsp,因为struts2在校验失败后会自动返回input页面

具体的项目文件见附件,也可去官网下载。

读书人网 >网络基础

热点推荐