【Spring】Spring Web MVC

📚博客主页:爱敲代码的小杨.

✨专栏:《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 |《MySQL探索之旅》 |《Web世界探险家》

❤️感谢大家点赞👍🏻收藏⭐评论✍🏻,您的三连就是我持续更新的动力❤️

🙏小杨水平有限,欢迎各位大佬指点,相互学习进步!


小杨近些在学习人工智能方面的知识,发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站

文章目录

  • [1. 什么是 Spring Web MVC](#1. 什么是 Spring Web MVC)
    • [1.1 MVC 的定义](#1.1 MVC 的定义)
    • [1.2 什么是Spring MVC](#1.2 什么是Spring MVC)
  • [2. Spring MVC](#2. Spring MVC)
  • [3. 建立连接](#3. 建立连接)
    • [3.1 `@RequestMapping` 注解介绍](#3.1 @RequestMapping 注解介绍)
    • [3.2 `@RequestMapping` 使用](#3.2 @RequestMapping 使用)
    • [3.3 `@RequestMapping` 的请求类型](#3.3 @RequestMapping 的请求类型)
  • [4. 请求](#4. 请求)
    • [4.1 传递单个参数](#4.1 传递单个参数)
    • [4.2 传递多个参数](#4.2 传递多个参数)
    • [4.3 传递对象](#4.3 传递对象)
    • [4.3 后端参数重命名(后端参数映射)](#4.3 后端参数重命名(后端参数映射))
    • [4.4 传递数组](#4.4 传递数组)
    • [4.5 传递集合](#4.5 传递集合)
    • [4.6 传递JSON数据](#4.6 传递JSON数据)
    • [4.7 获取URL参数`@PathVariable`](#4.7 获取URL参数@PathVariable)
    • [4.8 上传文件`@RequestPart`](#4.8 上传文件@RequestPart)
    • [4.9 获取Cookie/Session](#4.9 获取Cookie/Session)
    • [4.9.3 获取 Header](#4.9.3 获取 Header)
  • [5. 响应](#5. 响应)
    • [5.1 返回静态页面](#5.1 返回静态页面)
    • [5.2 返回数据`@ResponseBody`](#5.2 返回数据@ResponseBody)
    • [5.3 返回 HTML 代码界面](#5.3 返回 HTML 代码界面)
    • [5.3 返回 JSON](#5.3 返回 JSON)
    • [5.4 设置状态码](#5.4 设置状态码)
    • [5.5 设置Header (了解)](#5.5 设置Header (了解))

前言:

前面我们了解了SpringBootSpring Boot快速上手,并使用 SpringBoot 写了第一个hello SpringBoot的程序,实现和浏览器及用户的交互。接下来我们学习 Spring Web MVC。

1. 什么是 Spring Web MVC

学习Spring Web MVC 一定要知道它是什么?

官方介绍:

Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning. The formal name, "Spring Web MVC," comes from the name of its source module (spring-webmvc), but it is more commonly known as "Spring MVC".

翻译中文:

Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从一开始就包含在 Spring 框架中。正式名称"Spring Web MVC"来自其源模块的名称(spring-webmvc),但它更常见的名称是"Spring MVC"。

什么是Servlet?

Servlet 是Java编写的服务器端程序,其主要功能在于交互式地浏览和修改数据,生成动态Web内容

Servlet是Java Web开发的重要技术之一,它作为客户端和服务器之间的中间层,用于处理来自Web浏览器或其他HTTP客户端的请求并做出响应。这种机制使得Servlet能够高效地管理Web应用程序中的逻辑处理。

Servlet使用Java Servlet API进行编程,这个API包含了一系列的接口、类和监听器,用于处理HTTP请求和响应。典型的Servlet会实现Javax.servlet.Servlet接口,该接口定义了生命周期方法如init()、service()和destroy()等。开发人员通过重写这些方法,可以控制Servlet的创建、请求处理和销毁过程。

Servlet的主要任务包括读取客户端发送的数据、处理数据并生成结果、将数据发送回客户端等。例如,在处理HTTP请求时,一个Servlet可以通过分析请求参数来执行数据库查询,并将查询结果以HTML页面的形式返回给客户端。由于Servlet运行在Web服务器的地址空间内,因此它们不需要为每个客户端请求创建一个新的进程,从而大大提高了性能。

综上所述:Spring Web MVC 是一个 Web框架。简称:Spring MVC。

在理解什么是Spring MVC之前我们要搞清楚什么是MVC?

1.1 MVC 的定义

MVC(Model--View--Controller)模式 是软件工程中的一种软件架构模式 ,它把软件系统分为三个基本部分:模型(Model) 、**视图(View)**和 控制器(Controller)

  • View(视图): 指在应用程序中专们用来与浏览器进行交互,展示数据的资源。

  • Model(模型): 是应用程序的主体部分,用来处理程序中数据逻辑的部分。

  • Controller(控制器): 可以理解为⼀个分发器,用来决定对于视图发来的请求,需要用哪⼀个模型来处理,以及处理完后需要跳回到哪⼀个视图。即用来连接视图和模型。

1.2 什么是Spring MVC

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

总结:Spring MVC是一个实现了MVC模式的Web框架。

所以:Spring MVC主要关注有两个点:

  1. MVC

  2. Web 框架

Spring MVC全称是Spring Web MVC

其实, Spring MVC 我们在前面已经用过了, 在创建 Spring Boot 项目时,我们勾选的 Spring Web 框架其实就是 Spring MVC 框架:

Spring Boot 只是实现Spring MVC的其中一种方式而已

Spring Boot 可以添加很多依赖, 借助这些依赖实现不同的功能。Spring Boot 通过添加Spring Web MVC框架, 来实现Web功能。

不过Spring在实现MVC时, 也结合自身项目的特点,,做了⼀些改变, 相对而言, 下面这个图或许更加合适⼀些。

2. Spring MVC

既然是 Web 框架,那么当用户在浏览器中输入了 url 之后,我们的 Spring MVC 项目就可以感知到用户的请求, 并给予响应。

学习Spring MVC重点也就是学习如何通过浏览器和用户程序进行交互。

主要分为三个方面:

  1. 建立连接:将用户(浏览器)和 Java 程序连接起来,也就是访问一个地址能够调用到我们的Spring 程序。

  2. 请求:用户请求的时候会带一些参数,在程序中要想办法获取到参数, 所以请求这块主要是获取参数的功能。

  3. 响应:执行了业务逻辑之后,要把程序执行的结果返回给用户, 也就是响应。

比如:用户去银行取钱

  1. 建立连接:去柜台

  2. 请求:带着银行卡,身份证去存款

  3. 响应:银行返回一张存折

项目准备

Spring MVC 项目创建和 Spring Boot 创建项目相同,在创建的时候选择 Spring Web 就相当于创建 Spring MVC 的项目。

创建项目时, 勾选 Spring Web 模块即可,如下图所示:

3. 建立连接

在 Spring MVC 中使用 @RequestMapping 来实现 URL 路由映射,也就是浏览器连接程序的作用,我们先来看看代码怎么写的

创建一个 HelloController 类,实现用户通过浏览器和程序的交互,具体代码如下:

Java 复制代码
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String hell() {
        return "hello Spring MVC";
    }
}

注:方法名和路径名称无需一致

启动项目,打开浏览器访问127.0.0.1:8080/hello,就可以看到程序返回的结果了。

3.1 @RequestMapping 注解介绍

@RequestMapping 是 Spring MVC 应用程序中最常用被用到的注解之一,它是用来注册接口的路由映射的。表示服务器收到请求时,路径为/hello的请求就会调用 hello 这个方法代码。

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

3.2 @RequestMapping 使用

@RequestMapping 既可以修饰方法,也可以修饰类,同时修饰类和方法时,访问的地址是类路径 + 方法路径

  • @RequestMapping 修饰一个类:设置映射请求的请求路径的初始信息

  • @RequestMapping 修饰一个方法:设置映射请求的请求路径的具体信息

Java 复制代码
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/test")
public class HelloController {
    
    @RequestMapping("/hello")
    public String hell() {
        return "hello Spring MVC";
    }
}

启动项目,访问:127.0.0.1:8080/test/hello

3.3 @RequestMapping 的请求类型

Get 请求:

Post 请求:

从运行结果可以看出: @RequestMapping 既至此Get请求, 也支持Post请求. 同理, 也支持其他的请求方式.

可以看到源码中支持以上请求

指定请求类型

示例: 指定Get请求

Java 复制代码
@RequestMapping(value = "/test", method = {RequestMethod.*GET*})
public String test() {
    return "hello springboot";
}

但是使用post请求时, 则会报错

控制台日志: 不支持Post请求

4. 请求

访问不同的路径,就是发送不同的请求。在发送请求时,可能会带有一些参数,所以学习 Spring 的请求,主要时学习如何传递参数到后端以及后端如何接收。

传递参数,我们主要是使用浏览器和 APIfox插件来模拟。

后端开发人员无需过度关注如何传递参数,了解即可,实际开发中以 APIfox 测试为主。

例如餐厅的厨师, 不关注用户是在店里下单,还是外卖平台下单, 或者小程序下单,只需要知道如何接收订单,根据订单做出对应的菜就可以了。

4.1 传递单个参数

接收单个参数,在 Spring MVC 中直接用方法中的参数就可以,比如以下代码:

Java 复制代码
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/test")
public class  {

    @RequestMapping("/t1")
    public String t1(String name) {
        return "t1:" + name;
    }
}

启动项目,访问127.0.0.1:8080/test/t1?name=zhangsan

可以看到,后端程序正确拿到了 name参数的值

Spring MVC 会根据方法的参数名, 找到对应的参数, 赋值给方法

如果参数不一致,是获取不到参数的

注意事项:

使用基本类型来接收参数时, 参数必须传(除boolean类型), 否则会报500错误

类型不匹配时, 会报400错误

Java 复制代码
@RequestMapping("/m3/int")
public String m3(int num) {
    return "num = " + num;
}
  1. 传递正常参数

http://127.0.0.1:8080/m3/int?num=18

响应结果:

  1. 不传参数

http://127.0.0.1:8080/m3/int

响应结果:

可以看到HTTP 状态码为500

查看控制台日志:

一般看日志堆栈信息的首行, 报错信息显示:

int类型的参数age,虽然为可选的, 但由于被声明为基本类型而不能转换为空值. 考虑将其声明为对应基本类型的包装类型

  1. 传递参数类型不匹配

http://127.0.0.1:8080/m3/int?num=abc

响应结果:

可以看到HTTP 状态码为400

对于包装类型, 如果不传对应参数,Spring 接收到的数据则为null

所以开发中,对于参数可能为空的数据,建议使用包装类型

4.2 传递多个参数

传递多个参数和传递单个参数一样,直接使用方法的参数接收即可,使用多个形参。

Java 复制代码
@RequestMapping("/m4")
public String m4(Integer id, String name) {
    return "id = " + id + ", name = " + name;
}

发送请求并传参:http://127.0.0.1:8080/m4?id=1&name=zhangsan

可以看到后端程序正确的拿到了参数

当有多个参数时,前后端进行参数匹配时,是以参数的名称进行匹配的, 因此参数的位置是不影响后端获取参数的结果。

比如访问http://127.0.0.1:8080/m4?name=zhangsan&id=1, 同样也可以拿到正确的结果

4.3 传递对象

如果参数比较多时, 方法声明就需要有很多形参, 并且后续每次新增一个参数, 也需要修改方法的声明. 我们可以把这些参数封装为一个对象.

Spring MVC 也可以自动实现对象参数的赋值, 比如 User 对象:

Java 复制代码
public class User {
    private Integer id;
    private String name;
    private String password;

    public User() {
    }

    public User(Integer id, String name, String password) {
        this.id = id;
        this.name = name;
        this.password = password;
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

传递对象的实现:

Java 复制代码
@RequestMapping("/m5")
public String m5(User user) {
    return "id = " + user.getId() + ", name = " + user.getName() + 
            ", password = " + user.getPassword();
}

发送请求并传参: http://127.0.0.1:8080/m5?id=1&name=zhangsan&password=123456

可以看到后端程序正确的拿到了User 对象的值

Spring会根据参数名名称自动绑定到对象的各个属性上, 如果某个属性没有传递, 则赋值为null

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

在某些特殊情况下, 前端传递的key 和后端接收的key 可以不一致, 比如: 前端传递了一个userName 给后端, 而后端使用name 字段接收, 这样就会出现参数接收不到的情况, 如果出现这种情况, 我们就可以使用 @RequestParam 来重命名前后端的参数值

具体示例代码:

Java 复制代码
@RequestMapping("/m6")
public String m6(@RequestParam("userName") String name) {
    return "name = " + name;
}

发送请求并传参: http://127.0.0.1:8080/m6?userName=zhangsan

可以看到, Spring可以正确的把传递的参数userName绑定到后端参数name参数上, 如果这时使用name 进行参数传递呢

响应结果:

错误日志:

控制台日志显示: 请求参数userName 不存在

小结:

  1. 使用 @RequestParam 进行参数重命名时, 请求参数只能和 @RequestParam 声明的名称⼀致, 才能进行参数绑定和赋值.

  2. 使用 @RequestParam 进行参数重命名时, 参数就变成了必传参数.

非必传设置

如果我们的实际业务前端的参数是⼀个非必传的参数, 针对上述问题, 如何解决呢?

我们可以通过设置 @RequestParam 中的 required=false 来避免不传递时报错,具体实现如下

Java 复制代码
@RequestMapping("/m6")
public String m6(@RequestParam(value = "userName", required = false) String name) {
    return "name = " + name;
}

请求结果:

可以看到, 添加 required=false之后, userName前面也加了key, 变成了 value = "userName"

注解属性赋值时, 没有指明key的话, 默认为value属性.

如果需要有多个属性进行赋值时, 需要写上key

4.4 传递数组

Spring MVC 可以自动绑定数组参数的赋值

代码:

Java 复制代码
@RequestMapping("/m7")
public String m7(Integer[] nums) {
    return Arrays.*toString*(nums);
}

发送请求并传参

  1. http://127.0.0.1:8080/m7?nums=11&nums=22&nums=33

  2. http://127.0.0.1:8080/m7?nums=11,22,33

响应结果:

可以看到后端对数组参数进行了正确的接收和响应.

4.5 传递集合

集合参数: 和数组类似, 同一个请求参数名有多个, 且使用@RequestParam 绑定参数关系

默认情况下,请求中参数名相同的多个值,是封装到数组. 如果要封装到集合,要使用@RequestParam 绑定参数关系

代码:

Java 复制代码
@RequestMapping("/m8")
public String m8(@RequestParam List<String> listParam) {
    return "size:" + listParam.size() + "listParam:" + listParam;
}

请求方式和数组类型:

  1. http://127.0.0.1:8080/m8?listParam=zhangsan&listParam=lisi&listParam=wangwu

  2. http://127.0.0.1:8080/m8?listParam=zhangsan,lisi,wangwu

4.6 传递JSON数据

接收JSON对象, 需要使用@RequestBody 注解

RequestBody: 请求正文,意思是这个注解作用在请求正文的数据绑定,请求参数必须在写在请求正文中

代码实现:

Java 复制代码
@RequestMapping("/m9")
public String m9(@RequestBody User user) {
    return "id = " + user.getId() + ", name = " + user.getName() +
            ", password = " + user.getPassword();
}

发送请求并传参:

可以看到, 后端正确接收了

尝试去除@RequestBody 注解

Java 复制代码
@RequestMapping("/m9")
public String m9(User user) {
    return "id = " + user.getId() + ", name = " + user.getName() +
            ", password = " + user.getPassword();
}

发送请求并传参:

后端未能成功给User对象赋值.

4.7 获取URL参数@PathVariable

path variable: 路径变量

和字面表达的意思⼀样, 这个注解主要作用在请求URL路径上的数据绑定

默认传递参数写在URL上,SpringMVC就可以获取到

代码:

Java 复制代码
@RequestMapping("/m10/{id}/{userName}")
public String m10(@PathVariable Integer id, @PathVariable("userName") String name) {
    return "id = " + id + ", name = " + name;
}

发送请求并传参: http://127.0.0.1:8080/m10/1/zhangsan

可以看到, 后端正确获取到了URL中的参数

参数对应关系如下:

  • 如果方法参数名称和需要绑定的URL中的变量名称一致时, 可以简写, 不用给@PathVariable的属性赋值, 如上述例子中的id变量

  • 如果方法参数名称和需要绑定的URL中的变量名称不一致时, 需要@PathVariable的属性value赋值,如上述例子中的name变量.

4.8 上传文件@RequestPart

代码:

Java 复制代码
@RequestMapping("/m11")
public String m11(MultipartFile file) throws IOException {
    // 获取文件名
    String originalFilename = file.getOriginalFilename();
    // 保存文件路径
    file.transferTo(new File("E:/temp/" + originalFilename));
    return "originalFilename:" + originalFilename;
}

发送请求并传参:

查看D:/temp 路径下, 文件是否上传成功

4.9 获取Cookie/Session

cookie/session

4.9.1 获取Cookie

传统获取Cookie
Java 复制代码
@RequestMapping("/m12")
public String m12(HttpServletRequest request) {
    Cookie[] cookies = request.getCookies();
    System.*out*.println("cookie信息:");
    if (cookies != null) {
        for (Cookie cookie : cookies) {
            String name = cookie.getName();
            String value = cookie.getValue();
            System.*out*.println("key:" + name + ", value:" + value);
        }
    }
    return "获取Cookie成功";
}

此时没有设置Cookie, 通过浏览器访问http://127.0.0.1:8080/m12 , 控制台日志打印为null

我们设置一下Cookie的值

重新访问, 控制台日志打印结果:

从这个例子中, 也可以看出Cookie是可以伪造的, 也就是不安全的, 所以使⽤Cookie时, 后端需要进行Cookie校验

简介获取Cookie
Java 复制代码
@RequestMapping("/m13")
public String m13(@CookieValue String xiaoyang) {
    return "Cookie: xiaoyang:" + xiaoyang;
}

通过浏览器访问: http://127.0.0.1:8080/m13 , 响应结果:

4.9.2 获取Session

Session的存储和获取

Session是服务器的机制, 需要先存储, 才能获取

Session 也是 基于 HttpServletRequest 来存储和获取的

Session存储
Java 复制代码
@RequestMapping("/m14")
public String m14(HttpServletRequest request) {
    HttpSession session = request.getSession();
    if (session != null) {
        session.setAttribute("name", "xiaoyang");
    }

    return "session存储成功";
}

访问 http://127.0.0.1:8080/m14 , 查看 Cookie

获取Session的两种方式:

Session获取1
Java 复制代码
@RequestMapping("/m15")
public String m15(HttpServletRequest request) {
    HttpSession session = request.getSession(false);
    if (session != null) {
        System.*out*.println(session.getAttribute("name"));
    }
    return "session获取成功";
}

没有设置Session, 直接获取Session结果为 null

设置Session,http://127.0.0.1:8080/m15 获取Session结果:

Session获取2
Java 复制代码
@RequestMapping("/m16")
public String m16(@SessionAttribute(value = "name", required = false) String name) {
    return "session获取成功, name:" + name;
}

设置Session后, 访问 http://127.0.0.1:8080/m16 获取结果:

Session获取3
Java 复制代码
@RequestMapping("/m17")
public String m17(HttpSession session) {
    String name = (String) session.getAttribute("name");
    return "name:" + name;
}

设置Session后, 访问 http://127.0.0.1:8080/m17 获取结果:

4.9.3 获取 Header

传统获取

获取 header 也是从 HttpServletRequest 中获取

Java 复制代码
@RequestMapping("/m18")
public String m18(HttpServletRequest request) {
    String header = request.getHeader("User-Agent");
    return "获取header:" + header;
}

运行结果: http://127.0.0.1:8080/m18

简介获取

Java 复制代码
@RequestMapping("/m19")
public String m19(@RequestHeader("User-Agent") String header) {
    return "获取header:" + header;
}

运行结果: http://127.0.0.1:8080/m19

5. 响应

在我们前面的代码例子中,都已经设置了响应数据, Http响应结果可以是数据, 也可以是静态页面,也可以针对响应设置状态码, Header信息等.

5.1 返回静态页面

创建静态页面 index.html (注意路径)

HTML代码:

HTML 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>index页面</h1>
</body>
</html>

后端代码:

Java 复制代码
@RestController
public class ResponseController {

    @RequestMapping("/index")
    public String index() {
        return "/index.html";
    }
}

访问: http://127.0.0.1:8080/index , 结果如下⬇️:

结果却发现,页面未正确返回,http响应吧/index.html 当做了http响应正文的数据

那Spring MVC 如何才能识别出来 index.html 是一个静态页面,并进行返回呢?

只需要把 @RestController 改为 @Controller

正确代码如下⬇️:

Java 复制代码
@Controller
public class ResponseController {

    @RequestMapping("/index")
    public String index() {
        return "/index.html";
    }
}

再次运行: http://127.0.0.1:8080/index

发现页面正确展示了

@RestController@Controller 有着什么样的关联和区别?

咱们前面讲了MVC模式, 后端会返回视图, 这是早期时的概念

随着互联网的发展, 目前项目开发流行"前后端分离"模式, Java主要是用来做后端项目的开发, 所以也就不再处理前端相关的内容了

MVC的概念也逐渐发生了变化, View不再返回视图, 而是返回显示视图时需要的数据.

所以前面使用的 @RestController 其实是返回的数据.

@RestController = @Controller + @ResponseBody

  • @Controller : 定义一个控制器, Spring 框架启动时加载, 把这个对象交给Spring管理.

  • @ResponseBody : 定义返回的数据格式为非视图, 返回⼀个 text/html 信息

  • @RestController 源码:

Java 复制代码
@Target({ElementType.*TYPE*})
@Retention(RetentionPolicy.*RUNTIME*)
@Documented
@Controller
@ResponseBody
public @interface RestController {
    @AliasFor(
        annotation = Controller.class
    )
    String value() default "";
}

如果想返回视图的话, 只需要把 @ResponseBody 去掉就可以了, 也就是 @Controller

5.2 返回数据@ResponseBody

我们上面提到了@ResponseBody , 表示返回数据

Java 复制代码
@Controller
@ResponseBody
public class ResponseController {

    @RequestMapping("/index")
    public String index() {
        return "/index.html";
    }
}

加上@ResponseBody 注解, 该方法就会把"/index.html" 当做一个数据返回给前端.

访问: http://127.0.0.1:8080/index

@Responsebody 即是类注解, 也是方法注解

如果作用在类上, 表示该类的所有方法, 返回的都是数据, 如果作用在方法上, 表示该方法返回的是数.

也就是说: 在类上添加@ResponseBody 就相当于在所有的方法上添加了 @ResponseBody 注解

同样, 如果类上有RestController 注解时: 表示所有的方法上添加了 ResponseBody 注解, 也就是当前类下所有的方法返回值做为响应数据

如果一个类的方法里, 既有返回数据的, 又有返回页面的, 就把@ResponseBody 注解添加到对应的方法上即可

Java 复制代码
@Controller
public class ResponseController {

    @RequestMapping("/index")
    public String index() {
        return "/index.html";
    }

    @ResponseBody
    @RequestMapping("test1")
    public String test1() {
        return "返回数据";
    }
}

多个注解时, 没有先后顺序, 先写哪个都可以

运行程序, 浏览器响应结果如下: http://127.0.0.1:8080/test1

如果去掉@ResponseBody 注解, 程序则会直接报错

Java 复制代码
@Controller
public class ResponseController {

    @RequestMapping("/index")
    public String index() {
        return "/index.html";
    }

    @RequestMapping("test1")
    public String test1() {
        return "返回数据";
    }
}

程序认为需要返回的是视图, 根据内容去查找文件, 但是查询不到, 路径不存在, 报404

5.3 返回 HTML 代码界面

后端返回数据时, 如果数据中有HTML代码, 也会被浏览器解析

Java 复制代码
@ResponseBody
@RequestMapping("h1")
public String h1() {
    return "<h1>hello, html</h1>";
}

运行程序, 浏览器响应结果如下: http://127.0.0.1:8080/h1

通过Fiddler观察响应结果, Content-Type 为 text/html

响应中的 Content-Type 常见取值有以下几种:

  • text/html : body 数据格式是 HTML

  • text/css : body 数据格式是 CSS

  • application/javascript : body 数据格式是 JavaScript

  • application/json : body 数据格式是 JSON

5.3 返回 JSON

Spring MVC 也可以返回JSON

后端方法返回结果为对象

Java 复制代码
@ResponseBody
@RequestMapping("json")
public Map<String, String> json() {
    Map<String, String> map = new HashMap<>();
    map.put("name", "xiaoyang");
    map.put("age", "18");
    return map;
}

运行程序, 浏览器响应结果如下: http://127.0.0.1:8080/json

通过Fiddler观察响应结果, Content-Typeapplication/json

5.4 设置状态码

Spring MVC会根据我们方法的返回结果自动设置响应状态码, 程序员也可以手动指定状态码

通过Spring MVC的内置对象HttpServletResponse 提供的方法来进行设置

运行程序, 浏览器响应结果如下: http://127.0.0.1:8080/stat

通过Fiddler观察响应结果,

5.5 设置Header (了解)

Http响应报头也会向客户端传递⼀些附加信息, 比如服务程序的名称,请求的资源已移动到新地址等, 如:Content-Type, Local等.

这些信息通过 @RequestMapping 注解的属性来实现

先来看 @RequestMapping 的源码:

Java 复制代码
@Target({ElementType.*TYPE*, ElementType.*METHOD*})
@Retention(RetentionPolicy.*RUNTIME*)
@Documented
@Mapping
@Reflective({ControllerMappingReflectiveProcessor.class})
public @interface RequestMapping {
    String name() default "";

    @AliasFor("path")
    String[] value() default {};

    @AliasFor("value")
    String[] path() default {};

    RequestMethod[] method() default {};

    String[] params() default {};

    String[] headers() default {};

    String[] consumes() default {};

    String[] produces() default {};
}
  1. value: 指定映射的URL

  2. method: 指定请求的method类型, 如GET, POST等

  3. consumes: 指定处理请求(request)的提交内容类型(Content-Type),例如application/json,text/html;

  4. produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回

  5. Params: 指定request中必须包含某些参数值时,才让该方法处理

  6. headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求

设置Content-Type

我们通过设置 produces属性的值, 设置响应的报头Content-Type

Java 复制代码
@RequestMapping(value = "returnJson2", produces = "application/json;charset=utf-8")
public String returnJson2() {
    return "{\"success\":true}";
}   

运行程序, 浏览器响应结果如下: http://127.0.0.1:8080/returnJson2

通过Fiddler来观察设置的结果:

如果不设置produces , 方法返回结果为String时, Spring MVC默认返回类型, 是text/html.设置返回类型时, 也可以同步设置响应编码

Java 复制代码
@RequestMapping("returnJson2")
public String returnJson2() {
    return "{\"success\":true}";
}

运行结果:

通过Fiddler来观察设置的结果:

设置其他Header

设置其他Header的话, 需要使⽤Spring MVC的内置对象HttpServletResponse 提供的⽅法来进⾏设置

Java 复制代码
@ResponseBody
@RequestMapping("setHeader")
public String setHeader(HttpServletResponse  response) {
    response.setHeader("name", "xiaoyang");
    return "设置Header成功";
}

运行程序, 浏览器响应结果如下: http://127.0.0.1:8080/setHeader

通过Fiddler来观察设置的结果:


相关推荐
是立不是利1 小时前
深入理解JavaScript事件委托
开发语言·前端·javascript
晴天161 小时前
React 版本迭代解析:从15到19 核心差异-Day40
前端·react.js·前端框架
APItesterCris2 小时前
告别人工盯品!借助 Open‑Claw 快速搭建电商商品全自动监控与数据分析系统(完整实操代码)
java·大数据·前端·数据库
ly76892 小时前
Spring 中的 @Configuration 与 @Component 差异:为何代理时机决定 Bean 生命周期行为
java·后端·spring·注解·代理·bean生命周期
啊阿狸不会拉杆2 小时前
《计算机网络-自顶向下方法》6.7 回顾:Web页面请求的历程 读书笔记
前端·计算机网络
Wang's Blog3 小时前
Java框架快速入门: Spring Security+OAuth2之安全配置基础及函数式风格对比
java·安全·spring
云上工程笔记3 小时前
四柱记账法和复式记账法有什么区别?复式记账为什么更适合查错和对账
大数据·前端·人工智能
恋猫de小郭3 小时前
Dart Skills CLI 1.0 :AI 时代的 Dart 交付支持
android·前端·flutter
Hilaku3 小时前
为什么技术极强的前端,往往当不好前端 Team Leader?
前端·javascript·程序员