深入理解SpringMVC-基础篇

深入理解SpringMVC-基础

SpringMVC是一个轻量级的MVC框架,SpringMVC由于其轻量级的实现以及与Spring框架的无缝整合等诸多优势,近年来在MVC框架中脱颖而出,受到诸多开发人员的青睐,学习SpringMVC势在必行。

Web环境中使用SpringMVC:SpringMVC提供了可插拔式的框架嵌入形式,将SpirngMVC插入或者从Web项目中卸载只需要简单的修改配置文件即可。

  • 配置前端控制器,SpringMVC的入口程序为一个全局的Servlet,该Servlet拦截指定的一组请求交给SpringMVC框架执行后续的处理操作,在Web.xml中配置如下字段。

<!-- SpingMVC的前端控制器 -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置SpringMVC的IOC容器 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/root-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 配置拦截所有的请求 -->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping></span></span>

  • 创建SpringMVC IOC容器的配置文件root-context.xml并定义视图解析器,位置/WEB-INF/

<!-- 配置自动扫面的包 -->
<context:component-scan base-package="cn.com.xiaofen" />
<!-- 定义视图解析器 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- <mvc:default-servlet-handler /><mvc:annotation-driven /> --></span></span>

  • 定义控制器,SpringMVC中定义方法来响应客户端请求,内存开销更小效率更高。

@Controller
@RequestMapping("/T")
public class T {
@RequestMapping("/t_1")
public String t_1() {
System.out.println("t_1");
return "index";
}
}

  • 定义视图,根据实际的视图解析器完成相关视图的配置,当前配置视图应该在/WEB-INF/view/ 下且文件类型为JSP文件,具体的应该在该目录下新建一个名称为indexjsp文件名称。

 

SpringMVC处理请求的工作流:DispatcherServlet作为SpringMVC框架的入口程序,负责调度SpringMVC框架响应用户的请求,如下图为宏观上SpingMVC处理一次请求大概需要经过以下调度过程。

 

  1. 请求进入由前端控制器(DispatcherServlet )拦截。
  2. 前端控制器分析请求将请求委托至具体的控制器来处理。
  3. 控制器处理请求返回逻辑视图(Model)
  4. 前端控制器得到逻辑视图对象,调度视图解析器,解析视图模版给用户响应。
  5. 返回前端控制器。

SpringMVC请求流程(部分源码分析)DispatcherServletdoService()方法入手,篇幅关系,下文仅列出核心的代码,下文的代码并并保证时间上的顺序性。

  • DispatcherServlet 调用doDispatch处理请求。
try {
	/*逻辑视图及上文提到的Model*/
	ModelAndView mv = null;
	Exception dispatchException = null;
	try {
		/*文件上传预处理*/
		processedRequest = checkMultipart(request);
		multipartRequestParsed = (processedRequest != request);
		/*确定当前请求的处理者*/
		mappedHandler = getHandler(processedRequest);
		/*请求资源未发现*/
		if (mappedHandler == null || mappedHandler.getHandler() == null) {
			noHandlerFound(processedRequest, response);
			return;
		}
		/*确定当前请求的处理者适配器*/
		HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
		//...............
		/*请求调度前应用的拦截器*/
		if (!mappedHandler.applyPreHandle(processedRequest, response)) {
			return;
		}
		/*调用处理程序*/
		mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
		//......
		/*请求调度后应用的拦截器*/
		mappedHandler.applyPostHandle(processedRequest, response, mv);
	}
	catch (Exception ex) {
		dispatchException = ex;
	}
	/*解析视图给用户响应*/
	processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
  • 理解HandlerMapper,一个HandlerMapper代表一个请求到到处理对象的映射,该对象的创建依据是请求响应关系。getHandler方法部分源码分析如下。
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	遍历查找满足条件的HandlerMapping
	for (HandlerMapping hm : this.handlerMappings) {
		if (logger.isTraceEnabled()) {
			logger.trace(
					"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
		}
		HandlerExecutionChain handler = hm.getHandler(request);
		if (handler != null) {
			存在
			return handler;
		}
	}
	不存在
	return null;
}

  • 理解HandlerAapter,SpringMVC 中通过HandlerAdapter的handler方法来调用实际的处理请求的函数。getHandlerAapter 部分源码如下。
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
	for (HandlerAdapter ha : this.handlerAdapters) {
		if (logger.isTraceEnabled()) {
			logger.trace("Testing handler adapter [" + ha + "]");
		}
		是否支持处理当前的HandlerMapper
		if (ha.supports(handler)) {
			return ha;
		}
	}
	当前的HandlerMapper不能被处理报异常
	throw new ServletException("No adapter for handler [" + handler +
			"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
  • Model到视图,SpringMVC 中ModelAndView保存了逻辑视图与真实视图的关系,确定了当前请求为用户返回的View,processDispatchResult 源码分析如下。
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
		HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {

	boolean errorView = false;

	/*处理异常信息*/
	if (exception != null) {
		if (exception instanceof ModelAndViewDefiningException) {
			logger.debug("ModelAndViewDefiningException encountered", exception);
			mv = ((ModelAndViewDefiningException) exception).getModelAndView();
		}
		else {
			Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
			mv = processHandlerException(request, response, handler, exception);
			errorView = (mv != null);
		}
	}

	/*渲染视图,返回响应*/
	if (mv != null && !mv.wasCleared()) {
		render(mv, request, response);
		if (errorView) {
			WebUtils.clearErrorRequestAttributes(request);
		}
	}
	else {
		if (logger.isDebugEnabled()) {
			logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
					"': assuming HandlerAdapter completed request handling");
		}
	}
}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值