SpringMVC超详细入门
初识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处理请求的流程
通过上述的代码,我们能够总结出具体的运行流程:
客户端发送请求http://localhost:8080/hello
由tomcat接受到对应的请求
SpringMVC的前端控制器DispatcherServlet接收到所有的请求
查看请求地址和@RequestMapping注解的哪个匹配,来找到具体的类的处理方法
前端控制器找到目标处理类和方法之后,执行目标方法
方法执行完成之后会有一个返回值,SpringMVC会将这个返回值用视图解析器进行解析拼接成完整的页面地址
DispatcherServlet拿到页面地址之后,转发到具体的页面
浏览器对页面的标签进行渲染,返回给用户实际显示的花里胡哨的交互页面
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超详细入门相关推荐
- GoJS超详细入门(插件使用无非:引包、初始化、配参数(json)、引数据(json)四步)...
GoJS超详细入门(插件使用无非:引包.初始化.配参数(json).引数据(json)四步) 一.总结 一句话总结:插件使用无非:引包.初始化.配参数(json).引数据(json)四步. 1.goj ...
- arcgis 地图_ArcGIS超详细入门操作:ArcGIS矢量化地图详细步骤
今天给大家带来的干货是[ArcGIS超详细入门操作:ArcGIS矢量化地图详细步骤],欢迎大家收藏查阅! 在桌面上新建一个文件夹,打开ArcCatalog, "文件"--" ...
- TypeScript超详细入门教程(上)
TypeScript超详细入门教程(上) 01 开篇词:Hello~TypeScript 01 开篇词:Hello~TypeScript 更新时间:2019-10-30 13:49:46 既然我已经踏 ...
- Faster RCNN超详细入门 02 网络细节与训练方法
文章目录 前言 论文结构 Abstract Introduction Related Work Region Proposal Network Experiments Conclusion 网络架构 ...
- YOLO 超详细入门02 v2 (含代码及原文)
文章目录 前言 背景 总结 一.YOLOv2改进之框架 1.1 网络架构 1.2 Batch Normalization 二.YOLOv2改进方法之尺寸相关 2.1 High Resolution C ...
- 自学前端设计——【开源骚客】FPGA超详细入门视频教程
前言 本文基于[开源骚客]FPGA超详细入门视频教程,简单做个笔记 00. FPGA开发软件的安装 Quartus II 13.1 Modelsim Notepad++ Vim 01. 我的第一个FP ...
- Swig超详细入门教程(Java调用C/C++, CMake)——更新于2021.12
目录 相关教程 环境配置 0基础上手例子(C/C++) 使用CMake的例子(C语言) 使用CMake的例子(C++) 本文主要是手把手教萌新们如何用官方用例构建(有许多本人亲身踩坑血泪史) 相关教程 ...
- Apollo Control——超详细入门教程(二):连续状态空间方程离散化与离散LQR公式推导
专栏文章列表 Apollo Control--超详细入门教程(一):基于道路误差的车辆动力学模型 Apollo Control--超详细入门教程(二):连续状态空间方程离散化与离散LQR公式推导 Ap ...
- YOLO 超详细入门(含开源代码)——网络结构、细节、目标损失函数、优点
文章目录 前言 背景 一.YOLO的核心原理预览 二.网络结构 为什么每个网格有固定的B个Bounding Boes?(即B=2) 三.网络细节 3.1 网络单元(grid) 3.1.1 作用 3.1 ...
最新文章
- Python3中上下文管理器介绍
- 网络营销——网络营销专员到底是教你如何选择网站页面制作
- python 编程一日一练-Python每日一练0013
- 干货笔记|三分钟让你掌握360高级副总裁的产品之道
- 农业银行数据库最佳实践和发展规划
- 计算机实数表示法---浮点数(二)
- 使用RTL-SDR打开车门
- 分享些我见到的听到的各种创业经历(有成功也有失败)——分析下创业成功要做到哪些...
- 信号与系统(二)——正交
- H3CSE(路由)学习笔记----下
- 40_ZYNQ7020开发板RS485协议通信
- Asp.Net 5.0简介
- php生产环境配置,PHP生产环境配置 - osc_ifi9q17t的个人空间 - OSCHINA - 中文开源技术交流社区...
- Pyecharts绘图笔记
- js 只准输入数字_js 限制input只能输入数字
- WIN10系统如何开启终端
- STM32CubeIDE移植标准库
- CSDN新版个人空间不再显示注册日期,到搜索引擎快照备份下,呵呵
- Codis学习笔记--Java连接codis
- 一种基于Visio替代软件的绘图方案