3、  减小Controler对页面地址的依赖 
在上面的Controler中,return new ModelAndView("WEB-INF/jsp/hello.jsp", "now", now);指出了jsp页面的绝对路径,这可以改变。 
首先在springapp-servlet.xml中增加一个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> 
然后把Controler的返回写为: 
return new ModelAndView("hello", "now", now); 
这样InternalResourceViewResolver在返回页面之前,会自动加上prefix和suffix。 
(。。。我不清楚这有什么用,如果我的路径除了/WEB-INF/jsp之外还有多个,那该怎么加呢?。。。看来只好都放到jsp下面了) 
  
4、  bean定义中把其属性定义成其他的bean 
在springapp-servlet.xml中,我们做出如下定义 
<beans> 
    <bean id="springappController" class="web.SpringappController"> 
        <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> 
  
</beans>        
  
有2点需要理解的: 
1、  可以直接利用<property name="price"><value>75.25</value></property>为bean的属性赋值,也可以用<property name="productManager"> <ref bean="prodMan"/> </property>将属性赋为另一个定义的bean。 
2、  这些被定义为属性的bean是在Web Module被加载时同时被加载的并且赋给属性的。一旦加载完成,就可以直接使用,因此没有必要在Class定义中为这些属性赋值(但必须有这些属性的setter定义)。比如按照上面的XML定义,我们把SpringappController写成这样: 
public class SpringappController implements Controller { 
    private ProductManager prodMan; 
  
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException { 
        Map myModel = new HashMap(); 
        myModel.put("products", getProductManager().getProducts()); 
  
        return new ModelAndView("hello", "model", myModel); 
    } 
  
    public void setProductManager(ProductManager pm) { 
        prodMan = pm; 
    } 
  
    public ProductManager getProductManager() { 
      return prodMan; 
    } 
} 
可以看到,没有为属性private ProductManager prodMan赋值,但定义了它的setter――setProductManager,这个setter在<bean id="springappController">被加载的时候自动调用了,以给prodMan赋上值。 
  
5、  单元测试 
在WEB应用开发中,我们习惯的测试方法是实际测试,即把WEB Module部署好了之后,用测试用例测试。这样效率很低,因为编译、打包、部署、测试的过程很费时间。 
Spring的思想是及早测试以发现问题。 
例子中,为测试SpringappController编写了测试程序: 
package tests; 
  
import java.util.Map; 
import java.util.List; 
import java.io.IOException; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import javax.servlet.ServletException; 
import junit.framework.TestCase; 
import org.springframework.context.ApplicationContext; 
import org.springframework.context.support.FileSystemXmlApplicationContext; 
import org.springframework.web.servlet.ModelAndView; 
import web.SpringappController; 
import bus.ProductManager; 
import bus.Product; 
  
public class TestSpringappController extends TestCase { 
  
    private ApplicationContext ac; 
  
    public void setUp() throws IOException { 
        ac = new FileSystemXmlApplicationContext("src/tests/WEB-INF/springapp-servlet.xml"); 
    } 
  
    public void testHandleRequest() throws ServletException, IOException { 
        SpringappController sc = (SpringappController) ac.getBean("springappController"); 
        ModelAndView mav = sc.handleRequest((HttpServletRequest) null, (HttpServletResponse) null); 
        Map m = mav.getModel(); 
        List pl = (List) ((Map) m.get("model")).get("products"); 
        Product p1 = (Product) pl.get(0); 
        assertEquals("Lamp", p1.getDescription()); 
        Product p2 = (Product) pl.get(1); 
        assertEquals("Table", p2.getDescription()); 
        Product p3 = (Product) pl.get(2); 
        assertEquals("Chair", p3.getDescription()); 
    } 
} 
测试类继承自junit.framework.TestCase。测试的时候,主要是测试controler产生的model对不对。当然在上面的例子中,测试没有多大的意义,因为model的产生太简单了。但是如果model产生的逻辑非常复杂,那这种测试是非常有意义的。 
  
注意上面例子中的 
    public void setUp() throws IOException { 
        ac = new FileSystemXmlApplicationContext ( "src/tests/WEB-INF/springapp-servlet.xml" ); 
    } 
它为controler创建了一个类似于app server的环境(bean的加载就是在这里完成的)  
 
  |