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的加载就是在这里完成的)