Spring Web MVC 探秘

ops/2025/1/20 6:26:15/

一、生活中的Spring Web MVC

 对于Spring Web MVC这个专业名称,很多人都不清楚这个东西是干什么的,其实,Spring Web MVC在生活中无处不在,我们经常会使用到它们。

  假如你打开在线书店的网站,在首页的搜索框中输入了 “编程书籍”,然后点击搜索按钮。此时,浏览器会将这个搜索请求(包含关键词 “编程书籍”)发送到服务器。

  然后服务器会生成包含编程书籍信息的 HTML 视图后,将其发送回浏览器。浏览器接收到这个 HTML 页面后,就会解析并展示给用户,用户就可以看到搜索 “编程书籍” 后的结果页面,上面列有每本编程书籍的详细信息。

  这个例子就是基于 Spring Web MVC 实现的一个网站,你此时会不会对此产生一个问题:浏览器是如何通过处理用户的请求,并且返回用户想要的结果呢?

  接下来,就让我们对此进行一番 Spring Web MVC 的探秘,了解其背后的工作过程!

二、什么是MVC?

  Spring Web MVC 其实是基于 MVC 思想实现的一种是开发 Web 应用的有力工具。因此,要想了解 Spring Web MVC ,我们绕不开  MVC !    MVC 是一种软件架构模式,将项目分为模型(Model)、视图(View)和控制器(Controller)三个相互协作的部分,分别负责数据处理、界面展示和业务逻辑控制,以实现代码的解耦和高效开发维护。 

 

   让我们以在线书店网站为例子,深究一下基于 MVC 下的网站是如何工作的:

1、View(视图)层发起了一个请求

 当用户在在线书店网站的首页搜索框中输入 “编程书籍” 并点击搜索按钮时,这就相当于 View(视图)层发起了一个请求。视图层主要负责界面显示和人机交互,用户在这个层面上与系统进行交互操作,触发请求的发送。

2、Controller(控制器)选择合适的模型

  这个请求会被发送到 Controller(控制器)。 控制器接收到搜索 “编程书籍” 的请求后,它会分析这个请求,然后选择合适的模型来处理相关业务逻辑和数据。

3、Model(模型)处理业务逻辑

  Controller 选择好模型后,请求就会被传递到 Model(模型)。模型会根据控制器的要求,从数据库或其他数据源中获取与编程书籍相关的数据,并进行相应的处理和计算。

4、控制器返回响应

  最后,控制器将选择好的视图以及从模型获取的数据一起传递给视图层,视图层负责将这些数据填充到相应的模板中,并展示给用户。

  此时用户在浏览器上看到的就是经过视图层渲染后的页面,上面会列出搜索到的编程书籍的详细信息,如书名、作者、价格等,用户可以通过这个页面进行进一步的操作,如查看书籍详情、购买等。

三、Spring Web MVC 和 MVC 的区别

  MVC:是一种通用的软件架构模式,广泛应用于各类软件系统的开发,不局限于 Web 应用,旨在通过分离数据、界面和控制逻辑,提高代码的可维护性、可扩展性和可复用性。


  Spring Web MVC:是 MVC 架构模式在 Java Web 开发领域的具体实现框架,是 Spring 框架的一部分,专门用于构建基于 Java 的 Web 应用程序,提供了一套完整的 Web 开发解决方案,包括请求处理、视图解析、数据绑定等功能。

一句话来说:MVC 是一种思想,而Spring Web MVC 则是MVC 思想的一种具体实现。

(如果不懂得Spring框架是什么,可以参考我前面的文章:Spring 家族:项目开发的得力助手) 

四、Spring Web MVC 项目

(一)创建Spring Web MVC 项目

  Spring Web 是 Spring 框架中专门用于构建 Web 应用程序的重要组成部分,因此在创建Spring  Web MVC 项目时,我们要添加一个Spring Web 依赖。

  完成好上述步骤之后,我们就创建的项目就是Spring Web MVC 项目了。

(二)建立连接

  在创建好Spring Web MVC项目后,我们该如何让用户(浏览器)和我们的 Java 程序(服务器)进行连接呢?

   使用@Controller和@RequestMapping注解:

   通过在 Java 类上添加@Controller注解来标识这是一个控制器类,用于处理浏览器的请求。然后使用@RequestMapping注解来定义 URL 路径与控制器方法的映射关系。

  启动项目后,我们使用 Postman 通过URL路径访问服务器网站。

代码工作原理:

1. @RestController 注解

  @RestController 是一个组合注解,它相当于 @Controller 和 @ResponseBody 的组合。@Controller 注解用于标识这个类是一个控制器类,Spring MVC 会扫描到这个类,并将其纳入到请求处理的流程中。                                                                                                           
  @ResponseBody 注解表示该控制器类中的方法返回值直接作为 HTTP 响应体的内容。             
2. @RequestMapping注解

  在类上的 @RequestMapping("/user"):表示这个控制器类处理的请求路径的公共前缀是/user。也就是说,这个控制器中所有方法处理的请求路径都要以/user开头。                         
  在方法上的 @RequestMapping("/v1"):结合类上的@RequestMapping,完整的请求路径就是 /user/v1。当浏览器发送一个请求到 /user/v1 这个路径时,就会触发这个v1方法的执行。                                                                                                                                                    
3. 方法v1的执行

  当请求到达 /user/v1 时,v1方法会被调用。
  方法内部返回了一个字符串"Hello, my Spring Web MVC!"。由于类上有@RestController注解,这个字符串会直接作为 HTTP 响应的内容返回给浏览器,浏览器接收到后会显示这个字符串。

Postman:是一款支持发送 GET、POST、PUT、DELETE 等常见的 HTTP 请求方法,能够解析并格式化显示 JSON、XML 等格式的响应数据,方便开发者查看和分析接口返回结果的软件。可以和浏览器一样通过URL路径访问网站! 

(三)请求和响应

  要想探究浏览器和服务器之间的连接工作机制,我们还得专门学习两个特别常用的名词  "请求""响应" ,当我们使用URL路径访问服务器网站时,此时这个操作就会生成一个请求。

  浏览器会将这个请求发送给服务器,服务器针对这个请求,进行处理,返回给用户处理的结果,这个结果也就是响应。

五、请求

  有时候,用户使用浏览器进行搜索时,生成的URL路径(请求)会带有一些参数,服务器需要接收这些参数,以方便对用户请求的解析并且进行相应的处理,那么服务器是如何从浏览器中获取这些参数的呢?

(一)传递两个参数

传递两个参数代码:(类路径为 /urer,方法路径为 /v2)

Postman访问:

  注意:传递参数时,URL中的参数名称要和方法中的参数名称一致,否则服务器无法接收到参数的值,如下图就是参数名称不一致导致无法传参的情况。

  还有一点,参数的顺序可以改变,参数顺序的改变不会影响参数的传递!

    参数顺序可以改变的原因是:v2 方法的本质是 v21方法 ,首先服务器会从浏览器中获取到请求(request),再从 request 中去获取和方法参数名称一致的name 和age 。

(二)传递对象

  当我们需要传递多个参数时,在方法中可以使用一个对象来接收。

在这之前,我们先创建一个User类:

public class User {String name;Integer age;String sex;//生成setter方法(一定要生成Setter方法)public void setName(String name) {this.name = name;}public void setAge(Integer age) {this.age = age;}public void setSex(String sex) {this.sex = sex;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +", sex='" + sex + '\'' +'}';}
}

传递对象代码 :

 Postman访问:

  代码解析:  请求中发送了包含name、age、sex等字段的数据,并且这些字段与User类中的属性相对应,那么服务器会自动将这些数据填充到User对象中。(前提是User类中一定要有对应的Setter方法,否则服务器无法给User的属性赋值)

(三)参数绑定

  前面的学习中,我们知道了一件事,如果请求中的参数名称和方法中的参数名称不一致,那么就无法传参,那么有什么方法可以解决这个问题呢?

  使用@RequsetParam 注解 !

参数绑定代码: 

 Postman访问:

注解说明:@RequestParam 注解用于从 HTTP 请求的参数中获取指定名称的值,并将其绑定到方法的参数上。 

 

(四)传递数组

  当URL路径中包含多个名称相同的参数,此时服务器会将它们封装成一个数组。此时我们可以使用数组来接收。

传递数组代码:

Postman访问:

 在传递数组时,我们的URL路径也可以这样写:

(五)传递集合

那么传递集合类的数据,是不是也和数组差不多呢,让我们以List链表为例子。

 传递集合代码:

Postman访问:

  这里程序报错了,这是因为,默认情况下,URL中多个名称相同的参数会被封装成为一个数组,此时如果要使用List集合类来接收,需要使用 @RequestParam 进行参数绑定! 

  代码修改:将URL中获取到的 list 数组与方法中的 list 集合进行绑定

(六)传递Json对象

1、Json引入

  当我们需要传递一个对象给服务器,这个对象拥有很多属性时,比如传递一个Student对象。这个学生对象拥有学号、姓名、年龄、专业等很多很多属性,此时如果把这些参数都写入URL路径中,恐怕URL路径会特别长,那么我们就可以使用Json字符串,进行传递!

Json字符串示例: 

{"studentId": "123456","name": "小明","age": 20,"gender": "男","major": "计算机科学与技术","courses": ["数据结构", "操作系统", "编程语言"],"grades": {"数据结构": 85,"操作系统": 90,"编程语言": 88},"contact": {"email": "xiaoming@example.com","phone": "1234567890"}
}

 

  2、Json的概念:

  JSON 是一种轻量级的数据交换格式。在 Web 开发中,前端(如 JavaScript)和后端(如 Java、Python 等)之间经常使用 JSON 来传输数据。后端将数据封装成 JSON 格式发送给前端前端接收到 JSON 数据后进行解析和展示;前端也可以将用户操作产生的数据封装成 JSON 发送给后端进行处理。(Json本质上是一个字符串)

3、对象和Json之间的转换

使用之前创建的User类进行演示,注意User类中一定要有Getter和Setter和ToString方法。

4、传递Json对象

传递Json对象代码:

Postman访问:

 

(七)从URL中获取某个路径名

http: // 127.0.0.1 : 8080 / user / v1 ? name=zhangSan & age=18

  前面我们学习的,只是从URL路径的参数列表中获取数据,诸如 name=zhangSan 和 age=18,那么有没有什么方法,让我们可以获取到路径中的 user 和 v1路径名呢?

  使用 @PathVariable 注解!

获取URL路径代码:

 Postman访问:

注解解析:

1、访问的URL路径是 http:// 127.0.0.1:8080 /user /v8 /path1/path2

2、@RequestMapping("/v8/{aa}/{bb}")中的{aa} 的值为path1 和{bb}的值为path2

3、@PathVariable(”aa")  获取{aa}的值,赋值给s1,

      @PathVariable(”bb")  获取{bb}的值,赋值给s2。

 

(八)传递文件

传递文件代码:

Postman访问:

六、响应

1、什么是响应

  浏览器向服务器发送一个请求,服务器会解析这个请求,并且返回一个结果,这个结果就叫做 “响应”

接下来我们来看一个例子:

访问:http:127.0.0.1:8080/response/v1

  提问:这里我们想要return的明明是一个”index.html的视图,为什么服务器返回的不是html视图,而是 "/index.html" 的字符串?

  其实,服务器的响应结果可以是数据,也可以是静态⻚⾯,当我们将代码中的 @RestController

注解替换为@Controller注解,它的返回页面就变成了一个html页面。

  总结:服务器返回的数据类型,和 @Controller和@RestController两个注解有关,上面的例子中,当使用@Controller注解时,服务器返回一个html视图;当使用@RestController注解时,服务器返回一个字符串数据。

 

2、@RestController和@Controller 

 (1)  @RestController和@Controller 的区别:

  在早期的MVC项目开发中,后端的响应数据是一个视图(View),因此默认后端返回的数据都是html视图页面。

  随着互联网的发展,目前项目开发流行"前后端分离"模式,Java主要是用来做后端项目的开发,所以也就不再处理前端相关的内容了 ,MVC的概念也逐渐发生了变化,View不再返回视图,而是返回显示视图时需要的数据。

  所以前面使用的 @RestController 其实就是指定返回的结果是数据,而不是视图。当你使用@Controller注解时,服务器会默认你返回的响应是一个html视图。

  解析:当我们使用@RestController注解,返回值的内容(“/index.html")会被当成数据来作为响应,当使用@Controller注解,则会被当成一个html页面来作为响应。

(2)@RestController =@Controller+@ResponseBody

  @ResponseBody:  简单来说,它的作用是告诉框架,方法返回的数据应该直接作为响应内容发送给客户端,而不是经过视图解析器进行视图渲染。

  @ResponseBody既可以是类注解,也可以是方法注解,当注解在类时,表示这个类上的所有方法返回的数据直接作为响应内容发送给客户端;当注解在方法上时,表示该方法返回的数据直接作为响应内容发送给客户端。

 

(3)使用ResponseBody注解方法的例子:

去掉@ResponseBody注解:

  此时,当我们注释掉@ResponseBody注解时,浏览器访问时,会报错,这是因为,服务器此时认为应该返回一个视图 ,所有根据返回内容去查询文件,发现查询不到,因此报错!

(4)当返回的数据是html代码时,会被浏览器解析

 

 

(5)当返回的数据是一个对象时,会自动转换为Json字符串 

 

 

 

七、Cookie 和 Session

  你有没有过这样的经历,当你再次访问一个熟悉的网站时,它竟然能精准地记得你的喜好,甚至不用你重新登录就能直接进入个人页面?这背后其实都离不开两个关键的技术 ——Cookie 和 Session。那它们到底是什么,又是怎么做到这些神奇的事情的呢?接下来就让我们一起揭开 Cookie 和 Session 的神秘面纱 。

(一)Cookie和Session定义

  Cookie: 是存储在用户本地终端(通常是浏览器)上的小块数据。它是由服务器发送给浏览器,并由浏览器保存的文本信息。当浏览器再次向同一服务器发送请求时,会自动携带这些 Cookie 信息,服务器可以根据 Cookie 中的内容来识别用户的状态等相关信息。 

  Session :是一种服务器端的机制,用于在多个请求之间跟踪用户的状态。它在用户首次访问服务器时创建,在用户与服务器的交互过程中持续存在,直到用户退出登录或者会话超时等情况结束。

注意:由于Cookie和Session信息是存储在服务器内存中的,当服务器重新启动时,Cookie和Session会丢失。

(二)Cookie和Session的工作机制

为什么要有Cookei和Session? 

  因为互联网是无状态的,服务器不知道每次请求是不是来自同一个用户。Cookie 和 Session 的存在就是为了在多次请求之间识别用户身份、跟踪用户状态,让网站能够记住用户的偏好、购物车内容等信息,从而提供个性化和连贯的服务。 

  服务器会接收来自全球各地不同用户的请求,但是服务器为了给用户提供个性化的服务,必须得有一套识别机制,识别这个用户的身份。因此借助了Cookie和Session。

  (1)识别用户:当你第一次访问这个网站时,服务器会给你发送一个Cookie,这个东西是用来唯一识别你这个用户的。当你下次再次访问这同一个网站时,会自动携带这个Cookie发送给服务器,此时服务器就知道你是哪个用户了。 (接收到的Cookie存储在浏览器)

 (2)识别会话:光靠识别你是哪个用户还远远不够,服务器还必须得记住,你在这个网站上进行了一些什么操作,比如,当你正在使用一个购物网站,你在上次使用时添加一些商品进入购物车,服务器端需要记住你这些操作,以保证你下次再次访问时,你的购物车里面的东西和上次是一致的。

      Cookie里面一般会有一个 Session_id ,你可以把你和服务器之间的交互理解为你和服务器之间的进行的 ”会话“ ,Session_id 可以识别你和服务器之间的 ”会话“ ,它会唯一标识一个Session,而这个Session里面记录了你和这个网站交互的留下的信息(Session存储在服务器端)

session的创建:

  第一次访问网站时,当登录成功后,服务器会为用户创建一个 Session。服务器生成一个唯一的 Session ID,比如 “sess12345”,并将这个 Session ID 通过 Cookie 发送给 用户的浏览器。此时,浏览器存储这个 Cookie,其中包含 “sess12345” 这个 Session ID。

(三)获取Cookie

1、创建Cookie

在获取Cookie之前,由于我们首先来学习一下如何使用Postman给浏览器创建Cookie。(由于Cookie是存储在浏览器的,因此我们可以自己手动创建Cookie,Cookie的存在形式是“键--值”对)

 

  这里,我创建的Cookie如下图:

2、获取Cookie 

方式1:通过请求报文request获取

获取Cookie代码:

通过Postman访问后,服务器端输出结果:

方式2:通过@CookieValue获取Cookie

 获取Cookie代码:

通过Postman访问后,服务器端输出结果:

 

(四)获取Session

1、创建Session

  和获取Cookie一样,在获取之前,我们先来学习一下通过后端代码创建Session。(由于Session是存储在服务器的,因此我们要通过后端代码来创建,Session的存在形式是“键--值”对)

 创建Session代码:

通过Postman访问后,服务器端输出结果:

 

2、获取Session

方式1:通过请求报文(request)获取Session

获取Session代码:

Postman访问:

 方式2:直接获取Session

获取Session代码:

Postman访问:

方式3: 通过@SessionAttribute注解获取Session

获取Session代码:

Postman访问:

 


http://www.ppmy.cn/ops/151593.html

相关文章

HTML学习笔记(3)

一、元素种类 块级元素(标签,盒子) 特点:独占一行,对宽度高度支持内联级元素(标签,盒子) 特点:不独占一行,对宽度高度不支持内联块级元素(标签,盒子) 特点:不独占一行,对宽度高度支持弹性盒子 1.块级元素如div、p、h1~h6、ul、li等等,一个元素标签占一行&#xff0…

51单片机——DS18B20温度传感器

由于DS18B20数字温度传感器是单总线接口,所以需要使用51单片机的一个IO口模拟单总线时序与DS18B20通信,将检测的环境温度读取出来 1、DS18B20模块电路 传感器接口的单总线管脚接至单片机P3.7IO口上 2、DS18B20介绍 2.1 DS18B20外观实物图 管脚1为GN…

数据结构9——二叉搜索树

🥇1.二叉搜索树的概念 二叉搜索树(Binary Search Tree,BST)又称二叉排序树或二叉查找树,其要么是一棵空树,要么具有以下性质: ①:左子树上所有节点的值都小于根节点; ②:右子树上所有节点的值都…

iOS - Objective-C 底层实现中的哈希表

1. 关联对象存储&#xff08;AssociationsHashMap&#xff09; // 关联对象的哈希表实现 typedef DenseMap<const void *, ObjcAssociation> ObjectAssociationMap; typedef DenseMap<DisguisedPtr<objc_object>, ObjectAssociationMap> AssociationsHashMa…

oracle使用case when报错ORA-12704字符集不匹配原因分析及解决方法

问题概述 使用oracle的case when函数时&#xff0c;报错提示ORA-12704字符集不匹配&#xff0c;如下图&#xff0c;接下来分析报错原因并提出解决方法。 样例演示 现在有一个TESTTABLE表&#xff0c;本表包含的字段如下图所示&#xff0c;COL01字段是NVARCHAR2类型&#xff0…

Django SimpleUI 自定义功能实战

1. 引言 Django SimpleUI 是一个基于 Django 的后台管理界面美化工具,旨在帮助开发者快速构建现代化的后台管理系统。除了默认的功能外,SimpleUI 还支持高度自定义,开发者可以根据需求添加各种实用功能。本文将详细介绍如何在 Django SimpleUI 中实现自定义功能,包括数据同…

DeviceNet转Profinet网关+FANUC机器人:打造工业界的灭霸手套,掌控无限可能

在某车厂项目中&#xff0c;客户需将甲方的FANUC机器人接入自身Profinet网络系统。因机器人采用DeviceNET协议&#xff0c;所以选用稳联技术研发的Profinet转DeviceNET网关&#xff08;WL-DVN-PN&#xff09;实现通讯转换。 新建项目并导入稳联技术DeviceNET转Profinet网关&…

精通Python (13)

一&#xff0c;进程和线程 今天我们使用的计算机早已进入多CPU或多核时代&#xff0c;而我们使用的操作系统都是支持“多任务”的操作系统&#xff0c;这使得我们可以同时运行多个程序&#xff0c;也可以将一个程序分解为若干个相对独立的子任务&#xff0c;让多个子任务并发的…