初识Spring MVC

一、什么是MVC?

MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。就是将业务逻辑、数据、显示分离的方法来组织代码。MVC主要作用是降低了视图与业务逻辑间的双向偶合。MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在差异。

  • Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据Dao) 和 服务层(行为Service)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。
  • View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。
  • Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。 也就是说控制器做了个调度员的工作。Controller相当于定义了一堆的方法,不同的方法处理不同的客户端请求;最主要的工作就是接收客户浏览器的请求,并把请求向后转发调度。

最典型的MVC就是JSP + servlet + javabean的模式。

补充:前端页面展示用JSP,后端处理服务的时候用Servlet,封装的与数据库表相对应的实体类即javabean。现在前后端分离,公司中主要用的架构是——Spring Boot + VUE。

二、Spring MVC的概念

1、SpringMVC的介绍

从上面这个Spring的整体架构图,我们可以发现Spring MVC并不是一个单独的框架,而是Spring框架的一部分,是基于Java实现的一个轻量级web框架。

学习SpringMVC框架最核心的就是DispatcherServlet的设计,掌握好DispatcherServlet是掌握SpringMVC的核心关键。

2、SpringMVC的优点

模式清晰,各模块之间解耦,通过各模块间的协同合作来处理前后端的交互。

3、SpringMVC的实现原理

springmvc的mvc模式:

SpringMVC的具体执行流程:

当发起请求时被前置的控制器拦截到请求,根据请求参数生成代理请求,找到请求对应的实际控制器,控制器处理请求,创建数据模型,访问数据库,将模型响应给中心控制器,控制器使用模型与视图渲染视图结果,将结果返回给中心控制器,再将结果返回给请求者。

1、DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。
2、HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler。
3、返回处理器执行链,根据url查找控制器,并且将解析后的信息传递给DispatcherServlet
4、HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。
5、执行handler找到具体的处理器
6、Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView。
7、HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。
8、DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。
9、视图解析器将解析的逻辑视图名传给DispatcherServlet。
10、DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图,进行试图渲染
11、将响应数据返回给客户端

注意:以上的都是概念层面的东西,暂时不理解没关系,当我们熟练使用Spring MVC之后,有了相关的web开发经验之后再来看上面的理论东西,会有不一样的感受的。

三、Spring MVC的使用——基于注解

上面我们了解了Spring MVC的概念层面的理论知识,下面我们进行实际应用层面的操作。

补充:我们只演示如何通过注解来使用Spring MVC,注解简单快捷。我们不再演示通过XML文件的配置,因为用xml会很繁琐,实际中根本没人使用xml来进行开发。

以下操作基于IDEA开发演示,Eclipse进行开发有很多细节点是不一样的。

1、新建普通的Maven项目

2、添加web模块支持

右击项目名,可以发现一个选项如下:添加所需要支持的模块

此时在出现的功能区勾选Web Application模块支持即可:

然后我们就能发现在我们的项目目录结构下出现了一个新的目录


此时我们就能够在此目录结构下进行web开发了。

3、添加pom依赖

添加Spring框架以及web模块和mvc模块的支持

<dependencies><!-- https://mvnrepository.com/artifact/org.springframework/spring-context --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.3.RELEASE</version></dependency><!-- https://mvnrepository.com/artifact/org.springframework/spring-web --><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.2.3.RELEASE</version></dependency><!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.3.RELEASE</version></dependency>

4、编写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>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--关联Spring配置文件--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value></init-param></servlet><!--servlet标签和servlet-mapping标签必须成对出现--><servlet-mapping><servlet-name>springmvc</servlet-name><!--使用 / 标识匹配所有的servlet请求--><!-- / 和 /* 的区别??--><url-pattern>/</url-pattern></servlet-mapping>
</web-app>

其实就是配置了前端控制器DispatcherServerlet.

5、编写spring的配置文件

applicationContext.xml

<?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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!--开启包的扫描路径,有IOC容器来管理bean对象--><context:component-scan base-package="com.mjt"></context:component-scan><!--配置前端视图解析器--><bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!-- 配置请求资源的前缀 --><!--设置成如下的配置表示:必须要在/WEB-INF/page/路径下的文件才允许被访问--><property name="prefix" value="/WEB-INF/page/"></property><!-- 配置请求资源的后缀 --><!--设置成如下的配置表示:必须要是以 .jsp 结尾的文件才允许被访问--><property name="suffix" value=".jsp"></property></bean>
</beans>

主要是配置了包的扫描路径,支持注解的使用;然后还配置了视图解析器,主要就是把方法在处理请求之后返回的字符串进行拼接,使其能够访问到我们在WEB-INF目录下编写的前端页面渲染文件。

6、编写我们的逻辑处理:Controller

HelloController.java

package com.mjt.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Map;@Controller
public class HelloController {/**** springmvc处理过程*  1、浏览器要发送一个请求 http://localhost:8080/springmvc_helloworld_war_exploded/hello*  2、首先交给tomcat容器*  3、在web.xml文件中配置了DispatcherServlet的类,所以此时会由当前的DispatcherServlet来接受请求*  4、接受到请求之后找到对应的Controller,去Controller中寻找@RequestMapping注解标识的方法*  5、找到匹配的方法之后,执行方法的逻辑*  6、处理完成之后需要返回一个前端页面的名称,*  7、有视图处理器来根据名称映射到对应的jsp页面的路径*  8、DispatcherServlet拿到对应的路径地址之后返回给浏览器*/@RequestMapping("/hello")public String hello(Map<String, String> map){map.put("msg", "hello springmvc");return "hello";}
}

7、编写前端渲染页面显示

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>hello springmvc</title>
</head>
<body>
<%--获取Controller返回的信息,并进行渲染--%>
<h1>${msg}
</h1></body>
</html>

8、测试

注意:使用spring mvc时有一个步骤我们常常会忽略,此时我们是没办法交互成功的。我们还需要把所有依赖的jar包添加到Artifacts模块下,否则无法识别我们所需要的类,如前端控制器:DispatcherServerlet

运行结果:

能够获取到Controller返回的数据,并且进行了渲染,通过Spring MVC完成了基本的前后端交互效果。

四、各种配置的细节点

1、Spring MVC处理请求的流程

通过上述的代码,我们能够总结出具体的运行流程:

  1. 客户端发送请求http://localhost:8080/hello

  2. 由tomcat接受到对应的请求

  3. SpringMVC的前端控制器DispatcherServlet接收到所有的请求

  4. 查看请求地址和@RequestMapping注解的哪个匹配,来找到具体的类的处理方法

  5. 前端控制器找到目标处理类和方法之后,执行目标方法

  6. 方法执行完成之后会有一个返回值,SpringMVC会将这个返回值用视图解析器进行解析拼接成完整的页面地址

  7. DispatcherServlet拿到页面地址之后,转发到具体的页面

  8. 浏览器对页面的标签进行渲染,返回给用户实际显示的花里胡哨的交互页面

2、DispatcherServlet中url-pattern的设置

url-pattern的设置,我们一般会设置成 / ,其实还有一种 /* ,功能差不多,都是能匹配所有请求,那么这两者究竟有什么区别?

匹配servlet的请求有两种方式:

  • /:标识匹配所有请求,但是不会jsp页面
  • /*:拦截所有请求,拦截jsp页面

但是需要注意的是,此时我们请求index.html(所有以.html结尾的html文件)的时候,会发现请求不到。这是为什么?应该怎么解决?

原因在于,tomcat下也有一个web.xml文件,所有的项目下web.xml文件都需要继承此web.xml,在服务器的web.xml文件中有一个DefaultServlet用来处理静态资源,但是url-pattern是/,而我们在自己的配置文件中如果添加了url-pattern = /会覆盖父类中的url-pattern,此时在请求的时候DispatcherServlet会去controller中做匹配,找不到则直接报404。而在服务器的web.xml文件中包含了一个JspServlet的处理,所以不会拦截jsp请求。

解决也非常简单,我们只需要在配置文件中添加一个defaultServlet即可

<servlet><servlet-name>default</servlet-name><servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
</servlet>
<servlet-mapping><servlet-name>default</servlet-name><url-pattern>*.html</url-pattern>
</servlet-mapping>

3、@RequestMapping注解的使用

1、添加在方法上

@RequestMapping用来匹配客户端发送的请求。使用@RequestMapping加在方法上,可以指定此方法只会处理一个独一无二的路径的请求,如果有两个方法通过@RequestMapping注解设置处理同一个路径的请求,无法判断究竟使用哪一个,就会出错。

2、添加在类上

@RequestMapping用来匹配客户端发送的请求,除了可以在方法上使用,也可以在类上使用。

  • 添加在方法:表示用来匹配要处理的请求。

  • 添加在类上:表示为当前类的所有方法的请求地址添加一个前置路径,访问的时候必须要添加此路径。

什么时候再类上添加此注解

当存在同名请求的时候,需要在类上添加此注解,用以区分同名请求。

比如当有多个Controller处理不同的模块,当两个Controller中都有一个方法匹配的路径是相同的,如果不再类上添加,此时无法判断究竟由哪一个方法处理此请求。此时在每个类上再添加一层各自路径,用于区分不同类的两个方法处理的请求。

比如公司有两个人开发不同的模块,他们都喜欢 /hello 这个路径,都在各自编写的Controller中的方法上匹配此路径的请求,由于两个人独立开发无法知道对方是怎么匹配的,此时就会出现问题。可以让两个人再各自的Controller类上使用此注解,再外嵌一层各自的路径,就不会出错了。

3、@RequestMapping配置的参数

method:指定处理什么特定类型的请求。比如指定为GET、POST等

@Controller
public class HelloController {//只处理GET请求@RequestMapping(value = "/hello", method = RequestMethod.GET)public String hello(Map<String, String> map){map.put("msg", "hello springmvc");return "hello";}
}

其实@RequestMapping的参数有很多种,最常用的是method,其余的很少使用我们不再演示。当我们需要对方法处理的请求进行更加细粒度的匹配控制,再去查找和使用。

4、进行模糊匹配

@Controller
public class HelloController {/** @RequestMapping可以进行模糊匹配?:替代任意一个字符*:替代多个字符**:替代多层路径如果能匹配到多个请求,那么优先是精准匹配,其次是模糊匹配*///模糊匹配所有以hello开头的请求,比如hello_world、hello_mjt等@RequestMapping(value = "/hello*")public String hello(Map<String, String> map){map.put("msg", "hello springmvc");return "hello";}
}

5、获取请求路径的参数

如果需要在请求路径中的参数像作为参数应该怎么使用呢?可以使用@PathVariable注解,此注解就是提供了对占位符URL的支持,就是将URL中占位符参数绑定到控制器处理方法的参数中。

编写Controller,编写处理请求的方法,如果此方法需要用户传入参数,则在@RequestMapping中使用{“参数名称”},来识别用户传入的参数,然后在具体的处理方法上使用@PathVariable来获取传入的参数。

@Controller
public class PathVariableController {/*** 在RequestMapping中使用{变量名称}匹配请求的时候传递的参数* * 在方法参数中,使用@PathVariable,来获取请求传递的参数* 如果路径中的名称和方法的参数名称不一致的话,使用@PathVariable("变量名称")来匹配参数* 而且推荐都使用@PathVariable("变量名称"),不易出错*/@RequestMapping("/testPathVariable/{id}/{name}")public String testPathVariable(@PathVariable("id") Integer id, @PathVariable("name") String name){System.out.println(id);System.out.println(name);return "hello";}
}

浏览器请求(附带参数)

补充:起初我们如果要附加参数,要用 path?1&majuntao 这种方式(?、&)来传递参数,而使用 / 来分割参数,更加简单明了。

后台能获取到参数并输出打印

五、总结

在上面的学习中我们可以发现:Spring MVC的内容不难,但是设置的细节点比较杂,比较多。有很多细节点面试工作之后都不一定会用得到,可能只会用到比较常用的,但是在学习阶段,我们可以尽量系统的掌握即可。

SpringMVC超详细入门相关推荐

  1. GoJS超详细入门(插件使用无非:引包、初始化、配参数(json)、引数据(json)四步)...

    GoJS超详细入门(插件使用无非:引包.初始化.配参数(json).引数据(json)四步) 一.总结 一句话总结:插件使用无非:引包.初始化.配参数(json).引数据(json)四步. 1.goj ...

  2. arcgis 地图_ArcGIS超详细入门操作:ArcGIS矢量化地图详细步骤

    今天给大家带来的干货是[ArcGIS超详细入门操作:ArcGIS矢量化地图详细步骤],欢迎大家收藏查阅! 在桌面上新建一个文件夹,打开ArcCatalog, "文件"--" ...

  3. TypeScript超详细入门教程(上)

    TypeScript超详细入门教程(上) 01 开篇词:Hello~TypeScript 01 开篇词:Hello~TypeScript 更新时间:2019-10-30 13:49:46 既然我已经踏 ...

  4. Faster RCNN超详细入门 02 网络细节与训练方法

    文章目录 前言 论文结构 Abstract Introduction Related Work Region Proposal Network Experiments Conclusion 网络架构 ...

  5. YOLO 超详细入门02 v2 (含代码及原文)

    文章目录 前言 背景 总结 一.YOLOv2改进之框架 1.1 网络架构 1.2 Batch Normalization 二.YOLOv2改进方法之尺寸相关 2.1 High Resolution C ...

  6. 自学前端设计——【开源骚客】FPGA超详细入门视频教程

    前言 本文基于[开源骚客]FPGA超详细入门视频教程,简单做个笔记 00. FPGA开发软件的安装 Quartus II 13.1 Modelsim Notepad++ Vim 01. 我的第一个FP ...

  7. Swig超详细入门教程(Java调用C/C++, CMake)——更新于2021.12

    目录 相关教程 环境配置 0基础上手例子(C/C++) 使用CMake的例子(C语言) 使用CMake的例子(C++) 本文主要是手把手教萌新们如何用官方用例构建(有许多本人亲身踩坑血泪史) 相关教程 ...

  8. Apollo Control——超详细入门教程(二):连续状态空间方程离散化与离散LQR公式推导

    专栏文章列表 Apollo Control--超详细入门教程(一):基于道路误差的车辆动力学模型 Apollo Control--超详细入门教程(二):连续状态空间方程离散化与离散LQR公式推导 Ap ...

  9. YOLO 超详细入门(含开源代码)——网络结构、细节、目标损失函数、优点

    文章目录 前言 背景 一.YOLO的核心原理预览 二.网络结构 为什么每个网格有固定的B个Bounding Boes?(即B=2) 三.网络细节 3.1 网络单元(grid) 3.1.1 作用 3.1 ...

最新文章

  1. Python3中上下文管理器介绍
  2. 网络营销——网络营销专员到底是教你如何选择网站页面制作
  3. python 编程一日一练-Python每日一练0013
  4. 干货笔记|三分钟让你掌握360高级副总裁的产品之道
  5. 农业银行数据库最佳实践和发展规划
  6. 计算机实数表示法---浮点数(二)
  7. 使用RTL-SDR打开车门
  8. 分享些我见到的听到的各种创业经历(有成功也有失败)——分析下创业成功要做到哪些...
  9. 信号与系统(二)——正交
  10. H3CSE(路由)学习笔记----下
  11. 40_ZYNQ7020开发板RS485协议通信
  12. Asp.Net 5.0简介
  13. php生产环境配置,PHP生产环境配置 - osc_ifi9q17t的个人空间 - OSCHINA - 中文开源技术交流社区...
  14. Pyecharts绘图笔记
  15. js 只准输入数字_js 限制input只能输入数字
  16. WIN10系统如何开启终端
  17. STM32CubeIDE移植标准库
  18. CSDN新版个人空间不再显示注册日期,到搜索引擎快照备份下,呵呵
  19. Codis学习笔记--Java连接codis
  20. 一种基于Visio替代软件的绘图方案

热门文章

  1. 分析编程题c语言,二级C语言部分上机编程题详细分析
  2. java抢购_java redis 实现抢购秒杀
  3. linux下双网卡设置(内外网)
  4. 怎样用matlab把视频转gif动画,Matlab制作视频并转换成gif动态图的两种方法
  5. 双非生物医学硕士放弃研究院工作,零基础转型大数据开发
  6. 精读《web reflow》
  7. RK3568外设资源
  8. 说明人工神经网络的原理,人工神经网络结构图
  9. websocket-PacketCapture乱码包解密
  10. 简易防火墙建置与流量统计