Spring: A Developer's Notebook笔记和小结(10)

/**
作者:Willpower
来源:Rifoo Technology(
http://www.rifoo.com
时间:2006-01-15
备注:转载请保留以上声明
**/

今天,请大家跟我一起看看在Spring中如何使用Struts。其实Struts是一个标准的MVC框架,我们要配置一个中心分发器(dispatcher),这个分发器会将请求发送给控制器,控制器响应action中的form调用相关后台方法完成转发页面。

首先,我们来配置Struts,需要做到两点:在web.xml中配置中心分发器,在struts-config.xml中配置Struts控制器。

Example 3-1. web.xml
<!DOCTYPE web-app
  PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
  "
http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">

<web-app>

  <display-name>RentABike</display-name>
  <description>
    Renting bikes for fun and profit.
  </description>

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
      /WEB-INF/rentABikeApp-servlet.xml
    </param-value>
  </context-param>

 
<servlet>
    <servlet-name>SpringContext</servlet-name>
    <servlet-class>
      org.springframework.web.context.ContextLoaderServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet>
    <servlet-name>RentABike</servlet-name>
    <servlet-class>
      org.apache.struts.action.ActionServlet
    </servlet-class>
    <init-param>
      <param-name>config</param-name>
      <param-value>/WEB-INF/struts-config.xml</param-value>
    </init-param>
    <init-param>
      <param-name>validate</param-name>
      <param-value>true</param-value>12
    </init-param>
    <load-on-startup>2</load-on-startup>
  </servlet>


  <servlet-mapping>
    <servlet-name>RentABike</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>


  <welcome-file-list>
    <welcome-file>
        start.html
    </welcome-file>
  </welcome-file-list>

  <context-param>
    <param-name>log4jConfigLocation</param-name>
    <param-value>/WEB-INF/log4j.properties</param-value>
  </context-param>

  <listener>
    <listener-class>
        org.springframework.web.util.Log4jConfigListener
    </listener-class>
  </listener>

  <taglib>
    <taglib-uri>/spring</taglib-uri>
    <taglib-location>/WEB-INF/spring.tld</taglib-location>
  </taglib>

  <taglib>
    <taglib-uri>
http://java.sun.com/jstl/core</taglib-uri>
    <taglib-location>/WEB-INF/c.tld</taglib-location>
  </taglib>

  <taglib>
    <taglib-uri>/struts</taglib-uri>
    <taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
  </taglib>


  <listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
  </listener>

</web-app>


如果你以前对Struts很熟悉,那么这里其实没有什么新的东西。我们配置了两个servlet(代码中蓝色高亮的部分),一个用来加载Spring上下文,一个用来加载Struts。<load-on-startup>指定了它们加载的顺序,我们从代码中可以看到目前配置的是先加载Spring,在加载Struts。这里,我们首先加载Spring的原因是这里Struts要依赖Spring创建的RentABike对象,该对象在Struts加载时会用到。下面的紫色部分是jsp需要用到的标签库。我们也配置了servlet-mapping来将所有后缀名为.do的请求都提交到Struts的ActionServlet(代码中红色部分)。

接下来,我们配置action和actionform的映射信息。

Example 3-2. 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>

  <form-beans>
    <form-bean name="EditBikeForm"
          type="com.springbook.forms.EditBikeForm"/>
  </form-beans>


  <action-mappings>

    <action path="/bikes"
          type="org.apache.struts.actions.ForwardAction"
          parameter="/bikes.jsp"/>

    <action path="/editBike"
          type="org.apache.struts.actions.ForwardAction"
          parameter="/editBike.jsp"/>

    <action path="/submitBike"
          type="com.springbook.actions.SubmitBikeAction"
          name="EditBikeForm"
          scope="request"
          validate="true"
          input="/editBike.jsp">


          <display-name>Submit Bike</display-name>

          <forward name="success" path="/bikes.jsp"/>
          <forward name="failure" path="/editBike.jsp"/>

    </action>

  </action-mappings>

</struts-config>


这里定义了actionform bean和action的相关映射信息,这里定义了EditBikeForm用来保存山地车编辑页面的属性。SubmitBikeAction用来处理山地车编辑页面所提交后的表单。

以下是RentABike接口的实现类ArrayListRentABike.java的代码,它相当于一个facade,用作向action隐藏后台数据层的具体操作:

Example 3-3. ArrayListRentABike.java
public class ArrayListRentABike implements RentABike {
  private String storeName;
  final List bikes = new ArrayList( );

  public void saveBike(Bike bike) {
    if(bikes.contains(bike)) bikes.remove(bike);
    bikes.add(bike);
  }

  public void deleteBike(Bike bike) {
    bikes.remove(bike);
  }

  public ArrayListRentABike( ) {
    initBikes( );
  }

  public ArrayListRentABike (String storeName) {
    this.storeName = storeName;
    initBikes( );
  }

  private void initBikes( ) {
    bikes.add(new Bike(1, "Shimano",
      "Roadmaster", 20, "11111", 15, "Fair"));
    bikes.add(new Bike(2, "Cannondale",
      "F2000 XTR", 18, "22222",12, "Excellent"));
    bikes.add(new Bike(3, "Trek",
      "6000", 19, "33333", 12.4, "Fair"));
  }

  public String toString( ) {
    return "com.springbook.ArrayListRentABike: " + storeName;
  }

  public String getStoreName( ) {
    return storeName;
  }

  public void setStoreName(String storeName) {
    this.storeName = storeName;
  }

  public List getBikes( ) {
    return bikes;
  }

  public Bike getBike(String serialNo) {
    Iterator iter = bikes.iterator( );
    while(iter.hasNext( )) {
        Bike bike = (Bike)iter.next( );
        if(serialNo.equals(bike.getSerialNo( ))) return bike;
    }
    return null;
  }

  public Bike getBike(int bikeId) {
    if(bikeId > bikes.size( )) return null;
    return (Bike)bikes.get(bikeId);
  }

  //etc...
}


每个action有可能会调用这个facade去和后台数据进行操作。我们编写一个BaseAction,它继承Struts的Action类,负责从Spring上下文中去获得RentABike的一个对象实例(依赖注入思想)。

Example 3-4. BaseAction.java
public abstract class BaseAction extends Action {

  private RentABike rentABike;

  public void setServlet(ActionServlet actionServlet) {
    super.setServlet(actionServlet);
    ServletContext servletContext = actionServlet.getServletContext( );
    WebApplicationContext wac =    
      WebApplicationContextUtils.
        getRequiredWebApplicationContext(servletContext);
    this.rentABike = (RentABike) wac.getBean("RentABike");

  }

  protected RentABIke getRentABike( ) {
    return rentABike;
  }

  // 放置其他相关的实用方法在后面。。。

}


还记得我们已经在Spring加载的上下文文件rentaBike-Servlet.xml中定义过rentaBike这个bean吧,我们可以在未来可能会更改这个facade类而实现不同的后台操作,这样不用修改代码,实现了依赖注入。

Example 3-5. rentaBike-Servlet.xml
<beans>
  <bean id="rentaBike" class="com.springbook.ArrayListRentABike">
    <property name="storeName"><value>Bruce's Bikes</value></property>
  </bean>

  <!-- etc. -->
</beans>


然后我们所有的action都继承这个BaseAction,这样我们都可以实现Spring的依赖注入了。
Example 3-6. SubmitBikeAction.java
public class SubmitBikeAction extends BaseAction {

  public SubmitBikeAction( ) {
    super( );
  }

  public ActionForward execute(
    ActionMapping mapping,
    ActionForm form,
    HttpServletRequest request,
    HttpServletResponse response)
    throws java.lang.Exception {

    EditBikeForm editBikeForm = (EditBikeForm) form;

    Bike bike = new Bike( );
    bike.setManufacturer(editBikeForm.getManufacturer( ));
    bike.setModel(editBikeForm.getModel( ));
    bike.setFrame(editBikeForm.getFrame( ));
    bike.setSerialNo(editBikeForm.getSerialNo( ));
    bike.setWeight(editBikeForm.getWeight( ));

    try {
      //调用facade实现数据的保存
        this.rentABike.saveBike(bike);

        return mapping.findForward("success");
    } catch (Exception ex) {
        return mapping.findForward("failure");
    }

  }
}


接着,我们使用Struts标签来实现EditBike.jsp页面的编写:
Example 3-7. EditBike.jsp
<%@ page import="com.springbook.*"%>
<%@ include file="include.jsp" %>
<%@ taglib prefix="spring" uri="/spring" %>
<%@ taglib uri="/WEB-INF/struts-html-el.tld" prefix="html-el" %>

<html>
  <head>
    <title>
        Edit Bike
    </title>
  </head>
  <body>
    <h1>Edit Bike</h1>
    <form method="POST">
        <table border="1" cellspacing="2" cellpadding="2">
          <tr>
            <td align="right">Manufacturer:</td>
            <td>
                <html-el:text property="manufacturer" size="25"
                maxlength="50" styleClass="textBox" tabindex="1" />

            </td>
          </tr>
          <tr>
            <td align="right">Model:</td>
            <td>
                <html-el:text property="model" size="25"
                maxlength="50" styleClass="textBox" tabindex="1" />

            </td>
          </tr>
          <tr>
            <td align="right">Frame:</td>
            <td>
                <html-el:text property="frame" size="25"
                maxlength="50" styleClass="textBox" tabindex="1" />

            </td>
          </tr>
          <tr>
            <td align="right">Serial Number:</td>
            <td>
                <html-el:text property="serialNo" size="25"
                maxlength="50" styleClass="textBox" tabindex="1" />

            </td>
          </tr>
          <tr>
            <td align="right">Weight:</td>
            <td>
              <html-el:text property="weight" size="25"
                maxlength="50" styleClass="textBox" tabindex="1" />

            </td>
          </tr>
          <tr>
            <td align="right">Status:</td>
            <td>
                <html-el:text property="status" size="25"
                maxlength="50" styleClass="textBox" tabindex="1" />

            </td>
          </tr>
        </table>
        <html-el:submit styleClass="normal">
          Submit Bike
        </html-el:submit>

    </form>
  </body>
</html>


这个文件没什么特别的,都是标准的Struts标签。这里书中用的是struts-html-el标签而不是原始的struts-html标签,它只是可以将JSTL表达式用作Struts标签的属性值。如果你愿意,你仍旧可以使用原始的struts-html标签或其他的标签库。大家注意一下红色部分:为什么这里没有写form提交的action却还能成功提交呢?是因为我们在前面已经将这个editBike.jsp指向了EditBikeForm。

最后,我们来看看传递到action中的EditBikeForm是如何写的:

Example 3-8. EditBikeForm.java
public class EditBikeForm extends ActionForm {
 
  private String manufacturer;
  private String model;
  private int frame;
  private String serialNo;
  private double weight;
  private String status;
 
  public void reset(ActionMapping mapping, HttpServletRequest request) {
    manufacturer = null;
    model = null;
    frame = 0;
    serialNo = null;
    weight = 0.0;
    status = null;
  }

  public ActionErrors validate(
    ActionMapping mapping,
    HttpServletRequest request) {
    ActionErrors errors = new ActionErrors( );

    String mappingName = mapping.getPath( );

    if (mappingName.equalsIgnoreCase("/SubmitBike")) {
        if (manufacturer == null
          || manufacturer.trim( ).length( ) == 0) {
          errors.add(
            "bike",
            new ActionError("error.manufacturer.required));
        }

        if (model == null
          || model.trim( ).length( ) == 0) {
          errors.add(
            "bike",
            new ActionError("error.mo del.required"));
        }
    }

    return errors;
  }

 
  public EditBikeForm( ) {
    super( );
  }

  public void setManufacturer(String manufacturer) {
    this.manufacturer = manufacturer;
  }

  public String getManufacturer( ) {
    return manufacturer;
  }

  public void setModel(String model) {
    this.model = model;
  }

  public String getModel( ) {
    return model;
  }

  public void setFrame(int frame) {
    this.frame = frame;
  }

  public int getFrame( ) {
    return frame;
  }

  public void setSerialNo(String serialNo) {
    this.serialNo = serialNo;
  }

  public String setSerialNo( ) {
    return serialNo;
  }

  public void setWeight(Double weight) {
    this.weight = weight;
  }

  public Double getWeight( ) {
    return weight;
  }

  public void setStatus(String status) {
    this.status = status;
  }

  public String getStatus( ) {
    return status;
  }

}


现在,所有编码已完成,我们接下来写一个简单的测试程序来测试form中的validate方法。
Example 3-9. StrutsTest.java
public void testBikeValidation( ) throws Exception {
  //创建一个ActionMapping
  ActionMapping mapping = new ActionMapping( );
  mapping.setPath("/SubmitBike");
  //创建一个EditBikeForm
  EditBikeForm ebf = new EditBikeForm( );
  ebf.setManufacturer("a manufacturer");
  ebf.setModel("a model");
  ActionErrors errors = ebf.validate(mapping, null);
  assertEquals(0, errors.size( ));
  ebf = new EditBikeForm( );
  ebf.setManufacturer("a manufacturer");
  ebf.setModel("");
  //调用EditBikeForm中的validate方法
  errors = ebf.validate(mapping, null);
  assertEquals(1, errors.size( ));
}


要学习更多复杂的Actions和ActionMappings,大家可以参考这篇文章:
http://www.onjava.com/pub/a/onjava/2004/09/22/test-struts.html

下图是一个Struts应用程序流程图:



在本篇学习中,我们看到,在应用中Spring初始化对象并以属性的形式注入依赖。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值