深入jsp:useBean


 avaBean在JSP中的应用给我们带来了很大的方便,使得我们能够把功能较单纯的代码提取出来,增加了代码重用率。$#@60;jsp:useBean /$#@62;这个命令大家在每个JSP文件的开头一般都会用吧?下文将要介绍的是useBean命令的一些特殊用法,包括怎样为多个页面共享的bean进行初始化,以及怎样简便的把request的数据传递到bean中去。
  大家都知道bean有一个scope属性,指明bean的类型的实例建立的位置。默认的page就表示放在PageContext对象中,可以在本页面内部使用;request表示放在ServletRequest对象中,在当前request的处理期间都能够访问,这个其实和page差不多;session表示放在HttpSession对象中,只要当前页面的page.session设置为true就能够访问;application表示放在ServletContext对象中,当前服务器上面属于一个application的servlet都能访问。使用不同的scope属性值就能在不同的范围内共享bean内部的数据,但是当想为bean作一些初始化工作的时候,如果不能确定哪一个页面先运行怎么办?
  解决的方法是有的。除了常见的$#@60;jsp:useBean ... /$#@62;这种创建bean的格式以外,还有下面这种方式:
  $#@60;jsp:useBean ...$#@62;代码$#@60;/jsp:useBean$#@62;中间的代码就可以用来进行初始化工作,因为这些代码只在一个bean创建的时候执行。新创建一个bean的条件是,在一个application的范围内,没有id和scope都相同的bean存在。所以,如果你有许多页面上使用同一个bean,又想在初始化的时候设置一些bean的property,你可以把初始化代码放在每一个申明中,然后系统运行的时候只有第一个被执行的页面能够执行到这些初始化代码。
  举个例子,你有一个网站有许多的入口页面,现在你想跟踪一个用户在你的网站上逗留的时间,你可以用一个scope为session的bean来记录用户首次访问的时间,在他离开的时候把总时间存到用户数据库里面。这里只看看怎样记录首次访问时间。
  我们的bean中的关键部分是这个样子:
  /** a bean to record user browsing time
  * log-in time set by the first page visited
  */
  package myapp;
  public class TimeRecordBean {
  private long loginTime;
  private long logoutTime;
  ...
  public void setLoginTime(long time) {
  this.loginTime = time;
  }
  ...}//end of bean class然后,在所有可能的入口页面 娑脊灿谜庑┐耄?br>  $#@60;html$#@62;$#@60;body$#@62;$#@60;%@ page import=“java.util.*”%$#@62;$#@60;%@ page session=”true”%$#@62;$#@60;% ...long visitTime = Date.getTime();...
  %$#@62;$#@60;jsp:useBean id=”timerec”class=”myapp.TimeRecordBean”
  scope=”session”$#@62;$#@60;jsp:setProperty name=”timerec”
  property=”longinTime”
  value=”$#@60;%= visitTime%$#@62;”/$#@62;$#@60;/jsp:useBean$#@62;...$#@60;/body$#@62;$#@60;/html$#@62;现在,不论用户从哪一个页面进入你的网站,你都会得到进入的时间。再加上对用户id的记录和用户退出时的检测就能实现你的统计了。

  下面要讨论的问题是怎样方便的把request中的数据存放到bean中去。在许多web应用当中,把用户在html表单里面填写的数据送给一个bean去处理是非常常见的,因为在bean里面能够方便的进行各种复杂的逻辑处理,如果直接在jsp页面中写scriptlet就显得太臃肿了,而且不利于调试。但是,request.getParameter()方法返回的是String类型,对数据进行转换比较麻烦。如果你要存放数据本来就是一个String类型,那还好说:
  $#@60;jsp:useBean id=”store”class=”some.class”/$#@62;$#@60;jsp:setProperty name=”store”
  property=”userName”
  value=”$#@60;%= request.getParameter(“UserName”)%$#@62;”/$#@62;如果是int类型,你就要写成这样:
  $#@60;jsp:useBean id=”store”class=”some.class”/$#@62;$#@60;%
  int userAge = 0;
  try {
  userAge =
  Interger.parseInt(request.getParameter(“UserAge”));
  }
  catch (NumberFormatException ex) {
  userAge = AGE_UNKNOWN;
  }%$#@62;$#@60;jsp:setProperty name=”store”
  property=”userAge”
  value=”$#@60;%= userAge%$#@62;”/$#@62;要是你的表单里面有大量的int,double之类的变量,像这样编码就显得非常繁琐。好在jsp提供了专门解决这一问题的方法:属性自动关联。这个功能可以把一个特定的request里面的参数与bean中的属性建立关联,它的方便之处主要在于不需要手工进行参数类型转换,而是由系统自动的根据bean的属性的定义进行类型转换。
  自动关联的使用方法也很简单,把普通的jsp:setProperty命令的value参数改成param参数就行了,比如上面的userAge的例子就可以简写为:
  $#@60;jsp:setProperty name=”store”
  property=”userAge”
  param=”UserAge”/$#@62;两相比较,现在是不是简便多了?
  系统提供的自动类型转换只能作用于简单类型,下面是针对不同的属性类型所进行的转换的列表:
属性类型 转换方法
boolean Boolean.valueOf(param).booleanValue()
Boolean Boolean.valueOf(param)
byte Byte.valueOf(param).byteValue()
Byte Byte.valueOf(param)
char Chatacter.valueOf(param).charValue()
Character Chatacter.valueOf(param)
double Double.valueOf(param).doubleValue()
Double Double.valueOf(param)
int Integer.valueOf(param).intValue()
Integer Integer.valueOf(param)
float Float.valueOf(param).floatValue()
Float Float.valueOf(param)
long Long.valueOf(param).longValue()
Long Long.valueOf(param)

  需要注意的是,这些转换并不考虑输入中包含有非法字符的情况,也就是说照样有可能产生NumberFormatException。你可以加强客户端的数据校验,或者利用errorPage进行错误处理。另外一种特殊情况是request中根本没有你指定的参数,这个时候自动关联功能不会像getParameter方法得到null一样把null送入bean中,而是不进行任何操作。于是无法及时将输入不完整的信息反馈给服务器,你最好在bean里面给属性都赋予默认值,并且在最后的数据处理阶段做出判断。总之,数据校验的工作并不会因此变得轻松。
  自动关联的形式还有一种,全关联。全关联让你能够只用一行代码就完成全部变量的关联,没有比这更简便的了:
  $#@60;jsp:setProperty name=”store”property=”*”/$#@62;现在不用指定具体的property和param也可以进行关联,服务器自动在名称相同的request参数和bean属性之间建立关联。需要注意,所有的属性都将参加关联,如果你的某个属性不是简单类型的变量,就会出现错误。另外,参数和属性的名称必须完全一样,包括字母的大小写形式。
  最后提请大家注意,如果使用JSWDK或者JWS 2.0作为服务器,在目标参数是double类型的情况下会出现页面编译错误。