【SpringMVC】Spring Web MVC入门(一)

在这里插入图片描述

文章目录

  • 前言
  • 什么是Spring Web MVC?
    • 什么是MVC
    • 什么是Spring MVC?
  • Spring Boot 和 Spring MVC 的区别
    • 什么是Spring Boot?
    • 关系和区别
  • Spring MVC 学习
    • 注解介绍
      • 1. @SpringBootApplication
      • 2. @RestController
      • 3. @RequestMapping
        • 3.1 @RequestMapping 使用
        • 3.2 @RequestMapping 能接受 GET 方法还是 POST 方法
      • 4 请求
        • 4.1 传递单个参数
        • 4.2 传递多个参数
        • 4.3 传递对象
        • 4.4 参数重命名
        • 4.5 传递数组
        • 4.6 传递集合
        • 4.6 传递JSON数据
        • 4.7 获取URL中参数
        • 4.8 上传文件
        • 4.9 获取cookie 和 session
        • 4.10 获取 header
      • 5. 响应
        • 5.1 返回静态页面
        • 5.2 返回数据
        • 5.3 返回HTML代码片段
        • 5.4 返回JSON
        • 5.5 设置状态码
        • 5.6 设置header
        • 5.7 设置响应的Content-Type

前言

前面我们了解了什么是Spring,那么今天我将为大家分享一种在日常网站开发中使用非常广泛的框架——Spring Web MVC。

什么是Spring Web MVC?

先来看看官方解释。

在这里插入图片描述
在这里插入图片描述
Spring Web MVC是Spring Framework提供的Web组件,它是一个MVC设计模式的框架,主要用于开发灵活、松散耦合的Web应用程序。它提供了模型-视图-控制(Model-View-Controller,简称MVC)的体系结构和可以用来开发Web应用程序的组件。

Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架。它使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助简化日常Web开发的。Spring Web MVC也是要简化我们日常Web开发的。

一直提到 MVC 架构模式,那么到底什么是 MVC 呢?

什么是MVC

MVC(Model-View-Controller)架构模型是一种软件设计模式,用于将用户界面、数据模型和控制器分离开来。这种架构模式可以提高系统的可维护性、可扩展性和灵活性。在MVC架构中,模型(Model)负责处理应用程序的数据和业务逻辑,视图(View)负责展示数据给用户,控制器(Controller)负责处理用户请求并协调模型和视图之间的交互。
在这里插入图片描述

  • View(视图):指在应⽤程序中专⻔⽤来与浏览器进⾏交互,展⽰数据的资源.
  • Model(模型):是应⽤程序的主体部分,⽤来处理程序中数据逻辑的部分.
  • Controller(控制器):可以理解为⼀个分发器,⽤来决定对于视图发来的请求,需要⽤哪⼀个模型来处理,以及处理完后需要跳回到哪⼀个视图。即⽤来连接视图和模型

MVC架构模式通常应用于桌面应用程序和Web应用程序开发中。在Web应用程序中,控制器通常由Servlet或Controller类来实现,模型通常由Java类来实现,视图则由HTML或JSP页面来实现。通过MVC架构模式,可以使得程序的各个部分更加独立,更易于维护和扩展。

什么是Spring MVC?

MVC 是一种架构设计模式,也是一种思想,而 Spring MVC 则是对 MVC 思想的具体实现,除此之外,Spring MVC 还是一个 Web 架构。

总结来说,Spring MVC 就是一个实现了 MVC 架构模式的 Web 框架。

在前面我们创建 Spring Boot 项目的时候,勾选的 Spring Web 框架其实就是 Spring MVC 框架。

在这里插入图片描述
那么这里有 Spring Boot 又有 Spring MVC,那么它们两个之间的区别是什么呢?

Spring Boot 和 Spring MVC 的区别

什么是Spring Boot?

Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。Spring Boot是Spring家族的一个子项目,其设计初衷是为了简化Spring配置,从而可以轻松构建独立运行的程序,并极大提高开发效率。

关系和区别

Spring MVC是一个用于构建Web应用程序的框架,它基于MVC设计模式,将业务逻辑、数据和界面显示分离,减少了各组件之间的依赖,提高了代码的可重用性。Spring MVC需要手动配置XML或其他类型的配置文件来管理应用程序的各个组件和依赖关系。

Spring Boot则是一个更为现代化的框架,它旨在简化Spring应用的初始搭建以及开发过程。通过约定优于配置的原则,Spring Boot可以自动配置应用程序的各种组件和依赖关系,避免了繁琐的手动配置过程。此外,Spring Boot还提供了许多内置的功能和工具,如内嵌的Web服务器、自动化测试、安全控制等,使得开发人员可以更加专注于业务逻辑的实现。

因此,可以说Spring Boot是Spring MVC的一种升级和优化,它通过自动配置和内置的工具简化了开发过程,提高了开发效率。同时,Spring Boot也支持使用Spring MVC等其他Spring组件,可以与它们无缝集成。

简单点来说,就是 Spring MVC 是通过 Spring Boot 添加 Spring MVC 依赖来实现 web 功能的。

虽然 Spring MVC 实现了 MVC 架构模式,但 Spring MVC 也结合了自身的特点,做了一些改变。

在这里插入图片描述

Spring MVC 学习

在知道了什么是 Spring MVC 之后,我们就可以来学习 Spring MVC 了,而学习 Spring MVC 关键是学习它的注解,因为在 Spring MVC 中,会使用到非常多的注解。

注解介绍

1. @SpringBootApplication

当我们创建完成一个 Spring MVC 项目之后,就会自动生成一个 “项目名”+Application 的类,并且在这个类中我们就可以看到第一个注解。

在这里插入图片描述
@SpringBootApplication 是一个方便的注解,它是 @SpringBootConfiguration 和 @EnableAutoConfiguration 的组合。这个注解让我们快速地开始一个 Spring Boot 项目。

  • @SpringBootConfiguration:该注解表示当前类是一个 Spring Boot 的配置类,它会包含一些基础的 Spring Boot 配置。
  • @EnableAutoConfiguration:该注解用于告诉 Spring Boot,根据当前项目中的类路径以及已经配置的属性,自动地选择和配置需要的 Bean。这大大简化了新项目的设置。

当你在 Spring Boot 项目中使用 @SpringBootApplication 注解时,它会自动配置一个开发环境,以便你可以快速启动并测试你的应用程序。同时,它也提供了一个基础的目录结构,让你可以更容易地管理你的代码。

也就是说 @SpringBootApplication 注解的类是 Spring MVC 项目的启动类,项目启动就是从这个类启动的。

我们先写一个简单的 Spring MVC 代码。

package com.example.springmvcdemo2;

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

@RestController
public class HelloController {
    @RequestMapping("/hi")
    public String hi() {
        return "你好,Spring MVC";
    }
}

写完这段代码启动之后,控制台会出现下面这样的结果。

在这里插入图片描述
出现这样的结果就表示我们的 Spring MVC 项目启动成功。

然后我们就可以使用浏览器访问当前的 Spring MVC 项目,在浏览器搜索栏输入http"//127.0.0.1:8080/hi,为什么要这样输入 URL 呢?前面我们说过,Spring 是在 servlet 的基础上开发的,所以 Spring 使用的也是 tomcat 服务器,tomcat 默认绑定的是 8080 端口和 8005 管理端口,所以访问 Spring 项目也就需要访问我们电脑的 8080 端口,但是前面我们学习servlet的时候,会发现 URL 中除了有/hi之外,还会有一个项目名称在路径中,但是这里访问 Spring MVC 项目的时候为什么不需要在 URL 中添加项目名称呢?前面的 servlet 中,tomcat和项目之间的关系是:一个 tomcat 服务器下面可以有多个项目,而在 Spring MVC 中,tomcat 和项目之间的关系是:一个 Spring MVC 项目下含有一个 tomcat 服务器,也就是一个项目对应一个 tomcat 服务器,换句话说就是:Spring MVC 允许同一时间启动多个 tomcat 服务器,只要保证这多个 tomcat 服务器的端口不冲突就可以,所以我们在访问 Spring MVC 项目的时候就不需要指定项目名称。

然后 /hi 就是我们 @RequestMapping 中的内容。

在这里插入图片描述

上面的简单代码中也出现了两个新的注解 @RestController 和 @RequestMapping。我们来看看这两个注解的作用。

2. @RestController

⼀个 Spring MVC 项⽬中,会有很多类,每个类可能有很多的⽅法,Spring程序怎么知道要执⾏哪个⽅法呢?

Spring会对所有的类进⾏扫描,如果类加了注解 @RestController,Spring才会去看这个类⾥⾯的⽅法有没有加 @RequestMapping 这个注解,当然他的作⽤不⽌这⼀点,咱们先⽤,后⾯再详细讲。

3. @RequestMapping

在 Spring MVC 中使⽤ @RequestMapping 来实现 URL 路由映射,也就是浏览器连接程序的作⽤。

路由映射:当用户访问⼀个 URL 时, 将⽤⼾的请求对应到程序中某个类的某个⽅法的过程就叫路由映射。

我们在上面的代码中,当访问了 127.0.0.1:8080 ,也就是本地的 tomcat 服务器之后,后面的 /hi 就表示访问 /h1 路由映射的方法。

那么这个 @RequestMapping 中的 / 可以省略吗?其实是可以的,当你省略了这个 / 的时候,Spring 会为我们自动加上 / ,所以还是建议大家加上这个 /。

package com.example.springmvcdemo2;

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

@RestController
public class HelloController {
    @RequestMapping("hi")
    public String hi() {
        return "你好,Spring MVC";
    }
}

在这里插入图片描述

@RequestMapping 是 Spring MVC 项目中最常用到的注解之一,下面我们来详细学习一下 @RequestMapping 的使用。

3.1 @RequestMapping 使用

@RequestMapping 注解不仅可以使用在方法上,还可以使用在类上。

package com.example.springmvcdemo2;

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

@RestController
@RequestMapping("sayHi")
public class HelloController {
    @RequestMapping("hi")
    public String hi() {
        return "你好,Spring MVC";
    }
}

当 @RequestMapping 修饰了类之后,那么访问的地址就是 类路径 + 方法路径了。

这里访问的时候,没有加上类路径,就无法成功访问。
在这里插入图片描述
在这里插入图片描述

3.2 @RequestMapping 能接受 GET 方法还是 POST 方法

为了解决这个问题,我们需要使用 postman 来分别构造出 GET 请求和 POST 请求。

在这里插入图片描述
在这里插入图片描述
通过 postman 构造出 GET 请求和 POST 请求可以看出来,这个 @RequestMapping 默认是支持 GET 方法和 POST 方法的,那么是否有方法可以是它只能接收 GET 或者 POST 请求呢?答案是可以的。我们可以看看 @ReqeustMapping 的源码。

在这里插入图片描述

  1. @Target({ElementType.TYPE, ElementType.METHOD}): 这个注解可以用于类级别或方法级别。
  2. @Retention(RetentionPolicy.RUNTIME): 这个注解在运行时有效,即运行时的代码可以访问这个注解的信息。
  3. @Documented: 这是一个标准的JavaDoc注释,用于生成API文档。
  4. @Mapping: 这个注解通常与Spring的@Configuration类一起使用,用于映射处理方法到URL路径。
  5. @Reflective({ControllerMappingReflectiveProcessor.class}): 这个注解指示Spring在运行时解析和处理带有此注解的类和方法。

注解中的各个元素:

  1. name(): 返回一个字符串,表示这个映射的名称。如果没有指定,默认为空字符串。
  2. value(): 返回一个字符串数组,表示需要映射的URL路径。如果没有指定,默认为空数组。这个路径可以包含占位符,例如/users/{id}。
  3. path(): 另一个用于指定URL路径的数组。这个数组的值和value()返回的值是一样的,它们是互为别名的。
  4. method(): 返回一个RequestMethod数组,表示这个映射接受的HTTP方法类型。如果没有指定,默认为空数组,表示接受所有方法类型。
  5. params(): 返回一个字符串数组,表示请求参数。如果请求参数符合数组中的任何一个,那么这个映射就会被触发。
  6. headers(): 返回一个字符串数组,表示请求头。如果请求头符合数组中的任何一个,那么这个映射就会被触发。
  7. consumes(): 返回一个字符串数组,表示这个映射接受的媒体类型。如果没有指定,默认为空数组,表示接受所有媒体类型。
  8. produces(): 返回一个字符串数组,表示这个映射能产生的媒体类型。如果没有指定,默认为空数组,表示能产生所有媒体类型。

@RequestMapping 中 method 默认为接收所有方法的请求,如果我们想指定一种方法,就可以显式的指明请求的方法。

@RequestMapping(value = "sayHi", method = RequestMethod.GET)

当 @RequestMapping 中只有一个参数的时候,这个参数会被认为是 value,如果有多个参数,则需要显式的指明参数的 key,类似value=”sayhi“,method=RequestMethod.GET。

更改完 @RequestMapping 中的参数,只允许接收 GET 请求之后,我们再用 postman 构造 GET 请求和 POST 请求看看结果。

在这里插入图片描述
在这里插入图片描述
当构造出 POST 方法之后,就显示 405,方法不被允许。

4 请求

访问不同的路径,就是发送不同的请求。在发送请求的时候,可能会传递一些参数,我们后端就需要拿到这些传递的参数来做出相应的业务处理。

4.1 传递单个参数

在 Spring MVC 中,我们可以使用跟传递来的参数相同的名字就可以获取到这个参数,这都是 Spring MVC 底层都帮我们做好了的,其实 Spring MVC 底层为我们做了很多事情,发送来的请求在由 Controller 转发到 Mudel 的时候,一些我们可能需要用到的东西,都是 Spring MVC 底层帮我们处理过的,如果想要使用只需要拿到就可以了。

package com.example.springmvcdemo2;

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

@RestController
@RequestMapping("/request")
public class UserController {
    @RequestMapping("/r1")
    public String r1(String name) {
        return "name: " + name;
    }
}

在这里插入图片描述

但是如果我们将参数的名字和请求的参数名字不一样的话,那么我们后端这里就不能获取到这个参数。

package com.example.springmvcdemo2;

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

@RestController
@RequestMapping("/request")
public class UserController {
    @RequestMapping("/r1")
    public String r1(String username) {
        return "name: " + username;
    }
}

在这里插入图片描述

4.2 传递多个参数
@RequestMapping("/r2")
public String r2(String name, int age) {
    return "name: " + name + " age: " + age; 
}

在这里插入图片描述

可以发现,请求中参数的顺序和我们代码获取参数的顺序可以不用保持一致。

如果我们这里的 age 没有传递参数的话,会发生什么呢?

在这里插入图片描述
当 int 类型的 age 参数为传递的话,这里会报出一个 500 的错误,也就是我们的服务器,Java代码出现了错误,这时就需要我们去看看代码日志,看看出现了什么问题。

在这里插入图片描述
通过前面观察代码可以知道,如果参数未传递的话,会默认返回 null,但是由于我们接收参数使用的是 int 类型来接收这个参数的,int 类型不能够转换 null,所以就会报错,避免这个问题的方法就是使用 int 类型的包装类 Integer,这样就能够处理返回的 null。

@RequestMapping("/r2")
public String r2(String name, Integer age) {
    return "name: " + name + " age: " + age;
}

在这里插入图片描述
通过上面的一个例子,我们得出一个结论:在接收参数的时候,尽量使用基本数据类型的包装类。

还有一个问题,就是如果我们后端觉得这个参数是 Integer 类型,所以就用 Integer 来接收,但是请求中该参数传递的却是 String 类型,那么这会发生什么问题呢?来看看。

在这里插入图片描述
后端获取参数的数据类型需要和请求的参数数据类型之间能够转换,否则就会出现问题,这就需要前端和后端协商好。

4.3 传递对象

如果传递的参数很多的时候,那么方法声明就需要很多的的形参,在后续增加参数的时候,也需要更改方法中的形参 ,所以这样就会显得很麻烦,所以我们就可以把这些参数封装为一个对象,可以在这个对象中一次性把所有可能会用到的参数都给写进去,如果请求传递的参数没有的话,就会被设置为默认值,就算后续需要添加参数的话,也是在我们封装的这个对象中更改。当Spring MVC 接收的参数是对象类型的话,那么Spring MVC 就会根据对象中的属性,然后在请求中找到对应的值,并且将这些属性给赋值,这样就极大的方便了我们程序员的工作。

封装一个 UserInfo 对象。

package com.example.springmvcdemo2;

public class UserInfo {
    private String name;
    private Integer age;
    private Integer id;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "UserInfo{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", id=" + id +
                '}';
    }
}
@RequestMapping("/r3")
public String r3(UserInfo user) {
    return user.toString();
}

在这里插入图片描述
在这里插入图片描述

4.4 参数重命名

虽然在做项目之前,前端和后端肯定协商了请求中参数的名称,但是我后端程序员写的写的感觉这个名字不好,我想换一个可以吗?答案是可以的,这里需要使用到 @RequestParam 注解来实现参数的重命名。

@RequestMapping("/r4")
public String r4(@RequestParam("name") String username, @RequestParam("age") Integer userage) {
    return "username: " + username + " userage: " + userage;
}

在这里插入图片描述
如果我们加了这个注解之后,但是请求中没有这个参数的时候就会出现问题了。

在这里插入图片描述
这是因为该注解默认该参数是必须要传递的,所以就需要设置该默认值为非必传。

在这里插入图片描述

@RequestMapping("/r4")
public String r4(@RequestParam("name") String username, @RequestParam(value = "age", required = false) Integer userage) {
    return "username: " + username + " userage: " + userage;
}

在这里插入图片描述

4.5 传递数组

Spring MVC 可以自动绑定数组参数的赋值。也就是说:Spring MVC 会自动帮我们处理请求参数是数组的情况。

@RequestMapping("/r5")
public String r5(String[] arr) {
    return Arrays.toString(arr);
}

在这里插入图片描述
在这里插入图片描述

4.6 传递集合

和传递数组类似,当请求中的参数有多个相同的名称时,也可以看作是集合,只不过如果将他看作是集合的话,需要使用 @RequestParam 绑定参数关系。因为在默认情况下,请求中有多个参数名称相同的话,Spring MVC 会将它们封装为数组,要想封装为集合的话就需要使用 @RequestParam 来绑定参数关系。

@RequestMapping("/r6")
public String r6(@RequestParam("list") List<String> list) {
    return "size: " + list.size() + " list: " + list;
}

在这里插入图片描述

4.6 传递JSON数据

JSON数据格式因为其易于阅读和编写、跨平台、跨语言、、轻量级等优势称为网络传输中最常使用的一种数据格式,那么在 Spring MVC 中如何接收到请求中传递来的 JSON 数据格式呢?

因为 JSON 数据格式是键值对的形式,所以我们将需要接收的参数封装到 Java 对象中,然后 Spring MVC 参数中使用 @RequestBody 来修饰这个参数,这样当 Spring MVC 接收到 JSON 数据的时候,就会根据 Java 对象中的属性然后在这些 JSON 数据中查找相同名称的键值对,并且将值赋值给 Java 对象属性。

@RequestMapping("/r7")
public String r7(@RequestBody UserInfo user) {
    return user.toString();
}

在这里插入图片描述

fiddler 抓包结果。

在这里插入图片描述

4.7 获取URL中参数

通过使用 @PathVariable ,可以实现 URL 路径上的数据绑定。在路径上使用 {} 来表示要绑定的数据。

@RequestMapping("/r8/{name}/{age}")
public String r8(@PathVariable String name, @PathVariable Integer age) {
    return "name: " + name + " age: " + age;
}

在这里插入图片描述
Spring MVC 接收绑定数据的参数的时候,需要保证和请求中传递的参数顺序保持一致,否则就可能会出现问题。

在这里插入图片描述
被 @PathVariable 修饰的参数也是必传的,如果想要设置为非必传的话,不仅需要更改 @PathVariable 的默认值,还需要在路径上做出调整。

我们先是只更改 @PathVariable 的默认设置看看能不能成功。

@RequestMapping("/r8/{name}/{age}")
public String r8(@PathVariable(value = "name", required = false) String name, @PathVariable Integer age) {
    return "name: " + name + " age: " + age;
}

在这里插入图片描述
显然不能成功,所以就还需要在路径上做出修改。

@RequestMapping({"/r8/{name}/{age}", "r8/{age}"})
public String r8(@PathVariable(value = "name", required = false) String name, @PathVariable Integer age) {
    return "name: " + name + " age: " + age;
}

在这里插入图片描述

4.8 上传文件

Spring MVC 同样可以接收到请求传来的文件,使用 @RequestPart 修饰即可接收文件。

@RequestMapping("/r9")
public String r9(@RequestPart MultipartFile file) throws IOException {
    String fileName = file.getOriginalFilename();
    file.transferTo(new File("D:/tmp/" + fileName));
    return "接收到的文件的名称为" + fileName;
}

在 Spring MVC 中表示文件这种类型需要使用到 MultipartFile,transferTo()方法是将文件复制到指定的目录下。

postman 这样传递文件。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.9 获取cookie 和 session

获取cookie

前面我已经为大家介绍了关于 cookie 和 session 相关的知识,如果大家忘记了的话可以去看看,cookie 和 session。

由于 cookie 是由浏览器在发送请求的时候带上的,所以我们就需要得到 HttpServletRequest 类,然后通过这个类来获取到 cookie。

@RequestMapping("/r10")
public String r10(HttpServletRequest request) {
    Cookie[] cookies = request.getCookies();
    StringBuilder sb = new StringBuilder();
    for (Cookie cookie : cookies) {
        sb.append(cookie.getName());
        sb.append("=");
        sb.append(cookie.getValue());
        sb.append("<br>");
    }

    return sb.toString();
}

写完 Spring MVC 代码之后,我们就需要在 postman 中构造 cookie 了。

在这里插入图片描述
在这里插入图片描述

点击 add domain 之后,就会出现下面的页面,然后我们点击 add cookie,添加cookie。
在这里插入图片描述
在这里插入图片描述
这里 username 就表示的是这个 cookie 的 name,而 zhangsan 则表示该 cookie 的 value,Path 定义了Web站点上可以访问该 cookie 的目录,这里 / 表示所有目录。

在这里插入图片描述
构造完成之后,在 postman 的这个部分就会显式我们设置好的cookie。

在这里插入图片描述
在这里插入图片描述

以上是一种获取 cookie 的方式,Spring MVC 还为我们提供了更方便的获取 cookie 的方式。

@RequestMapping("/r11")
public String r11(@CookieValue("username") String username) {
    return "username=" + username;
}

在这里插入图片描述
但是这个方式一次只能获取到一个 cookie,如果我们需要获取到多个 cookie,就可以使用第一种获取 cookie 的方式。

获取session

咱们的服务器要想获取到 session,就需要依靠请求中 cookie 中携带的 sessionId,然后在服务器这里服务器根据这个获取到的 sessionId,拿到与这个浏览器的 session,所以我们还是需要获取到 HttpServletRequest 对象。

在获取到 session 之前呢,还需要我们手动设置出一个 session,然后再设置一些属性。

@RequestMapping("/setsession")
public String setSession(HttpServletRequest request) {
    HttpSession session = request.getSession(true);
    session.setAttribute("username", "zhangsan");

    return "设置session完成";
}

在这里插入图片描述
当设置完成session之后,我们查看cookie,可以发现,cookie中自动添加进去了一个cookie,这个cookie就记录了sessionId。

在这里插入图片描述

设置完成 session 之后,我们就可以获取到这个 session 了。

@RequestMapping("/getsession")
public String getSession(HttpServletRequest request) {
    HttpSession session = request.getSession(false);
    if (session != null) {
        return "username: " + (String)session.getAttribute("username");
    }

    return "session为null";
}

在这里插入图片描述

Spring MVC 提供了几个简单的获取 session 的方式。

@RequestMapping("/getsession1")
public String getSession1(HttpSession session) {
    return "username: " + (String)session.getAttribute("username");
}

在这里插入图片描述
不仅如此,如果该浏览器和服务器是第一次建立连接,不存在 session ,也就是session为null的时候,session.getAtttribute() 不会出现空指针一样,这是因为 Spring MVC 底层帮我们解决了这个问题。

我们把这个sessionId cookie给删除了,然后给服务器发送请求。
在这里插入图片描述
在这里插入图片描述

另一种 Spring MVC 提供的方式更加简单,可以直接获取到 session 中的属性值。

@RequestMapping("/getsession2")
public String getSession2(@SessionAttribute("username") String username) {
    return "username: " + username;
}

在这里插入图片描述

4.10 获取 header

首先我们还是使用传统的方式获取到 header:通过 HttpServletRequest 类来获取到我们需要的header。

@RequestMapping("/getheader")
public String getHeader(HttpServletRequest request) {
    String ua = request.getHeader("User-Agent");
    return "获取到User-Agent:" + ua;
}

在这里插入图片描述
在这里插入图片描述
使用 Spring MVC 提供的 @RequestHeader 注解来获取到 header。

@RequestMapping("/getheader2")
public String getHeader1(@RequestHeader("User-Agent") String ua) {
    return "获取到User-Agent:" + ua;
}

在这里插入图片描述

5. 响应

前面我们 Spring MVC 返回的响应都是数据类型,其实还可以返回一个静态页面、设置header、设置状态码等操作。

5.1 返回静态页面

我们在这里写一个静态页面。

在这里插入图片描述

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    hello, spring mvc,这里是html页面
</body>
</html>
package com.example.springmvcdemo2;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.Map;

@RequestMapping("/response")
@RestController
public class ResponseController {
    @RequestMapping("/index")
    public Object index() {
        return "/index.html";
    }
}

在这里插入图片描述
在这里插入图片描述
通过 postman 构造请求之后用 fiddler 抓包之后可以看到返回的是 text 类型的数据,而不是 html,也就是说我们的 Spring MVC 将“/index.htnl”当成了一个数据。那么这是为什么呢?

这是 @RestController 作用的结果,这个注解会默认将返回的都看作是数据,要想将返回的类型解析成 html 的话,就需要更换这个 @RestController 注解为 @Controller

package com.example.springmvcdemo2;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RequestMapping("/response")
@Controller
public class ResponseController {
    @RequestMapping("/index")
    public Object index() {
        return "/index.html";
    }
}

在这里插入图片描述

那么这个 @RestController 注解和 @Controller 注解有什么区别呢?我们来看看 @RestController 注解的源码。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

通过观察 @RestController 的源码我们可以发现,@RestController 注解可以写为 @Controller + @ResponseBody

  • @Controller:定义一个控制器,Spring 框架启动时加载,把这个对象交给 Spring 管理
  • @ResponseBody:定义返回的数据格式为非视图,返回一个 text/html 信息
5.2 返回数据

返回静态页面,我们使用 @Controller 注解,那么返回数据的话,我们只需要在 @Controller 注解的基础上加上 @ResponseBody 注解就可以了。所以我们的代码其实这样写更好,这样就可以使得一个类中的方法既可以返回视图也可以返回数据。

@RequestMapping("/response")
@Controller
public class ResponseController {

    @RequestMapping("/getstatus")
    @ResponseBody
    public String getStatus() {
        return "这返回的是一个数据";
    } 
}

在这里插入图片描述
在这里插入图片描述

5.3 返回HTML代码片段

在我们 Spring MVC 中返回的数据中如果存在HTML代码的时候,浏览器也会解析出这段HTML代码。

@RequestMapping("/returnhtml")
@ResponseBody
public String returnHtml() {
    return "<h1>Hello,HTML~</h1>";
}

在这里插入图片描述

通过 Fiddler 抓取 postman 发送的请求,我们可以发现,响应的数据类型是 text/plain 纯文本类型,而不是 html 类型。

在这里插入图片描述
而我们使用浏览器访问的话,使用 Fiddler 抓包可以观察到响应的数据的类型是 html 类型。

在这里插入图片描述
这是为什么呢?其实这个取决于发送方能接收的数据类型,抓取 postman 请求的数据包,可以发现 header 中的 accept 为 /,也就是可以接收所有类型的数据。

在这里插入图片描述

并且我们的 Spring MVC 代码中的返回类型写的是 String,也就是文本数据类型,所以使用 postman 发送请求的话,响应的数据类型就是 text/plain 类型。

再观察浏览器发送请求的数据包可以发现,accept 不是 /,而是指定了一些类型。

在这里插入图片描述

并且浏览器能接收的数据类型中没有 text/plain,所以浏览器就会对返回的数据进行解析,看返回的数据可以解析成能接收的数据类型中的哪一种,因为我们返回的字符串是一个 html 片段,所以就会被解析为 html 类型。

样,我们还可以使用同样的方法返回CSS、JavaScript、json等类型。

5.4 返回JSON

Spring MVC 也可以返回 JSON 数据。

@RequestMapping("/returnjson")
@ResponseBody
public Map<String, String> returnJson() {
    Map<String, String> map = new HashMap<>();
    map.put("java", "java value");
    map.put("python", "python value");
    return map;
}

在这里插入图片描述
在这里插入图片描述
这里为什么返回的类型是 Map 类型,最后我们抓包抓取到的响应的数据类型还是 JSON 呢?

在这里插入图片描述

通过 Fiddler 抓取到的请求数据包中的 Accept 可以知道,当前接收任何类型的响应,也就是说,发送端没有明确的指出接收响应的数据类型,因为我们代码返回的数据类型是 Map,是一个对象,那么我们的 Spring MVC 注解@ResponseBody 会默认使用 Jackson 库对返回的数据类型进行序列化/反序列化,所以就会将我们返回的 Map 类型转换为 JSON 数据类型,而接收端能接收到任何类型的响应,所以接收到的数据类型就是 JSON 数据类型。

5.5 设置状态码

Spring MVC 设置状态码需要使用到 HttpServletResponse 类中的 setStatus() 方法。

@RequestMapping("/returnstatus")
@ResponseBody
public String returnStatus(HttpServletResponse response) {
    response.setStatus(401);
    return "设置状态码成功";
}

在这里插入图片描述

5.6 设置header

Spring MVC 设置状态码需要使用到 HttpServletResponse 类中的 setHeader() 方法。

@RequestMapping("/setheader")
@ResponseBody
public String setHeader(HttpServletResponse response) {
    response.setHeader("myheader", "666");
    return "设置header成功";
}

在这里插入图片描述
在这里插入图片描述

5.7 设置响应的Content-Type

Spring MVC 会根据我们返回的数据或者视图自动为我们设置相应的数据类型,当然我们也可以自己设置相应的数据类型。在 Spring MVC 中,设置响应中的数据类型需要更改 @ReqeustMapping 注解中的 produces 参数的值。

在这里插入图片描述

  • name():指定注解的名称,默认值为空字符串。
  • value() 和 path():这两个属性是互为别名的,它们指定了请求映射的路径。如果未指定,默认为空数组。
  • method():这个属性指定了请求方法类型,例如 GET、POST、PUT 等。默认为空数组。
  • params():这个属性指定了请求参数,默认为空数组。
  • headers():这个属性指定了请求头信息,默认为空数组。
  • consumes():这个属性指定了请求内容类型,默认为空数组。
  • produces():这个属性指定了响应内容类型,默认为空数组。

我们返回一个由键值对构成的字符串。

@RequestMapping(value = "/returnjson2", produces = "application/json; charset=utf8")
@ResponseBody
public String returnJson2() {
    return "{\"sucess\":true}";
}

在这里插入图片描述
在这里插入图片描述

如果我们不设置这个 produces 参数的,这个响应的字符串将会解析为文本类型。

在这里插入图片描述
在这里插入图片描述

Spring MVC 其实会根据你返回值的类型来决定是以什么类型进行响应的,但是对于哪些可以是文本类型又可以被解析为HTML、JavaScrip、CSS……等多种类型的时候就可以通过设置 produces 参数来指定响应的数据类型。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

(c语言)作业讲解

例一&#xff1a; 题目&#xff1a; 答案&#xff1a; #include<stdio.h> #include<math.h> int main() {int x;double sum0; int g 0; int i 0;scanf("%d",&x);while (x > 0){g x % 10;if (g % 2 0){g 0;}else{g 1;}sum g*pow(10,i);…

电子印章管理系统:是什么、3个平台推荐

说到印章&#xff0c;相信看过近现代电视剧的人都见过&#xff0c;一般在订立合约时最常用到&#xff0c;双方在合约上加盖印鉴&#xff0c;即代表着合约的成立。 我小时候还见过我父亲的印章&#xff0c;只是随着时代的发展&#xff0c;印章因为不易携带&#xff0c;容易被盗…

Spring事务传播机制

在上篇文章中&#xff0c;小编带领大家了解了Spring事务&#xff1a;Spring事务-CSDN博客&#xff0c;那么&#xff0c;本篇文章将会带领大家深入了解&#xff1a;Spring事务传播机制&#xff0c;感兴趣的各位老铁&#xff0c;欢迎深入探讨&#xff01;&#xff01; 事务传播机…

10行代码实现vue路由最简单的登陆拦截

需求&#xff1a;不涉及任何角色权限&#xff0c;基本实现目标&#xff0c;有token就可查看任何页面&#xff0c;否则就去登陆&#xff0c;来一步步实现 1. 创建你的路由页面&#xff0c;此处略了 2. 导航守卫拦截判断思路 // 创建路由 const router createRouter({history…

深度学习手势识别算法实现 - opencv python 计算机竞赛

文章目录 1 前言2 项目背景3 任务描述4 环境搭配5 项目实现5.1 准备数据5.2 构建网络5.3 开始训练5.4 模型评估 6 识别效果7 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习手势识别算法实现 - opencv python 该项目较为新颖…

智能优化算法应用:基于狮群算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于狮群算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于狮群算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.狮群算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…

rman 0级 1级备份结合的注意事项 obsolete 和 FRA自动清理

1. 当心0级备份从controlfile中删除&#xff0c;0级备份决定recover windows时间 &#xff0c;一级不算 Incremental backup cycle: Sundays: Level 0 Monday-Sat: cumulative level 1 Every Friday and Saturday, the time for the incremental level 1 backup sud…

创投课程研报专题课 | 如何写出高质量研报

协会邀请了来自GPTDAO的分析师——Will作为VC创投课程研报专题课的嘉宾&#xff0c;将于北京时间12月2日(周六)晚上21:00 PM-22:00 PM&#xff0c;与所有对Web3投资、创业心怀热忱的朋友一同探讨《如何写出高质量的研报》这个激动人心的话题。 浙江大学学生区块链协会&#xff…

mybatis整合(手动添加jar包方式)

操作步骤 创建数据库 建立user表 放入数据 1、创建javaweb工程并添加Jar包 用到的jar包 junit 用于测试 mybatis框架&#xff1a;mybatis-3.5.9.jar mysql数据库&#xff1a;mysql-connector-java-8.0.28.jar 2、添加MyBatis核心配置文件 <?xml version"1.0"…

[原创][2]探究C#多线程开发细节-“线程的无顺序性“

[简介] 常用网名: 猪头三 出生日期: 1981.XX.XX QQ: 643439947 个人网站: 80x86汇编小站 https://www.x86asm.org 编程生涯: 2001年~至今[共22年] 职业生涯: 20年 开发语言: C/C、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python 开发工具: Visual Studio、Delph…

TensorRT之LeNet5部署(onnx方式)

文章目录 前言LeNet-5部署1.ONNX文件导出2.TensorRT构建阶段(TensorRT模型文件)&#x1f9c1;创建Builder&#x1f367;创建Network&#x1f36d;使用onnxparser构建网络&#x1f36c;优化网络&#x1f361;序列化模型&#x1f369;释放资源 3.TensorRT运行时阶段(推理)&#x…

工业机器视觉megauging(向光有光)使用说明书(二,轻量级的visionpro)

测试程序暂时支持80万&#xff08;包含1024*768&#xff09;以上的gige工业相机&#xff0c;以后会支持640*480分辨率相机。 我们程序中使用注意力机制&#xff0c;其实就是感兴趣区域&#xff08;roi&#xff0c;你看过我前面博文&#xff0c;就应该明白&#xff09;精神的延…

mac截图Snagit 中文介绍

1.超越普通的屏幕截图 TechSmith Snagit 是唯一具有内置高级图像编辑和屏幕录制功能的屏幕捕获软件。因此&#xff0c;您可以在一个程序中轻松创建高质量的图像和视频。 2.最后&#xff0c;屏幕捕获软件可以完成您所做的一切 快速解释一个过程如果您正在努力清楚地沟通&…

JS前端逆向

前言 js逆向一直没有相关了解&#xff0c;虽然目前渗透遇见的不是很多&#xff0c;大多数遇见的要么不加密&#xff0c;要么无法实现其加密流程&#xff0c;不过最近看到了一个较为简单的站点正好能够逆向出来&#xff0c;就做了简单记录。本文旨在介绍js逆向的一些基础思路&am…

WebGL笔记:矩阵旋转运算的原理和实现

矩阵 矩阵&#xff08;Matrix&#xff09;是一个按照矩形纵横排列的复数集合 矩阵就像一个矩形的阵盘&#xff0c;通过其中纵横排列的元素我们可以摆出不同功能的阵法&#xff0c;比如位移矩阵、旋转矩阵、缩放矩阵 …在矩阵中的每一行&#xff0c;或者每一列数字构成的集合&a…

设计模式-结构型模式之代理设计模式

文章目录 八、代理设计模式 八、代理设计模式 代理设计模式通过代理控制对象的访问&#xff0c;可以详细访问某个对象的方法&#xff0c;在这个方法调用处理&#xff0c;或调用后处理。既(AOP微实现) 。 代理有分静态代理和动态代理&#xff1a; 静态代理&#xff1a;在程序…

POSTGRESQL中如何利用SQL语句快速的进行同环比?

1. 引言 在数据驱动的时代&#xff0c;了解销售、收入或任何业务指标的同比和环比情况对企业决策至关重要。本文将深入介绍如何利用 PostgreSQL 和 SQL 语句快速、准确地进行这两种重要分析。 2. 数据准备 为了演示&#xff0c;假设我们有一张 sales 表&#xff0c;存储了销…

微信订阅号和服务号的区别

服务号和订阅号有什么区别&#xff1f;服务号转为订阅号有哪些作用&#xff1f;我们都知道&#xff0c;服务号一个月只能发4次文章&#xff0c;但是订阅号每天都能发文章。不过在接收消息这一方面&#xff0c;服务号群发的消息有消息提醒&#xff0c;并显示在对话框&#xff1b…

重新认识Word——样式

重新认识Word Word样式给所有一级标题加上一级标题样式修改标题一样式&#xff0c;符合要求 正文样式标题前的小黑点导航窗格样式的相互复制Word一键转PPT 话说回来&#xff0c;一个程序员平时可能还看不起office全家桶的软件&#xff0c;但是&#xff0c;在实际的生活运用中&a…

音视频的功耗优化

前言 在应用中&#xff0c;录制与音视频模块往往是高耗能的模块&#xff0c;设备容易发热&#xff0c;影响体验。 什么是功耗优化 手机有多个耗电模块&#xff0c; SOC(CPU&#xff0c;GPU&#xff0c;DDR)&#xff0c;Display&#xff0c;Audio&#xff0c;Video&#xff0…