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站的错误页面。

相关推荐
ZI Keep Going2 小时前
前来填坑:Search Around the World全球联合部署搜索引擎
前端·javascript·搜索引擎
孩子 你要相信光2 小时前
解决:React 中 map 处理异步数据不渲染的问题
开发语言·前端·javascript
程序员小李白2 小时前
js初相识:简介及基本语法
前端·javascript·html
软件开发技术深度爱好者2 小时前
JavaScript的p5.js库使用详解(下)
开发语言·前端·javascript
沛沛老爹2 小时前
从Web到AI:金融/医疗/教育行业专属Skills生态系统设计实战
java·前端·人工智能·git·金融·架构
洛_尘2 小时前
Java EE进阶4:Spring Web MVC入门
java·java-ee
C_心欲无痕2 小时前
Next.js 的哲学思想
开发语言·前端·javascript·ecmascript·nextjs
海鸥两三2 小时前
登录页面form表单
前端·javascript·css
光影少年2 小时前
前端如何开发ai生成图片及流式回答
前端·人工智能·langchain