Spring MVC简介

1、Spring MVC是什么?

         spring mvc是基于java实现了Web MVC设计模式的的轻量级框架,即使用了MVC的思想,讲web层进行解耦,使用请求->相应模型的请求驱动类型。    

        spring mvc的前端控制器是dispatcherServlet,应用控制器分为处理器映射器(handler mapping)、   处理器适配(handler adapter)和视图解析器(view resolver),页面控制器controller(仅包含ModelAndView handleRequest(request,response)方法)的实现;支持本地化(AcceptHeaderLocaleResolver、cookieLocaleResolver、sessionLocaleResolver、LocaleChangeInterceptor);提供了非常灵活的数据绑定、认证、格式化机制。

2、Spring MVC能帮我们做什么?

        简洁的web层;

        强大的数据绑定,验证;

        跟spring天生的无缝集成,ioc,aop等;

        能够容易的整合视图技术,如velocity,freemarker等,因为数据模型model、modelMap都是map;

        灵活的URL映射,相对于strust2来说;

        静态资源的访问控制;

        支持restful风格;

3、spring mvc的请求流程

        1、用户发送请求,前端控制器dispatcherServlet接收请求,执行doServie方法,加载一些request初始化参数,然后调用dispatch方法,优先判断request是不是上传文件的请求,如果是,讲调用multipartResolver来处理该请求;

        2、如果不是,根据URL找到对应的映射,执行getHandler方法,返回对应的handlerExecutionChain,找不到则报错,No  Mapping  found  for HTTP request with URI   XXX;

        3、找到对应的handler之后,接着调用getHandlerAdapter方法,返回适配该handler的adapter;

        4、HandlerExecutionChain执行applyPreHandle,即执行Interceptor的preHandle方法,根据preHandle的返回值来判断是够要执行interceptor.afterCompletion()方法;

        5、由适配器去执行adapter.handle()方法,来返回视图modelAndView(数据模型和逻辑视图名),

        6、如果modelAndView存在,则调用processDispatchResult方法去操作返回的mv,如果不出现异常,则执行render方法渲染视图;

        7、响应response,操作结束;

4、java代码

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
                //步骤1、检测是否是上传文件,如果是,则通过MultipartResolver解析
				processedRequest = checkMultipart(request);
				multipartRequestParsed = processedRequest != request;

//步骤2、请求到处理器的映射,通过handlerMapping进行映射,返回HandlerExecutionChain (一个handler,多个Interceptor),通过这种策略模式很容易增加别的策略
				mappedHandler = getHandler(processedRequest, false);
                //如果不存在,则抛出No Mapping 
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				//步骤3、将handler包装成处理器适配器
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// 判断请求类型 get  post
				String method = request.getMethod();
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (logger.isDebugEnabled()) {
						logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				try {
					// 步骤4、适配器执行handler,返回相应的modelAndView
					mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
				}
				finally {
					if (asyncManager.isConcurrentHandlingStarted()) {
						return;
					}
				}
               //如果viewName不存在,加载默认的
				applyDefaultViewName(request, mv);
               //执行post请求的preHandle
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
            //步骤5、详细见下边代码,处理mv,包含exception,errorview,当不存在异常的情况,执行render方法渲染视图
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Error err) {
			triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				return;
			}
			// Clean up any resources used by a multipart request.
			if (multipartRequestParsed) {
				cleanupMultipart(processedRequest);
			}
		}
	}

//步骤5详细代码,render渲染视图
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);
			}
		}

		// Did the handler return a view to render?
		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");
			}
		}

		if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
			// Concurrent handling started during a forward
			return;
		}

		if (mappedHandler != null) {
			mappedHandler.triggerAfterCompletion(request, response, null);
		}
	}

//render方法,会把model中的数据传入view.render(mv.getModelInternal(), request, response);
	protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
		// Determine locale for request and apply it to the response.
		Locale locale = this.localeResolver.resolveLocale(request);
		response.setLocale(locale);

		View view;
		if (mv.isReference()) {
			// We need to resolve the view name.
			view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
			if (view == null) {
				throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
						"' in servlet with name '" + getServletName() + "'");
			}
		}
		else {
			// No need to lookup: the ModelAndView object contains the actual View object.
			view = mv.getView();
			if (view == null) {
				throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
						"View object in servlet with name '" + getServletName() + "'");
			}
		}

		// Delegate to the View object for rendering.
		if (logger.isDebugEnabled()) {
			logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
		}
		try {
			view.render(mv.getModelInternal(), request, response);
		}
		catch (Exception ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
						getServletName() + "'", ex);
			}
			throw ex;
		}
	}

 

5、spring mvc的开发配置

        1、dispatcherServlet在web.xml中配置部署,从而拦截请求到spring mvc;

        2、handlerMapping的配置,将请求映射到处理器handler;

        3、handlerAdapter的配置,从而支持多种类型的处理器;

        4、viewReslover的配置,将modelAndView解析成view视图;

        5、controller处理器,可配置,可注解,通常采用注解方式。

6、hello world

        1、web.xml配置dispatcherServlet

<!-- servlet配置 -->
	<servlet>
		<servlet-name>springMvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:spring/applicationContext-mvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>springMvc</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

    2、handlerMapping和handlerAdapter的配置

第一种方式:

<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
	<bean
		class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
		<property name="messageConverters">
			<list>
				<ref bean="stringHttpMessageConverter" />
				<ref bean="mappingJacksonHttpMessageConverter" />

			</list>
		</property>
	</bean>
//ajax乱码问题
	<bean id="stringHttpMessageConverter"
		class="org.springframework.http.converter.StringHttpMessageConverter">
		<property name="supportedMediaTypes">
			<list>
				<value>text/plain;charset=UTF-8</value>
			</list>
		</property>
	</bean>
//接受json数据
	<bean id="mappingJacksonHttpMessageConverter"
		class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
		<property name="supportedMediaTypes">
			<list>
				<value>text/html;charset=UTF-8</value>
				<value>application/json;charset=UTF-8</value>
			</list>
		</property>
	</bean>

第二种方式:<mvc:annotation-driven/>注解可以自动装配handlerMapping和handlerAdapter这两个bean

<mvc:annotation-driven/>
	<mvc:annotation-driven>
		<mvc:message-converters>
//ajax请求拿到数据乱码,因为在StringHttpMessageConverter里面默认设置了字符集是ISO-8859-1,所以要修改成utf-8
			<bean class="org.springframework.http.converter.StringHttpMessageConverter">
				<property name="supportedMediaTypes">
					<list>
						<value>text/plain;charset=UTF-8</value>
					</list>
				</property>
			</bean>
//接受前台json数据配置				
<bean
		      class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
				<property name="supportedMediaTypes">
					<list>
						<value>text/html;charset=UTF-8</value>
						<value>application/json;charset=UTF-8</value>
					</list>
				</property>
			</bean>
		</mvc:message-converters>
	</mvc:annotation-driven>

        3、viewReslover配置,prefix和suffix分别是真实视图的前后缀

<!-- 配置SpringMVC的视图解析器 -->
	<bean
		class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
		<property name="viewResolvers">
			<list>
				<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />

				<!-- jsp view resolver -->
				<bean id="jspViewResolver"
					class="org.springframework.web.servlet.view.InternalResourceViewResolver">
					<property name="viewClass"
						value="org.springframework.web.servlet.view.JstlView" />
					<property name="prefix" value="/WEB-INF/jsp/" />
					<property name="suffix" value=".jsp" />
					<property name="contentType" value="text/html;charset=UTF-8" />
					<property name="order" value="1"></property>
				</bean>

			</list>
		</property>
		<property name="defaultViews">
			<list>
				<bean
					class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
			</list>
		</property>
	</bean>

        4、controller处理器的配置

   @RequestMapping(value = "hello")
    public ModelAndView hello() throws Exception {
        ModelAndView mv = this.getModelAndView();
        mv.addObject("hello", "hello world!");
        mv.setViewName("system/admin/hello");
        return mv;
    }
    

        5、jsp页面渲染,${hello}即modelAndView中的值

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@include file="/WEB-INF/jsp/common/taglib.jsp"%>
<!DOCTYPE html>
<html lang="en">
<head>
<base href="${project_name}/">

</head>
<body>

${hello}
</body>
</html>

7、POST请求中文乱码问题,在web.xml中配置编码Filter

<!-- 编码配置 -->
	<filter>
		<filter-name>encodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>utf-8</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>encodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

 

 

转载于:https://my.oschina.net/u/2527296/blog/853495

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值