ITEEDU

Struts Gossip: 第一个 Struts 程序

使用Struts来撰写一个基于 MVC 架构的Web程序是简单的,以下用一个简单的实例来示范如何使用Struts,您也可以从中了解到具体的MVC工作流程。

首先请至 Struts 官方网站 下载Struts,这边下载的是jakarta-struts-1.2.4.zip,解开后您可以在lib目录下找到struts.jar以及一些相依的 jar文件 ,对于第一个Struts程序来说,您需要以下的jar档,请将这些档案复制至您的Web应用程序的/WEB-INF/lib目录下:
  • struts.jar
  • commons-beanutils.jar
  • commons-digester.jar
  • commons-collections.jar
  • commons-logging.jar
值得一提的是,在Struts的下载档案中,/webapps目录是一些Struts的范例,将来您可以参考这些范例中的一些设定与设计方式来开发程序, 其中struts-blank.war是一个开发Struts的基础,具备了Struts的基础设定档案及设定,您可以用它来开速开发Web应用程序。

在Struts中,担任Controller角色的是ActionServlet,理想上所有客户端请求都透过它来完成转发,必须在/WEB- INF/web.xml中设定:
web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    version="2.4">
 <!-- 注意,xsi那行是沒換行的,排版關係才作了換行 -->
 <!-- 如果您是直接拷貝這個設定,請自行接上該行 -->
    <description>
        Struts Web Application
    </description>

    <display-name>Struts Web Application</display-name>

    <!-- Standard Action Servlet Configuration -->
    <servlet>
        <servlet-name>action</servlet-name>
        <servlet-class>
            org.apache.struts.action.ActionServlet
        </servlet-class>
        <init-param>
            <param-name>config</param-name>
            <param-value>
                /WEB-INF/conf/struts-config.xml
            </param-value>
        </init-param>
        <load-on-startup>2</load-on-startup>
    </servlet>

    <!-- Standard Action Servlet Mapping -->
    <servlet-mapping>
        <servlet-name>action</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

</web-app>
org.apache.struts.action.ActionServlet的设定中,设定config参数的作用是设定struts-config.xml的档案来源,struts-config.xml中包括了所有Struts的相关请求转发,以及一些资源设定。

在ActionServlet的servlet-mapping设定中,将所有以*.do结尾的请求交给ActionServlet来处理。

接下来看看struts-config.xml的设定:
struts-config.xml
<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE struts-config PUBLIC
 "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
 "http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd">
 <struts-config>
    <action-mappings>
        <action
            path="/hello"
            type="onlyfun.caterpillar.HelloAction">
            <forward
                name="helloUser"
                path="/WEB-INF/pages/hello.jsp"/>
        </action>
    </action-mappings>
</struts-config>
在struts-config.xml中,定义了<action-mappings>,这当中关系到请求与资源的转发设定对应,< action>中设定了path为/hello,这表示请求的资源若是/hello.do,则会呼叫HelloAction 来处理这个请求(type属性设定的),<forward>设定则是HelloAction处理完毕之后的转发对象,一个< action>中可以有多个 <forward>,在Action对象中将根据<forward>上的name来查找并返回对应的ActionForward 对象,ActionServlet会根据 Action 传回的ActionForward来将请求转发至指定的对象。

来看看HelloAction,在Struts中,一个Action对象必须继承org.apache.struts.action.Action,并覆写其execute()方法,看看HelloAction是如何撰写的:
HelloAction.java
package onlyfun.caterpillar;

import java.util.*;
import javax.servlet.http.*;
import org.apache.struts.action.*;

public class HelloAction extends Action {
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {

// get information from request object
String username = request.getParameter("user");

// prepare model
Map model = new HashMap();
if(username != null)
model.put("username", username);
else
model.put("username", "nobody");

// pass information to View by using reqeust object
request.setAttribute("userInfo", model);

return mapping.findForward("helloUser");
}
}
这边先关心一些execute()中传入的request与response,而暂不理会另两个参数,request与 response是HttpServletRequest及HttpServletResponse的实例,就如何在一个简单的Servlet一样,您可 以使用这两个对象来分别取得请求与响应的相关资源。

Action对象是Controller的一部份,如您在程序中所看到的,在Action对象中,您所要作的是:
  • 取得请求中的相关参数
  • 验证数据的逻辑正确性
  • 将请求参数复制给商务对象
  • 取得执行结果并准备结果
  • 转发给View物件

第一个Struts程序很简单,所以暂且没有使用到商务对象,在真正的程序中,您会使用到业务对象(Model)来处理业务,而您的Action中之逻辑应该只包括请求信息的收集、转交业务请求给业务对象、准备View所需要的数据等有关。

在View所需要的对象准备上,程序中使用了Map对象,在实际的程序中,您可以设计自己的数据Model对象。您可以看到,Struts会使用标准 JSP/Servlet相关对象的setAttribute()与getAttribute()方法来向View传递Model,在程序中使用的是 request物件的setAttribute()。

在Web MVC中,使用者的请求相关信息就到Action中就要结束了,所有的相关讯息必须复制为数据传输对象再设定给业务对象,而不是直接将请求相关对象或讯息 直接传递至业务层,这样作可以使得Web层不会与接下来的业务层紧密耦合。另一方面,View层的数据要透过数据Model对象来取得,而不是直接从使用 者的请求物件中获得。

在execute()方法中传入的ActionMapping对象,代表了struts-config.xml中<action- mappings>的设定对象,findForward()方法会寻找指定的forward资源name名称,如果找到,就传回一个 ActionForward对象,当中包括了转发的目的对象,目的地即path属性设定的路径。

回顾一下struts-config.xml,注意到"helloUser"的forward目的地是/WEB- INF/pages/hello.jsp,将资源放在/WEB-INF目录下,使用者就只能透过Controller的转发来取得资源,这是一个较具安全 性的作法。

hello.jsp如下:
hello.jsp
<html> 
<head>
<title>Hello, ${userInfo["username"]} !</title>
</head>
<body>
<H1>Hello, ${userInfo["username"]} !</H1>
</body>
</html>
在这边先使用JSP 2.0所提供的Express Language新功能来取得设定于request中的Model对象之数据,Struts提供有一组可以与其配合的标签库(Tag Library),如果您的View层技术使用的是JSP资源,也可以善加利用。

来检验一下第一个Struts的成果,启动您的Servlet Container,并在浏览器输入:
http://localhost:8080/strutsapp/hello.do?user=Justin
您将会得到以下的内容:
<html> 
<head> 
<title>Hello, Justin !</title> 
</head> 
<body>
    <H1>Hello, Justin !</H1></body> 
</html>