SpringMVC系列-基础概念介绍

本文主要介绍一下SpringMVC中射击的一些基本概念,后面还会继续补充…

一、servlet简介

1.1.什么是servlet

Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。

我们可以使用servlet创建一个服务端应用,来处理http客户端请求,用来操作/获取数据库数据.

1.2.servlet应用架构

在这里插入图片描述

1.3.Java Servlet

1.3.1.java对servlet的实现

java库中对servlet定义如下,你可以实现以下接口,在service方法里实现自己的业务逻辑,打包后就可以在web服务器上运行了.

早期的servlet应用一般都是通过这种方式实现.


package javax.servlet;
import java.io.IOException;
public interface Servlet {
    //初始化servlet配置
    public void init(ServletConfig config) throws ServletException;
    //获取servlet配置
    public ServletConfig getServletConfig();
    //处理请求
    public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException;
    //获取servlet应用信息
    public String getServletInfo();
    //销毁servlet
    public void destroy();
}

1.3.2.GenericServlet 和HttpServlet

1.3.2.1.GenericServlet

对Servlet接口关于ServletConfig相关操作的实现.

  • 持有ServletConfig类
  • 实现了init(ServletConfig config) 方法,但是定义了init()空方法,可以有子类覆盖.不建议直接覆盖init(ServletConfig config) .
  • 该类是一个抽象类,将Servlet的service方法改成了抽象方法
1.3.2.2.HttpServlet

HttpServlet主要作用是按照当前http请求的method类型,调用不同的方法,主要有以下几种:

  • doGet
  • doHead
  • doPost
  • doPut
  • doDelete
  • doOptions
  • doTrace

该类可以作为servlet应用开发中一个servlet继承的父类,我们只需要继承相应的doXXX方法来实现我们的逻辑.

二、MVC模式

为什么我们现在很少直接通过实现servlet或继承HttpServlet,来开发我们的程序?

在实际的开发中,我们最常用请求方式一般为GET、POST,而这两者,在大部分情况都会传入参数,并返回复杂数据结果.

那么如果直接通过实现servlet或继承HttpServlet来构建我们的应用,那么我们将会话费很多逻辑在参数的获取、参数校验、返回数据格式化上.

所以就出现了MVC模式.

2.1.MVC模式

MVC代表Model-View-Controller 即:模型-视图-控制器,这种模式可以进行很好的应用程序的分层开发.

  • Model:模型,模型代表一个存取数据的对象或Java POJO
  • View:视图,代表模型包含的数据的可视化
  • Controller:控制器,控制器作用与模型和视图上,用于处理用户请求,并将数据流向模型对象,并在数据变化时更新视图,使得视图和模型解耦.

MVC架构图如下:

在这里插入图片描述

有兴趣的可以了解一下:struts 和struts2 、jsp,本文主要讲springMVC ,这些内容不在这里做介绍了.

三、springMVC原理

3.1.SpringMVC简介

官网地址:https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-config

SpringMVC 是基于Servlet API构建的原始Web框架,正式名称是Spring Web MVC.

3.2.Spring MVC主要类结构

3.2.1.整体UML类图

在这里插入图片描述

3.2.2.ModelAndView

ModelAndView 持有springMVC框架中的model和View两个元素,代表了一个handler处理的结果,这个结果将会被DispatcherServlet解析.

定义如下:


public class ModelAndView {

	/** View instance or view name String
	当前视图的名称 或视图实例
  */
	@Nullable
	private Object view;

	/** Model Map 
	当前模型数据集合
	*/
	@Nullable
	private ModelMap model;

	/** Optional HTTP status for the response
	http请求状态
  */
	@Nullable
	private HttpStatus status;

	/** Indicates whether or not this instance has been cleared with a call to {@link #clear()} */
	private boolean cleared = false;

	public ModelAndView() {
	}
	public ModelAndView(String viewName) {
		this.view = viewName;
	}

	public ModelAndView(View view) {
		this.view = view;
	}
	public ModelAndView(String viewName, @Nullable Map<String, ?> model) {
		this.view = viewName;
		if (model != null) {
			getModelMap().addAllAttributes(model);
		}
	}

	public ModelAndView(View view, @Nullable Map<String, ?> model) {
		this.view = view;
		if (model != null) {
			getModelMap().addAllAttributes(model);
		}
	}

	public ModelAndView(String viewName, HttpStatus status) {
		this.view = viewName;
		this.status = status;
	}

	public ModelAndView(@Nullable String viewName, @Nullable Map<String, ?> model, @Nullable HttpStatus status) {
		this.view = viewName;
		if (model != null) {
			getModelMap().addAllAttributes(model);
		}
		this.status = status;
	}
	public ModelAndView(String viewName, String modelName, Object modelObject) {
		this.view = viewName;
		addObject(modelName, modelObject);
	}
	public ModelAndView(View view, String modelName, Object modelObject) {
		this.view = view;
		addObject(modelName, modelObject);
	}
}

ModelView 会根据返回的view名称找到对应的视图类或文件,进行渲染,渲染的数据存放在ModelMap中,ModelMap是一个LinkedHashMap,key为模型的名称,value为模型数据.

3.2.3.Controller

3.2.3.1.源码
@FunctionalInterface
public interface Controller {

  /**
  处理request、repsonse并返回一个ModelAndView ,由DispatcherServlet调用render方法渲染
  **/
	@Nullable
	ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;

}
3.2.3.2.Controller子类体系

在这里插入图片描述

3.2.3.2.1.AbstractController

AbstractController的主要作用有两个

  • 继承了WebContentGenerator,该类支持http 缓存,使得AbstractController具有的缓存功能.
  • synchronizeOnSession: session同步控制

缓存功能实现

通过设置header中的Cache-Control来实现.

protected final void applyCacheControl(HttpServletResponse response, CacheControl cacheControl) {
		String ccValue = cacheControl.getHeaderValue();
		if (ccValue != null) {
			// Set computed HTTP 1.1 Cache-Control header
			response.setHeader(HEADER_CACHE_CONTROL, ccValue);

			if (response.containsHeader(HEADER_PRAGMA)) {
				// Reset HTTP 1.0 Pragma header if present
				response.setHeader(HEADER_PRAGMA, "");
			}
			if (response.containsHeader(HEADER_EXPIRES)) {
				// Reset HTTP 1.0 Expires header if present
				response.setHeader(HEADER_EXPIRES, "");
			}
		}
	}

synchronizeOnSession说明:

sesion同步的含义:当前一个session会话中,之后的ajax请求,必须等待之前的ajax请求完成之后,才能执行.

	@Override
	@Nullable
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
			throws Exception {

		if (HttpMethod.OPTIONS.matches(request.getMethod())) {
			response.setHeader("Allow", getAllowHeader());
			return null;
		}

		// Delegate to WebContentGenerator for checking and preparing.
		checkRequest(request);
		prepareResponse(response);

		// Execute handleRequestInternal in synchronized block if required.
		if (this.synchronizeOnSession) {
			HttpSession session = request.getSession(false);
			if (session != null) {
				Object mutex = WebUtils.getSessionMutex(session);
				synchronized (mutex) {
					return handleRequestInternal(request, response);
				}
			}
		}

		return handleRequestInternal(request, response);
	}

handleRequest方式是处理request的核心方法,在执行handleRequestInternal处理数据之前,会先获取当前session的锁,这样就会导致当前session的其他请求,无法响应.

配置方式:

<init-param>
	<param-name>synchronizeOnSession</param-name>
    <param-value>true</param-value>
</init-param>

3.2.4.View

3.2.4.1.View子类体系

在这里插入图片描述

从上图我们可以看出,view主要分为两类:

  1. Json 渲染(但是springMVC 的json接口,不是通过该方式实现的,在spring 请求流程里面会讲到)
  2. 基于url渲染模版
    1. 重定向
    2. 模版渲染: freemark,pdf.xslt,script模版

这里不对这些类进行详细介绍了,后面会出详细介绍文章.

view类的作用就是根据不同的类型选择不同的实现来渲染数据.

3.2.5.ViewResovler

3.2.5.1.ViewResovler体系

在这里插入图片描述

3.2.5.2.ViewResovler的作用

细心的可以发现,ViewResovler和View的实现有对应关系.

ViewResovler是用来做什么的?

我们看下spring 源码关于ViewResolver的注释:

/***
 * Interface to be implemented by objects that can resolve views by name.
    一个可以用来根据名称来解析view对象的接口.
 *
 * <p>View state doesn't change during the running of the application,
 * so implementations are free to cache views.
 View对象的状态在程序运行时时不会改变的,所以实现类可以缓存这些view对象.
 *
 * <p>Implementations are encouraged to support internationalization,
 提倡实现类支持国际化
***/

从注视可以看出ViewResovler是一种将逻辑视图转换为实际View的一种机制.

正常的handler会返回一个ModelView对象,这里面包含视图,但是在我们开发时,可以返回一个视图名称,框架可以根据这个名称去找到对应的视图,提高开发效率、和代码结构.

3.2.5.3.ViewResovler主要子类
  • ViewResolverComposite:代理类,持有所有的ViewResovler实现.

  • AbstractCachingViewResolver:该类主要缓存View对象

  • ContentNegotiatingViewResolver:根据请求文件名或header信息,解析返回的view

  • BeanNameViewResolver: 将view名称和bean 名称做关联,查找该view名称时,实际去查找对应的Bean对象

  • UrlBasedViewResolver:实际最重要的一个,通过url来查找对应视图名称,最常使用的:定义prefix/suffix,Example: prefix=“/WEB-INF/jsp/”, suffix=“.jsp”, viewname=“test” -> “/WEB-INF/jsp/test.jsp”,大部分常用的ViewResovler都是直接继承该类,也可以继承它来自定义自己的ViewResovler

3.2.6.HandlerMapping和HandlerAdapter

3.2.6.1.HandlerMapping和HandlerAdapter体系图

在这里插入图片描述

在这里插入图片描述

3.2.6.2.HandlerMapping
 /** Interface to be implemented by objects that define a mapping between
 * requests and handler objects.
 **/

HandlerMapping的子类定义了request和handler子类之间的对应关系.

也就是说,当DispatcherServlet收到一个请求时,会根据HandlerMapping找到,一个处理该请求的handler,一般是一个handler处理链.

子类主要分为两大类:

  • AbstractHandlerMethodMapping: 定义了url和方法级的对应关系.通过该方法,可以找到对应的HandlerMethod
  • AbstractUrlHandlerMapping: url和类级别的关系.通过该类可以找到对应的Controller类
3.2.6.3.HandlerAdapter
 /***
* <p>Interface that must be implemented for each handler type to handle a request.
 * This interface is used to allow the {@link DispatcherServlet} to be indefinitely
 * extensible. The {@code DispatcherServlet} accesses all installed handlers through
 * this interface, meaning that it does not contain code specific to any handler type.
 **/

HandlerAdapter的主要作用就是DispatcherServlet通过它去执行每个类型的handler 的逻辑.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿老徐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值