读书人

《研磨struts2》第十二章 CRUD综合应用

发布时间: 2012-08-13 13:21:53 作者: rapoo

《研磨struts2》第十二章 CRUD综合运用 之 12.3 使用Struts2来实现表现层

2.3??使用Struts2来实现表现层

12.3.1??将一组相关的Action类合成一个

在前面学习的时候,每个Action类都只对应一个单独的web请求,那么,这样做会带来什么问题呢?

?????? 先想一下,用户在添加页面上点击添加按钮之后,会发生什么事呢?Struts2会提交到负责添加的Action中,这个Action只是接收前一个页面传过来的数据,然后把它填入数据库就可以了,所以,可以这样写:

?

java代码:查看复制到剪贴板打印
  1. public?class?UserAddAction?extends?ActionSupport{??
  2. ????private?UserModel?user;??
  3. ????public?UserModel?getUser()?{??
  4. ????????return?user;??
  5. ????}??
  6. ????public?void?setUser(UserModel?user)?{??
  7. ????????this.user?=?user;??
  8. ????}??
  9. ????public?String?execute()?throws?Exception{??
  10. ????????UserJDBCDAO?dao?=?new?UserJDBCDAO();??
  11. ????????//把接收到的数据添加到数据库里??
  12. ????????dao.create(user);??
  13. ????????return?this.toList();??
  14. ????}??
  15. ????//其它的省略了??
  16. }??

这个Action用自己的一个user属性接收了上一个页面上传过来的数据,然后新建了一个dao,用dao把这个UserModel放入了数据库。看起来没有什么问题,它做了它该做的事情。

?????? 再想一想其他Action呢?如果用户在修改页面上点击了修改按钮之后,Action要做什么呢?

同样也是接收页面传过来的数据,然后用dao把这个UserModel放入数据库吧,大致的写法会是这样:

?

java代码:查看复制到剪贴板打印
  1. public?class?UserUpdateAction?extends?ActionSupport{??
  2. ????private?UserModel?user;??
  3. ????public?UserModel?getUser()?{??
  4. ????????return?user;??
  5. ????}??
  6. ????public?void?setUser(UserModel?user)?{??
  7. ????????this.user?=?user;??
  8. ????}??
  9. ????public?String?execute()?throws?Exception{??
  10. ????????UserJDBCDAO?dao?=?new?UserJDBCDAO();??
  11. ????????//把接收到的数据更新到数据库里??
  12. ????????dao.update(user);??
  13. ????????return?this.toList();??
  14. ????}??
  15. ????//其它的省略了??
  16. }??

对比这两个类,会发现几乎是相同的,只是UserAddAction调用了dao的create方法,而UserUpdateAction调用了dao的update方法。

?????? 因此,在实际的开发中,并不会用一个Action来对应一个web请求的功能,而是把一组相关的web请求的功能,比如说都是处理UserModel的功能,放到一起,用一个Action来实现。

在struts.xml的配置中,仍然可以使用多份不同的配置,也就是一个Action对应多个<action>标签。这样做,既可以消除很多细粒度的类,又可以消除这些类之间的重复代码,比如说UserAddAction和UserUpdateAction都有的user属性及其getter/setter等。

在接下来的实现中,我们将使用一个Action,来完成对用户的增、删、改、查功能。

12.3.2??显示全部用户

首先来实现显示全部用户的功能。要显示全部数据,通常是先进入一个Action来检索出所有数据,然后跳转到负责显示数据的页面,把数据展示出来。

1:准备Action

?????? 在上一个小节中,已经说过,真正的开发中往往把一些列相关的web请求的功能放到一起,由一个Action响应。那么,怎么用一个Action来响应多个web请求的功能呢?

可以采用第四章学到的给Action起别名的方法:在struts.xml中,一个Action类对应多个<action>元素,每一个<action>元素都可以指定一个方法名(method属性),使得响应的时候可以不调用execute方法,而是调用指定方法。

?????? 因此,可以写出Action的代码,示例如下:

?

java代码:查看复制到剪贴板打印
  1. public?class?UserAction?extends?ActionSupport{??
  2. ????private?List<UserModel>?list;??
  3. ????public?List<UserModel>?getList()?{??
  4. ????????return?list;??
  5. ????}??
  6. ????public?void?setList(List<UserModel>?list)?{??
  7. ????????this.list?=?list;??
  8. ????}??
  9. ????public?String?toList()?throws?Exception{??
  10. ????????UserJDBCDAO?dao?=?new?UserJDBCDAO();??
  11. ????????//从数据库里检索出所有的数据,并赋给Action的属性list??
  12. ????????list?=?dao.getAll();??
  13. ????????return?"toList";??
  14. ????}??
  15. }??

在这里,代码本身并不难,只是需要注意,现在的响应方法不是execute方法了,而是写的toList方法。

2:准备JSP

?????? 在Action中,将从数据库里检索出来的数据放到了一个叫list的属性里,所以,列表页面(list.jsp)上只要循环的显示这个list属性里的所有东西就可以了。

这会用到<s:iterator/>标签,注意,这个标签会把当前正在循环的对象放到值栈的栈顶,所以,在引用正在循环对象的某个属性的时候,在<s:iterator/>标签范围内的<s:property/>标签里的OGNL表达式只需要写属性名就可以了。

示例代码如下:

?

java代码:查看复制到剪贴板打印
  1. <%@?page?language="java"?contentType="text/html;?charset=gb2312"??
  2. ????pageEncoding="gb2312"%>??
  3. <%@taglib?prefix="s"?uri="/struts-tags"?%>??
  4. <!DOCTYPE?html?PUBLIC?"-//W3C//DTD?HTML?4.01?Transitional//EN"???
  5. "http://www.w3.org/TR/html4/loose.dtd">??
  6. <html>??
  7. <head>??
  8. <meta?http-equiv="Content-Type"?content="text/html;?charset=gb2312">??
  9. <title>显示用户信息</title>??
  10. </head>??
  11. <body>??
  12. <hr>??
  13. <table?border="1"?cellpadding="1"?cellspacing="0"?align="center">??
  14. ????<tr>??
  15. ????????<td>编号</td>??
  16. ????????<td>姓名</td>??
  17. ????????<td>性别</td>??
  18. ????????<td>年龄</td>??
  19. ????????<td>操作</td>??
  20. ????</tr>??
  21. <s:iterator?value="list">??
  22. ????<tr>??
  23. ????????<td><s:property?value="userId"/>?</td>??
  24. ????????<td><s:property?value="name"/>?</td>??
  25. ????????<td><s:property?value="sex"/>?</td>??
  26. ????????<td><s:property?value="age"/>?</td>??
  27. ????????<td>??
  28. ????????????操作??
  29. ????????</td>??
  30. ????</tr>??
  31. </s:iterator>??
  32. </table>??
  33. </body>??
  34. </html>??

3:struts.xml配置

在struts.xml中需要进行配置,才能让UserAction的toList方法被执行后,跳转到指定的list.jsp。

?

java代码:查看复制到剪贴板打印
  1. <package?name="crud1"?namespace="/crud1"?extends="struts-default">??
  2. <action?name="userToList"?class="cn.javass.crud1.action.UserAction"?method="toList">??
  3. ????????<result?name="toList">/jsp/list.jsp</result>??
  4. ????</action>??
  5. </package>??

在这里,唯一要注意的就是<action>标签的method属性,指明了在访问名为userToList的Action时,要调用的不是execute方法,而是指定的toList方法。

?????? 启动数据库和Tomcat服务器,访问“http://localhost:9080/crud1/crud1/userToList.action”就可以看到全部数据了。当然,建完表之后还没有数据,可以先手工向数据库里加几条,看一下结果。

《研磨struts2》第十二章 CRUD综合应用 之 12.3 使用Struts2来实现表现层

图12.1 显示全部用户页面

12.3.3??添加用户

做完显示全部用户之后,接下来开始实现添加用户的功能。

添加用户的操作要分两个阶段:首先,要跳入一个“添加页面”,在这个页面上可以填入想添的数据;然后,点击添加按钮时,提交这个页面,进行真正的数据库操作。

1:准备跳转到添加页面的链接

先要在list.jsp页面上添加一个转到“添加用户”页面的链接:

?

java代码:查看复制到剪贴板打印
  1. <a?href="/crud1/crud1/userToAdd.action">添加用户</a>??

点击这个链接,访问名为userToAdd的Action。

2:准备跳转到添加页面之前的Action

?????? 在添加页面上,需要收集用户的输入:分别用三个普通的文本框收集用户的编号、姓名、年龄;用一个下拉框来收集用户的性别,下拉框有两个选项,分别是男和女。因此,在跳转到添加页面之前的Action中,只需要准备一个字符串数组设定两个选项“男”和“女”。

?????? 把关于UserModel的一组操作都放到UserAction中,各个方法之间是互不影响的,UserAction中已经有了toList方法,那么,只要新添加的方法不叫toList就可以了。所以,在UserAction中添加以下内容,注意,这里的添加不要影响原有的内容,是在已有的内容上添加的,示例代码如下:

?

java代码:查看复制到剪贴板打印
  1. public?class?UserAction?extends?ActionSupport{??
  2. ????private?String[]?sexs?=?new?String[]{"男","女"};??
  3. ????public?String[]?getSexs()?{??
  4. ????????return?sexs;??
  5. ????}??
  6. ????public?void?setSexs(String[]?sexs)?{??
  7. ????????this.sexs?=?sexs;??
  8. ????}??
  9. ????public?String?toAdd()?throws?Exception{??
  10. ????????return?"toAdd";??
  11. ????}??
  12. ????//原有代码请参见实现toList方法的UserAction??
  13. }??

在这里,新建了一个toAdd方法,它什么也没做,只是返回了toAdd这个字符串。还新建了一个String数组,定义了“男”和“女”,这样,在下一个页面上就可以引用这个数组来生成下拉框了。

2:准备添加页面

?????? 添加页面,也就是add.jsp页面,示例代码如下:

?

java代码:查看复制到剪贴板打印
  1. <%@?page?language="java"?contentType="text/html;?charset=gb2312"??
  2. ????pageEncoding="gb2312"%>??
  3. <%@taglib?prefix="s"?uri="/struts-tags"?%>??
  4. <!DOCTYPE?html?PUBLIC?"-//W3C//DTD?HTML?4.01?Transitional//EN"??
  5. ?"http://www.w3.org/TR/html4/loose.dtd">??
  6. <html>??
  7. <head>??
  8. <meta?http-equiv="Content-Type"?content="text/html;?charset=gb2312">??
  9. <title>添加用户信息</title>??
  10. </head>??
  11. <body>??
  12. <s:form?action="userAdd"?method="post">??
  13. ????<s:textfield?name="user.userId"?label="编号"/>??
  14. ????<s:textfield?name="user.name"?label="姓名"/>??
  15. ????<s:select?list="sexs"?name="user.sex"?label="性别"/>??
  16. ????<s:textfield?name="user.age"?label="年龄"/>??
  17. ????<s:submit?value="添加"/>??
  18. </s:form>??
  19. </body>??
  20. </html>??

在这个页面上,<s:form>标签,没有设置namespace属性,说明要提交到同包内的名为userAdd的Action去,没有指定theme属性,说明使用默认的xhtml主题。

<s:textfield>标签很简单,其label属性为文本框前面显示的文字,name属性指定了提交的参数名。

<s:select>标签的list属性指定了生成选项的数据源为上一个Action的sexs属性,正是建立的String数组,没有指定listKey属性和listValue属性说明生成<option>的时候value和<option>标签中间的文本都使用String数组中的字符串即可,所以,在页面上看到的选项是“男”、“女”,将来在下一个Action中接到的值也将是“男”或“女”。

3:struts.xml配置

?????? 那么,下一步是让UserAction的toAdd方法运行完之后,跳转到add.jsp页面,而进入这个页面是在list.jsp上跳转到名为userToAdd的Action,所以在配置的时候采取以下方式:

?

java代码:查看复制到剪贴板打印
  1. <action?name="userToAdd"?class="cn.javass.crud1.action.UserAction"?method="toAdd">??
  2. ????<result?name="toAdd">/jsp/add.jsp</result>??
  3. </action>??

注意,这个<action>元素与上一个<action>名为userToList的元素的关系是:同一个包内的两个<action>元素,因此,这里就体现了解决问题的思路:同一个Action类通过取不同别名的方法,在struts.xml中配置为多个<action>元素,来执行一组相关的web请求所对应的功能。

《研磨struts2》第十二章 CRUD综合应用 之 12.3 使用Struts2来实现表现层

图12.2 添加用户页面

4:提交Action

?????? 添加页面的初始化完成之后,可以来实现点击“添加按钮”后如何向数据库里提交了。在add.jsp上,点击“添加按钮”提交到名为userAdd的Action中。仍然使用UserAction,这时,UserAction的add方法只需要接收add.jsp传过来的参数,并把它添加到数据库即可,在向数据库添加完之后,只需要跳转到显示所有用户的页面,示例代码如下:

?

java代码:查看复制到剪贴板打印
  1. public?class?UserAction?extends?ActionSupport{??
  2. ????private?UserModel?user;??
  3. ????public?UserModel?getUser()?{??
  4. ????????return?user;??
  5. ????}??
  6. ????public?void?setUser(UserModel?user)?{??
  7. ????????this.user?=?user;??
  8. ????}??
  9. ????public?String?add()?throws?Exception{??
  10. ????????UserJDBCDAO?dao?=?new?UserJDBCDAO();??
  11. ????????//把接收到的数据添加到数据库??
  12. ????????dao.create(user);??
  13. ????????//调用toList方法,在添加到数据库之后??
  14. //把所有的数据检索出来,然后跳转到显示所有用户的页面??
  15. ????????return?this.toList();??
  16. ????}??
  17. ????//原有代码请参见实现toAdd方法的UserAction??
  18. }??

由于add方法最后调用了toList方法,而且add方法以toList方法的返回值作为自己的返回值,所以add方法的返回值实际上是toList。而且,添加用户最终要跳转到显示所有用户的页面。所以在配置struts.xml的时候要注意,这个<action>元素的<result>子元素应该以toList为名,最终指向到list.jsp。

6:struts.xml配置


java代码:查看复制到剪贴板打印
  1. <action?name="userAdd"?class="cn.javass.crud1.action.UserAction"?method="add">??
  2. ????<result?name="toList">/jsp/list.jsp</result>??
  3. </action>??

去运行测试一下看看,现在的新增和列表功能是否好用。

12.3.4??修改用户

做完显示所有用户和添加用户的功能之后,接下来实现修改用户的功能。

修改用户要分两个阶段:首先,要跳转到一个“修改页面”,在这个页面上展示需要修改的数据,用户在此基础上可以修改要改的数据,然后点击修改按钮时,提交这个页面,进行真正的数据库操作。

1:准备跳转到修改页面的链接

先要在list.jsp页面上为每条用户数据准备一个跳转到修改页面的链接,这个链接自然应该放到table中,每一行都有一个,而且每行都把自己这行显示的用户的userId数据传给后续处理的Action,示例代码如下:

?

java代码:查看复制到剪贴板打印
  1. <hr>??
  2. <table?border="1"?cellpadding="1"?cellspacing="0"?align="center">??
  3. ????<tr>??
  4. ????????<td>编号</td>??
  5. ????????<td>姓名</td>??
  6. ????????<td>性别</td>??
  7. ????????<td>年龄</td>??
  8. ????????<td>操作</td>??
  9. ????</tr>??
  10. <s:iterator?value="list">??
  11. ????<tr>??
  12. ????????<td><s:property?value="userId"/>?</td>??
  13. ????????<td><s:property?value="name"/>?</td>??
  14. ????????<td><s:property?value="sex"/>?</td>??
  15. ????????<td><s:property?value="age"/>?</td>??
  16. ????????<td>??
  17. ????????????<a?href="/crud1/crud1/userToUpdate.action?user.userId=<s:property?value='userId'/>">修改</a>??
  18. ????????</td>??
  19. ????</tr>??
  20. </s:iterator>??
  21. </table>??

在上面的代码中,加粗的代码就是跳转到名为userToUpdate的Action的链接,需要以user.userId的名字传入当前行显示的用户的userId,而且整个这一行在<s:iterator/>标签中,所以,使用<s:property value=”userId”/>即可引用当前行显示的用户的userId。

2:准备跳转到修改页面之前的Action

?????? 修改页面先要展示需要修改的数据,通常的做法是在转向修改页面之前的Action里面,就把这条数据检索出来并放到值栈里,等待修改页面去引用,示例代码如下:

?

java代码:查看复制到剪贴板打印
  1. public?class?UserAction?extends?ActionSupport{????
  2. ????public?String?toUpdate()?throws?Exception{??
  3. ????????UserJDBCDAO?dao?=?new?UserJDBCDAO();??
  4. ????????//按照接收到的userid,检索出对应记录??
  5. ????????user?=?dao.getSingle(user.getUserid());??
  6. ????????return?"toUpdate";??
  7. ????}??
  8. ????//原有代码请参见实现add方法的UserAction??
  9. }??

在这个Action里,toUpdate方法操作了user属性,由于各个操作都共用这个UserAction,所以,在做add方法时,已经为UserAction增添了user属性,这里就不要再声明了。

由于在list.jsp页面上写链接传值的时候,用户的userId以名为user.userId属性传入这个Action,因此,自然要调用其user属性的getUserId()方法来获得。

3:准备修改页面

?????? 修改页面与添加页面的布局完全一样,只是要展示需要修改的数据,示例代码如下:

?

java代码:查看复制到剪贴板打印
  1. <%@?page?language="java"?contentType="text/html;?charset=gb2312"??
  2. ????pageEncoding="gb2312"%>??
  3. <%@taglib?prefix="s"?uri="/struts-tags"?%>??
  4. <!DOCTYPE?html?PUBLIC?"-//W3C//DTD?HTML?4.01?Transitional//EN"??
  5. ?"http://www.w3.org/TR/html4/loose.dtd">??
  6. <html>??
  7. <head>??
  8. <meta?http-equiv="Content-Type"?content="text/html;?charset=gb2312">??
  9. <title>修改用户信息</title>??
  10. </head>??
  11. <body>??
  12. <s:form?action="userUpdate"?method="post">??
  13. ????<s:textfield?name="user.userId"?label="编号"/>??
  14. ????<s:textfield?name="user.name"?label="姓名"/>??
  15. ????<s:select?list="sexs"?name="user.sex"?label="性别"/>??
  16. ????<s:textfield?name="user.age"?label="年龄"/>??
  17. ????<s:submit?value="修改"/>??
  18. </s:form>??
  19. </body>??
  20. </html>??

请读者比较一下这个update.jsp和原来的add.jsp,发现除了<title>不同,<s:form>要提交的目标不同,<s:submit/>显示的文字不同之外,别的都与add.jsp一模一样,不是要展示数据吗?怎么没有赋值呢?

请大家回忆一下前面学过的知识:<s:textfield/>标签的name属性,不仅仅指定了这个文本框在提交的时候的参数名;在没有指定value属性的时候,name属性还可以当作OGNL表达式来向值栈请求值,作为这个文本框的初始值。

?????? 因此,在update.jsp上的<s:textfield name=”user.userid”/>,由于在Action(userToUpdate)中初始化了其user属性,而这个属性的值被放到了值栈中,所以页面能够自动获取道这些值,并展示在相应的表单域里面。

3:struts.xml配置

?????? 首先是在list.jsp上跳转到名为userToUpdate的Action,然后让UserAction的toUpdate方法运行完之后,跳转到update.jsp页面,所以在配置的时候采取以下方式:

?

java代码:查看复制到剪贴板打印
  1. <action?name="userToUpdate"?class="cn.javass.crud1.action.UserAction"??
  2. method="toUpdate">??
  3. ????<result?name="toUpdate">/jsp/update.jsp</result>??
  4. </action>??

4:运行测试一下

?????? 先跳转到修改页面,如下图所示:

《研磨struts2》第十二章 CRUD综合应用 之 12.3 使用Struts2来实现表现层

图12.3 修改用户页面

5:处理修改提交的Action

?????? 修改页面的初始化完成之后,用户将值修改成需要的数据,然后点击“修改按钮”向后台提交修改信息。在update.jsp上,点击“修改按钮”提交到名为userUpdate的Action去进行处理。

这时,UserAction的update方法只需要接收update.jsp传过来的参数,并把它更新到数据库即可,在向数据库更新完之后,仍然跳转到显示所有用户的页面,示例代码如下:

?

java代码:查看复制到剪贴板打印
  1. public?class?UserAction?extends?ActionSupport{??
  2. ????public?String?update()?throws?Exception{??
  3. ????????UserJDBCDAO?dao?=?new?UserJDBCDAO();??
  4. ????????//把接收到的数据更新到数据库??
  5. ????????dao.update(user);??
  6. ????????return?this.toList();??
  7. ????}??
  8. ????//原有代码请参见实现toUpdate方法的UserAction??
  9. }??

6:struts.xml配置

由于update方法最后调用了toList方法,而且update方法以toList方法的返回值作为自己的返回值,所以update方法的返回值实际上是“toList”。所以在配置struts.xml的时候要注意,这个<action>元素的<result>子元素应该以toList为名,最终指向到list.jsp。

?

java代码:查看复制到剪贴板打印
  1. <action?name="userUpdate"?class="cn.javass.crud1.action.UserAction"?method="update">??
  2. ????<result?name="toList">/jsp/list.jsp</result>??
  3. </action>??

12.3.5??删除用户

现在,该考虑如何删除用户了。在做任何企业级应用软件时,在删除之前都必须进行询问,决不能让用户点击了删除按钮之后就马上删除,实现的方式很多,其中一种简单的方式就是使用javascript中的询问框confirm来完成这个功能。当用户选择确认删除之后,就真的执行删除并跳回到显示所有用户的页面就可以了。

1:准备删除的链接

在list.jsp页面上为每个用户准备一个删除的链接,这个链接自然也像修改一样应该放到table中,每一行都有一个,而且每行都把自己这行显示的用户的userid传给下一个Action:

?

java代码:查看复制到剪贴板打印
  1. <hr>??
  2. <table?border="1"?cellpadding="1"?cellspacing="0"?align="center">??
  3. ????<tr>??
  4. ????????<td>编号</td>??
  5. ????????<td>姓名</td>??
  6. ????????<td>性别</td>??
  7. ????????<td>年龄</td>??
  8. ????????<td>操作</td>??
  9. ????</tr>??
  10. <s:iterator?value="list">??
  11. ????<tr>??
  12. ????????<td><s:property?value="userId"/>?</td>??
  13. ????????<td><s:property?value="name"/>?</td>??
  14. ????????<td><s:property?value="sex"/>?</td>??
  15. ????????<td><s:property?value="age"/>?</td>??
  16. ????????<td>??
  17. ????????????<a?href="/crud1/crud1/userToUpdate.action?user.userId=<s:property?value='userId'/>">修改</a>|??
  18. ????????????<a?href="javascript:if?(confirm('确认删除吗?'))?window.location.href='/crud1/crud1/userDelete.action?user.userId=<s:property?value='userId'/>'">删除</a>??
  19. ????????</td>??
  20. ????</tr>??
  21. </s:iterator>??
  22. </table>??

在上面的代码中,“<a href="javascript:if (confirm('确认删除吗?')) window.location.href='/crud1/crud1/userDelete.action?user.userId=<s:property value='userId'/>'">删除</a>”这句话就是要进行删除的链接。虽然看着比较长,不要着急,一点一点来分析,对这个链接的href属性:

读书人网 >软件架构设计

热点推荐