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值,如下图所示:

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

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

相关推荐
ApiHug2 小时前
ApiSmart x Qwen2.5-Coder 开源旗舰编程模型媲美 GPT-4o, ApiSmart 实测!
人工智能·spring boot·spring·ai编程·apihug
杨哥带你写代码2 小时前
网上商城系统:Spring Boot框架的实现
java·spring boot·后端
camellias_2 小时前
SpringBoot(二十一)SpringBoot自定义CURL请求类
java·spring boot·后端
背水2 小时前
初识Spring
java·后端·spring
晴天飛 雪2 小时前
Spring Boot MySQL 分库分表
spring boot·后端·mysql
weixin_537590452 小时前
《Spring boot从入门到实战》第七章习题答案
数据库·spring boot·后端
孤客网络科技工作室2 小时前
在 Jupyter Notebook 中使用 Matplotlib 进行交互式可视化的教程
ide·jupyter·matplotlib
AskHarries3 小时前
Spring Cloud Gateway快速入门Demo
java·后端·spring cloud