Spring Web MVC 详解(1)

目录

[一、介绍 MVC](#一、介绍 MVC)

[二、Spring MVC 的三个基本功能](#二、Spring MVC 的三个基本功能)

[1.1 连接功能](#1.1 连接功能)

[1.2 Spring MVC 的创建和使用](#1.2 Spring MVC 的创建和使用)

[1.3 @RequestMappig 介绍](#1.3 @RequestMappig 介绍)

[1.4 Spring MVC 实现用户和 Spring 程序的连接](#1.4 Spring MVC 实现用户和 Spring 程序的连接)

[1.5 @GetMapping 和 @ PostMaping 注解](#1.5 @GetMapping 和 @ PostMaping 注解)

[1.6 Get 和 Post请求注解的多种写法](#1.6 Get 和 Post请求注解的多种写法)

[2.1 获取请求中参数的功能](#2.1 获取请求中参数的功能)

[2.2 获取7种类型的参数](#2.2 获取7种类型的参数)

(1)获取一个参数

(2)获取多个参数

(3)获取一个对象

[(4)获取一个 json 对象](#(4)获取一个 json 对象)

[(5)获取 URL中携带的参数](#(5)获取 URL中携带的参数)

(6)上传一个文件

(7)参数重命名

[1. 参数少传递:](#1. 参数少传递:)

[2. 参数传递名称不一样:](#2. 参数传递名称不一样:)

[3. 参数传递的顺序不同:](#3. 参数传递的顺序不同:)

[(8)Cookie 和 Session 以及 Header 的获取](#(8)Cookie 和 Session 以及 Header 的获取)


前言

Spring Web MVC 通常被称为 Spring MVC,是基于 Servlet API 构建的一个 Web 框架,前文介绍过的 Spring 项目的使用还不够,Spring 只是一个 IoC容器,将各种方法和类托管给 Spring,之后就需要和前端建立连接,所以 Spring MVC 可以实现和前端的交互,Spring MVC 就是 Spring 框架的核心模块,而 Spring Boot 是 Spring 框架的脚手架,是为了快速开发 Spring 项目的,这就是三者的区别。

一、介绍 MVC

MVC 就是三个模块的缩写:Model(数据库模块),View(视图,也就是前端),Conller(控制器,校验前端请求的数据并向后端数据库发送数据)。

MVC是一种模式,而 Spring MVC 是这种模式的具体实现,Spring MVC 实现了这种思想,并且基于 Servlet API 构建,形成的一个 Web 框架,有了Spring MVC 我们就可以和前端建立连接,然后基于 Spring MVC,实现一些业务逻辑。

二、Spring MVC 的三个基本功能

  • 1. 和浏览器建立连接
  • 2. 获取 URL 或请求中的参数
  • 3. 输出数据给浏览器

1.1 连接功能

将浏览器和 Java 程序连接起来,当用户访问一个地址时,Spring MVC 可以帮我们实现 URL 和 Spring 中的业务代码连接起来

1.2 Spring MVC 的创建和使用

首先创建一个 Spring 项目:

然后添加起步依赖:(在添加完 devTools 外部 jar 包之后就已经是 Spring MVC 项目了)

最后点击 Finish 即可。

1.3 @RequestMappig 介绍

@RequestMapping 注解也是开发中很常用的注解,可以实现路由注册,所谓路由注册就是用户在浏览器中输入了一个 URL 之后,可以将用户的请求对应到 Spring MVC 项目中的某个类的某个方法,这个映射的过程就是 路由注册。

1.4 Spring MVC 实现用户和 Spring 程序的连接

建立 UserController 类,写入 sayHi()方法,加上 @RequestMapping 和 @RestController 注解,如下代码:

java 复制代码
package com.example.demo.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController2 {
    @RequestMapping("/user/sayHi")
    public String sayHi() {
        return "do sayHi()";
    }
}

然后在程序启动类中启动项目,记住日志信息中的端口号,最后在浏览器中访问 路由映射的 url:

注:++可以看到上述代码是将 @RequestMapping 注解中的参数 设置了两个层级的路由,这是一种方式,还可以在类上加 @RequestMapping 注解然后设置 一个类的 路由地址,如果在一个类上设置了 @RequestMapping 注解,url 的格式就是 类 + 方法 的路由地址。++

1.5 @GetMapping 和 @ PostMaping 注解

在网络协议中介绍过,请求的方式有很多种,有get,post,put,delete 方法,而常用的请求方法就是 get 和 post 方法,那此时 @RequestMapping属于什么方式呢。可以使用 fiddle 抓包工具看一下:

上图所示:请求的方法是 Get 方法,那如果是 Post 方法是否可行。可以使用 postman 模拟请求工具试一下,下图所示:

注:++在浏览器中输入的url 默认就是一个 Get 方法,所以要使用 Post 方式构造 http 请求就需要借助工具。++

上图所示,@RequestMapping 注解可以实现两种 http 请求 方式,但是如果某种业务需求下如果只能使用 Get 或者 Post 一种请求方式,此时就需要使用@GetMapping 和 @ PostMaping 注解或者给 @RequestMapping 加一个参数 来限制用户请求只能使用一种方式构造 http 请求:

重启项目,再去访问 sayHi()方法之后:可以看到报405状态码,显示 get 方法请求不能访问:

1.6 Get 和 Post请求注解的多种写法

Get请求的三种使用注解写法:

java 复制代码
    @RequestMapping(value = "/user/sayHi", method = RequestMethod.GET)
    @GetMapping("/user/sayHi")
    @RequestMapping("/user/sayHi")

Post请求的两种使用注解写法:

java 复制代码
@RequestMapping("/user/sayHi")
@RequestMapping(value = "user/sayHi", method = RequestMethod.POST)

使用上述请求方法的写法可以达到同样的效果。

2.1 获取请求中参数的功能

当用户输入 URL后可以在 URL 中,也可以是在 http 请求中携带数据,这部分数据就是用户传过来的参数,Spring MVC 可以帮我们获取到这些各种各样的参数

2.2 获取7种类型的参数

|--------------------------|
| (1)获取一个参数 |
| (2)获取一个表单参数 / 获取多个参数 |
| (3)获取一个普通对象 |
| (4)获取一个 json 格式的对象 |
| (5)获取 URL 中携带的参数 |
| (6)上传一个文件 |
| (7)Session 的存储和获取 |

(1)获取一个参数

java 复制代码
package com.example.demo.controller;
import org.springframework.web.bind.annotation.*;

@RestController
public class UserController2 {
    @RequestMapping("/user/sayHi")
    public String sayHi(String name) {
        return "do sayHi() --> " + name;
    }
}

注:++此时在 URL 中传递的参数必须和 传递的形参名保持一致,否则无法获取到这个参数。++

浏览器访问 url 中加上 name 参数:

(2)获取多个参数

java 复制代码
@RestController
public class UserController2 {
    @RequestMapping("/user/sayHi")
    public String sayHi(String name, String password) {
        return "do sayHi() --> " + name + "  " + password;
    }
}

浏览器访问 url 中加上 name 和 passpord 参数:

获取一个表单参数和获取多个参数是同样的写法,此处不再介绍。

(3)获取一个对象

获取一个对象,首先在程序中要有一个实体类来作为数据传输的载体:

java 复制代码
package com.example.demo.entity;
import lombok.Data;

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

之后在 Controller 层写入获取对象的方法:

java 复制代码
@RequestMapping("/reg")
    public Object reg(Userinfo userinfo) {
        System.out.println(userinfo);
        return userinfo;
    }

之后在浏览器中传入响应的参数即可 (注:++此时不需要传递一个真正的对象,只需要把响应的参数写对,之后 Spirng MVC 框架就会帮我们自动实现 参数 和 对象属性 之间的映射,而且参数在返回的时候也是不需要指定返回的类型,因为 Object 类是所有类的父类,此时 框架在数据返回的时候也会帮我们进行 数据类型的判断,最后返回一个合适的类型++

我们可以写另一个方法来验证上述注意中的结论是否正确:

在 Controller 层中写入方法:

java 复制代码
@RequestMapping("/h1")
    public Object getH1() {
        return "<h1>我是h1标签</h1>";
    }

可以看到上述代码中的 geth1 方法的返回类型是一个 Object 类型,但是通过下图中的抓包可以看到 响应的数据正文中的类型已经是 html 格式的类型了,所以不用设置 响应的数据类型,这些事情 Spring MVC 框架已经帮我们实现好了。

(4)获取一个 json 对象

注:++如果前端传递的数据是一个json 对象,此时用一个 普通的对象来接收这个 json 对象是不可以拿到参数的。++

前端传递一个对象有两种方式:1. 构造一个 Ajax 请求来封装一个 json 对象。 2. 使用 postman 模拟请求工具构造一个带有 json 格式的对象 的请求。

第二种方式是最简单的构造一个 json 对象,所以介绍下用 postman 来传递一个 json 对象:

先在 Controller 层中写入 方法,此时用一个普通的对象这种形参是拿不到 json 格式的对象的;需要加一个 @RequestBody 注解来实现接收一个 json 对象 。

@RequestBody 注解也很好理解:就是在一个请求正文中获取一个对象。

java 复制代码
//传递一个json 对象
    //使用 @RequestBody 来获取
    @RequestMapping("/user/reg")
    public Object getJson(@RequestBody Userinfo userinfo) {
        System.out.println(userinfo);
        return userinfo;
    }

用 postman 构造一个带有 json 对象的请求:

用 fiddle 抓包工具抓以下看一下前端传递的是否是一个 json 对象:

(5)获取 URL中携带的参数

++++注:++此处的获取 URL 中的参数不是从 URL 参数部分获取参数,而是就在一个 URL 中获取参数。++

获取 URL 中的参数需要使用注解 @PathVariable,就是从路径中获取一个变量的 意思

先在Controller 层中写入方法:

java 复制代码
// 获取一个 URL 中的参数
    @RequestMapping("/reg2/{name}/{password}")
    public Object reg2(@PathVariable String name,@PathVariable String password) {
        return "name --> " + name + " password --> " + password;
    }

之后在浏览器输入 URL:

注:++一种参数是 query string 的形式,在 " ?" 之后的参数,一种是在 url 中的参数,第一种方式的参数更加简洁,而且浏览器抓取关键字优先级更高(就是在浏览器中会在页面种优先显示),第二种 query string 的格式更适合传递多个参数。++

所以,如果是很少的参数,推荐使用第一种方式,如果参数很多,不推荐使用第一种方式。

(6)上传一个文件

上传一个文件也需要使用注解:@RequestPart

java 复制代码
//上传一个文件
    @RequestMapping("/myUpload")
    public Object upload(@RequestPart("myImg")MultipartFile file) {
        File saveFile = new File("D:\\home\\myImg.png");
        try {
            file.transferTo(saveFile);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

使用 postman 模拟一个上传文件的请求:

如果上传的文件不是图片或者有下沟通的文件名要上传两份,上述代码的写法就不合适了,就需要生成不同的文件名,最主要的就是文件名后缀,上传的文件可以是各种各样的文件,所以后缀名不能是固定的,应该是如下代码:

(UUID中的 randomUUID() 方法可以生成一个唯一的文件名)

(在文件IO中有 getOriginalFilename() 方法,就是获取原始的文件名,这个文件名中就包含了文件后缀名,然后通过字符串截取的方式来获取文件后缀名)

java 复制代码
//上传一个文件
    @RequestMapping("/myUpload")
    public Object upload(@RequestPart("myImg")MultipartFile file) {
        String fileName = UUID.randomUUID() + //文件名
                file.getOriginalFilename().substring(// 文件名后缀
                        file.getOriginalFilename().lastIndexOf("."));
        File saveFile = new File("D:\\home\\myImg" + fileName);
        try {
            file.transferTo(saveFile);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

注:++需要注意上传文件大小是有限制的,单次上传文件大小不能超过 1 MB,否则会报异常;如果上传的文件大小超过 1MB,此时可以在配置文件中设置 最大上传的文件大小;如下代码:++

java 复制代码
spring.servlet.multipart.max-file-size=100MB
spring.servlet.multipart.max-request-size=100MB

(7)参数重命名

上述几种传递参数的方式如果前端的参数没有传递过来 或者 传递的形参名称不一样 以及 参数的顺序不一致 会怎么样呢?

例如:在传递多个参数时,可以看下图的执行结果:

1. 参数少传递:

2. 参数传递名称不一样:

3. 参数传递的顺序不同:

解决方法:++加注解 @RequestParam 来实现后端参数的 映射 并且 设置 参数是否必须传递。++

如下代码:

java 复制代码
 //传递多个参数
    @RequestMapping("/user/sayHi")
    public String sayHi(@RequestParam String name,@RequestParam String password) {
        return "do sayHi() --> " + name + "  password = " + password;
    }

加注解之后,此时的参数就必须传递:

如果参数名不一致,可以在注解的参数中设置重命名,然后设置一个参数是否为必须传递的参数:

java 复制代码
//传递多个参数  & 参数重命名
    @RequestMapping("/user/sayHi")
    public String sayHi(@RequestParam String name,@RequestParam(value = "pwd", required = false) String password) {
        return "do sayHi() --> " + name + "  password = " + password;
    }

@RequestParam 注解中的参数 required 默认值 就是 True,也就是只要后端有这个参数,在前端就必须传递过来;设置为 false 之后, pwd 这个参数就不是 必传的参数了

(8)Cookie 和 Session 以及 Header 的获取

获取Cookie:

此时需要加注解**@CookieValue**,就是获取到 Cookie 中的 value 值,然后在前端设置 Cookie 字段即可(因为已经在注解的参数中指定 Cookie 的key 值了,所以在前端设置的 name 必须和此处是一样的)

java 复制代码
//获取一个 cookie 对象
    @RequestMapping("/getCookie")
    public Object getSession(@CookieValue(name = "java", required = false) String java) {
        return java;
    }

获取 Header:

通过注解 @getHeader来实现 获取请求头部信息

java 复制代码
//获取 Header 中的信息
    @RequestMapping("/getHeader")
    public String getHeader(@RequestHeader("User-Agent") String userAgent) {
        return "userAgent : " + userAgent;
    }

在浏览器中找一个请求 Header 查看头部信息,之后将 Key 值复制到 代码中注解的参数中即可;如下图中运行结果:

获取 Session:

首先要想存储一个Session,需要先进行存储,之后才能获取到这个Session,但是存储Session 对象不能使用注解,前文中已经介绍过:Spring MVC 是基于 Servlet API 封装的框架,所以在存储 Session 会话时依然可以使用 servlet API 来存储 Session。如下代码:

java 复制代码
private static final String SESSION_KEY = "USERINFO_SESSION_KEY";
    //存储一个 Session
    @RequestMapping("/setSession")
    public void doPostConstruct(HttpServletRequest request) {
        //此处需要允许创建一个 Session 会话,因为用户第一次登录是需要创建一个 Session 会话的,
        //只有在之后的用户再次的登录的校验中才不允许创建一个会话
        HttpSession session = request.getSession();//通过这个请求获取一个 Session
        session.setAttribute(SESSION_KEY, "张三");
    }

    //获取一个Session
    @RequestMapping("/getSession")
    public Object getSession(@SessionAttribute(SESSION_KEY) String name) {
         return "session -- > " + name;
    }

由于 Spring MVC框架在进行初始化的时候,初始化的时机是在创建 HttpServletRequest 对象之前的,所以不能将 存储 Session 的业务写在初始化的方法中,因为在 Spring MVC 注入对象时,如果一个方法中有这个参数,就必须在初始化的时候将这个 参数 传递过来,所以我们需要用访问 路由的方式先存储一个 Session,然后再获取 Session 中的Key值,如下图所示:

注:++本文中没有介绍热部署,所以在获取参数时,修改代码之后需要重启项目才能看到正确的运行结果。++

最后就只剩下数据的返回了,下一篇文章再进行详细介绍。

相关推荐
sniper_fandc4 分钟前
使用Spring Cloud LoadBalancer报错java.lang.IllegalStateException
java·spring·spring cloud
bobz9655 分钟前
kubevirt 替换为 hostnetwork 的优势
后端
大象席地抽烟6 分钟前
Nginx Ingress 证书
后端
心之语歌6 分钟前
Java 设计 MCP SSE 配置
java·后端
华仔啊22 分钟前
推荐一款比Cursor更懂中国程序员的AI编程工具
前端·后端
海风极客29 分钟前
Ping命令这种事情用Go也能优雅实现
后端·go·github
liujing102329291 小时前
vscode里面怎么配置ssh步骤
ide·vscode·编辑器
天天摸鱼的java工程师1 小时前
“你能从字节码层面解释JVM内存模型吗?”——面试官的死亡提问
java·后端·面试
这里有鱼汤1 小时前
分享一个年化96%的小市值策略
后端
LaoZhangAI1 小时前
沉浸式翻译API深度解析:500万用户的翻译神器如何配置[2025完整指南]
前端·后端