现在我们还要给web.xml添加一个<taglib>条目。
WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC '-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN' 'http://java.sun.com/dtd/web-app_2_3.dtd'>
 
<web-app>
    <servlet>
    <servlet-name>springapp</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
 
  <servlet-mapping>
    <servlet-name>springapp</servlet-name>
    <url-pattern>*.htm</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>
      index.jsp
    </welcome-file>
  </welcome-file-list>
  <taglib>
    <taglib-uri>/spring</taglib-uri>
    <taglib-location>/WEB-INF/spring.tld</taglib-location>
  </taglib>
</web-app>我们还需要在jsp文件的page指令中申明这个taglib。我们用普通的方法通过<form>标签声明一个表单,以及一个<input>文本域和一个提交按钮。WEB-INF/jsp/priceincrease.jsp
<%@ include file="/WEB-INF/jsp/include.jsp" %>
<%@ taglib prefix="spring" uri="/spring" %>
 
<html>
<head><title><fmt:message key="title"/></title></head>
<body>
<h1><fmt:message key="priceincrease.heading"/></h1>
<form method="post">
  <table width="95%" bgcolor="f8f8ff" border="0" cellspacing="0" cellpadding="5">
    <tr>
      <td alignment="right" width="20%">Increase (%):</td>
      <spring:bind path="priceIncrease.percentage">
        <td width="20%">
          <input type="text" name="percentage" value="<c:out value="${status.value}"/>">
        </td>
        <td width="60%">
          <font color="red"><c:out value="${status.errorMessage}"/></font>
        </td>
      </spring:bind>
    </tr>
  </table>
  <br>
  <spring:hasBindErrors name="priceIncrease">
    <b>Please fix all errors!</b>
  </spring:hasBindErrors>
  <br><br>
  <input type="submit" alignment="center" value="Execute">
</form>
<a href="<c:url value="hello.htm"/>">Home</a>
</body>
</html>
<spring:bind>标记是用于将一个<input>表单元素绑定到一个命令对象PriceIncrease.java上的。这个命令对象以后会被传送给效验器,同时如果它通过了检验,它会被继续传送给控制器。${status.errorMessage}和${status.value}是由框架声明的特殊变量,可以用来显示错误信息和当前域的值。
bus/PriceIncrease.java
package bus;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
 
public class PriceIncrease {
 
    /** Logger for this class and subclasses */
 
    protected final Log logger = LogFactory.getLog(getClass());
 
    private int percentage;
 
    public void setPercentage(int i) {
        percentage = i;
        logger.info("Percentage set to " + i);
    }
 
    public int getPercentage() {
        return percentage;
    }
 
}这是一个十分简单的JavaBean类,同时这里有一个属性以及他的获取器和设置器。在用户按下了提交按钮之后,Validator类将获取控制。在表单中输入的值会被框架设置在命令对象上。然后会调用方法validate,并传入命令对象和一个用来存放错误信息的对象。
bus/PriceIncreaseValidator.java
package bus;
 
import java.io.Serializable;
import org.springframework.validation.Validator;
import org.springframework.validation.Errors;
 
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
 
public class PriceIncreaseValidator implements Validator {
    private int DEFAULT_MIN_PERCENTAGE = 0;
    private int DEFAULT_MAX_PERCENTAGE = 50;
    private int minPercentage = DEFAULT_MIN_PERCENTAGE;
    private int maxPercentage = DEFAULT_MAX_PERCENTAGE;
 
    /** Logger for this class and subclasses */
 
    protected final Log logger = LogFactory.getLog(getClass());
 
    public boolean supports(Class clazz) {
        return clazz.equals(PriceIncrease.class);
    }
 
    public void validate(Object obj, Errors errors) {
        PriceIncrease pi = (PriceIncrease) obj;
 
        if (pi == null) {
            errors.rejectValue("percentage", "error.not-specified", null, "Value required.");
        }
        else {
            logger.info("Validating with " + pi + ": " + pi.getPercentage());
 
            if (pi.getPercentage() > maxPercentage) {
                errors.rejectValue("percentage", "error.too-high",
                    new Object[] {new Integer(maxPercentage)}, "Value too high.");
            }
 
            if (pi.getPercentage() <= minPercentage) {
                errors.rejectValue("percentage", "error.too-low",
                    new Object[] {new Integer(minPercentage)}, "Value too low.");
            }
        }
    }
  
 
    public void setMinPercentage(int i) {
        minPercentage = i;
    }
 
    public int getMinPercentage() {
        return minPercentage;
    }
    public void setMaxPercentage(int i) {
        maxPercentage = i;
    }
    public int getMaxPercentage() {
        return maxPercentage;
    }
}

解决方案 »

  1.   

    现在我们要在springapp-servlet.xml文件中添加一条内容来定义新的表单和控制器。我们定义命令对象和效验器的属性。我们还要指明两个视图,一个用来显示表单,另一个将是在成功的表单处理之后我们将看到的。后一个也叫做成功视图,可以是两种类型之一:它可以是一个普通的视图引用直接引导到我们某个JSP页面。但这种方法的一个缺点是,如果用户刷新页面,那么表单的数据就会被重新提交,然后你可能最后就做了两次priceIncreace。另一种方法是使用一个重定向,它将给用户浏览器返回一个应答并且指示浏览器重定向到一个新的URL。我们这里使用的这个URL不可以是我们的JSP页面之一,因为他们对于直接访问是不可见的。必须一个从外部可以获取的URL。所以我选择了“hello.htm”来作为我的重定向URL。这个URL影射到“hello.jsp”页面,这个应该运行得很令人满意。WEB-INF/springapp-servlet.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
     "http://www.springframework.org/dtd/spring-beans.dtd">
     
    <!--
      - Application context definition for "springapp" DispatcherServlet.
      -->
     
    <beans>
        <!--  Controller for the initial "Hello" page -->
        <bean id="springappController" class="web.SpringappController">
            <property name="productManager">
                <ref bean="prodMan"/>
            </property>
        </bean>
     
        <!--  Validator and Form Controller for the "Price Increase" page -->
        <bean id="priceIncreaseValidator" class="bus.PriceIncreaseValidator"/>
        <bean id="priceIncreaseForm" class="web.PriceIncreaseFormController">
            <property name="sessionForm"><value>true</value></property>
            <property name="commandName"><value>priceIncrease</value></property>
            <property name="commandClass"><value>bus.PriceIncrease</value></property>
            <property name="validator"><ref bean="priceIncreaseValidator"/></property>
            <property name="formView"><value>priceincrease</value></property>
            <property name="successView"><value>hello.htm</value></property>
            <property name="productManager">
                <ref bean="prodMan"/>
            </property>
        </bean>
     
        <bean id="prodMan" class="bus.ProductManager">
            <property name="products">
                <list>
                    <ref bean="product1"/>
                    <ref bean="product2"/>
                    <ref bean="product3"/>
                </list>
            </property>
        </bean>
        <bean id="product1" class="bus.Product">
            <property name="description"><value>Lamp</value></property>
            <property name="price"><value>5.75</value></property>
        </bean>
     
        <bean id="product2" class="bus.Product">
            <property name="description"><value>Table</value></property>
            <property name="price"><value>75.25</value></property>
        </bean>
     
        <bean id="product3" class="bus.Product">
            <property name="description"><value>Chair</value></property>
            <property name="price"><value>22.79</value></property>
        </bean>
     
        <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
            <property name="basename"><value>messages</value></property>
        </bean>
     
        <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
            <property name="mappings">
                <props>
                    <prop key="/hello.htm">springappController</prop>
                    <prop key="/priceincrease.htm">priceIncreaseForm</prop>
                </props>
            </property>
        </bean>
     
        <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="viewClass">
               <value>org.springframework.web.servlet.view.JstlView</value>
            </property>
            <property name="prefix"><value>/WEB-INF/jsp/</value></property>
            <property name="suffix"><value>.jsp</value></property>
        </bean>
    </beans>下面,让我们看一下这个表单的控制器。onSubmit方法获取了控制并且在它调用ProductManager对象的increasePrice方法之前进行了一些日志记录。然后它使用successView的url创建了RedirectView的一个新的实例,并传递这个实例给ModelAndView,最后返回这个ModelAndView的实例。
    web/PriceIncreaseFormController.java
    package web;
     
    import org.springframework.web.servlet.mvc.SimpleFormController;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.view.RedirectView;
     
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
     
    import java.io.IOException;
    import java.util.Map;
    import java.util.HashMap;
     
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
     
    import bus.Product;
    import bus.ProductManager;
    import bus.PriceIncrease;
     
    public class PriceIncreaseFormController extends SimpleFormController {
     
        /** Logger for this class and subclasses */
     
        protected final Log logger = LogFactory.getLog(getClass());
     
    private ProductManager prodMan;
     
    public ModelAndView onSubmit(Object command)
                throws ServletException {
     
            int increase = ((PriceIncrease) command).getPercentage();
            logger.info("Increasing prices by " + increase + "%.");
     
            prodMan.increasePrice(increase);
            String now = (new java.util.Date()).toString();
            logger.info("returning from PriceIncreaseForm view to " + getSuccessView() +
                        " with " + now);
     
            Map myModel = new HashMap();
            myModel.put("now", now);
            myModel.put("products", getProductManager().getProducts());
     
            return new ModelAndView(new RedirectView(getSuccessView()));
     
        }
     
        protected Object formBackingObject(HttpServletRequest request) throws ServletException {
     
            PriceIncrease priceIncrease = new PriceIncrease();
            priceIncrease.setPercentage(20);
     
            return priceIncrease;
        }
      
        public void setProductManager(ProductManager pm) {
            prodMan = pm;
        }
      
        public ProductManager getProductManager() {
            return prodMan;
        }
      
    }我们还要在message.properties资源文件里面添加一些消息。WEB-INF/classes/messages.properties
    title=SpringApp
     
    heading=Hello :: SpringApp
     
    greeting=Greetings, it is now
     
    priceincrease.heading=Price Increase :: SpringApp
    error.not-specified=Percentage not specified!!!
    error.too-low=You have to specify a percentage higher than {0}!
    error.too-high=Don't be greedy - you can't raise prices by more than {0}%!
    required=Entry required.
    typeMismatch=Invalid data.
    typeMismatch.percentage=That is not a number!!!最后,我们要从hello.jsp中提供一个指向priceincrease页面的链接。
    WEB-INF/jsp/hello.jsp
    <%@ include file="/WEB-INF/jsp/include.jsp" %>
      
    <html>
    <head><title><fmt:message key="title"/></title></head>
    <body>
    <h1><fmt:message key="heading"/></h1>
    <p><fmt:message key="greeting"/> <c:out value="${model.now}"/>
    </p>
    <h3>Products</h3>
    <c:forEach items="${model.products}" var="prod">
      <c:out value="${prod.description}"/> <i>$<c:out value="${prod.price}"/></i><br><br>
    </c:forEach>
      <br>
    <a href="<c:url value="priceincrease.htm"/>">Increase Prices</a>
    <br>
    </body>
    </html>编译并运行,在重新载入应用之后,我们就可以再测试它了。下面是表单出错时所显示的样子:
    注意:priceincrease.htm在提交的时候是通过spring在web.xml中定义的映射规则来进行的,不是通过form的action动作来提交请求。