随笔-86  评论-767  文章-3  trackbacks-3

第五章 LPMT中的控制结构

在 Struts 的控制逻辑中, Controller 的 ActionServlet 、 RequestProcessor 是由 Struts 自身实现的。用户需要实现的是 Model 的 Action 的 Perform 或者 Execute 方法。我们定义了两个 Action : IssueAction 和 MainAction ,在 Action 中根据参数 action 的类型判断并实现各种逻辑操作。下面以 IssueAction 、 IssueActionForm 、 IssueDetail.jsp 为例说明 LPMT 中的控制结构实现。

5.1 Action中的控制结构实现

在 IssueAction 中,定义参数 action 来判断各种操作类型。 Action 值来自客户端请求的 URL , action = httpServletRequest.getParameter("action").trim() 。

action == “view” :分页查看所有 Issue

action == “viewDetail” : 查看单个 Issue 及其 IssueDatas 和 ChangeLogs

action == “create” : 新建一个 Issue

action == “edit” :编辑选定 Issue

action == “delete” :删除选定 Issue

action == “save” :保存新建或修改过的 Issue

action == ” createIssueData” :为选定的 Issue 新建 IssueData

action == “saveIssueData” :保存新建或修改过的 IssueData

action == “editIssueData” :修改选定的 IssueData

action == “deleteIssueData” :删除选定的 IssueData

在判定操作类型之后, Action 根据需要初始化对象,调用 IssueBean 的方法完成相应的业务逻辑操作,最后返回相应的 ActionMapping 对象。

5.2 ActionForm中的控制逻辑实现

在 IssueActionForm 中,处理对应表单页面的所有项之外,我们另外定义了一个 actionType 参数,来保存并传递 Action 的操作类型。

private String actionType = "create";

在 Action 判定操作类型之后,要设置对应 IssueActionForm 对象的 actionType 值。比如:

issueActionForm.setActionType(action);

issueDataActionForm.setActionType(action);

5.3 View中的控制逻辑实现

在 IssueAction 对应的 IssueDetail.jsp 页面中,需要根据当前 IssueActionForm 参数 actionType 的值来判断当前操作类型,继而实现相应的显示逻辑。比如:

当 actionType = “create” 时,操作类型为新建 Issue ,此时显示一张空白表单,初始化 Component 、 Environment 等可选项;当 actionType = “edit” 时,操作类型为编辑 Issue ,此时要载入表单值,如 issueId , title , Component 等等;当 actionType = “viewDetail” 时,操作类型为查看 Issue 内容。这里使用 <logic:equal> 标签来实现控制显示逻辑,用 <logic:present> 和 <logic:notPresent> 判断对应的 issueActionForm 是否已经载入页面。我们以显示 IssueId 为例:

       <logic:equal name="issueActionForm" property="actionType" value="create">

              <html:text property="issueId"/>

       </logic:equal>

       <logic:equal name="issueActionForm" property="actionType" value="edit">

              <logic:present name="issueActionForm">

                     <html:text name="issueActionForm" property="issueId"/>

              </logic:present>

              <logic:notPresent name="issueActionForm">

                     <b>Error:No issue.</b>

              </logic:notPresent>

       </logic:equal>

       <logic:equal name="issueActionForm" property="actionType" value="viewDetail">

              <logic:present name="issueActionForm">

                     <bean:write name="issueActionForm" property="issueId" />

              </logic:present>

              <logic:notPresent name="issueActionForm">

                     <b>Error:No issue.</b>

              </logic:notPresent>

       </logic:equal>

页面效果如下:

13.jpg


第六章 LPMT中的WebForm技术实现

在 Web 系统设计中, WebForm 作为直接呈现给客户端的 View ,其实现技术一直为业界所关注。从最初的单纯的 HTML ,到后来的 CGI 、 PERL ,到最近的 ASP 、 JSP ,到目前的标签库,业界一直在寻找一种能够快速开发、灵活、高效率、可重用的技术来实现业务逻辑呈现。在 LPMT 中,我们采用 HTML 结合 Jakarta Struts 标签的技术来实现, JSP 页面作为单纯的 View 使用,而业务逻辑完全由 Action 完成。同样是运行于 Server 端的技术,与单纯的 ASP 、 JSP 技术相比,运用 Jakarta Struts 标签库构建的 JSP 页面结构更清晰,可重用性和扩展性更优秀。

6.1 Jakarta Struts 标签库

Jakarta Struts1.0 的标签库包括:

l        Bean 标签:

提供一组操作标签,用于在必要的时候封装逻辑,使用JavaBeans、HTTP Cookies、HTTP Headers。这些标签封装在文件名为struts-bean.tld的标签包中。

l        Logical 标签:

提供一组用来在JSP页中有条件地产生输出文本,在对象集合中循环从而重复地产生输出文本,以及应用程序流程控制的标签。Logical标签库定义的标记能够执行条件逻辑、重复循环、转发/重定向等功能,可以完全替代scriptlet。这些标签封装在文件名为struts-logic.tld的标签包中。

l        HTML 标签:

用来生成HTML标签,显示表单元素、控件及其数据,使用会话ID对URL进行编程,以及显示错误信息。这些标签封装在文件名为struts-html.tld的标签包中。

l        Templete 标签:

提供一组用于定义可重用的模板视图的标签,包括:<template:get/>、<template:insert/>、<template:put>。这些标签被封装在文件名为struts-template.tld的标签包中。

Struts1.1 还引入了struts-nested和struts-tiles两个标签库。在LPMT中,我们采用了Struts1.0的四个标签库。

6.2 WebForm的Jakarta Struts标签技术实现

WebForm 即是通常 MVC 设计模式中的 View 。在 LPMT 中, View 由通过 HTML 和 Struts 标签构建的 JSP 页面充当。 JSP 页面作为 View 使用,只负责显示业务逻辑的处理结果,并不负责业务逻辑处理。为使 View 具有较高的可复用性,通常将多个逻辑显示集合在一个 View 完成;为使 View 具有较高的稳定性, JSP 页面应该保留通用的接口,即使 Action 的业务逻辑改变了, View 仍然不需要修改。另外,为使 View 具有较高的可扩展性和可维护性,降低未来可能的维护成本, View 结构应该清晰易读。以 IssueDetail.jsp 为例说明 WebForm 的 Jakarta Struts 技术实现。

IssueDetail.jsp 的设计需求是要实现 Issue 创建、查看、修改、删除的页面显示。当操作类型为创建 — “ create ”时, View 应该初始化一张空白的 Issue 表单,等待用户输入;当操作类型为查看 — “ viewDetail ”时, View 应该把相应的 Issue 的值及其 IssueData 、 ChangeLog 显示出来,内容为不可编辑;当操作类型为修改时, View 表单应该初始化相应 Issue 的值并于相应的 HTML 控件集合,内容为可编辑;当操作类型为删除 — “ delete ”时, View 不显示或者显示 Issue 的内容,不可编辑。 为实现上述上述逻辑,我们采用 <logic:equal> 标签,通过判断 issueActionForm 对象的 actionType 参数的 value 值来判断操作类型,继而实现相应的显示逻辑。以显示 Issue 的 description 值为例,代码实现如下:

<logic:equal name="issueActionForm" property="actionType" value="create">

              <html:textarea property="description" rows="8" cols="40"/>

       </logic:equal>

    <logic:equal name="issueActionForm" property="actionType" value="edit">

              <logic:present name="issueActionForm">

                     <html:textarea property="description" rows="8" cols="40"/>

              </logic:present>

              <logic:notPresent name="issueActionForm">

                     <b>Error:No issue.</b>

              </logic:notPresent>

       </logic:equal>

       <logic:equal name="issueActionForm" property="actionType" value="viewDetail">

              <logic:present name="issueActionForm">

                     <bean:write name="issueActionForm" property="description" />

              </logic:present>

              <logic:notPresent name="issueActionForm">

                     <b>Error:No issue.</b>

              </logic:notPresent>

       </logic:equal>

       而在 View 通用性设计方面, IssueDetail.jsp 通过使用 <logic:present> 和 <logic:notPresent> 标签判断对象 issueActionForm 是否已经加载到 scope 以及加载进来的 issueActionForm 的 actionType 等属性值来完成逻辑显示。这意味着当 Action 完成相应的业务逻辑之后,在返回指向 IssueDetail.jsp 的 ActionMapping 对象之前,只需要把相应的 IssueActionForm 对象实例加载到如 Request 、 Session 或者 PageContext 即任何一个 scope 里面就可以了,不需要在 URL 中传递任何参数。

比如在 IssueAction 中,当操作类型为查看相应 Issue 的详细内容时, URL 请求为 http://localhost:8000/issuecontrol/issueAction.do?action=viewDetail&issueId=... , IssueAction 先取得 URL 传递过来的 issueId 参数值,然后通过 IssueBean.getIssueById 方法取得对应的 IssueActionForm 对象实例 issueActionForm ,设置 issueActionForm 对象的 actionType 参数,把 issueActionForm 放到 httpServletRequest 对象中,最后设置转向参数 address 的值为 ”viewIssueDetail” 。代码示例如下:

if("viewDetail".equals(action)) {

String issueId = "";

            if(httpServletRequest.getParameter("issueId")!=null)

issueId = httpServletRequest.getParameter("issueId").trim();

IssueActionForm issueActionForm = IssueBean.getIssueById(issueId);

if(issueActionForm == null) {

runningErrors.add(new ActionError("Issue(IssueID=" + issueId + ") not found."));

             httpServletRequest.setAttribute("runningErrors",runningErrors);

             address = "error";

        }

        else {

             httpServletRequest.setAttribute("issueActionForm",issueActionForm);

                     issueActionForm.setActionType(action);

        address = "viewIssueDetail";

          }

}

当操作类型为新建一个 Issue 实例的时候, URL 请求为 http://localhost:8000/issuecontrol/issueAction.do?action=create , IssueAction 取得 typeActionForm 对象数组、 componentActionForm 对象数组、 flagActionForm 对象数组、 environmentActionForm 对象数组和 priorityActionForm 对象数组并放到 httpServletRequest 对象中,最后设置转向参数 address 的值为 ”viewIssueDetail” 。代码示例如下:

       else if("create".equals(action)) {

          httpServletRequest.setAttribute("typeActionForms",IssueBean.getAllTypes());

httpServletRequest.setAttribute("componentActionForms",IssueBean.getAllComponents());

httpServletRequest.setAttribute("flagActionForms",IssueBean.getAllFlags());    httpServletRequest.setAttribute("environmentActionForms",IssueBean.getAllEnvironments());

        httpServletRequest.setAttribute("priorityActionForms",IssueBean.getAllPriorities());

              address = "viewIssueDetail";

}

当操作类型为编辑修改一个 Issue 实例的时候, URL 请求为 http://localhost:8000/issuecontrol/issueAction.do?action=edit&issueId =... , IssueAction 根据取得的参数 issueId 的值取得相应的 IssueActionForm 对象实例 issueActionForm ,设置 issueActionForm 的参数 actionType 的值,取得 typeActionForm 对象数组、 componentActionForm 对象数组、 flagActionForm 对象数组、 environmentActionForm 对象数组和 priorityActionForm 对象数组并将所有对象实例放到 httpServletRequest 对象中,最后设置转向参数 address 的值为 ”viewIssueDetail” 。代码示例如下:

else if("edit".equals(action)) {

address = "viewIssueDetail";

String issueId = "";

if(httpServletRequest.getParameter("issueId") != null)

IssueId = httpServletRequest.getParameter("issueId").trim();

IssueActionForm issueActionForm = IssueBean.getIssueById(issueId);

if(issueActionForm == null) {

runningErrors.add(new ActionError("Issue(IssueID=" + issueId + ") not found."));

          httpServletRequest.setAttribute("runningErrors",runningErrors);

          address = "error" ;

}

else {

issueActionForm.setActionType(action);

          httpServletRequest.setAttribute("issueActionForm",issueActionForm);

httpServletRequest.setAttribute("typeActionForms",IssueBean.getAllTypes());        httpServletRequest.setAttribute("componentActionForms",IssueBean.getAllComponents());

httpServletRequest.setAttribute("flagActionForms",IssueBean.getAllFlags());        httpServletRequest.setAttribute("environmentActionForms",IssueBean.getAllEnvironments());        httpServletRequest.setAttribute("priorityActionForms",IssueBean.getAllPriorities());

address = "viewIssueDetail";

       }

}

另外,由于 View 只负责逻辑显示,而不需要实现业务逻辑,因此结构非常清晰,扩展和修改都将非常容易,可以将扩展和修改维护的成本降低到很小的水平。

6.3 与单纯的JSP代码的比较

与目前业界比较常用的单纯 ASP/JSP 代码构建的 WebForm 方法相比,上述 WebForm 构建技术有明显的优势:

l        构建成本低,效率高

Jakarta Struts 标签库提供了一系列的标签用于快速构建 JSP View ,标签库包括一般的 HTML 元素和控件 (html 标签 ) ,流程和逻辑控制的标签 (logic 标签 ) , bean 操作标签等等。这里以循环显示所有的 Component 为例比较一下两种方法的效率,假设 Component 对象数组可以从 request 中得到。

Logical 标签:

<logic:iterate id="components" name="componentActionForms">

              <bean:write name="components" property="component" />

</logic:iterate>

单纯的 JSP 代码:

<%

       ComponentActionForm[] components

= (ComponentActionForm[])request.getAttribute(“componentActionForms”);

              For(int i=0;i<components.length;i++) {

                     out.println(components[i].getComponent);

}

%>

可以预见,显示逻辑越复杂,用 Jakarta Struts 标签库构建的 JSP View 效率越高,结构也更清晰,构建和维护成本更低。详细代码请看附录 IssueDetail.jsp 代码。

l        可扩展性高

对于单纯的 JSP/ASP 代码构建的 View 而言,由于业务逻辑通常是在 JSP 页面完成的,所以当业务逻辑改变或扩展之后,相应的 View 也必须改变;如果业务逻辑是在多个页面完成的话,修改的成本更大,可扩展性更差。而用 Jakarta Struts 标签库构建的 View ,由于业务逻辑在相应的 Action 中完成,所以只需要修改相应的 Action 操作就可以了。尤其当 Action 复用程度比较高的时候,这种修改需要的工作量更小,而且 View 根本不需要修改,这种优势也是 MVC 设计模式 Model 和 View 的分离所带来的良好的可扩展性。

l        可重用性高

运用 Jakarta Struts 的 Logical 标签,可以构建高度可复用的 WebForm 。虽然单纯的 JSP/ASP 代码技术也可以实现,但由此所带来的构建、修改和维护成本将随着逻辑的复杂度增加而急剧增长。比如上文提到的,运用 Jakarta Struts 的 Logical 标签,我们很容易将 Issue 的创建、查看、修改、删除显示逻辑集中在一个 IssueDetail.jsp View 中完成。

l        可读性高,结构清晰

Jakarta Struts 标签和 HTML 代码很接近,不需要额外的用 <%%> 等标签包含起来,可读性更高。而 Jakarta Struts 标签集合了逻辑和流程控制,与 HTML 结合所构建的 JSP View 结构更清晰。下图为 HTML 中内嵌 JSP 代码和 Struts 标签的代码截图,可以看到,使用 Struts 标签的 View 结构更清晰,更易读。

14.jpg

图 14 HTML 中内嵌 JSP 代码

15.jpg

图15 HTML中内嵌Struts标签代码

posted on 2005-01-27 14:52 eamoi 阅读(3407) 评论(0)  编辑  收藏 所属分类: Java 、毕业设计文档