一文带你搞懂Spring MVC和servlet(面试必备)

一、Spring MVC与Jsp/Servlet比较

1、传统的 Jsp/Servlet 技术体系弊端

Servlet: 是用java编写的服务端应用程序。

  • 作用:主要用于交互式的浏览和修改数据,生成web内容,这个过程为:客户端发送请求到服务器 -> 服务器将请求信息发送至Servlet–>Servlet生成相应内容并将其传给服务器-> 服务器将响应返回给客户端。
  • 在传统的 Jsp/Servlet 技术体系中,如果要开发接口,一个接口对应一个
    Servlet,每个请求都去在web.xml中配置一个servlet节点。会导致我们开发出许多 Servlet,使用 SpringMVC可以有效的简化这一步骤。
2、Spring Web MVC 特点
  • Spring Web MVC 是一种基于 Java 的实现了 Web MVC 设计模式的请求驱动类型的轻量级 Web 框架,即使用了 MVC 架构模式的思想,将 web 层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发,SpringWeb MVC 也是要简化我们日常 Web 开发的。
  • Spring Web MVC 也是服务到工作者模式的实现,但进行可优化。前端控制器是DispatcherServlet应用控制器可以拆为处理器映射器(Handler Mapping)进行处理器管理和视图解析器(View
    Resolver)进行视图管理
    页面控制器/动作/处理器为 Controller 接口(仅包含 ModelAndView handleRequest(request, response) 方法,也有人称作 Handler)的实现(也可以是任何的 POJO类);支持本地化(Locale)解析、主题(Theme)解析及文件上传等;提供了非常灵活的数据验证、格式化和数据绑定机制;提供了强大的约定大于配置(惯例优先原则)的契约式编程支持。
3、Spring MVC工作流程

在这里插入图片描述
1、用户发送请求至前端控制器DispatcherServlet。

2、DispatcherServlet收到请求调用HandlerMapping处理器映射器。

3、处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

4、 DispatcherServlet调用HandlerAdapter处理器适配器。

5、HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。

6、Controller执行完成返回ModelAndView。

7、HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。

8、DispatcherServlet将ModelAndView传给ViewReslover视图解析器。

9、ViewReslover解析后返回具体View。

10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。

11、DispatcherServlet响应用户。

二、idea创建servlet项目

1、搭建过程

在这里插入图片描述

  • 步骤1

在这里插入图片描述

  • 步骤2

在这里插入图片描述
编写 HelloWorld.java 代码

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class HelloWorld extends HttpServlet {
    private String message;

    @Override
    public void init() throws ServletException
    {
        // 初始化
        message = "Hello, First Servlet!";
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 设置:响应内容类型
        response.setContentType("text/html");

        // 输出文本
        PrintWriter out = response.getWriter();
        out.write("<h1> " + message + " </h1>");
    }

}

编写web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>HelloWorld</servlet-name>
        <servlet-class>HelloWorld</servlet-class>
    </servlet>


    <servlet-mapping>
        <servlet-name>HelloWorld</servlet-name>
        <url-pattern>/demo</url-pattern>
    </servlet-mapping>
</web-app>
  • tomcat配置

在这里插入图片描述
在这里插入图片描述
启动后测试结果
在这里插入图片描述

2、servlet的工作流程

在这里插入图片描述

1. 浏览器请求

浏览器向服务器请求时,服务器不会直接执行我们的类,而是到web.xml里寻找路径名
①:第一步,浏览器输入访问路径后,携带了请求行,头,体
②:第二步,根据访问路径找到已注册的servlet名称,既图中的demo
③:第三步,根据映射找到对应的servlet名
③:第四步,根据根据servlet名找到我们全限定类名,既我们自己写的类
2. 服务器创建对象
在这里插入图片描述
①:服务器找到全限定类名后,通过反射创建对象,同时也创建了servletConfig,里面存放了一些初始化信息(注意服务器只会创建一次servlet对象,所以servletConfig也只有一个

3. 调用init方法
在这里插入图片描述
①:对象创建好之后,首先要执行init方法,但是我们发现我们自定义类下没有init方法,所以程序会到其父类HttpServlet里找
②:我们发现HttpServlet里也没有init方法,所以继续向上找,既向其父类GenericServlet中继续寻找,在GenericServlet中我们发现了init方法,则执行init方法(对接口Servlet中的init方法进行了重写)
注意:
在GenericServlet中执行public void init(ServletConfig config)方法的时候,又调用了自己无惨无方法体的init()方法,其目的是为了方便开发者,如果开发者在初始化的过程中需要实现一些功能,可以重写此方法

4. 调用service方法
在这里插入图片描述
接着,服务器会先创建两个对象:ServletRequest请求对象和ServletResponse响应对象,用来封装浏览器的请求数据和封装向浏览器的响应数据
①:接着服务器会默认在我们写的类里寻找service(ServletRequest req, ServletResponse res)方法,但是DemoServlet中不存在,那么会到其父类中寻找
②:到父类HttpServlet中发现有此方法,则直接调用此方法,并将之前创建好的两个对象传入
③:然后将传入的两个参数强转,并调用HttpServlet下的另外个service方法
④:接着执行service(HttpServletRequest req, HttpServletResponse resp)方法,在此方法内部进行了判断请求方式,并执行doGet和doPost,但是doGet和doPost方法已经被我们自己重写了,所以会执行我们重写的方法
看到这里,你或许有疑问:为什么我们不直接重写service方法?
因为如果重写service方法的话,我们需要将强转,以及一系列的安全保护判断重新写一遍,会存在安全隐患

5. 向浏览器响应
在这里插入图片描述

3、servlet的生命周期

Servlet_生命周期:首先加载servlet的class,实例化servlet,然后初始化servlet调用init()的方法,接着调用服务的service的方法处理doGet和doPost方法,最后是我的还有容器关闭时候调用destroy 销毁方法。

  • 1.被创建:执行init方法,只执行一次
    Servlet什么时候被创建?
    –默认情况下,第一次被访问时,Servlet被创建,然后执行init方法
    –可以配置执行Servlet的创建时机;
  • 2.提供服务:执行service方法,执行多次
  • 3.被销毁:当Servlet服务器正常关闭时,执行destroy方法,只执行一次

下图显示了一个典型的 Servlet 生命周期方案。

  1. 第一个到达服务器的 HTTP 请求被委派到 Servlet 容器。
  2. Servlet 容器在调用 service() 方法之前加载 Servlet。
  3. 然后 Servlet 容器处理由多个线程产生的多个请求,每个线程执行一个单一的 Servlet 实例的 service() 方法
    在这里插入图片描述在这里插入图片描述

三、idea创建Spring MVC项目

1、搭建过程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
maven的依赖

<dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>4.3.3.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.3.3.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.0.1</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>

项目结构
在这里插入图片描述
配置web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

<!--  配置前端控制器-->
  <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/spring-*.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
<!--    表示拦截所有的请求
所有的访问地址都由dispatcherServlet进行解析-->
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

springmvc的相关配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">


    <!-- 配置扫描的包 -->
    <context:component-scan base-package="com.jp.*" />

    <!-- 注解进行查找,注册HandlerMapper、HandlerAdapter两个映射类 -->
    <mvc:annotation-driven/>
    <!-- 访问静态资源 -->
    <mvc:default-servlet-handler />

    <!-- 视图解析器 -->
    <bean
            class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/view/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

</beans>

在这里插入图片描述
demo.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>首页</title>
</head>
<body>
<h1>This is SpringMVC Demo</h1>
</body>
</html>

使用注解@Controller定义一个控制器

package com.jp.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * @program: springmvc
 * @description: 测试demo
 * @author: CoderPengJiang
 * @create: 2020-04-28 14:59
 **/
@Controller
@RequestMapping("/demo")
public class WebController {
    @RequestMapping(value = "/index",method = RequestMethod.GET)
    public String index() {
        return "demo";
    }
}

返回的字符串demo会被配置拼接成WEB-INF/view/demo.jsp
启动后测试结果
在这里插入图片描述

2、Spring MVC接口解释
接口解释

(1)DispatcherServlet接口:
Spring提供的前端控制器,所有的请求都有经过它来统一分发。在DispatcherServlet将请求分发给Spring Controller之前,需要借助于Spring提供的HandlerMapping定位到具体的Controller。
(2)HandlerMapping接口:
能够完成客户请求到Controller映射。
(3)Controller接口:
需要为并发用户处理上述请求,因此实现Controller接口时,必须保证线程安全并且可重用。
Controller将处理用户请求,这和Struts Action扮演的角色是一致的。一旦Controller处理完用户请求,则返回ModelAndView对象给DispatcherServlet前端控制器,ModelAndView中包含了模型(Model)和视图(View)。
从宏观角度考虑,DispatcherServlet是整个Web应用的控制器;从微观考虑,Controller是单个Http请求处理过程中的控制器,而ModelAndView是Http请求过程中返回的模型(Model)和视图(View)。
(4)ViewResolver接口:
Spring提供的视图解析器(ViewResolver)在Web应用中查找View对象,从而将相应结果渲染给客户。

DispatcherServlet

是整个Spring MVC的核心。它负责接收HTTP请求组织协调Spring MVC的各个组成部分。其主要工作有以下三项:
(1)截获符合特定格式的URL请求。
(2)初始化DispatcherServlet上下文对应WebApplicationContext,并将其与业务层、持久化层的WebApplicationContext建立关联。
(3)初始化Spring MVC的各个组成组件,并装配到DispatcherServlet中。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值