目录
[一、Spring MVC简介](#一、Spring MVC简介)
[Spring MVC和MVC的关系:](#Spring MVC和MVC的关系:)
[二、Spring MVC学什么及创建Spring MVC项目](#二、Spring MVC学什么及创建Spring MVC项目)
[三、Spring MVC实现连接](#三、Spring MVC实现连接)
[编辑 3.3、@GetMapping 和 PostMapping](#编辑 3.3、@GetMapping 和 PostMapping)
[4.2、 后端参数重命名及设置参数必传](#4.2、 后端参数重命名及设置参数必传)
[编辑 4.4、获取URL中的参数](#编辑 4.4、获取URL中的参数)
前言
本篇博客主要介绍Spring MVC是什么,Spring MVC项目的创建和连接,Spring MVC获取各种参数,以及Spring MVC如何返回数据。
一、Spring MVC简介
Spring MVC的官方描述:
Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从⼀开始就包含在 Spring 框架中。它的正式名称"Spring Web MVC"来⾃其源模块的名称(Spring-webmvc),但它通常被称为Spring MVC" 。
从上面的描述中,我们可以知道:Spring MVC其实就是一个框架,一个Web的框架;是基于Servlet API构建的。
MVC是什么?
M代表的是model,V代表的是view,C代表的是controller,所以MVC的意思是模型、视图、控制器。
**Model:**是应用程序中用于处理应用数据的逻辑的部分,通常用于在数据库中存取数据;
View: 视图负责展示模型的数据给用户,并接收用户的输入。它通常是用户界面的一部分,如HTML页面、JSP页面、Thymeleaf模板等。视图负责将模型的数据以适当的方式呈现给用户。
**Controller:**控制器是处于模型和视图之间的,属于二者的协调者,用于处理与用户交互部分,一般就是从视图中读取数据转发给模型,接着再将模型返回的数据返回给视图,这样子做的目的主要是为了可以解耦合。
Spring MVC和MVC的关系:
这二者间的关系就像IoC(控制反转)和DI(依赖注入)的关系,DI就是IoC的一种具体实现方式,MVC 是⼀种思想,⽽ Spring MVC 是对 MVC 思想的具体实现。 总结来说,**Spring MVC 是⼀个实现了 MVC 模式,并继承了 Servlet API 的 Web 框架。**既然是 Web 框架,那么当⽤户在浏览器中输⼊了 url 之后,我们的 Spring MVC 项⽬就可以感知到⽤户的请求。
二、Spring MVC学什么及创建Spring MVC项目
**Spring MVC学什么:**Spring MVC主要就是为了将Java程序及浏览器连接起来,使得浏览器和我们的Java程序之间互通起来,因此,我们学习Spring MVC主要就是学浏览器如何和我们的Java程序建立连接;Spring MVC建立连接之后Java程序如何从浏览器中拿到数据;以及建立连接之后Java程序如何返回数据给浏览器。
创建一个Spring MVC项目:
Spring MVC项目的创建很简单,只要在创建Spring Boot项目的基础上在创建的时候加上Spring Web依赖就可以了,如下所示:

三、Spring MVC实现连接
我们要实现的连接就是在浏览器输入一个url后,我们的Java程序可以感知到,并且做出响应。在Spring MVC项目中我们可以使用注解来实现响应的功能。
3.1、@RequestMapping注解
在 Spring MVC 中使⽤ @RequestMapping 来实现 URL 路由映射,也就是浏览器连接程序的作⽤。
@RequestMapping 注解既可以修饰类,也可以修饰方法,接下来我们就直接通过代码来看@RequestMapping的使用:
@RequestMapping修饰方法:

当 @RequestMapping修饰方法时,我们访问的路径就是:http://localhost:8080/sayhi
(上面的url中localhost代表的是访问的是本地服务器也可以写为127.0.0.1;8080是端口号)
结果如下所示:

@RequestMapping修饰类和方法:
当RequestMapping修饰类和方法时,我们要访问的路径就是:http://localhost:8080/user/sayhi
如果我们还是访问:http://localhost:8080/sayhi ,就会出现404错误,如下:

正确访问结果如下所示:

3.2、@RequestMapping指定请求类型
我们在上面在浏览器地址栏中输入url去请求@RequestMapping修饰的方法,触发的是GET请求,那么@RequestMapping注解是否支持POST或者OPTIONS、PUT等等其他请求呢?这时候我们可以使用Postman来试一下;
结果如下:

从以上结果我们可以看出**@RequestMapping是可以支持任何类型的请求的**,但是我们在实际开发中,有时候是需要指定请求类型的,不能让所有的请求都可行。因此我们需要对@RequestMapping指定请求类型。
@RequestMapping设置请求类型:

这时候我们再使用Postman模拟post请求就会出现以下结果:
3.3、@GetMapping 和 PostMapping
我们在一般的开发中,用的比较多的请求就是GET和POST,因此,当我们需要指定请求类型时,也可以使用@GetMapping 和 PostMapping来进行指定,@GetMapping就是代表的是只允许GET请求,@PostMapping代表的是只允许POST请求。
具体使用代码示例如下:

四、获取各种参数
因为我们这里的Spring MVC是基于Servlet封装的,所以我们还是可以使用原Servlet的方式来进行参数获取的,这里就不再介绍使用Servlet的方式获取,这里直接使用Spring MVC中的注解的方式获取,如果对Servlet获取参数不了解或者感兴趣,可以看这篇文章☞【JavaWeb】Servlet API详解_小白学编程~的博客-CSDN博客
4.1、获取单个参数与多个参数
获取单个参数:
在Spring MVC中,想要获取参数比Servlet简单得多,只需要直接在方法的形参列表中写下相应的参数就可以实现前端传参到后端的功能,具体代码如下:

运行结果如下:
这里需要注意的是,后端方法中的形参列表的形参名字要与浏览器中query String中的key相对应,否则是无法获取的。
我们后端现在的参数名是name,假如我们现在前端浏览器中key使用username,那么后端是无法获取到的,如下所示:

获取多个参数:
获取多个参数其实和获取单个参数是差不多的,只要方法的形参列表中多写上几个参数就可以了,如下所示:

运行结果如下:
从上述运行结果中可以看出,我并没有去传递id这个属性,所以id就为null了,因为这里我们并没有去设置一定要有参数传递过来,所以即使没有传递参数也不会报错,这里的参数的顺序也是不重要的,因为这里是根据key来进行匹配的,而不是根据顺序。
还有需要注意的一点就是,这里后端代码中的id属性使用的是Integer这个包装类,并不是使用基本数据类型int,其实在前端传参数给后端时,我们后端接收参数一般不建议使用基本数据类型,都要使用对于的包装类,因为基本数据类型如果遇到前端没有传值过来,但是在接下去的代码中又继续使用到了,就会直接报异常,可能会导致程序直接出错了,所以一般建议使用包装类来接收参数,即使前端没传值过来,默认值就是null。
使用对象获取多个参数:
上面的代码中,我们已经可以获取到多个数据了,但是可以试想一下,假如要传的数据比较多时,我们就需要在方法的形参列表中写很长的代码,这样子就很冗余,因此,我们遇到参数较多时,话可以使用对象进行接收,首先,我们需要先定义一个对象,演示代码如下:
定义的对象:

获取参数的代码:

程序运行结果:

以上获取单个参数个多个参数的方法**,不仅是可以获取URL中query String(query String就是问号后的那一串),也可以获取form表单传递过来的参数。**
4.2、 后端参数重命名及设置参数必传
在前面的代码中,我们也提到过,如果前端传递过来的参数的参数名和后端这里的参数名不一致,后端是无法获取到参数的,但是,假如我们后端不小心把参数名写错了,且已经使用错的参数名写了很多代码,这时候如果再去修改参数名,要改的地方是很多的,工作量很大,所以,这时候我们比较好的解决方案就是为参数重命名。这里我们使用@RequestParam注解来实现参数重命名。
演示代码如下:

此时运行结果如下: 依旧可以正常获取
但是这时候我们需要注意的是,当我们像上面的代码那样写之后,这时候如果前端不给后端传参数,就会直接报错,如下所示:

为什么我们上面不传参数就会直接报错呢?这其实就跟@RequestParam这个注解有关 , 我们这时候可以按住ctrl然后点击@RequestParam注解,去源码中找找原因,源码如下所示:

我们从源码中可以看到required属性,这个属性就是要求我们参数必传的,且默认值为true。 所以我们使用**@RequestParam注解** ,如果只设置了name属性,没去设置required属性,那么就会变成参数必传属性。所以这时候,如果不想要参数是必传参数,就需要设置required属性,设置方法如下所示:
4.3、使用@RequestBody注解获取JSON对象
前端传递json对象在实际开发中还是很常见的,但是想要获取json对象并不像获取其他对象一样,如果还是根据原本获取对象的方法,我们是无法正常获取到的。
示例如下:
以下为后端代码:


使用Postman模拟发送请求:

我们可以看出,使用之前的获取参数的方式确实是已经无法获取到json对象的数据了。这里我们正确的方式是要添加@RequestBody注解了。正确的方式如下所示:
4.4、获取URL中的参数
我们这里获取的URL中的和前面的是不一样的 ,前面我们获取的参数虽然也属于URL中的,但是二者还是有区别的,我们前面获取的是"?"之后的字符串 ,那个字符串叫做query String,而我们现在要获取的是"?"之前的参数。

我们要想获取这个参数,和我们之前的方式都不一样,我们需要使用**@PathVariable注解,具体获取方式如下所示:**

运行结果:

使用 @PathVariable这个注解,需要注意的是,在每一个参数前都要加上这个注解,还有参数的名称也要与@RequestMapping()中有加{}的参数名字一致, 才能正确获取到url中的参数,这个注解和前面的@RequestParam注解相似,只要使用了,就会默认带上参数必传的设置,如果不要参数必传,就需要设置required属性为false。
4.5、获取文件@RequestPart
在我们的实际开发中,我们经常会有上传文件的需求,最常见的就是上传头像之类的,这时候当前端把文件发送到后端时,我们应该怎样接收呢?接下来就来详细介绍一下。
代码:
java
@RequestMapping("/getfile")
public String getAFile(@RequestPart("myfile") MultipartFile file) throws IOException {//获取前端传递过来的文件,并保存至指定路径,返回保存位置
//1.使用UUID生成一个不会重复的字符串作为文件名,并将其中的'-'字符删除
String fileName = UUID.randomUUID().toString().replace("-","");
//2.获取文件的后缀名,以下方法截取会带上'.'
fileName += file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
//保存到当前项目的static目录下
String path = ClassUtils.getDefaultClassLoader().getResource("static").getPath() + "/"+fileName;
file.transferTo(new File(path));//将文件保存
return path;
}
我们这里使用UUID来生成文件名是因为UUID是可以保证每一次是生成的都是不一样的字符串,否则要是我们将文件名设置为固定的,那么每一次文件上传都会覆盖前一次的,这样子的文件上传就没有意义了。
使用Postman模拟上传文件:

运行完之后target就变成了如下样子:

在这个上传过程中,如果与我上面那个代码一致的话,还是有可能会出错的,可能会出现NULLPointException空指针异常, 这是因为你的static下没有任何文件导致的,如果static文件目录里面没有文件,那么项目编译后一般就不会生成static目录,所以导致取不到路径就出现空指针异常。只要在static目录下随便创建个文件就可以了(注意是文件,不是文件夹)。
上传文件还有需要注意的是,SpringBoot官方默认的上传文件的大小是1MB,如果我们使用上述代码上传大小超过1MB的文件,就会报org.springframwork.web.multipart.MultipartException异常,最终上传失败。所以,如果我们**改变默认的上传的文件大小,**就需要在配置文件中修改默认的上传文件的大小,设置如下所示:

4.6、获取Cookie和Session、Header
使用@CookieValue获取cookie:
java
@RequestMapping("/getcookie")
public String getCookie(@CookieValue(name = "cook",required = false)String cook){
return cook;
}
要获取cookie,首先需要在网页上构建一个cookie,构建方法及构建后运行结果如下:
因为cookie是可以有很多个的,所以我们需要在@CookieValue注解中指定要获取的cookie名称

使用@SessionAttribute获取session:
java
@RequestMapping("/setsession")
public void setSession(HttpServletRequest request){//需要先设置setAttribute才能获取
HttpSession session = request.getSession(true);//不存在就创建session
if(session !=null){
session.setAttribute("username","zhangsan");
}
}
@RequestMapping("/getsession")
public String getSession(@SessionAttribute(value = "username")String username){
return username;
}
运行结果:运行getsession方法前,需要先执行setsession方法

使用@RequestHeader获取Header:
head中的属性是很多的,所以我们要获取head的的时候也是需要指定获取header中的属性名的,当然,如果是要全部获取,就可以使用原Servlet方法获取全部的Header。
java
@RequestMapping("/gethead")
public String getHead(@RequestHeader(name = "Host")String host){
return host;
}
运行结果如下: Header中的信息还有很多,可以根据需要获取到自己需要的数据。

五、返回数据
我们前面写的很多代码其实已经使用Spring MVC返回数据的功能了,我们在使用@ResponseBody注解来表明了返回的数据直接作为HTTP响应的内容,不会做任何的渲染,可以理解为就是直接返回文本类型数据。但是,其实我们不仅可以返回这种文本类型的数据,我们也可以返回静态视图,JSON格式数组,对象等等。
5.1、返回静态页面
我们可以直接在后端返回一个静态页面给浏览器,也就是html页面。我们接下来返回一个Login.html的页面,代码如下所示:

运行结果:需要注意的是,这里我们不能够加@ResponseBody注解,不然返回的就会是数据,而不是页面了。

5.2、返回HTML文本
对于返回HTML文本,我们只需要在原来返回数据的基础上加上html的标签就可以,不需要额外的操作,因为框架会自动的帮我们识别,如果有html标签就会将文本渲染成html格式的文本。
代码如下所示:这里依旧是需要加上@RequestBody注解的

运行之后的结果:

5.3、返回JSON对象
其实,在Spring MVC中,**如果我们给前端返回一个对象,框架都会把这个对象转成JSON格式的对象,**我们可以通过抓包来观察这个现象。如下所示:

总结:
现在实际的开发中都是采用前后端分离的,所以一般是不会使用@ResponseBody注解来直接返回文本数据的,也不会直接返回静态页面,而是处理前端提交过来的请求,根据前端的请求,在去查询数据库,将数据以对象的形式返回给前端,前端再对数据进行渲染,渲染后再将页面展示给用户。