JBuilder2005 Struts深度体验之新增

作者:网络 来源:佚名 更新时间:2008-07-07 12:23:28 点击:
  新增一个struts配置文件

  考虑到图书模块是一个比较独立的模块,为了避免对struts配置文件的资源争用导致团队工程的覆盖或冲突,我们为这个模块单独提供一个新的struts配置文件,用这个配置文件配置图书模块所有struts关联的信息。

  我们按照如下的方式为webmodule模块添加一个名为book-struts-config.xml的配置文件。

  首先到<工程目录>/webmodule/web-inf拷贝一个原有的struts-config.xml文件,更名为book-struts-config.xml放在struts-config.xml相同的目录下,删除原有配置的内容,将其调整成:

<?xml version="1.0" encoding="utf-8"?>
<!doctype struts-config public "-//apache software foundation//dtd struts configuration 1.1//en" "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
</struts-config>


  然后,在工程窗格的资源树中定位到webmodule->deployment descriptors-><struts 1.1>节点上,右击<struts 1.1>节点,在弹出的菜单中选择properties...弹出properties for ’<struts 1.1>’对话框,如图 16所示:


图 16 struts配置文件维护对话框

  点击add...按钮,在弹出的choose struts config file对话框中选择book-struts-config.xml配置文件,按ok这个新的struts配置文件将添加到struts config file in web.xml列表中。

  新增配置文件成功后,在工程窗格资源树的<struts 1.1>节点下,你将会发现这个新加入的struts配置文件,如下图所示:


图 17 两个struts配置文件

  这样,在创建新的formbean或action时,你就可以选择用哪个配置文件来保存struts的配置信息了。

  图书action form

  下面我们着手创建用于接收新增图书页面表单数据的bookactionform,使用book-struts-config.xml保存bookactionform的配置信息。bookactionform需要进行数据有效性自检,也就是说,要让bookactionform实现validate()方法。

  创建bookactionform和创建useractionform相似,但是在向导的第1步需要指定book-struts-config.xml记录bookactionform配置信息,如图 18所示:


图 18 选择不同的配置文件

  我们在前一节为web模块添加了一个配置文件,在struts config下拉框中列出了web模块所有配置文件,这里我们选择web-inf/book-struts-config.xml。

  在向导的第2步,我们为bookactionform定义下列5个属性:

string bookid;//图书id,对应t_book表的book_id,是主键。
string isbn;//isbn
string createdate;//创建日期
string bookname;//书名
string author;//作者


  在向导的第2步直接按finish创建bookactionform。由于bookid属性是主键,所以不能和t_book中已有的记录重复,这可以通过bookactionform的数据自检机制来完成,数据自检是通过定义validate()方法来实现的。向导已经为bookactionform生成了validate()方法框架,我们只需要在validate()方法编写bookid的校验的代码就可以了,bookactionform的最终代码如代码清单 10所示:

  代码清单 10 bookactionform.java

1. package bookstore;
2.
3. import javax.servlet.http.httpservletrequest;
4. import org.apache.struts.action.*;
5. import java.sql.*;
6.
7. public class bookactionform
8.  extends actionform {
9.   …
10.   public actionerrors validate(actionmapping actionmapping,
11.   httpservletrequest httpservletrequest) {
12.    actionerrors errors = new actionerrors();
13.    connection conn = null;
14.    try {
15.     conn = dbconnection.getconnection();
16.     preparedstatement pstat = conn.preparestatement(
17.      "select count(*) count from t_book where book_id=?");
18.     pstat.setstring(1, this.bookid);
19.     resultset rs = pstat.executequery();
20.     if (rs.next()&& rs.getint(1) > 0) {
21.      errors.add("bookid ",
22.      new actionmessage("bookstore.duplicate.bookid",
23.      "图书id和数据库中已经有的id重复"));

24.     }
25.    }
26.    catch (sqlexception se) {
27.     se.printstacktrace();
28.     errors.add("bookid",
29.     new actionmessage("bookstore.dbaccess.error", "访问数据库时出错"));

30.    }
31.    finally {
32.     try {
33.      if (conn != null) {
34.       conn.close();
35.      }
36.     }
37.     catch (sqlexception ex) {
38.      ex.printstacktrace();
39.      errors.add("bookid",
40.      new actionmessage("bookstore.dbaccess.error",
41.        "访问数据库时出错"));

42.     }
43.    }
44.   return errors;
45.  }
46.
47.  public void reset(actionmapping actionmapping,
48.   httpservletrequest servletrequest) {
49.    this.createdate = getcurrdatestr();
50.   }
51.
52.  //获取当前时间字符
53.  private static string getcurrdatestr() {
54.   simpledateformat sdf = new simpledateformat("yyyymmdd");
55.   return sdf.format(new date());
56.  }
57. }


  当用户提交表单后,struts框架自动把表单数据填充到actionform中,接着struts框架自动调用actionform的validate()方法进行数据验证。如果validate()方法返回的actionerrors为null或不包含任何actionmessage对象,表示通过验证,struts框架将actionform和http请求一起传给action的execute(),否则struts框架将http请求返回到输入的页面中,而输入页面即可通过<html:errors>显示对应request域中的actionerrors错误信息显示出来。

  此外,我们在reset()方法中将createdate属性置为当前的日期,因为这个属性值不是通过页面表单提供的。

  新增图书jsp页面

  1.通过向导创建bookadd.jsp

  通过jsp向导创建bookadd.jsp页面,在向导的第2步选择使用struts1.1的struts-bean和struts-html标签,如图 19所示:


图 19 指定选用struts标签

  2.使用jbuilder的struts标签构建jsp页面

  你可以直接用拖拽的方法从jbuilder编辑器左边的标签库将struts标签添加到jsp页面中,如图 20所示:


图 20 用拖拽的方式添加struts标签

  struts的html标签可以完成和标准的html元素相同的功能,struts提倡使用struts html标签库,因为这些标签可以和struts框架的其他组件紧密地联系起来。而strtus的bean标签库可以访问已经存在的javabean及其属性,有一些bean标签还可以访问http请求头信息及web资源文件的信息。

  我们希望用struts的html标签库创建添加图书的表单,通过bean标签库访问web资源文件作为表单组件前的标识文字。

  bookadd.jsp的最终代码如代码清单 11所示:

  代码清单 11 bookadd.jsp

1. <%@page contenttype="text/html; charset=gbk" %>
2. <%@taglib uri="/web-inf/struts-bean.tld" prefix="bean"%>
3. <%@taglib uri="/web-inf/struts-html.tld" prefix="html"%>
4. <html>
5. <head>
6. <title>bookinsert</title>
7. <script language="javascript" >
8. function mysubmit(form)
9. {
10. if(form.isbn.value == null || form.isbn.value == "")
11. {
12.  alert("图书的isbn不允许为空");
13.  return false;
14. }
15. if(form.bookname.value == null || form.bookname.value == "")
16. {
17.  alert("图书名不允许为空");
18.  return false;
19. }
20. }
21. </script>
22. </head>
23. <body bgcolor="#ffffff">
24. <html:errors/>
25.  <html:form action="/bookinsertaction.do" focus="bookid" method="post"
26.   onsubmit="return mysubmit(this)" >
27.  <table width="100%%" border="0">
28.   <tr>
29.    <td>
30.     <bean:message bundle="bookstore" key="bookstore.bookid"/>
31.    </td>
32.    <td>
33.     <html:text name="bookactionform" property="bookid"/>
34.    </td>
35.    <td>
36.     <bean:message bundle="bookstore" key="bookstore.isbn"/>
37.    </td>
38.    <td>
39.     <html:text name="bookactionform" property="isbn"/>
40.    </td>
41.   </tr>
42.   <tr>
43.    <td>
44.     <bean:message bundle="bookstore" key="bookstore.bookname"/>
45.    </td>
46.    <td>
47.     <html:text name="bookactionform" property="bookname"/>
48.    </td>
49.   <td>
50.   <bean:message bundle="bookstore" key="bookstore.author"/>
51.   </td>
52.   <td>
53.    <html:text name="bookactionform" property="author"/>
54.   </td>
55.  </tr>
56.  <tr align="center">
57.   <td colspan="4">
58.    <html:submit value="保存"/>
59.    <html:reset value="取消"/>
60.   </td>
61.  </tr>
62.  </table>
63. </html:form>
64. </body>
65. </html>


  其中第25~63行是表单的定义代码,将<html:form>的action指定为"/bookinsertaction.do", 它是bookinsertaction的访问uri,将在下一节实现,通过<html:form>访问action时,action只需保证和配置文件中指定的path一致就可以了,无需在前面添加上诸如/webmodule的web部署子目录。

  在第26行我们为<html:form>指定了一个onsubmit客户端校验函数,当isbn和bookname两组件中的任何一个为空时,拒绝提供表单。

  我们定义了4个<html:text>,它们对应标签html的<input type="text">输入框标签,其中name属性为对应的actionform名字,而property对应actionform的属性。图 21是bookadd.jsp的设计期效果图:


图 21 bookadd.jsp设计时的界面图

  当然,你可以直接在表单组件前写入具体的标识,如"图书id",而非第30行的<bean:message>标签,但后者通过一个资源文件产生具体的标识,这样不但可直接通过资源文件控制标识还提供了国际化的特性。

  上面,我们只是简单地引用了名为bookstore的资源文件,下面我们需要创建这个资源文件并在struts配置文件中描述它。

  到<工程目录>/src目录下,创建一个名为bookstoreresource_zh_cn.properties的资源文件,其内容如下所示:

bookstore.bookid=\u56fe\u4e66idbookstore.isbn=isbnbookstore.bookname=_
\u56fe\u4e66\u540dbookstore.author=\u4f5c\u8005bookstore.dbaccess.error=_
\u6570\u636e\u5e93\u8bbf\u95ee\u9519\u8befbookstore.duplicate.bookid=_
\u56fe\u4e66\u7f16\u53f7\u548c\u6570\u636e\u5e93\u4e2d\u5df2\u6709\u7684\u7f16\u53f7\u91cd\u590d


  这儿的中文必须采用unicode编码格式,其对应的中文文件的内容为:

bookstore.bookid=图书idbookstore.isbn=isbnbookstore.bookname=图书名bookstore.author=作者bookstore.dbaccess.error=数据库访问错误bookstore.duplicate.bookid=图书编号和数据库中已有的编号重复


  在编译工程时,jbuilder会将位于<工程目录>/src下的资源文件拷贝到web模块的web-inf/classes目录下。

  提示:

  jdk提供了一个将中文转换为unicode编码格式的工具native2ascii.exe,它位于<jdk>/bin/目录下。在dos命令窗口下,通过native2ascii -encoding gbk <源文件>

  <目标文件>即可以完成转换。


  注意:

  在前文中,我们曾提到了jbuilder 2005的一个bug,即web模块中的类或资源有时得不到同步,需要手工将类和资源拷贝到对应的目录。如果你发现资源文件没有同步到web-inf/classes目录时,bookstoreresource_zh_cn.properties需要在编译工程后手工拷贝到这个目录下,否则struts就无法找到资源了。


  在工程窗格的资源树中找到book-struts-config.xml双击打开其对应的struts config editor,切换到message resources标签页,如所示:


图 22 定义资源文件

  通过add...按钮定义一个键名为bookstore的bookstoreresource资源文件。不同的语言环境的客户端将会访问不同的资源文件,如客户端为中文环境时,将访问bookstoreresource_ch_cn.properties,如果是英语的客户端将访问bookstoreresource_cn.properties资源文件,如果没有找到对应语言的资源文件,将访问默认的资源文件,这里,默认资源文件为bookstoreresource.properties。<bean:message>的boudle即为parameter栏定义的名称。

  实战经验:

  笔者原来对struts标签是比较排斥的,因为虽说它本意希望将页面展现逻辑和程序逻辑完美地分离开来。页面设计的工作由页面设计人员在dreamweaver中完成,由于dreamweaver不认识struts的标签,那些像<html:text>,<html:submit>等表单组件的struts标签在页面设计时看不到效果,所见即所得的理念被无情的剥夺了,界面设计人员对包含struts标签的页面常常感到如堕五里雾中。

  许多struts开发人员一直梦寐以求,希望能得到一个dreamweaver的struts标签扩展插件,让页面设计人员可以象标准的html组件标签一样设计页面。fwa公司的visual tags for struts插件终于使我们梦想成真。通过这一插件,可以将dreamweaver完美地和struts结合起来,使用struts标签的jsp页面可以在设计期得到使用标准html标签一样的可视化效果。你可以通过http://www.fwasi.com/downloads/下载visual tags for struts的试用版。图 21的bookadd.jsp效果界面,即是在dreamweaver 2004中使用了visual tags for struts插件后的效果页面。

  此外,有一点关于struts标签的事情也必须提及:sun开发出了jsf页面标签,这和struts的标签在功能上是有重叠的,struts 以后的版本将逐渐往jsf靠近,jsf的标签可能将最终取代struts自己的标签,以实现天下大统。

  创建bookinsertaction

  下面,我们来创建bookinsertaction,在该action中将图书记录添加到t_book表中。如果操作成功定向到insertsuccess.htm操作成功页面,如果在进行数据库操作时发现sqlexception,则转向sqlfail.htm页面。我们需要事先创建这两个html页面,为了简单,仅在其中写入报告操作成功和失败的信息即可。

  按3.2相似的方式创建bookinsertaction,用book-struts-config.xml记录配置信息,在向导的第2步,将formbean name指定为bookactionform,scope为request,将input jsp指定为/bookadd.jsp,如图 23所示:


图 23 指出bookinsertaction的配置信息

  按finish直接创建bookinsertaction,jbuilder将打开struts config editor显示/bookinsertaction的流程,如图 24所示:


图 24 bookinsertaction流程

  添加1个出口,名为success,路径为/insertsuccess.htm。最终的/bookinsertaction的流程如图 5所示。

  代码清单 12是bookinsertaction的代码,它完成图书添加,出口控制的操作:

  代码清单 12 bookinsertaction.java

1. package bookstore;
2.
3. import javax.servlet.http.*;
4. import org.apache.struts.action.*;
5. import java.sql.*;
6.
7. public class bookinsertaction
8. extends action {
9.  public actionforward execute(actionmapping actionmapping,
10.  actionform actionform,
11.  httpservletrequest servletrequest,
12.  httpservletresponse servletresponse)
13.  throws exception
14.  {
15.   bookactionform bookactionform = (bookactionform) actionform;
16.   connection conn = null;
17.   conn = dbconnection.getconnection();
18.   preparedstatement pstat = conn.preparestatement(
19.    " insert into t_book1(book_id,isbn,book_name,author,"+
20.    "create_date) values(?,?,?,?,?)");
21.   pstat.setstring(1, bookactionform.getbookid());
22.   pstat.setstring(2, bookactionform.getisbn());
23.   pstat.setstring(3, bookactionform.getbookname());
24.   pstat.setstring(4, bookactionform.getauthor());
25.   pstat.setstring(5, bookactionform.getcreatedate());
26.   pstat.executeupdate();
27.   return actionmapping.findforward("success");
28.
29.  }
30. }


  bookinsertaction将bookactionform的数据通过jdbc添加到t_book表中,添加成功则转向insertsuccess.htm页面。有些观察细致的读者也许已经注意到bookinsertaction的execute()方法并未直接对sqlexception进行处理,而是将异常抛出,如第13行所示。这里,我们要用到struts1.1的新功能:通过配置方式处理异常。

  在工程窗格的webmodule/deployment descriptors/<struts 1.1>下找到并双击book-struts-config.xml文件,调出的struts config editor配置编辑器,切换到global exceptions标签页,如图 25所示:


图 25 异常处理配置

  点击add...定义一个名为sqlexception的异常处理配置项,处理java.sql.sqlexception异常,定义完这个配置项后,选中这个配置项,点击edit...切换到这个配置项的详细设置页面,如图 26所示:


图 26 异常处理配置窗口

  在窗口下部切换到source视图页中,这个异常配置项的配置信息如代码清单 13所示:

  代码清单 13 sqlexception的异常处理配置项

1. …
2. <struts-config>
3.  …
4.  <global-exceptions>
5.   <exception key="sqlexception" type="java.sql.sqlexception"
6.    path="/sqlfail.htm"/>

7.  </global-exceptions>
8.  …
9. </struts-config>


  第5~6行将/sqlfail.htm和java.sql.sqlexception"挂接"起来,这样程序中任何action的execute()方法抛出的sqlexception异常都将由sqlexception配置项处理。

  在welcome.jsp页面中添加一个调用bookadd.jsp的链接,登录系统后,通过这外链接调出bookadd.jsp页面,如图 27所示:


图 27 添加图书页面

  填写图书记录,点击保存提交表单到/bookinsertaction的action中,如果提供的图书id和t_book中已有的book_id重复,则struts总控制器将直接返回到bookadd.jsp页面中,由<html:errors/>报告错误信息。如果数据通过bookactionform的自检并成功添加到数据库中,将最终转向insertsuccess.htm页面。

  提示:

  如果用tomcat为web服务器,如果图书记录会出现中文乱码的问题,可以使用我们上面介绍过的一个编码过滤器,你可以在web.xml中配置这个过滤器,乱码问题就可以解决了。