一文通关Spring MVC

news2024/12/23 9:33:52

目录

🐳今日良言:少年负壮气,奋烈自有时

🐳一、Spring MVC的相关介绍

🐕1.Spring MVC的定义

🐕2.MVC 和 Spring MVC的关系

🐳二、Spring MVC的创建及使用

🐯1.Spring MVC项目创建

🐯2.Spring MVC相关注解介绍

🐯3.获取参数

🐳三、请求转发和请求重定向的区别

🐍1.请求转发

🐍2.请求重定向

🐍3.二者的区别


🐳今日良言:少年负壮气,奋烈自有时

🐳一、Spring MVC的相关介绍

🐕1.Spring MVC的定义

Sprintg MVC的定义:Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从⼀开始就包含在 Spring 框架中。它的正式名称“Spring Web MVC”来⾃其源模块的名称(Spring-webmvc),但它通常被称为“Spring MVC”。

要理解Spring MVC之前,首先需要了解一下什么是 MVC?

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

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

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

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

🐕2.MVC 和 Spring MVC的关系

在了解了MVC后,那么Spring MVC 和 MVC的关系是什么呢?

总结来说,MVC 是⼀种思想,⽽ Spring MVC 是对 MVC 思想的具体实现。

Spring MVC 是⼀个实现了 MVC 模式,并继承了 Servlet API 的 Web 框架。既然是 Web框架,那么当⽤户在浏览器中输⼊了 url 之后,我们的 Spring MVC 项⽬就可以感知到⽤户的请求。


 

🐳二、Spring MVC的创建及使用

🐯1.Spring MVC项目创建

在创建 Spring Boot 项⽬时,我们勾选的 Spring Web 框架其实就是 Spring MVC 框架,如下图所
示:
  
Spring MVC 项⽬创建和 Spring Boot 创建项⽬相同(Spring MVC 使⽤ Spring Boot 的⽅式创
建), 在创建的时候选择 Spring Web 就相当于创建了 Spring MVC 的项目。

🐯2.Spring MVC相关注解介绍

2.1@RequestMapping

在Spring MVC 中使用 该注解实现 URL 路由映射,也就是浏览器连接程序的作用。

路由映射:所谓的路由映射指的是,当⽤户访问⼀个 url 时,将⽤户的请求对应到程序中某个类 的某个⽅法的过程就叫路由映射

接下来,创建⼀个 UserController 类,实现⽤户到 Spring 程序的互联互通,具体实现代码如下:

@Controller   
@ResponseBody // 返回非静态页面数据
public class Controller1 {
    @RequestMapping("/index")
    public Object getIndex() {
        return "hello Spring MVC";
    }
}

 启动项目后,输入URL:127.0.0.1:8080/index

@RequestMapping 即可修饰类,也可以修饰⽅法,当修饰类和⽅法时,访问的地址是类 + ⽅法。
@RequestMapping 也可以直接修饰⽅法。
@RequestMapping 是get请求还是post请求,通过Fiddler抓包可以观察到:

 默认情况下是get请求。

那么,能不能指定GET或者POST 请求类型呢?

答案是可以的。

GET请求的三种写法:

1.@RequestMapping("/index")

2.@RequestMapping(value = "/exe1",method = RequestMethod.GET)

3.@GetMapping("/exe2")

 POST请求的两种写法:

1.@RequestMapping(value = "/post1",method = RequestMethod.POST)

2.@PostMapping("/post2") 

2.2@RequestBody

默认请求下⽆论是 Spring MVC 或者是 Spring Boot 返回的是视图(xxx.html),而现在都是 后端分离的,后端只需要返给给前端数据即可,这个时候我们就需要使用@ResponseBody 注解了。
注意:如果仅仅只是返回数据,需要给当前方法或者类加上@RequestBody注解,否则会报错。

🐯3.获取参数

3.1传递单个参数并获取

在 Spring MVC 中可以直接⽤⽅法中的参数来实现传参,⽐如以下代码:
 @RequestMapping("/input")
    public String get(String name) {
        System.out.println("参数 name:"+name);
        return "ok";
    }

此时,在对应的URL后跟上键值对,key是name,value随便值即可。

启动项目,输入URL:

 此时查看控制台打印信息:

通过上述方法即可获取单个参数。 

注:由于返回的是非静态页面的数据,因此,需要使用@RequestBody注解,否则会报错,如果需要返回的是静态页面,则不需要添加这个注解。

3.2传递对象

 Spring MVC 可以⾃动实现参数对象的赋值,⽐如 Student对象:

@Data
public class Student {
    private int id;
    private String name;
    private int age;
}

 传递对象代码如下:

 @RequestMapping("/input")
    public String get(Student student) {
        System.out.println("对象中的 id:"+student.getId());
        System.out.println("对象中的 name:"+student.getName());
        System.out.println("对象中的 age:"+student.getAge());
        return "ok";
    }

启动项目,输入网址:

查看控制台打印信息:

 如果查询字符串中没有该对象的属性,则获取到的属性是该属性类型的默认值,如int为0,boolean 是false。

3.3传递多个参数(非对象)

 获取多个参数的代码如下:

 @RequestMapping("/input")
    public String get(String name,String password) {
        System.out.println("参数中的 name:"+name);
        System.out.println("参数中的 password:"+password);
        return "ok";
    }

启动项目,输入网址:

查看控制台打印信息:

 当有多个参数时,前后端进⾏参数匹配时,是以参数的名称进⾏匹配的,因此参数的位置

是不影响后端获取参数的结果。

3.4后端参数重命名(后端参数映射)

某些特殊的情况下,前端传递的参数 key 和我们后端接收的 key 可以不⼀致,⽐如前端传递了⼀个 time 给后端,⽽后端⼜是有 createtime 字段来接收的,这样就会出现参数接收不到的情况,如果出现 这种情况,我们就可以使⽤ @RequestParam 来重命名前后端的参数值。
后端参数重命名的代码如下:
@RequestMapping("/input")
    public String get(@RequestParam("time")String creatime) {
        System.out.println("时间:"+creatime);
        return "ok";
    }

启动项目,输入网址:

 查看控制台打印信息:

3.5设置参数必传@RequestParam

在3.4的代码中,如果输入的URL的查询字符串中传递一个非time的参数,就会出现程序报错的情况,如下图:

 

这是因为后端已经声明了前端必须传递⼀个 time 的参数,但是前端没有给后端传递,我们查看
@RequestParam 注解的源码可以发现:

可以通过设置 @RequestParam 中的 required=false 来避免不传递时报错,具体代码实现如下:
 @RequestMapping("/input")
    public String get(@RequestParam(value = "time",required = false)String creatime) {
        System.out.println("时间:"+creatime);
        return "ok";
    }

此时,再次传入非time参数,不会发生错误。

 3.6@RequestBody 接收JSON对象

注意,这里并不是像3.2一样,在查询字符串中传入参数。

使用 Postman 构造JSON对象:

 

相关代码如下:

@RequestMapping("/input")
    public Object get(Student student) {
        return student;
    }

 启动项目,会发现即使输入了对象的属性,但是还是接收不到对象:

 此时,需要使用注解@RequestBody

@RequestMapping("/input")
    public Object get(@RequestBody Student student) {
        return student;
    }

启动项目,构造JSON对象,获取成功:

 

3.7获取URL中参数@PathVariable 

后端代码如下:

  @RequestMapping("/input/{name}/{password}")
    public Object get(@PathVariable String name,@PathVariable String password) {
        return "name:"+name+"password:"+password;
    }

启动项目,输入URL: 

 需要注意,前端必须和 /input 后面的{name}和{password}一一对应,否则会报错:

当修改input后面的password为pwd后,此时启动项目会发现报错:

 

观察@PathVariable 源码会发现:

想要不报错,将这个参数的requred设置为false即可。

 启动项目,输入URL:

注:

@PathVariable    获取的是 ?之前的参数

@RequestParam 获取的是 ? 之后的参数

 3.8上传对象@RequestPart

后端代码:

 @RequestMapping("/myupload")
    public Object upload(@RequestPart("haiyang")MultipartFile file) {
        // 要上传到的路径
        File save = new File("D:\\Data\\haiyang.png");
        try {
            file.transferTo(save);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

通过Postman 上传文件:

 此时观察D盘下的Data文件夹,会发现上传文件成功:

 

 但是这种传输会导致一种问题,后面传输的文件会覆盖前面传输的文件,该如何解决这种问题呢?

只需要让用户上传的文件保存后的文件名不同即可,使用UUID(通用唯一符)生成全球唯一的标识符再拼接上用户上传的文件名的后缀名作为新文件名进行保存。

修改后的代码如下:

 @RequestMapping("/myupload")
    public Object upload(@RequestPart("haiyang")MultipartFile file) {
        String fileName = UUID.randomUUID() + // 文件名
                file.getOriginalFilename().substring(  // 文件后缀
                        file.getOriginalFilename().lastIndexOf(".")
                );
        // 要上传到的路径
        File save = new File("D:\\Data\\"+fileName);
        try {
            file.transferTo(save);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

 此时,再次使用Postman上传文件,会发现每次提交的文件都会保存。

 

 


🐳三、请求转发和请求重定向的区别

🐍1.请求转发(forward)

请求转发的定义:请求转发是指在服务器端将用户请求转发到另一个URL,这个URL可以是同一个Web应用程序中的另一个Servlet或JSP页面,也可以是另一个Web应用程序中的URL。

相关代码:

@RestController
@RequestMapping("/test")
class Controller1{
    @RequestMapping("/forward")
    public Object getFw() {
        return "forward:/index.html";
    }
}

这里的 /index.html 的 / 表示去根路径下找这个index.html 文件。

在static 下创建一个静态页面 index.html.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>我的静态页面</title>
</head>
<body>
    <h1>hello 这是静态页面</h1>
</body>
</html>

 启动项目,输入URL:127.0.0.1:8080/test/forward

 使用Fiddler 进行抓包:

会发现,对于客户端而言,只向服务器发送了一次请求。 

🐍2.请求重定向(redirect)

请求重定向的定义:请求重定向是指服务器端接收到客户端的请求之后,会给客户端返回了一个临时响应头,这个临时响应头中记录了,客户端需要再次发送请求(重定向)的 URL 地址,客户端再收到了地址之后,会将请求发送到新的地址上。

相关代码:

  @RequestMapping("/redirect")
    public Object getRD() {
        return "redirect:/index.html";
    }

 启动项目,输入URL:127.0.0.1:8080/test/redirect

 使用Fiddler 进行抓包:

 

 会发现,对于客户端而言,向服务器发送了两次请求。 

🐍3.二者的区别

举一个简单的例子:

有一天,你跟妈妈说你想吃辣条,妈妈说:好,我去给你买。过了一会,妈妈买回辣条,然后交到你的手上,这个过程可以理解为:请求转发。

有一天,你跟妈妈说你想吃辣条,妈妈说:我给你钱,你自己去买。当你拿到钱后,你自己买到了辣条。这个过程可以理解为:请求重定向。

下面这幅图可以帮助理解。

假设你们学校的教务系统更换了网址,URL 由之前的/hello 更改为 /hello2。

 forward 和 redirect 具体区别如下:
1. 请求重定向(redirect)将请求重新定位到资源;请求转发(forward)服务器端转发。
2. 请求重定向地址发⽣变化,请求转发地址不发⽣变化。
3. 请求重定向与直接访问新地址效果⼀直,不存在原来的外部资源不能访问;请求转发服务器端转发有可能造成原外部资源不能访问。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/676409.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring Boot 如何使用 Log4j2 进行日志记录

Spring Boot 如何使用 Log4j2 进行日志记录 在开发 Java 应用程序时&#xff0c;日志记录是非常重要的一环。Spring Boot 提供了多种日志输出方式&#xff0c;其中 Log4j2 是一种比较常用的日志框架。本文将介绍如何在 Spring Boot 应用程序中使用 Log4j2 进行日志记录。 为什…

Verilog基础:标识符的向上向下层次名引用

相关文章 Verilog基础&#xff1a;表达式位宽的确定&#xff08;位宽拓展&#xff09; Verilog基础&#xff1a;表达式符号的确定 Verilog基础&#xff1a;数据类型 Verilog基础&#xff1a;位宽拓展和有符号数运算的联系 Verilog基础&#xff1a;case、casex、ca…

基于阿尔法均值滤波的FPGA图像系统(工程+原理图+PCB+仿真)

目录 前言一、研究背景及意义二、本文研究内容三、硬件系统框架设计1、总框架设计2、原理图&PCB设计3、实物设计4、电路介绍 三、中值滤波算法研究及改进1、图像噪声的产生及危害2、中值滤波算法3、高斯滤波算法4、改进的中值滤波算法&#xff08;α均值滤波算法&#xff0…

【跑实验05】利用CLIP中的图像编码器,如何遍历文件夹中的图像,将图像文件改为28*28的尺寸,然后输出到excel中的每一列,最后一列全都标记为0

文章目录 一、初步实现二、警告信息的解决 一、初步实现 要遍历文件夹中的图像并将其尺寸调整为28x28&#xff0c;并将结果输出到Excel中&#xff0c;可以按照以下步骤进行操作&#xff1a; 首先&#xff0c;确保您已经安装了Pandas库&#xff0c;用于处理Excel文件。可以使用…

简单认识Nginx主配置文件及实操模拟

文章目录 一、Nginx主配置文件1、全局配置2、添加 I/O事件配置4.HTTP配置 实操模拟部分一、Nginx虚拟主机配置1.1基于域名1.2.基于IP1.3.基于端口 二、Nginx访问状态统计三、Nginx配置访问控制1.基于授权的访问控制2.基于客户端的访问控制 一、Nginx主配置文件 位置&#xff1…

【机器学习】sklearn数据集的使用,数据集的获取和划分

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 sklearn数据集 二、安装sklearn二、获取数据集三、…

python第三方库概览

目录 第三方库的获取和安装 脚本程序转变为可执行程序的第三方库PyInstaller jieba库(必选)、wordcloud库&#xff08;可选&#xff09; 知识导图&#xff1a; 1.Python第三方库的获取和安装 Python第三方库依照安装方式灵活性和难易程度有三个方法&#xff1a;pip工具安装…

树莓派使用VNC、SSH、Xrdp等方式进行远程控制的方法和注意事项

下面来总结一下远程操控树莓派用到的三种方式及其注意事项&#xff0c;其实这三种方式对于所有的Linux系统来说都是适用的。 目录 一、ssh控制树莓派 1.开启 ssh服务方法一 2.开启 ssh服务方法二 二、VNC远程连接 三、xrdp远程连接 四、其他注意事项 一、ssh控制树莓派 S…

石油化工领域生产作业流程合规检测 yolov8

石油化工领域生产作业流程合规检测通过引入yolov8视觉数据智能分析技术&#xff0c;石油化工领域生产作业流程合规检测对生产作业流程进行实时监测和合规性检测&#xff0c;通过与预设标准进行比对&#xff0c;系统能够检测出不合规的操作或异常情况&#xff0c;并及时发出警报…

【Python】实现一个鼠标连击器,每秒点击1000次

前言 鼠标连击是指在很短的时间内多次点击鼠标按钮&#xff0c;通常是鼠标左键。当触发鼠标连击时&#xff0c;鼠标按钮会迅速按下和释放多次&#xff0c;产生连续的点击效果。 在这里鼠标连击的主要用途是&#xff1a; 帮助我们进行鼠标点击&#xff0c;疯狂连击&#xff1…

NUCLEO-F411RE RT-Thread 体验 (6) - GCC环境 I2C驱动移植以及i2c-tool的编写

NUCLEO-F411RE RT-Thread 体验 (6) - GCC环境 I2C驱动移植以及i2c-tool的编写 1、I2C驱动移植 RT-Rhread这里用的是软件模拟i2c&#xff0c;stm32的驱动里并没有找到硬件i2c的驱动&#xff0c;但是在GD32里面却有硬件i2c的驱动&#xff0c;有兴趣的小伙伴可以根据gd32的代码写…

Ubutun开机黑屏解决方法

开机黑屏解决方法 临时性解决方法永久性解决方法补充说明 在项目支持过程中发现Ubuntu 16 在新终端上开机黑屏&#xff0c;没有显示图形界面&#xff0c;这个可能是因为系统版本太低&#xff0c;对新显卡不兼容导致的&#xff0c;后通过查资料有如下解决方法。 临时性解决方法 …

腾讯云+PicGo+Typora图床,生成专属图片链接

腾讯云PicGoTypora搭建自己的图床 原创声明&#xff0c;转载请注明文章链接来源、作者信息 TyporaPicGogitHub搭建自己的图床&#xff0c;写作效率大大提升 索奇问答 问&#xff1a;图床是什么&#xff1f; 答&#xff1a;用户可以将图片上传到图床&#xff0c;然后将生成的…

代码随想录算法训练营第四十一天 |

01背包&#xff1a;n种物品&#xff0c;每种物品只有1个&#xff0c;有相应的重量和价值 最多只能装m的重量&#xff0c;最多价值为多少&#xff1f; dp[i][j] : [0, i]物品任取放进容量为j的背包里 不放物品i&#xff1a;dp[i-1][j] 放物品i&#xff1a;dp[i-1][j-weight[…

递归的浅浅应用

首先&#xff0c;这里是一道简单题目&#xff0c;浅浅地验证了我之前发过的这篇文章 写递归题目的思路 &#xff0c;我结合它来讲解一下这道题的思路&#xff1a; 剑指 Offer 27 和 method 226.翻转二叉树 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;…

python数据清洗 —— re.split()划分字符串

需求 对于一行字符串&#xff1a; route-views6.routeviews.org 141694 2a0c:b641:24f:fffe::7 184891 | CN | apnic | OTAKUJAPAN-AS Otaku Limited, CN要将其划分成如下7个部分&#xff0c; [route-views6.routeviews.org, 141694…

【C++篇】OOP下部分:友元、运算符重载与多态

友情链接&#xff1a;C/C系列系统学习目录 知识总结顺序参考C Primer Plus&#xff08;第六版&#xff09;和谭浩强老师的C程序设计&#xff08;第五版&#xff09;等&#xff0c;内容以书中为标准&#xff0c;同时参考其它各类书籍以及优质文章&#xff0c;以至减少知识点上的…

精选MyBatis面试题

什么是MyBatis&#xff1f; MyBatis是一个半ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;它内部封装了JDBC&#xff0c;加载驱动、创建连接、创建statement等繁杂的过程&#xff0c;开发者开发时只需要关注如何编写SQL语句&#xff0c;可以严格控制sql执行性能&a…

Python高级语法--迭代器和生成器的区别

迭代器 在 Python 中&#xff0c;迭代器&#xff08;iterator&#xff09;是访问集合元素的一种方式&#xff0c;它可以遍历一个序列中的元素&#xff0c;而无需事先确定序列的大小&#xff08;即无需全部载入到内存中&#xff09;&#xff0c;且支持惰性求值。使用迭代器可以…

程序员 35 岁以后就真的要返乡种田了么?如果家里没田怎么办?

前言 在科技互联网高速发展的当下&#xff0c;程序员这个职业无疑是备受关注的。然而&#xff0c;这个行业似乎总是被一种说法所笼罩&#xff1a;程序员年龄一旦超过35岁&#xff0c;就会面临职业生涯的下坡路&#xff0c;甚至需要考虑“返乡种田”。这种说法是否真实呢&#x…