JavaEE 进阶第十期:Spring MVC - Web开发的“交通枢纽”(四)

专栏:JavaEE 进阶跃迁营

个人主页:手握风云

目录

一、响应

[1.1. 返回静态页面](#1.1. 返回静态页面)

[1.2. 返回数据 @ResponseBody](#1.2. 返回数据 @ResponseBody)

[1.3. 返回 HTML 代码片段](#1.3. 返回 HTML 代码片段)

[1.4. 返回 JSON](#1.4. 返回 JSON)

[1.5. 设置状态码](#1.5. 设置状态码)


一、响应

1.1. 返回静态页面

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
</head>
<body>
    <h1>我是 index 页面</h1>
</body>
</html>
html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>hello</title>
</head>
<body>
  <form action="/hello/v3" method="post">
      <input type="submit" value="发送请求">
  </form>
</body>
</html>
java 复制代码
package com.yang.test1_15_2;

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

@RequestMapping("/return")
@RestController
public class ReturnController {
    @RequestMapping("/returnPage")
    public String returnPage() {
        return "index.html";
    }
}

按照上述代码,我们启动程序,在浏览器的地址栏输入http://127.0.0.1:8080/return/returnPage,会发现并没有按照预期返回 index.html 这个页面。http 响应把 "index.html" 只是当做了一个字符串。要想让 Spring MVC 正确识别出 index.html 是一个静态页面,我们就需要把 @RestController 改成 @Controller。

可是我们再次运行程序时,这个界面就会出现"404"错误。如果我们在 "index.html" 前面加上 "/" 就能正常显示。这个 "/" 就表示相对路径是 ""

如果 "index.html" 前面没有 "/",就默认的请求路径是 "return/index.html";如果 "index.html" 前面有 "/",就默认的请求路径是 "/index.html",我们还可以把浏览器请求路径的"/return/returnPage"省略掉,直接写"http://127.0.0.1:8080/"。

@RestController 与 @Controller 的关联与区别:从关联来看,@RestController 和 @Controller 均是 Spring 框架中用于标识 "控制器" 的核心注解,Spring 程序启动时会自动扫描并加载被这两个注解修饰的类,将其纳入 Spring 容器管理,核心作用都是接收前端发送的 HTTP 请求,并协调后续业务逻辑处理与响应操作,是 Spring MVC 中连接前端请求与后端服务的关键入口。且二者存在明确的底层语法关联,@RestController 本质是 @Controller 与 @ResponseBody 两个注解的 "组合注解",其源码中明确包含 @Controller 和 @ResponseBody 注解,意味着 @RestController 天然继承了 @Controller 作为控制器的核心能力,同时自带 @ResponseBody 的数据响应特性。

@RequestController 源码:

java 复制代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.web.bind.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Controller;

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

从区别来看,二者最核心的差异体现在 "响应内容类型" 与 "适用场景" 上。首先是响应内容类型不同:@Controller 作为传统控制器注解,默认行为是 "返回视图"(如 HTML 静态页面),即方法返回的字符串会被 Spring 解析为视图路径(如返回 "/index.html" 会跳转到 static 目录下的 index.html 页面);若需让 @Controller 修饰的方法返回数据(如文本、JSON),则必须在方法或类上额外添加 @ResponseBody 注解,否则会因 Spring 无法找到对应视图路径而报 404 错误。而 @RestController 因内置 @ResponseBody 注解,所有方法默认返回 "数据" 而非视图,方法返回的字符串、对象(如 HashMap、实体类)会被自动处理为 HTTP 响应正文(如文本格式、JSON 格式),不会被解析为视图路径,例如返回 "/index.html" 时,前端会直接显示该字符串而非跳转页面。

其次是适用场景不同:@Controller 更适合传统 "前后端不分离" 的项目,这类项目需要后端直接返回页面(如 JSP、HTML),例如传统管理系统中点击菜单后后端返回对应的页面视图;而 @RestController 则专为 "前后端分离" 项目设计,这类项目中前端负责页面渲染,后端仅需提供数据接口(如用户信息查询、业务数据提交),例如返回 JSON 格式的用户列表、计算结果等,无需处理视图相关逻辑。此外,@Controller 支持 "部分方法返回视图、部分方法返回数据" 的混合场景(只需在返回数据的方法上单独加 @ResponseBody),而 @RestController 无法实现返回视图的需求,因其类级别的 @ResponseBody 会强制所有方法返回数据,无法切换为视图响应模式。

1.2. 返回数据 @ResponseBody

@ResponseBody 是 Spring MVC 中用于指定方法或类返回 "数据" 而非 "视图" 的注解,即它会将方法的返回值直接作为 HTTP 响应正文(响应体)返回给前端,而非按照视图路径去查找页面文件(如 HTML)。

@ResponseBody 兼具类注解方法注解的属性,作用范围不同,效果也不同。如果作用在类上,该类中所有方法的返回值都会被视为 "数据",无需在每个方法上单独添加该注解;如果作用在方法上,仅当前方法的返回值被视为 "数据",类中其他未加该注解的方法仍默认返回视图。

java 复制代码
package com.yang.test1_19_1;

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

@RequestMapping("/return")
@ResponseBody
@Controller
// 等价于 @RestController
public class ReturnController {
    @RequestMapping("/returnPage")
    public String returnPage() {
        return "/index.html";
    }
}
java 复制代码
package com.yang.test1_19_1;

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

@RequestMapping("/return")
@Controller
public class ReturnController {
    @RequestMapping("/returnPage")
    public String returnPage() {
        return "/index.html";
    }

    @RequestMapping("/returnData")
    @ResponseBody
    public String returnData() {
        return "该方法返回数据";
    }
}

如果我们去掉 returnData() 方法上的 @ResponseBody 注解,就会因为找不到 "该方法返回数据.html" 而报 404 错误。

1.3. 返回 HTML 代码片段

需在方法上添加 @ResponseBody 注解,确保返回的字符串被视为 "数据" 而非 "视图路径"。

java 复制代码
package com.yang.test1_19_2;

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

@RequestMapping("/return")
@Controller
public class ReturnController {
    @RequestMapping("/returnHTML")
    @ResponseBody
    public String returnHTML() {
        return "<h1>我是一级标题</h1>";
    }
}

我们接下来通过 Fiddler 抓包观察下响应结果,Content-Type 类型为 text/html,text/html 是 HTTP 协议中用于标识 "响应体为 HTML 格式" 的标准类型,这是浏览器能够解析 HTML 代码的核心原因。

Content-Type 类型 含义 适用场景
text/html 响应体为 HTML 格式 返回 HTML 代码片段、静态 HTML 页面
text/css 响应体为 CSS 格式 返回 CSS 样式文件
application/javascript 响应体为 JavaScript 格式 返回 JS 脚本文件
application/json 响应体为 JSON 格式 返回 JSON 数据(如接口响应)

1.4. 返回 JSON

Spring MVC 支持将后端方法的返回对象(如集合、自定义实体类、Map 等)自动转换为 JSON 格式数据,无需手动处理字符串拼接,底层依赖 jackson/databind 工具包(Spring MVC 已默认集成,无需额外引入),最终以 applicaion/json 格式的响应体返回给前端。通过 @ResponseBody 注解声明 "返回数据而非视图",Spring MVC 会自动完成 "对象 → JSON 字符串" 的转换。

java 复制代码
package com.yang.test1_19_3;

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

@RequestMapping("/return")
@Controller
public class ReturnController {
    @RequestMapping("/returnJSON")
    public Person returnJSON() {
        Person person = new Person();
        
        person.setAge(22);
        person.setName("Sandman");
        person.setPassword("12345");

        return person;
    }
}
java 复制代码
package com.yang.test1_19_3;

public class Person {
    private int age;
    private String name;
    private String password;

    public int getAge() {
        return age;
    }

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

    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;
    }
}

1.5. 设置状态码

Spring MVC 会根据方法的返回结果自动设置 HTTP 响应状态码 (如成功返回数据时默认 200、资源未找到时默认 404 等),同时也支持开发者通过 **Spring MVC 内置对象 HttpServletResponse**手动指定响应状态码,以满足业务中对特定状态码的需求(如未授权返回 401、服务器错误返回 500 等)。

java 复制代码
package com.yang.test1_19_4;

import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@RequestMapping("/return")
@Controller
public class ReturnController {
    @ResponseBody
    @RequestMapping("/setStatus")
    public String setStatus(HttpServletResponse response) {
        response.setStatus(502);
        return "设置状态码成功";
    }
}

如果说请求失败,并不会影响页面的显示。比如 B站的错误页面。

相关推荐
崔庆才丨静觅8 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60619 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了9 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅9 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅10 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅10 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment10 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅10 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊10 小时前
jwt介绍
前端
爱敲代码的小鱼11 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax