1月21日——培训第51天

小总结:
Struts特点:
1、实现MVC模式的WEB服务器端应用的框架,最主要的是控制器Controller
2、总控制器是ActionServlet,请求控制器Action是介于请求和相应逻辑之间的适配器。
3、Struts是完全地址驱动的框架,login.do-->.do决定了到ActionServlet,而login则决定了到哪一个Action,
   ActionServlet只有一个,而Action有多个。
4、<html:form>和ActionForm之间的关系。Action在整个应用中只会创建唯一的一个实例,会被存储在Map中去,所以
   Action要保证是线程安全的。假如Action有一个属性是count,int类型,假如在execute方法里面让count++的话,
   由于每个人来访问的时候都要执行这个count++,假如两个人同时访问的话,如果不设置同步的话就会少计数一次!
   而且Action中不能存储特定于某个用户的信息。ActionServlet在整个Struts中只有一个。ActionServlet最主要的
   作用是去读取配置文件!

   如果总控制器的<load-on-startup>0</load-on-startup>元素没有配置的话,进入<html:form>标签就会出问题。
   因为这个自定义标签会根据action属性去根据配置文件去找action-mapping,由此去找和他绑定的ActionForm,但是
   由于ActionServlet没有加载进来,就出问题了,因为并没有访问.do地址,所以ActionServlet不会加载进来。

   ActionServlet在整个应用中只有一个实例,要求服务启动的时候就加载进来,如果不加载的话第一次访问的时候会根据用户
   访问的内容是否设计ActionServlet而可能出现异常。Action转向的时候可以用重定向也可以使用请求转发,如果要使用
   重定向的话,在配置文件的forward元素中设置redirect属性为true就可以了。

   页面上只要有一个<html:form>就必须给它指定一个继承自ActionForm的javaBean,而且<html:form action="/loginUrl">
   中的action里面必须以/开头并且不加.do,而且这个自定义标签表单只能提交到ActionServlet,不可以提交到一般的Servlet
   或是其他的什么地方,否则这个自定义标签表单无法和具体的formbean关联!(一定要配置name属性,否则无法关联!)

   在进入有自定义标签表单的jsp页面的时候,首先根据action属性找formbean,找到以后,会去指定作用域里面去根据attribute或是
   name去找formbean,如果找到了的话,用bean里面的同名属性给底下的表单元素赋值(表单元素也是用Struts自定义标签写的)。
   但是当提交的时候,先要调用reset方法,因为属性和提交过来的参数的个数未必完全一样,所以先要使用reset方法把所有以前的值全部
   恢复成为原来的默认值,然后用同名的参数设置formbean中的同名的属性(其实就是用了beanUtil包的populate方法,就像论坛项目里
   面的做法一样),然后把这个javaBean封装好后再传给Action,然后返回。

   既然formbean是存储在作用域中,那么完全可以在页面中使用表达式语言取出它来。

================================================================================================================
Struts中的国际化:

简单回忆一下国际化:根据操作系统的不同设置显示不同的文本。

可以使用ListResourceBundle或是jstl标签
创建Struts的时候MyEclipse会自动给我们创建一个名为ApplicationResources.properties的属性文件。
而且配置文件里面还有一个叫做 <message-resources parameter="com.yuanbin.struts.ApplicationResources" />
的东西。

在上面那个属性文件中加入:
username=User Name
password=Passowrd
index.welcome=Please login First

再建立一个ApplicationResources_zh.properties:(注意这个属性文件的编码必须设置为GBK!!在属性中设置)
username=用户名
password=密码
index.welcome=请先登录

还要首先进行转码!在命令行中:
先转到对应的路径中,然后:
执行:native2ascii ApplicationResources_zh.properties t
这样就生成了一个t文件,将t文件命名成刚才的ApplicationResources_zh.properties
就可以了。

页面上用的时候呢,首先:
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%>

下面三行代码就可以根据具体操作系统的本地化信息显示对应的中文或是英文信息了。
<bean:message key="username" />

<bean:message key="password" />

<bean:message key="index.welcome" />

其实配置文件中已经加载进了资源包,<bean>标签默认使用的是请求里面得到的Locale对象,其实就是先找到配置文件中的
资源包,再从请求中找locale对象,然后找key就可以了。

==============================================================================================

资源包其实是可以有多个的。
也就是可以有多个<message-resources>标签。
我可以再写一个:
<message-resources parameter="com.yuanbin.struts.aa" />
这时候我还要在资源包中加入一个aa.properties文件
如果aa.properties中也设置了用户名、密码等信息,就会看到其实页面中使用的是新加进来的这个aa.properties

其实从源代码中可以看到initModuleMessageResources方法,访问权限是protected类型,可以看一下这个方法,
其实是把资源包以一个属性的形式存储在应用程序的作用域里面了。
其实<message-resources>通过查看dtd文档可以看到里面的key属性就是作用域中存储的属性名,如果你不指定的话,
默认就会在org.apache.struts.Globals类中定义的静态字符串常量MESSAGES_KEY命名存储在应用程序作用域中,
可以通过
<%
 org.apache.struts.util.MessageResources mr =
  (MessageResources)application.getAttribute(Globals.MESSAGES_KEY) ;
 if(mr!=null)
 {
  System.out.println(mr.getMessage("index.welcome!!"));
 }
%>
因为两个资源包都会存储在同一个作用域里面的同一个属性上面,所以如果你不指定key的话,后面的必然覆盖前面的!

<message-resources key="first" parameter="com.yuanbin.struts.ApplicationResources" />
<message-resources key="second" parameter="com.yuanbin.struts.aa" />

但是这样一来,<bean:message key="username" />是去找哪个资源包呢??由于没有指明,肯定是去找
默认的包,但是由于上面两个都用key给指明了,所以默认的包就没有了,所以:

<bean:message bundle="first" key="username" />
就可以了,用bundle来指明访问哪个key指明的资源包。

由于涉及forbean、国际化等多种配置信息的读取,所以启动的时候一定最好把ActionServlet给加载进来,不然
很麻烦。整个过程:先根据key将实例化的资源包(用parameter指定)存入应用程序作用域里面,然后再根据
页面中的<message-resources>中的bundle属性来找是哪一个key指明的资源包!key表明了是将资源包存储在哪个
属性里面……

==============================================================================================

Struts的错误处理:

客户端的校验可以放到javaScript中去校验,但是唯一性校验必须得交给服务器去完成……Struts提供了这样一个功能,在
自定义标签表单中。
可以通过在自己写的formbean中(继承了ActionForm)重写validate方法(ActionMapping和HttpServletRequest为
传入参数)

//一旦ActionErrors被返回,那么ActionServlet便不会把请求再转到具体的Action中,而是转回到表单那里。
//谁产生这个错误就回到谁那里去,而且要产生错误提示信息字符串,这个字符串也应该国际化才对,在Struts中,强制要求
//错误提示的信息必须国际化,其实传回给页面的是那个key
public ActionErrors validate(ActionMapping actionMapping,HttpServletRequest request)
{
 ActionErrors errors = new ActionErrors() ;
 if(username==null||username.length()==0)
 {
  errors.add("username",new ActionMessage("error.username.empty"));
 }
 if(password==null||password.length()==0)
 {
  errors.add("password",new ActionMessage("error.password.empty"));
 }

 return errors ;//错误返回给ActionServlet,ActionServlet会调用erros.isEmpty,如果返回值为true
 //的话,说明该返回到原来提交过来的页面,注意配置文件中的action里面有个input属性,这个input指明在formbean
 //中校验发生错误之后返回哪个页面去,还有个属性叫做validate,可以将它设为true,但是可以不设,因为默认就是true!
 //action里面有很多的属性,具体情况要去查看dtd文件!
}


这样在属性文件中可以加上:

errors.header=<h3><font color=red>Error List:</font></h3><ul>
error.username.empty=<li>User name can't be empty!
error.password.empty=<li>Password can't be empty!
errors.footer=</ul><hr width=800>

下面的标签可以完成提示错误信息的工作!!
<html:errors/>
上述标签作用:先到资源包属性文件里面去找errors.header,遍历里面的所有错误,然后最后直到errors.footer为止。

递交之前先是reset一下,然后把属性塞进去,看validate属性是否为true,如果为true,调用validate方法,如果返回的errors不为
空,则根据input属性返回页面,返回的页面中如果有<html:errors/>,那么就去资源包属性文件中去找errors.header,然后从那里开始
往下遍历,直到errors.footer为止!

其实<html:errors>里面有属性可以设置errors.header和errors.footer名字,
比如<html:errors header="111">


=================================================================================
=================================================================================
下午课程开始:

在登录的Action中,如果登录失败的话:
ActionErrors errors = new ActionErrors();
errors.add(ActionErrors.GLOBAL_MESSAGE,new ActionMessage("error.login.fail"));
addErrors(request,errors)//request.setAttribute(Globals.ERROR_KEY,errors);
上面两种添加错误的信息的方法都是可以的!
return actionMapping.findAttribute("");

但是现在的问题是,现在是在Action里面,Action可不能像ActionForm一样只返回错误信息就完事了,还得
返回某个页面才行,于是可以考虑使用Action中的addErrors方法,就把它存在请求的属性中去了。
然后再返回某个页面就可以了。

错误存储的属性名字是什么呢?是GLOBAL类中的ERROR_KEY

在资源包里面加上:
error.login.fail=<li>User or Password error !

 

errors.header=<h3><font color=red>Error List:</font></h3><ul>
error.username.empty=<li>User name can't be empty!
error.password.empty=<li>Password can't be empty!
error.login.fail=<li>User or Password error !
errors.footer=</ul><hr width=800>

也就是说除了ActionForm的validate方法以外,别的地方要想处理错误的话,应该将错误放到
请求作用域里面,就像上面所写的那样。

既然new ActionMessage("error.login.fail")中的"error.login.fail"是资源包里面的键的话,那么能不能
指定值呢?可以的。

只需要:new ActionMessage("error.login.fail",false)这就是不到资源包里面去找,直接页面上显示的错误
提示信息就是字符串“error.login.fail”!

==========================================================
其实<html:errors>可以被<html:messages>取代的。
<html:messages id="msg">
${msg}<br>
</html:messages>
作用:默认情况下会到请求作用域中去找Global.ERROR_KEY,取出ActionErrors,然后对其进行迭代,
迭代后每次都取出一个ActionMessage对象,然后通过ActionMessage对象取其对应的值,也就是调用getValue,
然后存储到${msg}里面去。

ActionMessages可以遍历ActionErrors,每一个ActionErrors里面存储的是属性properties和ActionMessages对象。
取的时候先取出ActionMessage对象,先调用isResource方法,看是资源包里面的键还是字符串,如果是前者就调用getValue方法,
然后存到页面作用域的msg里面去;如果是后者的话,就调用getKey,将这个值直接返回,还是存储到页面作用域msg里面

伪代码如下:

String id ;
ActionErrors errors = (ActionErrors)request.getAttribute(…………);
if(errors!=null && !errors.isEmpty())
{
 Iterator it = errors.get() ;
 while(it.hasNext())
 {
  ActionMessage msg = (ActionMessage)it.next();
  Object message = null ;
  if(msg.isResource())
  {
   message = msg.getValue();
  }
  else
  {
   message = msg.getKey() ; //因为传入的类似error.username.empty就是key,如果不是资源的话
   //直接取这个key显示就ok了。
  }
  pageContext.setAttribute(id,message) ;
 }
}

================================================================================

errors.add("username",new ActionMessage("error.username.empty"));
上面那句话中的"username"是设置错误的属性,使用的时候可以具体在<html:text property="username">
的后面使用:
<html:errors property="username" header="" footer="" />
就可以保证只在文本框中的后面输出错误信息了!这样错误信息中的property就可以对应到<html:errors>标签中的
property属性了,可以帮助我们定位是哪个表单元素提交发生了错误!但是还要注意,如果错误信息的资源包里面
有上面所写的header和footer的话,为了不把他们打印出来,可以默认设为空值!

对于<html:messages>也是一样的,
<html:messages id="msg" property="username" />
${msg}

这样就不会去迭代了,而只是取出一条属性为username的错误信息。

==============================================================
如果是图片国际化的话,只能换图片

<html:img srcKey="index.img" altKey="index.alt.key"/>
然后在中文资源包里面:
index.img=zh.GIF
index.alt.key=中

英文资源包里面:
index.img=en.GIF
index.alt.key=zhong

这样的话就可以在页面上根据indexm.img这个键去定位具体的图片地址了。

对于按钮上的字来说,<html:submit></html:submit>,在标签体之间加入bean:message就可以国际化了。

=========================================================================================
=========================================================================================
=========================================================================================

今天内容小结:

一个内容是国际化,一个内容是错误处理!

对于国际化,想使用一个国际化的资源包的话,第一步我要向Struts注册,使用<message-resources>元素,这样就会
存储到应用程序作用域中,页面中使用<bean:message>就取出来了!

对于错误处理,可以在两个地方进行错误处理(ActionForm的validate方法和Action的execute方法里面都可以进行处理,
前者返回一个ActionErrors就可以了,后者必须手工的将其存储在请求作用域里面,当然你手工的存储ActionMessages也是
可以的,但是如果你存储的是ActionMessages的话必须在页面中使用html:messages拿出来)
或者使用ActionErrors或者使用ActionMessages两种方式都可以进行错误处理!

formbean的生命周期:
第一:进入这个页面的时候,使用Actionform的默认值去设置表单。
第二:提交到ActionServlet,使用提交上来的值去设置actionForm


              actionErrors                       actionMessages
属性   Globals.ERROR_KEY                   Globals.MESSAGE_KEY
显示         <html:errors>或者<html:messages>     只能用<html:messages message="true">    

由于validate方法返回的是ActionErrors,所以ActionErrors仍然保留,没有废除。

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值