Spring MVC: 一种简洁且强大的Web应用框架

简介: 这篇文章介绍Spring MVC,Spring MVC是现在基本所有Java程序的主流开发框架,这篇文章主要介绍三部分内容:实现用户和程序的映射(在浏览器输入URL地址之后,能够在程序中匹配到相应方法)。服务器端得到用户的请求参数服务器端将结果返回给用户(前端)

1.什么是Spring MVC?


1.1 MVC的定义


MVC是Model View Controller的缩写,它是软件工程中的一种软件架构模式,它把软件系统分为模型、视图和控制器三个部分。


微信图片_20230111204241.png

Model(模型) 是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存储数据。

View(视图) 是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。

Controller(控制器) 是应用程序中处理用户交互的部分。通常控制器负责从视图中读取数据,控制用户输入,并向模型发送数据


1.2 MVC和Spring MVC的关系


MVC是一种思想,而Spring MVC是对MVC思想的具体实现。就类似于我们在学习Spring时的IoC和DI一样,IoC是一种思想,而DI是具体的实现。


1.3 Spring、Spring Boot、Spring MVC三者的关系


Spring是包含了众多工具方法的IoC容器。


Spring Boot是为了简化Spring开发而产生的脚手架。


Spring MVC是一个基于MVC设计模式和Servlet API实现的Web项目,同时Spring MVC又是Spring框架中的一个Web模块,它是随着Spring的诞生而存在的一个框架。


2.使用用户和程序的映射


Spring MVC项目创建和Spring Boot创建项目相同(Spring MVC使用Spring Boot),在创建的时候选择了Spring Web就相当于创建了Spring MVC的项目。

先完成Spring MVC项目的创建,再进行下边的工作:


2.1 @RequestMapping注解


@RequestMapping是Spring Web应用程序中最常用到的注解之一,它是用来注册接口的路由映射的。


路由映射:当用户访问一个url时,将用户的请求对应到应用程序的某个类的某个方法中的过程就叫做路由映射。


@RequestMapping基础使用如下:

微信图片_20230111204236.png

@RequestMapping既可以修饰类,也可以修饰方法,当修饰类和方法时,访问的地址是类+方法对应的url。访问结果如下图:


微信图片_20230111204233.png

默认情况下,@RequestMapping既支持POST请求方式,也支持GET请求方式。但如果想要只支持一种请求,也可以指定哪种请求,如下代码所示:


@RequestMapping(value="/sayhi",method=RequestMethod.GET)
@RequestMapping(value="/sayhi",method=RequestMethod.POST)

2.2 @GetMapping和@PostMapping


如果既想要只支持一种访问方式,还想要更简单的写法,就可以使用下边的方式:


GET请求


@GetMapping("/sayhi")

POST请求


@PostMapping("/sayhi")

3.服务端得到用户的请求参数


3.1 获取单个参数


微信图片_20230111204229.png

使用postman来构造请求:

微信图片_20230111204226.png

注意,整形建议设置类型为包装类(Integer),在设置为包装类时,如果没有传参数,则该参数只是为空,而如果设置的是int类型,不传参数将会报错。


微信图片_20230111204223.png

微信图片_20230111204217.png


3.2 获取多个参数


代码:


微信图片_20230111204214.png

构造请求:


微信图片_20230111204210.png

注意:


在获取多个参数的时候,前端传来的参数顺序没影响,参数是按照Key-Value来赋值的,只要保证前后端参数的名称Key一致即可。

在进行交互时一般参数命名都用小写,防止出现解析错误的情况。


3.3 参数重命名


在3.2中获取到多个参数的前提,是要保证前后端参数的命名相同(即Key值相同),但如果前端传来的参数并不合理,可以通过参数重命名的方法,将前端传来的参数映射到自己命名的参数上,进一步完成后续的开发。


方法为使用@RequestParam注解;

比如在3.2中的示例中,前端传来的参数是name,而不是username,就需要进行重命名,代码演示如下:


微信图片_20230111204207.png


构造请求:

微信图片_20230111204204.png

注意事项:

在加了@RequestParam注解以后,那么前端一定要传递此参数,否则就会报错,如果想要解决此问题,可以给@RequestParam里面添加required=false。


微信图片_20230111204201.png

微信图片_20230111204158.png


3.4 获取对象


在程序中编写对象类,前端传来参数就给对象完成了初始化。


User类:


微信图片_20230111204156.png

获取对象:


微信图片_20230111204150.png


基于form表单构造请求:


微信图片_20230111204142.png

注意:在对象中的整形,Integer类不传参数默认为null,int类不传参数默认为0,并不会报错。


构造JSON格式请求:

微信图片_20230111204139.png

我们发现如果构造JSON格式的请求,并不能获取到参数,我们用Fiddler来进行抓包


微信图片_20230111204135.png

我们可以发现,请求报文中确实是有参数,但并没有被获取到,需要在参数列表中加上@RequestBody注解才能解决这个问题。


微信图片_20230111204132.png

微信图片_20230111204129.png


3.5 从URL地址中获取参数


注意,此处获取参数是通过URL地址,而不是从URL的参数获取


微信图片_20230111204126.png

实现需要通过注解@PathVariable,代码演示如下:


微信图片_20230111204122.png

构造请求:


微信图片_20230111204119.png

3.6 获取文件


实现获取文件的功能,需要用到注解@RequestPart。


因为在不同的环境下图片的保存位置不同,所以需要在配置文件中声明图片的保存路径,配置文件设置如下:


微信图片_20230111204115.png

防止图片由于路径的相同而导致图片被覆盖,还需要给图片名增添随机性,就是使用UUID,整体实现代码如下:


微信图片_20230111204112.png

使用Postman模拟上传文件(基于form-data格式上传文件)


微信图片_20230111204109.png

3.7 获取Cookie


因为Spring MVC是基于Servlet API实现的,所以其天然支持Servlet API,在Spring MVC项目中的每个方法,都可以获取到HttpServletRequest和HttpServletResponce对象。


所以获取Cookie有传统的基于Servlet的方法,和使用Spring MVC中注解的方法来获取Cookie


a)基于Servlet的方式获取Cookie


微信图片_20230111204106.png

为了防止空指针异常,我们先在浏览器随便加上一些Cookie。


微信图片_20230111204101.png

然后刷新页面,看idea控制台的日志信息打印:


微信图片_20230111204058.png

b)使用@CookieValue注解实现Cookie的读取


微信图片_20230111204055.png

请求访问:


微信图片_20230111204052.png

3.8 获取Header


a)基于Servlet的方式获取请求头中的信息


微信图片_20230111204049.png

微信图片_20230111204046.png


b)使用@RequestHeader注解来实现


微信图片_20230111204043.png

微信图片_20230111204040.png



3.9 存储和获取Session


存储Session的实现,Servlet和Spring MVC的操作方法相同,代码如下:


微信图片_20230111204037.png


存储成功后,浏览器的cookie中会多出一条记录(如下图),红框记录的Key-Value中的Value就是sessionID,可以根据这个sessionID来找到session会话,对应的session中就是我们刚刚通过setAttribute()方法存进去的session属性Key-Value。


微信图片_20230111204034.png

获取session还是有两种方法:


a)基于Servlet


微信图片_20230111204030.png

微信图片_20230111204027.png


b)使用@SessionAttribute注解


微信图片_20230111204024.png

红框中的代码通常要加,如果不加的话,那么当session中不存在此属性的时候程序就会报错。


构造请求:


微信图片_20230111204020.png

4.服务端返回结果给用户


4.1 返回静态页面


在1.1 中我们就提到了Spring MVC的MVC架构模式(如下图),因为Spring MVC是随着Spring的诞生而诞生的,在那个时期并没有将前后端分离开来,所以在View层也就不存在前后端视图的说法,所以,在Spring MVC的方法中,默认返回的都是静态页面的名称。


微信图片_20230111204017.png

我们先在resource资源文件路径下新建前端页面


微信图片_20230111204014.png

前端代码如下:


微信图片_20230111204010.png

后端代码:


微信图片_20230111204007.png

浏览器访问路径:


微信图片_20230111204003.png

4.2 返回非静态页面数据


因为在4.1中我们提到了Spring MVC方法默认返回的是一个静态页面,如果我们想要返回非静态页面的数据,就需要通过注解@ResponseBody或者组合注解@RestController来实现。


@ResponseBody

与4.1相同的代码,加上@ResponseBody注解,我们再来看浏览器访问的结果


微信图片_20230111204000.png

再次通过浏览器进行访问,就会发现返回的是非静态页面的数据了。


微信图片_20230111203956.png

注意:

@ResponseBody注解既可以修饰类,又可以修饰方法,如果加在类上:表示当前类中所有方法都会返回一个非静态页面的数据;但如果加在方法上:表示当前方法返回的是一个非静态页面数据。


@RestController

@RestController注解相当于@Controller+@ResponseBody,所以它的效果就相当于两个注解的效果和。


微信图片_20230111203952.png

4.3 返回JSON对象


在Spring MVC的方法中,服务器给前端返回一个JSON格式的对象,要比Servlet的方式简单很多,直接返回存储了键值对的HashMap对象给前端,Spring就能让其自动识别转变为JSON格式返回给前端。


代码如下:


微信图片_20230111203949.png

构造请求,结果如下:


微信图片_20230111203945.png

4.4 综合练习


计算器

前端使用form表单的方式提交参数,在后端实现计算器的功能返回结果给前端。


前端代码如下:

微信图片_20230111203941.png

后端代码:

微信图片_20230111203939.png

浏览器构造请求演示:


微信图片_20230111203935.gif

登录

前端使用ajax请求传递参数,后端返回状态给前端,实现登录的功能。


前端代码如下:


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="js/jquery.min.js"></script>
    <title>登录</title>
    <script>
        // ajax提交
        function mysub(){
            // 1.判空
            let username=jQuery("#username");
            let password=jQuery("#password");
            if(jQuery.trim(username.val())=="") {
                alert("请先输入用户名!");
                username.focus();// 光标重置到此处
                return;
            }
            if(jQuery.trim(password.val())=="") {
                alert("请先输入密码!");
                password.focus();// 光标重置到此处
                return;
            }
            jQuery.ajax({
                url:"/login",
                type:"POST",
                data:{"username":username.val(),
                "password":password.val()},
                success:function(body) {
                    alert(JSON.stringify(body));
                }
            });
        }
    </script>
</head>
<body>
    <div style="text-align: center;">
        <h1>登录</h1>
        用户:<input id="username"><br>
        密码:<input id="password" type="password"><br>
        <input type="button" value="提交" onclick="mysub()" style="margin-top: 20px;margin-left: 50px;">
    </div>
</body>
</html>


后端代码:


微信图片_20230111203931.png

浏览器构造请求演示运行:


微信图片_20230111203928.gif


4.5 请求转发或请求重定向


forward VS redirect

return 不但可以返回视图或者数据,还可以实现跳转,跳转的方式有以下两种:


forward实现请求转发

redirect实现请求重定向

两者的理解可以用一个借钱的例子来理解,张三向李四借钱,李四没有钱,但他向王五借来钱,又给了张三,这就是请求转发的过程,李四代为完成了张三的请求;但如果李四没有钱,他告诉张三王五有钱,让张三去找王五借钱,这个过程就是请求重定向的过程。


微信图片_20230111203925.png


分别来看两种方法的请求结果:


forward

微信图片_20230111203922.png

redirect

微信图片_20230111203919.png


可以发现两个方法都跳转成功到了同一个界面,但两者又有不同,具体区别如下:

【参考文章链接跳转】


经典面试题:请求转发和请求重定向的区别

1.定义不同


请求转发(forward)发生在服务端程序内部,当服务端收到一个客户端的请求之后,会先将请求转发给目标地址,再将目标地址返回的结果转发给客户端。

而请求重定向(redirect)是指服务端接受到客户端的请求以后,会给客户端返回一个临时响应头,这个临时响应头中记录了客户端需要再次发送请求(重定向)的URL地址,然后客户端按照这个URL再次发送请求。


2.请求方不同

请求转发(forward)是服务端的行为,而请求重定向(redirect)是客户端的行为。

交互流程如下图所示:


微信图片_20230111203915.png

3.数据共享不同

请求转发(forward)是由服务端实现的,所以整个执行流程中,客户端只发送了一次请求,因此整个交互过程中都是同一个Request对象和一个Response对象,所以请求和返回的数据是共享的;而请求重定向(redirect)是向由客户端发送两次完全不同的请求,所以两次请求中的数据是不同的。


4.最终URL地址不同

在上边的浏览器访问结果中我们也可以看出,虽然访问到的是同一个界面,诞生两次访问的最终URL地址是不同的。这是因为请求转发(forward)是在服务器端代为完成的,整个过程URL地址不变,而请求重定向(redirect)是服务器端告诉客户端另一个地址,客户端进行了再一次访问,而非刚开始请求的地址,所以URL地址发生了改变。


5.代码实现不同

微信图片_20230111203907.png

相关文章
|
23天前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
36 4
|
6天前
|
设计模式 前端开发 数据库
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第27天】本文介绍了Django框架在Python Web开发中的应用,涵盖了Django与Flask等框架的比较、项目结构、模型、视图、模板和URL配置等内容,并展示了实际代码示例,帮助读者快速掌握Django全栈开发的核心技术。
79 44
|
2天前
|
SQL 安全 PHP
探索PHP的现代演进:从Web开发到框架创新
PHP是一种流行的服务器端脚本语言,自诞生以来在Web开发领域占据重要地位。从简单的网页脚本到支持面向对象编程的现代语言,PHP经历了多次重大更新。本文探讨PHP的现代演进历程,重点介绍其在Web开发中的应用及框架创新,如Laravel、Symfony等。这些框架不仅简化了开发流程,还提高了开发效率和安全性。
8 3
|
1天前
|
前端开发 JavaScript 开发工具
从框架到现代Web开发实践
从框架到现代Web开发实践
7 1
|
5天前
|
SQL 安全 PHP
探索PHP的现代演进:从Web开发到框架创新
PHP 自发布以来一直在 Web 开发领域占据重要地位,历经多次重大更新,从简单的脚本语言进化为支持面向对象编程的现代语言。本文探讨 PHP 的演进历程,重点介绍其在 Web 开发中的应用及框架创新。自 PHP 5.3 引入命名空间后,PHP 迈向了面向对象编程时代;PHP 7 通过优化内核大幅提升性能;PHP 8 更是带来了属性、刚性类型等新特性。
13 3
|
7天前
|
前端开发 JavaScript
Bootstrap Web 前端 UI 框架
Bootstrap 是快速开发 Web 应用程序的前端工具包。
21 3
|
7天前
|
安全 数据库 开发者
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第26天】本文详细介绍了如何在Django框架下进行全栈开发,包括环境安装与配置、创建项目和应用、定义模型类、运行数据库迁移、创建视图和URL映射、编写模板以及启动开发服务器等步骤,并通过示例代码展示了具体实现过程。
25 2
|
3月前
|
存储 JavaScript NoSQL
构建高效Web应用:使用Node.js和Express框架
【8月更文挑战第30天】本文将引导你了解如何使用Node.js和Express框架快速搭建一个高效的Web应用。通过实际的代码示例,我们将展示如何创建一个简单的API服务,并讨论如何利用中间件来增强应用功能。无论你是新手还是有经验的开发者,这篇文章都将为你提供有价值的见解。
|
2月前
|
Web App开发 JavaScript 前端开发
构建高效Web应用:Node.js与Express框架的深度整合
【9月更文挑战第28天】在现代Web开发领域,Node.js和Express框架的结合已成为打造高性能、易扩展应用的黄金组合。本文将深入探讨如何利用这一技术栈优化Web应用架构,提供具体实践指导,并分析其性能提升的内在机制。通过代码示例,我们将展示从基础搭建到高级功能的实现过程,旨在为开发者提供一条清晰的学习路径,以实现技术升级和项目效率的双重提升。
47 3
|
2月前
|
JSON JavaScript 前端开发
构建高效Web应用:Node.js与Express框架的完美结合
【9月更文挑战第28天】在现代Web开发中,Node.js和Express框架的结合为创建高性能、易扩展的应用提供了强有力的支持。本文将深入探讨如何利用这两种技术构建一个简单但功能强大的Web服务,同时提供代码示例以加深理解。