Spring的定义
对DI的初步理解
对AOP的初步理解
对DI的深入探究
对AOP的深入探究
Spring的事务管理
Spring MVC
先来谈谈一个web请求在Spring MVC中的流程。首先,第一个停留点是Spring的DispatcherServlet,它的工作就是查找每一个处理器(HandlerMapping)得到应该把该请求分发给哪一个控制器(controller);然后,它将会把请求分派给这个控制器,在该控制器中,完成业务逻辑;然后将model和视图等信息打包成一个ModelAndView对象并返回给DispatcherServlet;一旦DispatcherServlet得到ModelAndView,它就会要求一个视图解析器来查找实际的JSP文件;最后,找到实际的JSP之后,将模型提交给该页面执行渲染,流程结束。下面,我们将结合一个再简单不过的例子进行说明。首先就是配置DispatcherServlet,在web.xml文件中需要加入如下代码段:
<context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:roadrantz-services.xml classpath:roadrantz-data.xml </param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>roadrantz</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:roadrantz-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>roadrantz</servlet-name> <url-pattern>*.htm</url-pattern> </servlet-mapping>
上面这一段中,首先定义一个名字为roadrantz的servlet。该servlet会从xml文件中载入spring的应用上下文,xml文件的名字默认是servletName加上“-servlet.xml”,因此在本例中,它是“roadrantz-servlet.xml”。但是这里我们给出了显示的定义,这样更加清晰。并且我们声明了servlet-mapping,以处理一切以htm结尾的请求。
然而,在实际中,我们的应用都是分层的,各层有各层的配置文件。因此,为了载入其他各层的配置文件,我们需要定义一个“ContextLoaderListener”类型的listener。这个listener默认会去/WEB-INF/applicationContext.xml去寻找。但这样无法实现配置文件分层的目的,因此,我们需要显式的方式去替代它。这时就有了“context-param”标签下的内容。配置的过程大概就是这样,接下来我们要做的就是完成后台的代码。
public class HomePageController extends AbstractController {
protected ModelAndView handleRequestInternal(
HttpServletRequest request, HttpServletResponse response) throws Exception {
List recentRants = rantService.getRecentRants();
return new ModelAndView("home", "rants", recentRants);
}
// injected
private RantService rantService;
public void setRantService(RantService rantService) {
this.rantService = rantService;
}
}
这里的rantService是一个业务逻辑层的类,要依赖spring的注入。new ModelAndView("home", "rants", recentRants);这行代码中,第一个参数告诉视图解析器实际的view对象,第二个和第三个参数是一个键值对,即返回值。定义了该控制器之后,还要在DispatcherServlet(roadrantz-servlet.xml)中加入该控制器的配置,如下:
<bean name="/home.htm" class="com.roadrantz.mvc.HomePageController"> <property name="rantService" ref="rantService" /> </bean>
这里有几个地方需要说明。第一,这个bean没有id属性,只有name属性,是因为这里含有id属性的非法字符,即斜杠。第二,为什么使用这样的字符串作为name属性的值,因为这么做省去了上面说到的流程中的处理器查找控制器的这一环节。因为这个name属性值定义了URL的样式,即以“/home.htm”结尾的url请求都交由“HomePageController”来处理。之所以name属性值写成url样式的原因,是因为spring默认使用“BeanNameUrlHandlerMapping”这种处理器的方式进行映射。然而,现在控制器完成业务逻辑之后,还要显示出来才行,这就还需要一个视图解析器(更多种类型的视图解析器和处理器、控制器将在后面提到,这里只给出一个最基本流程的概况)。因此,我们需要在“roadrantz-servlet.xml”文件中追加这样一个bean的定义:
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/ " /> <property name="suffix" value=".jsp" /> </bean>
InternalResourceViewResolver类型的视图解析器是最简单的类型了。还记得上面代码返回的ModelAndView的第一个参数吗?是“home”,这个视图解析器就会在该值前面加上“/WEB-INF/jsp/”,后面加上“.jsp”,因此,经过该视图解析器之后,该视图解析器就会在这个路径下“/WEB-INF/jsp/home.jsp”查找视图,并返回客户端给予显示。
这样,一个最简单的spring MVC请求的流程就结束了。下面,我们将介绍流程中的每一个环节的部件。我们以处理器、控制器、视图解析器的顺序进行。在spring MVC中,常用的处理器一共有四种:BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping、
ControllerClassNameHandlerMapping、CommonsPathMapHandlerMapping。其中,
BeanNameUrlHandlerMapping在前面已经提到了。剩下三种,这里只着重讲一下SimpleUrlHandlerMapping这一种。
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/login.htm">loginController</prop> <prop key="/home.htm">homePageController</prop> <prop key="/error.htm">errorController</prop> <prop key="/addRant.htm">addRantController</prop> </props> </property> </bean>
这就是SimpleUrlHandlerMapping处理器的配置方式,相信读过之后大家就已经明白了。其中每一个prop标签的值都是一个bean的id。然而,在实际当中,只使用一种处理器是很难满足现状的。如果要使用多种处理器的话,又会有冲突,因为spring不知道要用哪一种处理器去解析,这时就需要在配置当中设置每个处理器的优先级。配置方法是在每个处理器的bean当中加入(其中,0代表的处理器的优先级最高):
<property name="order" value="0" />
至于控制器,也就是spring MVC的核心。在上面的例子当中的控制器是继承了AbstractController类的。而一般情况下,如果你需要的控制器比较简单,功能上类似一个servlet的话,用这个类就够了。当然你也可以重写一个控制器,但是要实现controller接口。spring内置的控制器有大约十种,这里就不一一举例了,大家用到时候可以去现学。
视图解析器,在spring当中就是一个实现了ViewResolver接口的bean。常用的视图解析器有前面提到的InternalResourceViewResolver,还有BeanNameViewResolver,如果你的项目的页面渲染是基于velocity实现的,还可以用VelocityViewResolver。这里也不详细举例了。