您的位置:首页 > 游戏 > 游戏 > 广东企业网站seo哪里好_整站seo优化哪家好_巨量数据官网_福州seo推广

广东企业网站seo哪里好_整站seo优化哪家好_巨量数据官网_福州seo推广

2025/4/17 19:15:04 来源:https://blog.csdn.net/eternal__day/article/details/147002142  浏览:    关键词:广东企业网站seo哪里好_整站seo优化哪家好_巨量数据官网_福州seo推广
广东企业网站seo哪里好_整站seo优化哪家好_巨量数据官网_福州seo推广

📌 前言

在 Web 应用开发中,如何管理用户会话(Cookie & Session)以及正确返回不同类型的 HTTP 响应,是开发者必须掌握的核心能力。无论是实现用户身份认证、跨请求数据共享,还是返回 HTML 页面、JSON 数据、设置状态码与响应头,这些功能的合理设计都直接影响到系统的安全性、扩展性和用户体验。

在本期内容中,我们将深入解析 Spring MVC 如何处理 Cookie 和 Session,并详细讲解 各种类型的 HTTP 响应方式。你不仅会学习到 原理机制,还会通过代码实战 + 最佳实践,掌握如何在项目中灵活应用这些知识点,让你的 Spring MVC 开发更专业、更高效!

💡 你将学到:

Spring MVC 如何操作 Cookie & Session(会话管理)
如何返回静态页面 / HTML 代码 / JSON 数据 / HTTP 状态码(多种响应格式)
如何使用 @ResponseBody、ResponseEntity 灵活控制 HTTP 响应
如何正确设置 Header(跨域 CORS、Token 认证、自定义头信息)
如何用拦截器、过滤器控制用户身份与权限

本期内容既适用于 Spring MVC 初学者,也适合想要深入理解 HTTP 响应机制 的开发者,帮助你在企业级 Web 开发中更加游刃有余! 🚀

准备好了吗?让我们一起深入探索 Spring MVC 的 Cookie & Session 机制,以及 HTTP 响应的最佳实践! 🎯

1. Spring MVC 获取 Cookie & Session(会话管理核心)


1.1 Cookie 基础 🍪

📌 Cookie 在 Web 开发中的作用
Cookie 是 Web 应用中的 客户端存储机制,用于在 浏览器和服务器之间传递小型数据。常见用途包括:

  • 身份识别:存储用户登录凭据,避免重复登录。

  • 个性化设置:如主题偏好、语言设置等。

  • 跟踪用户行为:分析用户访问习惯,优化用户体验。


📌 在 Spring MVC 中获取 Cookie

Spring MVC 提供了 @CookieValue 注解,可以轻松获取客户端的 Cookie。

示例:读取 Cookie

@RestController
public class CookieController {@GetMapping("/get-cookie")public String getCookie(@CookieValue(value = "username", defaultValue = "Guest") String username) {return "Hello, " + username;}
}
  • @CookieValue("username"):直接获取名为 username 的 Cookie 值。

  • defaultValue = "Guest":如果 Cookie 不存在,返回默认值。


📌 设置 Cookie(生命周期、作用域、安全性)

Spring MVC 通过 HttpServletResponse 设置 Cookie,支持多种属性:
示例:设置 Cookie

@GetMapping("/set-cookie")
public ResponseEntity<String> setCookie(HttpServletResponse response) {Cookie cookie = new Cookie("username", "JohnDoe");cookie.setMaxAge(60 * 60 * 24); // 1 天cookie.setPath("/"); // 作用域:整个网站cookie.setHttpOnly(true); // 防止 JavaScript 访问(提高安全性)cookie.setSecure(true); // 仅 HTTPS 传输response.addCookie(cookie);return ResponseEntity.ok("Cookie 设置成功!");
}
  • setMaxAge(60 * 60 * 24):Cookie 有效期 1 天(单位:秒)。

  • setPath("/"):作用域设置为整个站点,所有路径都能访问该 Cookie。

  • setHttpOnly(true):防止 JavaScript 读取,防止 XSS 攻击。

  • setSecure(true):仅 HTTPS 传输,提升安全性。


📌 删除 Cookie(前端 & 后端方式)

✅ 方式 1:前端删除(JavaScript)

document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
  • 通过设置过期时间为过去的日期,浏览器会自动删除该 Cookie。

✅ 方式 2:后端删除(Spring MVC)

@GetMapping("/delete-cookie")
public ResponseEntity<String> deleteCookie(HttpServletResponse response) {Cookie cookie = new Cookie("username", null);cookie.setMaxAge(0); // 立即删除cookie.setPath("/"); response.addCookie(cookie);return ResponseEntity.ok("Cookie 已删除!");
}
  • setMaxAge(0):立即删除 Cookie。

  • setPath("/"):确保作用域匹配,否则无法正确删除。


💡 总结

  1. Cookie 是存储在 客户端 的数据,适用于 小型数据存储(如登录信息)。

  2. @CookieValue 方便获取 Cookie,而 HttpServletResponse 可用于创建和删除 Cookie。

  3. 安全最佳实践

    • HttpOnly 保护 Cookie,不被 JavaScript 访问(防止 XSS)。

    • Secure 确保 Cookie 仅通过 HTTPS 传输(防止劫持)。

    • 合理的 MaxAge 避免 Cookie 长期存留,影响安全性。


 

1.2 Session 管理 🔑


📌 什么是 Session?为什么比 Cookie 更安全?

Session存储在服务器端 的会话数据,与客户端的 Cookie 不同,它不会暴露敏感信息到浏览器,因此 安全性更高

🛠 Cookie vs Session 对比
对比项CookieSession
存储位置客户端浏览器服务器端
安全性易被窃取(可见 & 可篡改)更安全(存储在服务器端)
数据大小受浏览器限制(通常 ≤ 4KB)依赖服务器存储,不受客户端限制
生命周期取决于 Max-AgeExpires取决于 Session Timeout 或手动销毁
使用场景记住用户偏好(如语言、主题)需要存储敏感信息(如登录状态)

📌 结论Session 更适用于存储敏感数据(如登录状态、购物车),而 Cookie 更适用于 轻量级存储(如用户偏好设置)


📌 @SessionAttribute vs @SessionAttributes(局部 vs 全局存储)

Spring MVC 提供两种方式存储 Session 数据:

@SessionAttribute(局部会话数据)
  • 适用于 只在当前请求范围内 使用的 Session 数据。

@RestController
public class SessionController {@GetMapping("/get-session")public String getSession(@SessionAttribute(value = "user", required = false) String user) {return user != null ? "当前用户:" + user : "未登录";}@GetMapping("/set-session")public String setSession(HttpSession session) {session.setAttribute("user", "JohnDoe");return "用户已存入 Session";}
}

解析

  • @SessionAttribute("user"):获取存储在 Session 里的 "user" 值。

  • session.setAttribute("user", "JohnDoe"):存储 Session 数据。


@SessionAttributes(全局会话存储)
  • 适用于 多个请求间共享数据,通常用于表单提交或用户登录状态存储。

@Controller
@SessionAttributes("user") // 让 "user" 这个属性存入 Session
public class UserController {@ModelAttribute("user")public User getUser() {return new User("默认用户");}@GetMapping("/set-user")public String setUser(Model model) {model.addAttribute("user", new User("JohnDoe"));return "userPage"; // 返回 HTML 页面}
}

解析

  • @SessionAttributes("user"):所有存入 Model"user" 数据都会自动进入 Session。

  • @ModelAttribute("user"):如果 Session 里没有 "user",则默认提供一个。


📌 手动操作 HttpSession(存储、读取、删除、超时机制)

Spring MVC 允许直接操作 HttpSession,以更灵活地管理 Session 数据。

存储 & 读取 Session
@RestController
public class ManualSessionController {@GetMapping("/set-session")public String setSession(HttpSession session) {session.setAttribute("username", "JohnDoe");return "Session 已存储";}@GetMapping("/get-session")public String getSession(HttpSession session) {return "当前 Session 用户:" + session.getAttribute("username");}
}
  • session.setAttribute("username", "JohnDoe"):存入 Session。

  • session.getAttribute("username"):读取 Session 值。

删除 & 过期 Session
@GetMapping("/remove-session")
public String removeSession(HttpSession session) {session.removeAttribute("username"); // 删除 Session 数据return "Session 已删除";
}@GetMapping("/invalidate-session")
public String invalidateSession(HttpSession session) {session.invalidate(); // 彻底销毁 Sessionreturn "Session 已销毁";
}
  • session.removeAttribute("username"):删除指定 Session 数据。

  • session.invalidate():销毁整个 Session(清空所有数据)。

Session 过期时间配置

方法 1:在 application.properties 配置

server.servlet.session.timeout=30m
  • 单位:支持 s(秒)、m(分钟)、h(小时)等。

方法 2:Java 代码配置

session.setMaxInactiveInterval(1800); // 设置 Session 30 分钟后失效

📌 Session 共享方案(分布式 Session、Redis 实现)

集群环境 下,默认 Session 存储在单台服务器,一旦重启或请求被负载均衡到另一台服务器,Session 就会丢失。为了解决这个问题,通常采用 分布式 Session 方案,常见有两种方式:

✅ 方式 1:数据库存储 Session(MySQL)
  • 优点:持久化存储,不会因服务器重启丢失。

  • 缺点:数据库查询压力大,性能不如 Redis。

步骤

  1. 在数据库创建 session 表,存储用户的 Session 数据。

  2. 每次请求读取数据库中的 Session,实现共享。


✅ 方式 2:Redis 作为 Session 存储(推荐)
  • 优点:读写速度快,支持分布式缓存,可实现高可用。

  • 缺点:需要额外安装 Redis。

Spring Boot + Redis 共享 Session 配置: 1️⃣ 引入 Redis 依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency><groupId>org.springframework.session</groupId><artifactId>spring-session-data-redis</artifactId>
</dependency>

2️⃣ 配置 application.properties

spring.session.store-type=redis
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.session.timeout=1800

3️⃣ Spring Boot 自动配置
一旦引入 Redis 依赖,Spring Boot 会自动将 Session 存入 Redis,无需额外代码。


📌 总结
  1. Session 比 Cookie 更安全,适合存储敏感数据(如登录状态)。

  2. @SessionAttribute 适合局部 Session,@SessionAttributes 适合全局共享

  3. 可以手动操作 HttpSession 进行存储、读取、删除,并配置超时机制。

  4. 在分布式环境中,建议使用 Redis 共享 Session,提升可用性和扩展性。


 

1.3 Cookie vs Session(深入对比)

在 Web 开发中,CookieSession 是两种常见的会话管理方式。它们在身份认证、状态保持等方面各有优劣,如何选择取决于具体的应用场景。


📌 Cookie vs Session:区别对比

对比项CookieSession
存储位置客户端浏览器(本地存储)服务器端(内存 / Redis)
数据安全性较低,数据存储在客户端,可能被篡改较高,数据存储在服务器端,客户端仅存 Session ID
存储大小≤ 4KB(浏览器限制)服务器可存储更大的数据
生命周期Expires / Max-Age 控制,可长久存储默认短暂(通常随用户会话结束而失效)
访问方式每次请求都会自动携带服务器存储,客户端通过 Session ID 访问
适用场景轻量级数据存储(如用户偏好、访问记录)需要存储用户身份、购物车、临时状态数据
跨设备 / 跨浏览器❌ 不支持(绑定在本地浏览器)✅ 可通过 分布式 Session 实现
服务器压力❌ 无(存储在客户端)❌ 高(存储在服务器端,用户多时可能消耗内存)

✅ 什么时候用 Cookie?

  • 需要长期存储数据(如 "记住我" 功能)。

  • 存储非敏感数据(如用户语言偏好、主题设置)。

  • 减少服务器压力(避免 Session 造成过多的内存占用)。

✅ 什么时候用 Session?

  • 存储用户身份信息(如登录状态)。

  • 存储临时数据(如购物车、验证码)。

  • 不希望数据被客户端篡改(Session 存储在服务器端,较安全)。


📌 如何选择合适的身份认证方案?(基于 Token 的方案对比)

除了 Cookie / Session,现代 Web 认证越来越倾向于 Token(令牌) 认证,例如 JWT(JSON Web Token)

1️⃣ Cookie + Session 认证(传统方案)

🔹 流程

  1. 用户登录后,服务器创建 Session,并存储在 服务器内存(或 Redis)。

  2. 服务器返回一个 Session ID 给客户端,存入 Cookie

  3. 之后的每个请求,浏览器 自动携带 Cookie(含 Session ID)

  4. 服务器根据 Session ID 验证用户身份。

优点

  • 简单易用:Spring MVC / Spring Boot 内置支持 HttpSession

  • 自动携带:浏览器会自动在请求头带上 Cookie,无需额外处理。

缺点

  • 跨域问题:不同域名之间默认不能共享 Cookie(需 SameSite=None)。

  • 不支持无状态服务器必须存储 Session,不适合微服务架构。

  • 不适合移动端:Cookie 主要用于浏览器,移动 App 不适用。


2️⃣ Token 认证(基于 JWT 的方案)

🔹 流程

  1. 用户登录后,服务器签发一个 JWT Token 给客户端(Base64 编码)。

  2. 客户端(浏览器 / 移动端)将 Token 存储在 LocalStorage / SessionStorage / Cookie

  3. 之后的每个请求,客户端 手动在 Header 里附带 Authorization: Bearer <token>

  4. 服务器验证 JWT 的有效性,并解析其中的用户信息。

优点

  • 无状态:Token 认证不依赖服务器存储,适用于微服务 / 分布式架构。

  • 支持跨域 & 移动端:Token 可通过 HTTP Header 发送,不受 Cookie 限制。

  • 可扩展性强:JWT 里可以存用户角色、权限等信息,减少数据库查询。

缺点

  • 安全性问题:Token 一旦泄露,可能会被滥用(可用 短生命周期 + 刷新 Token 机制 解决)。

  • 无法主动失效:Session 可在服务器端清除,而 Token 失效前一直有效(可结合 Redis 黑名单机制 解决)。


📌 Cookie + Session vs Token 认证:总结选择

方案Cookie + SessionToken 认证(JWT)
存储方式服务器内存 / Redis客户端(LocalStorage / Cookie)
适合场景Web 应用(单体架构)微服务 / 移动端 / 跨域应用
跨域支持❌ 需要 CORS + SameSite=None✅ 可跨域(存储在 Header)
扩展性❌ 需要依赖数据库 / Redis✅ 易扩展,可存用户角色、权限
安全性(存储在服务器)中等(Token 泄露有风险)
主动失效✅ 可随时删除 Session❌ 只能等 Token 过期(需黑名单机制)

📌 结论:如何选择?

🔹 Web 单体应用(普通网站): ✅ 首选 Cookie + Session 方案(简单易用,服务器存储身份信息)。

🔹 前后端分离 / 移动端 / 跨域应用: ✅ Token 认证(JWT)更适合(无状态、支持跨设备 & 微服务)。

🔹 企业级项目(安全要求高): ✅ 结合 Token + Session(短 Token + 刷新机制 + 服务器端存储黑名单)。


📌 实践:Spring Boot 实现基于 JWT 的认证

1️⃣ 添加 JWT 依赖

<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.11.5</version>
</dependency>

2️⃣ 生成 JWT Token

public String generateToken(String username) {return Jwts.builder().setSubject(username).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 1 小时过期.signWith(SignatureAlgorithm.HS256, "mySecretKey").compact();
}

3️⃣ 解析 JWT Token

public String getUsernameFromToken(String token) {return Jwts.parser().setSigningKey("mySecretKey").parseClaimsJws(token).getBody().getSubject();
}

4️⃣ 在 Spring Security 过滤器中使用

@RequestHeader("Authorization") String token
  • 客户端请求时,在 Header 里带上 Authorization: Bearer <token>

  • 服务器端拦截请求,解析 Token,验证用户身份


📌 总结
  1. Cookie 适用于小型、简单的 Web 认证,而 Session 更安全(但有服务器开销)。

  2. JWT 适用于前后端分离、跨域、微服务架构,但 Token 一旦泄露,容易被滥用。

  3. 结合 Token + Session 是目前主流的安全方案,可兼顾 安全性性能


2  返回静态页面 📄

在 Spring MVC 中,返回静态页面(如 HTML、JS、CSS)是常见的需求。Spring Boot 默认提供了一套静态资源管理机制,使得开发者可以轻松地访问和优化静态资源。


📌 2.1 Spring Boot 默认的静态资源目录

Spring Boot 约定优于配置,默认会在以下目录中查找静态资源(HTML、CSS、JS、图片等):

目录作用
/src/main/resources/static/默认的静态资源目录(推荐)
/src/main/resources/public/公开可访问的静态文件
/src/main/resources/resources/传统 Spring 方式存放资源
/src/main/resources/META-INF/resources/兼容 Servlet 规范的目录

📌 访问方式

  • 假设 static 目录下有一个 index.html

    • URL 访问:http://localhost:8080/index.html

  • static/js/app.js

    • URL 访问:http://localhost:8080/js/app.js

默认规则

  1. Spring Boot 自动映射 staticpublicresources 目录下的资源,无需额外配置。

  2. 静态文件不会经过 Controller 处理,直接由 ResourceHttpRequestHandler 进行返回,提高性能。

  3. 如果路径和 Controller 冲突,Controller 的映射优先


📌 2. 访问 HTML 页面

Spring Boot 默认不支持直接访问 HTML 页面,需要配置 视图解析器

方法 1:使用 Thymeleaf 作为模板引擎(推荐)

Spring Boot 内置了 Thymeleaf 作为模板引擎,支持动态渲染 HTML:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
  • HTML 页面应存放在 /src/main/resources/templates/ 目录中。

  • 访问方式:

    • Controller

      @Controller
      public class PageController {@GetMapping("/home")public String home() {return "home"; // 对应 /templates/home.html}
      }
      
    • 浏览器访问http://localhost:8080/home

方法 2:直接访问静态 HTML
  • HTML 文件放在 static/ 目录,无需配置。

  • 直接访问:http://localhost:8080/index.html

  • 适用于 纯静态页面(如前后端分离项目)。


📌 3. 静态资源优化

为了提高性能,可以使用以下方式优化静态资源:

1️⃣ 缓存策略

Spring Boot 提供 默认缓存,但可以手动调整:

  • 方法 1:配置 HTTP 头缓存

    @Configuration
    public class WebConfig implements WebMvcConfigurer {@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/").setCachePeriod(3600); // 1 小时缓存}
    }
    
  • 方法 2:使用 Nginx 配置缓存

    location /static/ {expires 30d;add_header Cache-Control "public, max-age=2592000";
    }
    
2️⃣ 使用 CDN 加速
  • 将 JS、CSS 放入 CDN(如 cdnjsjsDelivr

  • 示例:使用 BootCDN 加速 jQuery

    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    
3️⃣ 资源压缩
  • 压缩 CSS / JS:使用 Webpack / Gulp 进行打包 & 压缩。

  • 启用 Gzip 压缩

    server.compression.enabled=true
    server.compression.mime-types=text/html,text/css,application/javascript
    

📌 4. 总结

方式适用场景访问方式
静态 HTML 文件(static/)纯静态网站http://localhost:8080/index.html
Thymeleaf 模板引擎需要动态渲染@Controller + return "home";
CDN 加速提高加载速度<script src="cdn.js">
Nginx 代理静态资源大型项目配置 Nginx

推荐

  • 前后端分离:使用 static/ 存放 HTML,前端 Vue/React 交给 Nginx 处理。

  • Spring MVC 动态页面:使用 Thymeleaf 作为模板引擎。

  • 优化静态资源:配置缓存、使用 CDN、压缩 JS/CSS,提高加载速度。


 

2.2 返回数据(@ResponseBody) 📢

在 Spring MVC 中,@ResponseBody 注解的作用是使得控制器方法的返回值直接写入 HTTP 响应体,而不是通过视图解析器来渲染视图。这是实现 RESTful 风格服务的基础,使得控制器方法能够返回数据(如字符串、JSON、XML 等)。

📌 @ResponseBody 注解原理
  • 功能@ResponseBody 注解的作用是将控制器方法的返回值直接绑定到 HTTP 响应的 body 中,Spring MVC 会将返回的对象序列化成指定格式的响应体,如字符串、JSON 或 XML。

  • 自动处理:Spring 自动根据返回类型选择合适的消息转换器,将对象或数据转换成相应的格式,像 JSON 就是通过 Jackson 库来处理的。

📌 如何让方法直接返回字符串 / JSON?
返回字符串

使用 @ResponseBody 注解,可以直接返回一个字符串,Spring MVC 会将其直接写入响应体中。例如:

@GetMapping("/message")
@ResponseBody
public String getMessage() {return "Hello, World!";
}
  • 当客户端访问该接口时,响应内容就是 "Hello, World!"

返回 JSON

当控制器方法返回一个对象时,Spring MVC 会通过 HttpMessageConverter 将该对象自动转换为 JSON 格式,并写入响应体。默认情况下,Spring Boot 会自动配置 Jackson 作为 JSON 转换器。

@GetMapping("/user")
@ResponseBody
public User getUser() {return new User("John", "Doe", 30);
}

假设 User 类如下:

public class User {private String firstName;private String lastName;private int age;// 构造函数、getter、setter
}
  • 当客户端访问 /user 接口时,Spring MVC 会将 User 对象转换为 JSON 格式响应:

{"firstName": "John","lastName": "Doe","age": 30
}

📌 结合 HttpMessageConverter 解析数据(自动转换机制)

Spring MVC 中的 HttpMessageConverter 负责将 Java 对象与 HTTP 请求/响应体之间进行转换。根据返回数据的类型,Spring MVC 会选择合适的 HttpMessageConverter 来进行处理。

  • 请求数据转换HttpMessageConverter 也负责将请求体中的数据(如 JSON、XML)转换成 Java 对象。

  • 响应数据转换HttpMessageConverter 负责将 Java 对象转换成 HTTP 响应体(如 JSON、XML)。

自动转换机制

Spring Boot 默认使用以下几种 HttpMessageConverter

  • Jackson:将 Java 对象转换为 JSON 格式,反之亦然。

  • JAXB:将 Java 对象转换为 XML 格式。

  • StringHttpMessageConverter:将字符串转换为响应体。

  • MappingJackson2HttpMessageConverter:专门用于处理 JSON 格式数据。

这些 HttpMessageConverter 会根据请求和响应的 Content-TypeAccept 头来自动选择合适的转换器。

例如,客户端请求一个 JSON 格式的数据,Spring 会使用 MappingJackson2HttpMessageConverter 将请求体中的 JSON 转换为 Java 对象。

自定义 HttpMessageConverter

你可以在 Spring 配置中添加或修改 HttpMessageConverter 来适应项目的需求,例如:

@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void extendMessageConverters(List<HttpMessageConverter<?>> converters) {// 添加自定义的 HttpMessageConverterconverters.add(new MyCustomMessageConverter());}
}
📌 总结
  • @ResponseBody:使得控制器方法直接返回数据到 HTTP 响应体,适用于 RESTful API 和数据返回。

  • HttpMessageConverter:Spring MVC 提供了一系列的消息转换器,用于自动将 Java 对象转换成 HTTP 请求/响应体(如 JSON、XML)。

  • 默认行为:Spring Boot 默认提供了 Jackson 作为 JSON 转换工具,它自动将 Java 对象转换为 JSON 格式,反之亦然。

通过 @ResponseBodyHttpMessageConverter,Spring MVC 能够非常方便地处理不同格式的数据,使得构建 RESTful 风格的 Web 服务变得更加简单。

2.3 返回 HTML 代码片段 📝

在某些场景下,我们希望通过 Spring MVC 返回的是 HTML 代码片段,而不是传统的视图页面。这通常用于富文本渲染、动态内容展示等需求。Spring MVC 允许我们通过 @ResponseBody 注解直接返回 HTML 字符串,使得 HTML 代码片段能够嵌入到响应中。

📌 @ResponseBody 返回 HTML 代码(富文本渲染)
返回 HTML 字符串

使用 @ResponseBody 注解,我们可以将 HTML 内容直接作为字符串返回。例如:

@GetMapping("/htmlFragment")
@ResponseBody
public String getHtmlFragment() {return "<h1>Welcome to Spring Boot!</h1><p>This is a simple HTML fragment returned as a response.</p>";
}
  • 在上述例子中,getHtmlFragment() 方法将直接返回 HTML 代码片段。客户端接收到的响应内容将是:

<h1>Welcome to Spring Boot!</h1>
<p>This is a simple HTML fragment returned as a response.</p>
富文本渲染

这种方式常用于富文本编辑器的场景。前端可以接收到 HTML 内容并进行渲染。例如,在一个富文本编辑器中,后端可能返回含有 HTML 标记的字符串,前端再将其渲染成实际的 HTML 页面。

@GetMapping("/richText")
@ResponseBody
public String getRichText() {return "<div><h2>Rich Text Content</h2><p>This is a <strong>rich text</strong> example!</p></div>";
}
  • 客户端渲染该 HTML 内容时,<div><strong> 等 HTML 标签会被解析,最终呈现为格式化的文本。


📌 Controller 直接返回 HTML 字符串的示例

在 Spring Boot 中,我们不仅可以直接返回 HTML 代码片段,还可以结合其他技术生成和返回 HTML 字符串。例如,直接在控制器中通过 @ResponseBody 返回 HTML 字符串:

@RestController
public class HtmlController {@GetMapping("/greeting")@ResponseBodypublic String greeting() {return "<h1>Hello, Spring Boot!</h1><p>This is an example of returning HTML from Spring Boot controller.</p>";}@GetMapping("/user")@ResponseBodypublic String userGreeting(@RequestParam String name) {return "<h2>Welcome, " + name + "!</h2><p>Your user data is successfully loaded.</p>";}
}
  • 访问 /greeting 会返回:

<h1>Hello, Spring Boot!</h1>
<p>This is an example of returning HTML from Spring Boot controller.</p>
  • 访问 /user?name=John 会返回:

<h2>Welcome, John!</h2>
<p>Your user data is successfully loaded.</p>

📌 如何防止 XSS 攻击?(HtmlEscape + 安全过滤)

返回 HTML 代码片段时,必须格外小心 跨站脚本攻击(XSS)。XSS 攻击允许恶意用户在网页中注入恶意脚本代码,从而对其他用户进行攻击。为了防止 XSS 攻击,我们可以采取以下措施:

1. 使用 HtmlEscape 对特殊字符进行转义

为了防止恶意脚本被注入,可以对 HTML 内容中的特殊字符进行转义。Spring 提供了 HtmlEscape 来处理这些特殊字符,例如将 < 转义为 &lt;> 转义为 &gt;

  • 例如,假设我们接收到一个用户输入并将其返回为 HTML 内容,我们可以使用 HtmlEscape 来防止恶意代码注入:

@GetMapping("/escapedText")
@ResponseBody
public String getEscapedText(@RequestParam String input) {String escapedInput = HtmlUtils.htmlEscape(input);  // 转义 HTML 特殊字符return "<h2>Your input: " + escapedInput + "</h2>";
}
  • 假设用户输入 <script>alert('XSS')</script>,通过 HtmlUtils.htmlEscape 转义后,返回的内容将是:

<h2>Your input: &lt;script&gt;alert('XSS')&lt;/script&gt;</h2>
  • 这样,浏览器将显示文本 "<script>alert('XSS')</script>",而不是执行恶意的 JavaScript 代码。

2. 使用安全的模板引擎(如 Thymeleaf)

在使用模板引擎(如 Thymeleaf)渲染 HTML 时,Spring Boot 默认会对输出进行 HTML 转义,避免 XSS 攻击。Thymeleaf 会自动将数据转义为安全的 HTML 代码,避免恶意脚本注入。

  • 在 Thymeleaf 中,如果你输出用户输入的内容,框架会自动进行转义,确保 HTML 安全:

<p th:text="${userInput}"></p>
  • 如果 userInput"<script>alert('XSS')</script>",Thymeleaf 会将其转义为:

<p>&lt;script&gt;alert('XSS')&lt;/script&gt;</p>
  • 这意味着浏览器会显示文本内容,而不是执行脚本。

3. 安全过滤(使用 OWASP 防护)

你还可以使用 OWASP 提供的安全库进行 HTML 内容过滤和清理,去除潜在的恶意脚本。OWASP 提供了 Java HTML Sanitizer 来过滤 HTML 内容,剥离不安全的标签和属性。

例如:

import org.owasp.validator.html.*;// 使用 OWASP HTML Sanitizer 清理用户输入的 HTML 内容
@GetMapping("/safeHtml")
@ResponseBody
public String safeHtml(@RequestParam String input) {PolicyFactory policy = new HtmlPolicyBuilder().allowElements("b", "i", "u", "p", "h1", "h2", "a")  // 只允许特定标签.toFactory();String sanitizedHtml = policy.sanitize(input);  // 清理不安全的 HTML 内容return "<div>" + sanitizedHtml + "</div>";
}
  • 通过使用 HtmlPolicyBuilder 配置允许的 HTML 元素,我们可以确保只有安全的 HTML 标签被渲染。


📌 总结
  • 使用 @ResponseBody 可以让 Spring 控制器方法直接返回 HTML 代码片段,常用于富文本渲染等场景。

  • 为了防止 XSS 攻击,建议对用户输入进行 HTML 转义,使用 HtmlEscapeOWASP 安全过滤 来剥离恶意内容。

  • 如果使用模板引擎(如 Thymeleaf),框架会自动处理 HTML 转义,确保输出的内容是安全的。

通过这些措施,我们可以在安全的基础上返回 HTML 内容,避免恶意脚本注入,从而保证应用程序的安全性和稳定性。

2.4 返回 JSON 🛠

在开发 RESTful API 时,我们通常需要返回 JSON 数据。Spring MVC 提供了 @ResponseBody 注解,可以方便地将 Java 对象转换为 JSON 格式,并返回给客户端。Spring Boot 默认集成了 Jackson 库,用于自动将 Java 对象转换为 JSON 格式,简化了开发过程。

📌 @ResponseBody + Jackson 自动转换对象为 JSON
自动转换为 JSON

当我们在 Spring 控制器方法上使用 @ResponseBody 注解时,Spring MVC 会通过 HttpMessageConverter 自动将 Java 对象转换为 JSON 格式。默认情况下,Spring Boot 集成了 Jackson 库作为 JSON 转换器。

例如:

@GetMapping("/user")
@ResponseBody
public User getUser() {return new User("John", "Doe", 30);
}

假设 User 类如下:

public class User {private String firstName;private String lastName;private int age;// 构造函数、getter、setter
}
  • 返回 JSON:客户端访问 /user 时,Spring 会自动将 User 对象转换为 JSON 格式,返回的响应是:

{"firstName": "John","lastName": "Doe","age": 30
}
  • Jackson 自动化:Spring Boot 自动配置了 Jackson,无需手动配置,框架会根据返回值类型自动选择合适的消息转换器,将 Java 对象转化为 JSON 数据。


📌 ResponseEntity 自定义 JSON 响应(携带状态码 & 额外数据)

除了简单的返回 Java 对象外,我们还可以使用 ResponseEntity<T> 类来返回更复杂的响应内容,包含 HTTP 状态码响应头数据

ResponseEntity 是一个通用的响应实体,可以让我们自定义响应的内容、状态码、以及其他额外的数据。

自定义响应
@GetMapping("/customResponse")
public ResponseEntity<Map<String, Object>> customResponse() {Map<String, Object> response = new HashMap<>();response.put("message", "Hello, World!");response.put("status", "success");return ResponseEntity.status(HttpStatus.OK)        // 设置 HTTP 状态码.body(response);              // 设置响应体数据
}
  • 在上述示例中,我们使用 ResponseEntity 来返回一个包含 messagestatus 的 JSON 响应:

{"message": "Hello, World!","status": "success"
}
其他自定义功能
  • 状态码:通过 ResponseEntity.status(HttpStatus) 可以自定义 HTTP 状态码,如 200(OK)、404(Not Found)、500(Internal Server Error)等。

  • 自定义头信息:通过 ResponseEntity.header(String key, String value) 可以自定义 HTTP 响应头。

例如:

@GetMapping("/headersResponse")
public ResponseEntity<String> getHeadersResponse() {return ResponseEntity.status(HttpStatus.CREATED).header("Custom-Header", "value").body("Resource created successfully");
}
  • 该响应会携带 Custom-Header 自定义头部和 201 Created 状态码。


📌 JSON 序列化优化(忽略字段、格式化、日期处理)

为了提高 JSON 输出的灵活性和可读性,Spring Boot 和 Jackson 提供了多个配置选项来优化 JSON 的序列化过程。

1. 忽略字段(@JsonIgnore)

有时我们不希望某些字段出现在 JSON 中,@JsonIgnore 注解可以帮助我们忽略这些字段:

public class User {private String firstName;private String lastName;@JsonIgnoreprivate int age;  // 该字段将不会被序列化成 JSON// 构造函数、getter、setter
}
  • 这样,返回的 JSON 将不包括 age 字段:

{"firstName": "John","lastName": "Doe"
}
2. 格式化数字(@JsonFormat)

如果你希望在 JSON 中格式化日期或数字,可以使用 @JsonFormat 注解。常见的应用场景包括格式化日期和数字:

public class Event {private String name;@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")  // 格式化日期private LocalDateTime eventDate;// 构造函数、getter、setter
}
  • 返回的 JSON 会格式化日期:

{"name": "Conference","eventDate": "2025-04-05 10:00:00"
}
3. 处理日期(@JsonSerialize 和 @JsonDeserialize)

如果你需要自定义日期的序列化和反序列化,Jackson 提供了 @JsonSerialize@JsonDeserialize 注解,允许你指定自定义的序列化/反序列化逻辑。

public class Event {private String name;@JsonSerialize(using = CustomDateSerializer.class)  // 自定义日期序列化器@JsonDeserialize(using = CustomDateDeserializer.class)  // 自定义日期反序列化器private Date eventDate;// 构造函数、getter、setter
}

通过这种方式,你可以灵活地处理日期等类型的字段。

4. 忽略空值字段(@JsonInclude)

在某些情况下,你可能希望在序列化时忽略空值字段。@JsonInclude(JsonInclude.Include.NON_NULL) 注解可以帮助我们实现这一点:

public class User {private String firstName;private String lastName;@JsonInclude(JsonInclude.Include.NON_NULL)  // 只有非 null 的字段会被序列化private Integer age;// 构造函数、getter、setter
}
  • 如果 age 字段为 null,它将不会出现在返回的 JSON 中。


📌 总结
  • @ResponseBody + Jackson:Spring Boot 默认集成 Jackson 库,可以自动将 Java 对象转换为 JSON 格式并返回给客户端。

  • ResponseEntity:可以使用 ResponseEntity 来定制 JSON 响应,控制 HTTP 状态码、响应头、以及返回的数据。

  • JSON 序列化优化

    • @JsonIgnore:忽略某些字段不进行序列化。

    • @JsonFormat:格式化日期、数字等字段。

    • @JsonSerialize / @JsonDeserialize:自定义日期、对象等的序列化和反序列化方式。

    • @JsonInclude:忽略空值字段,优化返回的 JSON 结果。

通过合理地使用这些注解和配置,您可以更加灵活和高效地返回结构化的 JSON 数据,优化 RESTful API 的实现。

2.5 设置 HTTP 状态码 🏷

在 RESTful API 中,HTTP 状态码是非常重要的,它帮助客户端理解请求的处理结果。Spring Boot 提供了多种方式来控制和设置响应的 HTTP 状态码。

📌 ResponseEntity 设置 HTTP 状态码(200、400、403、404、500)

ResponseEntity<T> 是 Spring 提供的一个类,它让我们能够自定义 HTTP 状态码、响应头和响应体内容。通过使用 ResponseEntity,我们可以更加灵活地控制 HTTP 响应。

1. 返回 200 OK

200 OK 状态码通常表示请求已经成功处理,并返回了正常的响应内容。

@GetMapping("/success")
public ResponseEntity<String> success() {return ResponseEntity.status(HttpStatus.OK)  // 状态码 200 OK.body("Request was successful");
}
  • 返回的 JSON 响应:

{"message": "Request was successful"
}
2. 返回 400 Bad Request

400 Bad Request 状态码表示客户端请求的参数无效或错误,通常用于请求参数验证失败时。

@GetMapping("/badRequest")
public ResponseEntity<String> badRequest() {return ResponseEntity.status(HttpStatus.BAD_REQUEST)  // 状态码 400 Bad Request.body("Invalid request parameters");
}
  • 返回的 JSON 响应:

{"message": "Invalid request parameters"
}
3. 返回 403 Forbidden

403 Forbidden 状态码表示请求的资源不可访问,通常是因为权限不足。

@GetMapping("/forbidden")
public ResponseEntity<String> forbidden() {return ResponseEntity.status(HttpStatus.FORBIDDEN)  // 状态码 403 Forbidden.body("You do not have permission to access this resource");
}
  • 返回的 JSON 响应:

{"message": "You do not have permission to access this resource"
}
4. 返回 404 Not Found

404 Not Found 状态码表示请求的资源不存在,通常用于查找不存在的用户、数据或页面。

@GetMapping("/notFound")
public ResponseEntity<String> notFound() {return ResponseEntity.status(HttpStatus.NOT_FOUND)  // 状态码 404 Not Found.body("The requested resource was not found");
}
  • 返回的 JSON 响应:

{"message": "The requested resource was not found"
}
5. 返回 500 Internal Server Error

500 Internal Server Error 状态码表示服务器遇到了无法处理的错误,通常用于系统异常或无法预料的错误。

@GetMapping("/serverError")
public ResponseEntity<String> serverError() {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)  // 状态码 500 Internal Server Error.body("An internal server error occurred");
}
  • 返回的 JSON 响应:

{"message": "An internal server error occurred"
}
📌 自定义异常处理(@ExceptionHandler)

Spring 提供了 @ExceptionHandler 注解,用于捕获和处理控制器方法中抛出的异常。通过它,我们可以在出现异常时设置合适的 HTTP 状态码,并返回自定义的错误信息。

1. 定义一个自定义异常类

首先,我们定义一个自定义异常类,表示业务逻辑中的错误。

public class ResourceNotFoundException extends RuntimeException {public ResourceNotFoundException(String message) {super(message);}
}
2. 在控制器中抛出自定义异常

在控制器方法中,当出现特定情况时,我们抛出 ResourceNotFoundException 异常。

@GetMapping("/resource/{id}")
public ResponseEntity<String> getResource(@PathVariable Long id) {// 假设我们查找资源时没有找到if (id == null || id <= 0) {throw new ResourceNotFoundException("Resource not found for id: " + id);}return ResponseEntity.ok("Resource found");
}
3. 使用 @ExceptionHandler 处理异常

然后,我们可以通过 @ExceptionHandler 注解来捕获该异常,并返回带有合适状态码和消息的响应。

@ControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(ResourceNotFoundException.class)public ResponseEntity<String> handleResourceNotFound(ResourceNotFoundException ex) {return ResponseEntity.status(HttpStatus.NOT_FOUND)  // 状态码 404 Not Found.body(ex.getMessage());  // 异常消息}
}
  • 当抛出 ResourceNotFoundException 异常时,@ExceptionHandler 会捕获它,并返回 HTTP 状态码 404 Not Found 和自定义的错误消息。

  • 例如,如果用户访问 /resource/0,则会抛出异常,返回:

{"message": "Resource not found for id: 0"
}
📌 返回 404 / 500 页面(结合全局异常处理)

除了返回 JSON 错误信息外,我们也可以配置 Spring Boot 返回特定的错误页面(如 404 页面、500 页面等)。这通常用于 Web 应用而非纯 API。

1. 配置 404 页面

src/main/resources/templates 目录下,创建一个 404.html 页面,用于处理 404 Not Found 错误。

<!-- src/main/resources/templates/404.html -->
<!DOCTYPE html>
<html>
<head><title>Page Not Found</title>
</head>
<body><h1>Oops! The page you are looking for does not exist.</h1>
</body>
</html>
2. 配置 500 页面

同样,你也可以创建一个 500.html 页面,用于处理服务器错误。

<!-- src/main/resources/templates/500.html -->
<!DOCTYPE html>
<html>
<head><title>Server Error</title>
</head>
<body><h1>Sorry, something went wrong on our server.</h1>
</body>
</html>
3. 自定义错误页面的配置

Spring Boot 默认会自动加载 error.html 作为全局错误页面。你可以通过修改 application.properties 来启用或定制这些页面的处理。

server.error.whitelabel.enabled=false  # 禁用默认错误页面

然后,你可以配置 ErrorController 类来自定义错误页面逻辑。例如:

@Controller
public class CustomErrorController implements ErrorController {@Override@RequestMapping("/error")public String handleError() {// 根据不同的错误状态码返回不同的页面return "errorPage";}@Overridepublic String getErrorPath() {return "/error";}
}
📌 总结
  • 使用 ResponseEntity 可以自定义 HTTP 响应的状态码、响应头和内容,方便处理不同的业务需求。

  • @ExceptionHandler 允许我们对异常进行集中处理,并返回合适的状态码和错误消息,改善用户体验。

  • Spring Boot 提供了便捷的方式来处理常见的错误状态码(如 404 和 500),并支持通过模板引擎(如 Thymeleaf)返回自定义的错误页面。

通过这些机制,我们可以提高应用的健壮性和用户体验,使其更易于维护和扩展。

2.6 设置 Header(深入了解) 📩

HTTP 头部(Headers)在客户端和服务器之间传递额外的控制信息。Spring MVC 使得我们可以非常灵活地设置和控制 HTTP 响应头部信息。我们可以使用这些头部信息来处理跨域问题、认证信息、缓存策略等。

📌 如何在 ResponseEntity 中自定义 HTTP 头信息?

Spring 提供了 ResponseEntity 类,它允许我们轻松地自定义响应头信息。在响应中设置自定义的 HTTP 头部,可以帮助控制缓存策略、内容类型、跨域策略等。

1. 自定义 HTTP 头

ResponseEntity 中,我们可以使用 header 方法来添加自定义的 HTTP 响应头。通过这种方式,可以将特定的头部信息添加到响应中。

例如,设置一个 X-Custom-Header 头:

@GetMapping("/customHeader")
public ResponseEntity<String> customHeader() {return ResponseEntity.status(HttpStatus.OK).header("X-Custom-Header", "This is a custom header")  // 自定义响应头.body("Hello, Custom Header");
}
  • 访问 /customHeader 时,响应的 HTTP 头部会包含我们设置的 X-Custom-Header

HTTP/1.1 200 OK
X-Custom-Header: This is a custom header
Content-Type: text/plain;charset=UTF-8
2. 设置多个头部信息

可以在 ResponseEntity 中一次性设置多个头部信息。利用 HttpHeaders 类,我们可以更灵活地管理头部信息。

@GetMapping("/multipleHeaders")
public ResponseEntity<String> multipleHeaders() {HttpHeaders headers = new HttpHeaders();headers.add("X-Api-Version", "1.0");headers.add("X-Request-Id", "12345");return ResponseEntity.status(HttpStatus.OK).headers(headers)  // 添加多个自定义头.body("Response with multiple headers");
}
  • 该响应会携带两个头部信息:X-Api-VersionX-Request-Id

3. 使用 ResponseEntity 来控制其他常见头部

除了自定义头部外,还可以通过 ResponseEntity 设置常见的标准 HTTP 头信息,如 Content-TypeCache-ControlLocation 等。

@GetMapping("/fileDownload")
public ResponseEntity<Resource> downloadFile() throws IOException {Path filePath = Paths.get("path/to/file.pdf");Resource resource = new UrlResource(filePath.toUri());return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"file.pdf\"")  // 设置文件下载.header(HttpHeaders.CONTENT_TYPE, "application/pdf")  // 设置文件类型.contentLength(resource.contentLength())  // 设置文件大小.body(resource);
}

在这个示例中,Content-Disposition 头部被设置为文件下载,并指定了文件的 MIME 类型和大小。


📌 Spring MVC 如何控制 CORS(跨域资源共享)?

CORS(Cross-Origin Resource Sharing,跨域资源共享)是浏览器的一种安全机制,用于防止跨站请求伪造攻击。Spring MVC 提供了多种方法来处理 CORS 问题,使得来自不同域的请求能够被允许访问资源。

1. 在全局配置 CORS

Spring Boot 可以通过全局配置来启用 CORS。通常,我们在 WebMvcConfigurer 接口中进行配置,指定哪些域名、哪些请求方法可以跨域访问资源。

@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/api/**")  // 允许访问的 URL 路径.allowedOrigins("http://example.com")  // 允许的域.allowedMethods("GET", "POST")  // 允许的请求方法.allowedHeaders("*")  // 允许的请求头.allowCredentials(true);  // 是否允许发送 cookies}
}
  • 在上述配置中,只有来自 http://example.com 的请求能够访问 /api/** 路径下的资源,且只允许 GETPOST 请求。

2. 在控制器中单独配置 CORS

如果你只想为某些特定的控制器方法启用 CORS,可以使用 @CrossOrigin 注解:

@RestController
public class MyController {@CrossOrigin(origins = "http://example.com", allowedHeaders = "*")@GetMapping("/corsTest")public String corsTest() {return "CORS is enabled for example.com!";}
}
  • @CrossOrigin 注解允许来自 http://example.com 的跨域请求访问 corsTest 方法。

3. 处理跨域的常见问题
  • Access-Control-Allow-Origin:此头部表示允许访问资源的域。若设置为 *,表示允许所有域访问。

  • Access-Control-Allow-Methods:此头部表示允许的 HTTP 请求方法。

  • Access-Control-Allow-Headers:此头部表示允许的请求头。

  • Access-Control-Allow-Credentials:此头部控制是否允许跨域请求发送凭证(如 cookies 或 HTTP 认证信息)。


📌 Header 在身份认证中的作用(JWT 示例)

JWT(JSON Web Token)是一种轻量级的身份认证方式,通常用于在客户端和服务器之间传递认证信息。在 Spring Boot 中,通常通过设置 HTTP 头部来传递 JWT 令牌。

1. JWT 的工作原理

JWT 令牌通常通过 HTTP 头部的 Authorization 字段进行传递。客户端在请求中包含 JWT 令牌,服务器验证令牌的合法性后进行身份认证。

2. 在请求中传递 JWT 令牌

客户端向服务器发送请求时,将 JWT 令牌放入 Authorization 头部:

GET /protected-resource HTTP/1.1
Host: example.com
Authorization: Bearer <your-jwt-token>
  • Bearer <token> 是 JWT 的标准传递方式,Bearer 是授权类型,后面紧跟 JWT 令牌。

3. Spring Security 解析 JWT

Spring Security 提供了灵活的机制来解析和验证 JWT 令牌。你可以通过过滤器来实现此功能,通常会在 Authorization 头中提取 JWT 令牌并验证其有效性。

public class JwtTokenFilter extends OncePerRequestFilter {private JwtTokenProvider tokenProvider;public JwtTokenFilter(JwtTokenProvider tokenProvider) {this.tokenProvider = tokenProvider;}@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws ServletException, IOException {String token = request.getHeader("Authorization");if (token != null && token.startsWith("Bearer ")) {token = token.substring(7);  // 去除 "Bearer " 前缀if (tokenProvider.validateToken(token)) {Authentication authentication = tokenProvider.getAuthentication(token);SecurityContextHolder.getContext().setAuthentication(authentication);}}chain.doFilter(request, response);}
}

在这个过滤器中,JWT 令牌从 Authorization 头中提取,验证令牌并设置认证上下文。

4. 返回 JWT 令牌

在登录或认证成功后,服务器会生成并返回一个 JWT 令牌,通常通过 HTTP 头部返回给客户端:

@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody LoginRequest loginRequest) {String jwtToken = authenticationService.authenticate(loginRequest);return ResponseEntity.ok().header("Authorization", "Bearer " + jwtToken)  // 将 JWT 令牌放入响应头.body("Login successful");
}

客户端在接收到响应后,保存 JWT 令牌,并在之后的请求中通过 Authorization 头部发送给服务器。


📌 总结
  • 自定义 HTTP 头部:通过 ResponseEntity,我们可以灵活地设置响应头,包括缓存策略、文件下载、CORS 设置等。

  • CORS 控制:可以全局或局部配置跨域资源共享策略,允许不同域的客户端访问服务器资源。

  • JWT 身份认证:通过 Authorization 头部传递 JWT 令牌,Spring Security 可以验证并使用该令牌进行用户身份验证和授权。

HTTP 头部在 Web 开发中扮演着重要的角色,掌握如何控制和自定义这些头部是构建安全和高效 Web 应用的关键。

3. 视图解析与模板引擎(返回动态页面)

3.1 返回 HTML 视图 

在 Spring MVC 中,视图解析和模板引擎用于处理动态内容和生成 HTML 页面。它们的主要作用是将后端数据与视图模板结合起来,生成最终的 HTML 内容并发送到客户端。Spring MVC 提供了多种方法来返回视图,最常见的方式是使用 ModelAndViewViewResolver,并且可以结合模板引擎(如 Thymeleaf)来渲染页面。


📌 @Controller vs @RestController(如何区分 JSON 和 HTML 返回?)
  • @Controller@RestController 都是 Spring MVC 的控制器注解,但它们的行为有所不同:

    • @Controller:通常用于返回视图(如 HTML)。它与视图解析器(如 JSP 或 Thymeleaf)结合使用,返回视图的名称,并让 Spring 根据该名称解析对应的视图文件(例如 index.htmlhome.jsp)。

    • @RestController:用于构建 RESTful API,直接返回对象(如 JSON 或 XML)。所有返回的对象会自动序列化为 JSON 格式,并通过 HTTP 响应体返回,而不是通过视图解析器返回视图。

区别

  • @Controller 适合用于 Web 应用中的传统服务器端渲染(返回 HTML 页面)。

  • @RestController 适合用于构建 API 接口(返回 JSON)。

示例

// @Controller 用于返回 HTML 视图
@Controller
public class ViewController {@GetMapping("/home")public String home(Model model) {model.addAttribute("message", "Welcome to Spring Boot!");return "home";  // 返回视图名称 (home.html 或 home.jsp)}
}
// @RestController 用于返回 JSON 数据
@RestController
public class ApiController {@GetMapping("/api/message")public Map<String, String> getMessage() {Map<String, String> response = new HashMap<>();response.put("message", "This is a JSON response");return response;  // 返回 JSON 数据}
}
  • 访问 /home 会返回一个 HTML 页面,访问 /api/message 会返回一个 JSON 格式的响应。


📌 ModelAndView:Spring MVC 如何管理视图?

ModelAndView 是 Spring MVC 中用来控制视图和模型数据的一种方式。它不仅可以存储数据模型(Model),还可以存储视图名称(View)。在使用 @Controller 时,可以通过 ModelAndView 返回一个包含模型数据和视图的对象。

用法

  • ModelAndView 可以同时包含视图名称和模型数据,这使得控制器方法能更方便地进行视图解析和数据传递。

示例

@Controller
public class ViewController {@GetMapping("/greet")public ModelAndView greet() {ModelAndView modelAndView = new ModelAndView();modelAndView.setViewName("greeting");  // 设置视图名称modelAndView.addObject("message", "Hello, Spring Boot!");  // 添加数据return modelAndView;}
}
  • 在上述示例中,ModelAndView 设置了视图名称 "greeting",并将数据 "Hello, Spring Boot!" 放入模型中。最终,Spring 会根据视图名称解析出 greeting.htmlgreeting.jsp,并将数据渲染到页面中。


📌 视图解析器(ViewResolver)的作用和自定义配置

ViewResolver 是 Spring MVC 中的视图解析器,用于根据视图名称(如 greeting)解析到具体的视图实现(如 greeting.htmlgreeting.jsp)。Spring 提供了多种视图解析器,最常用的是 InternalResourceViewResolver(用于解析 JSP 视图)和 ThymeleafViewResolver(用于解析 Thymeleaf 视图)。

视图解析器的作用是:

  1. 根据返回的视图名称(如 greeting)查找对应的视图模板文件(如 greeting.jspgreeting.html)。

  2. 将模型数据渲染到视图模板中并返回完整的 HTML 页面。

常见的视图解析器

  • JSP 视图解析器:InternalResourceViewResolver

@Configuration
public class ViewConfig implements WebMvcConfigurer {@Overridepublic void configureViewResolvers(ViewResolverRegistry registry) {registry.jsp("/WEB-INF/views/", ".jsp");  // 配置 JSP 路径和扩展名}
}
  • Thymeleaf 视图解析器:ThymeleafViewResolver

Spring Boot 默认使用 Thymeleaf 作为模板引擎,因此我们可以直接在 application.propertiesapplication.yml 中进行配置:

spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML
spring.thymeleaf.encoding=UTF-8
  • Freemarker 视图解析器

如果使用 Freemarker 模板引擎,可以通过如下配置:

@Configuration
public class ViewConfig implements WebMvcConfigurer {@Overridepublic void configureViewResolvers(ViewResolverRegistry registry) {registry.freemarker().suffix(".ftl");  // 配置 Freemarker 模板的扩展名}
}

📌 总结
  • @Controller vs @RestController

    • @Controller:用于返回 HTML 视图,适用于传统的服务器端渲染。

    • @RestController:用于返回 JSON 数据,适用于 RESTful API。

  • ModelAndView:Spring MVC 用 ModelAndView 来管理视图和模型数据,允许在返回视图的同时传递模型数据。

  • 视图解析器(ViewResolver):Spring MVC 使用 ViewResolver 根据视图名称解析具体的视图文件。我们可以通过配置视图解析器来指定视图的存放位置和文件扩展名,支持多种模板引擎,如 JSP、Thymeleaf 和 Freemarker。

掌握这些基本概念和配置,可以帮助我们在 Spring MVC 中灵活地处理和返回动态页面,提供更好的用户体验。

3.2 使用 Thymeleaf 渲染页面 🎨

Thymeleaf 是一个非常流行的 Java 模板引擎,用于生成动态 HTML 页面。它能够将数据与 HTML 模板结合,生成最终的 HTML 页面,适用于后端渲染。在 Spring Boot 中,Thymeleaf 被广泛用于视图解析和页面渲染。

📌 Thymeleaf 语法简介(变量、条件、循环)
  1. 变量渲染

    • 使用 ${} 语法来渲染表达式的结果。

    • 常用来显示变量值或计算结果。

    示例

    <p>Hello, ${user.name}!</p>
    
    • 在上面的例子中,user.name 将会被渲染成 user 对象的 name 属性的值。

  2. 条件判断

    • 使用 th:ifth:unless 来进行条件判断。

    • th:if:当条件为 true 时,渲染该元素。

    • th:unless:当条件为 false 时,渲染该元素。

    示例

    <div th:if="${user.active}">User is active.
    </div><div th:unless="${user.active}">User is not active.
    </div>
    
    • 这个示例判断 user.active 是否为 true,如果为 true,则渲染第一个 div;如果为 false,则渲染第二个 div

  3. 循环遍历

    • 使用 th:each 来进行集合的遍历。

    • th:each 用于迭代集合(如列表、数组、集合等)。

    示例

    <ul><li th:each="item : ${items}" th:text="${item}"></li>
    </ul>
    
    • 在这个例子中,items 是一个集合,th:each 会遍历该集合,每个 item 会被显示在一个 <li> 元素中。

📌 后端如何向 Thymeleaf 页面传递数据?

在 Spring Boot 中,后端控制器通过 ModelModelAndView 将数据传递到 Thymeleaf 页面。Spring MVC 会将数据模型渲染到模板中,使得页面可以显示动态内容。

  • 使用 Model 传递数据

    • Model 对象允许控制器将数据添加到模型中,这些数据可以在 Thymeleaf 模板中访问。

    示例

    @Controller
    public class HomeController {@GetMapping("/home")public String home(Model model) {model.addAttribute("message", "Welcome to Thymeleaf!");return "home";  // 返回视图名称 home.html}
    }
    
    • 在上面的控制器方法中,message 被添加到 model 中,并且返回的是视图名 "home",Spring Boot 会自动渲染 home.html 页面,并将 message 传递给模板。

    • home.html 页面中,可以通过 ${message} 来访问这个变量:

    <h1 th:text="${message}"></h1>
    
  • 使用 ModelAndView 传递数据

    • ModelAndView 允许同时传递视图名称和数据。

    示例

    @Controller
    public class HomeController {@GetMapping("/greet")public ModelAndView greet() {ModelAndView modelAndView = new ModelAndView("greeting");modelAndView.addObject("message", "Hello, Thymeleaf!");return modelAndView;}
    }
    
    • 同样,greeting.html 可以通过 ${message} 渲染数据。

📌 表单提交 + 后端处理的完整流程

Thymeleaf 提供了强大的表单支持,可以轻松地进行表单提交并与后端进行交互。

  1. 创建表单视图

    • 使用 th:action 来指定表单提交的 URL,th:field 用于绑定表单字段到模型属性。

    示例:创建登录表单

    <form th:action="@{/login}" th:object="${user}" method="post"><label for="username">Username:</label><input type="text" id="username" th:field="*{username}" /><label for="password">Password:</label><input type="password" id="password" th:field="*{password}" /><button type="submit">Login</button>
    </form>
    
    • th:action 指定表单提交到 /login URL。

    • th:object 绑定表单到 user 对象。

    • th:field 自动生成输入框的 name 属性并绑定到 user 对象的字段。

  2. 处理表单提交

    • 在后端控制器中,使用 @ModelAttribute 注解将表单数据绑定到模型对象中。

    示例:处理登录请求

    @Controller
    public class LoginController {@PostMapping("/login")public String login(@ModelAttribute User user, Model model) {if ("admin".equals(user.getUsername()) && "password".equals(user.getPassword())) {model.addAttribute("message", "Login successful!");return "welcome";  // 登录成功,返回 welcome.html 页面} else {model.addAttribute("message", "Invalid username or password.");return "login";  // 登录失败,返回 login.html 页面}}
    }
    
    • @ModelAttribute 将表单字段映射到 User 对象。

    • 根据用户输入的用户名和密码,返回不同的视图。

  3. 数据验证(可选)

    • 可以使用 Spring 的 @Valid 注解进行表单数据验证,确保输入的数据符合预期。

    示例:添加数据验证

    @PostMapping("/login")
    public String login(@Valid @ModelAttribute User user, BindingResult result, Model model) {if (result.hasErrors()) {model.addAttribute("message", "Form validation failed.");return "login";  // 如果验证失败,返回 login 页面}// 验证通过,处理登录逻辑...
    }
    

📌 总结
  • Thymeleaf 语法简介:使用 ${} 渲染变量,使用 th:ifth:unless 进行条件判断,使用 th:each 进行循环遍历。

  • 数据传递:通过 ModelModelAndView 将数据从后端传递到 Thymeleaf 页面,并在页面中使用 Thymeleaf 表达式渲染这些数据。

  • 表单提交:使用 th:actionth:field 创建表单,并通过 @ModelAttribute 注解将表单数据绑定到后端模型对象中,处理提交的数据并返回结果。

掌握 Thymeleaf 的基础语法和表单处理流程,可以让我们在 Spring Boot 中更高效地实现动态页面渲染和与前端的交互。

4. 拦截器 & 过滤器(高级控制机制)

4.1 拦截器(HandlerInterceptor) 🚧

拦截器是 Spring MVC 提供的一种功能强大的机制,用于在请求处理的生命周期中执行特定的操作。拦截器的主要作用是拦截 HTTP 请求,并在请求被处理之前或之后进行操作。与过滤器不同,拦截器是 Spring MVC 层面的功能,能够访问 Spring 控制器的方法,而过滤器则是基于 Servlet 容器的机制,不能直接与 Spring 控制器交互。

📌 拦截器的工作原理

拦截器在请求处理过程中有三个重要的生命周期方法:

  1. preHandle:在控制器方法调用之前执行。

  2. postHandle:在控制器方法调用之后,视图渲染之前执行。

  3. afterCompletion:在整个请求处理完成后执行(包括视图渲染后)。

这三个方法可以用来处理日志记录、权限校验、修改响应数据等任务。

📌 如何使用拦截器(HandlerInterceptor)
  1. 创建拦截器类

    创建一个类实现 HandlerInterceptor 接口,并重写 preHandlepostHandleafterCompletion 方法。

    @Component
    public class MyInterceptor implements HandlerInterceptor {// 在控制器方法执行之前调用@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("Request intercepted: " + request.getRequestURI());// 可以访问 Cookie、SessionString user = (String) request.getSession().getAttribute("user");if (user == null) {response.sendRedirect("/login");return false;  // 返回 false 表示拦截请求,防止继续向下执行}return true;  // 返回 true 表示放行请求}// 在控制器方法执行之后,视图渲染之前调用@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {// 可以操作 ModelAndViewSystem.out.println("Post handling request...");}// 在整个请求处理完成后调用,视图渲染后@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("Request completed.");}
    }
    
  2. 注册拦截器

    要使拦截器生效,必须将其注册到 Spring MVC 配置中。通过实现 WebMvcConfigurer 接口并重写 addInterceptors 方法来注册拦截器。

    @Configuration
    public class WebConfig implements WebMvcConfigurer {@Autowiredprivate MyInterceptor myInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(myInterceptor).addPathPatterns("/**")  // 拦截所有请求.excludePathPatterns("/login", "/register");  // 排除不需要拦截的路径}
    }
    
📌 拦截器常见应用场景
  1. 权限校验与用户身份认证

    • preHandle 方法中,可以检查用户是否登录,是否具有访问权限。如果未登录或权限不足,可以直接重定向到登录页面或错误页面。

    示例

    // 判断是否登录
    String user = (String) request.getSession().getAttribute("user");
    if (user == null) {response.sendRedirect("/login");return false;  // 拦截请求,阻止后续处理
    }
    
  2. 日志记录

    • preHandlepostHandle 方法中,记录请求的详细信息,如 URL、请求时间、请求方法等。可以用于分析系统性能、请求的处理时间等。

    示例

    String requestURI = request.getRequestURI();
    String method = request.getMethod();
    System.out.println("Request Method: " + method + ", URI: " + requestURI);
    
  3. 操作请求和响应数据

    • 可以通过 preHandle 修改请求数据,通过 postHandle 修改响应数据,或者在 afterCompletion 进行额外的资源清理操作。

📌 拦截器 vs 过滤器(Filter)

拦截器和过滤器都能拦截请求,执行某些任务,但它们有以下几个区别:

特性拦截器(HandlerInterceptor)过滤器(Filter)
适用范围Spring MVC 层Servlet 层,适用于整个 Web 应用
能否访问 Spring MVC 控制器可以访问不能直接访问
请求与响应处理时机请求到达控制器之前、控制器之后、请求完成后请求到达 servlet 之前、响应返回之前
依赖关系与 Spring MVC 紧密集成与 Servlet 容器相关,独立于 Spring MVC
配置方式使用 Spring 配置类注册配置 web.xml 或使用 FilterRegistrationBean 注册
功能处理与 Spring MVC 相关的功能,如权限验证、数据绑定、日志记录等主要用于过滤请求和响应数据,如 CORS 处理、安全过滤、日志、请求缓存等
📌 拦截器与过滤器的应用场景对比
  1. 使用拦截器的场景

    • 需要与 Spring MVC 控制器交互的功能,如权限校验、用户身份认证、日志记录、数据绑定等。

    • 对请求处理有深度控制需求时,使用拦截器更为合适。

  2. 使用过滤器的场景

    • 需要跨越整个 Web 应用的功能,如跨域请求(CORS)、防火墙、日志、性能监控等。

    • 需要对 HTTP 请求和响应进行底层处理时,使用过滤器更为合适。

📌 小结
  • 拦截器(HandlerInterceptor) 是 Spring MVC 中用于处理请求的工具,适用于请求的前后操作、权限校验、日志记录等。

  • 拦截器和过滤器在某些功能上有交集,但它们的作用层次、配置方式和适用范围不同。选择使用哪种工具取决于需求的具体场景,拦截器适用于 Spring MVC 层面的操作,过滤器适用于更底层的请求和响应过滤。

通过合理配置和使用拦截器与过滤器,可以实现更精细化的请求处理和优化 Web 应用的性能与安全性。

4.2 过滤器(Filter) 🛑

过滤器(Filter)是基于 Servlet 规范的组件,它允许我们在请求进入 Servlet 或控制器之前和响应离开 Servlet 之前对请求和响应进行处理。与拦截器不同,过滤器是独立于 Spring MVC 的,是 Servlet 容器的一部分,适用于整个 Web 应用。

📌 过滤器的工作原理

过滤器的工作过程主要通过 doFilter 方法来完成。doFilter 方法接收三个参数:

  1. ServletRequest:包含请求信息。

  2. ServletResponse:包含响应信息。

  3. FilterChain:用来将请求传递给下一个过滤器或目标资源(如 Servlet)。

通过调用 filterChain.doFilter(request, response),可以将请求传递给下一个过滤器,或直接交给 Servlet 处理。

📌 过滤器的常见应用
  1. 全局处理 Cookie 和 Session

    • 过滤器可以用于全局处理 Cookie 和 Session,例如检查用户是否登录,或者检查请求的有效性。通过读取 Cookie 或 Session,可以实现用户认证、权限校验等功能。

  2. 修改 HTTP 响应

    • 过滤器能够修改 HTTP 响应,包括设置自定义的响应头,修改返回的内容,或者添加缓存控制等。

  3. 解决跨域(CORS)问题

    • CORS(跨域资源共享)问题是 Web 应用中常见的挑战之一。通过过滤器,可以解决跨域请求的问题,允许不同域的客户端访问服务器资源。

📌 如何使用过滤器
  1. 创建过滤器类

    创建一个实现 Filter 接口的类,并重写 doFilter 方法。在该方法中,可以获取请求和响应数据,并进行相应的操作。

    @Component
    public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 初始化方法System.out.println("Filter initialized");}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {// 可以在这里修改请求数据或者响应数据HttpServletRequest httpRequest = (HttpServletRequest) request;HttpServletResponse httpResponse = (HttpServletResponse) response;System.out.println("Request URL: " + httpRequest.getRequestURI());// 继续将请求传递到下一个过滤器或目标资源chain.doFilter(request, response);// 响应返回后执行(可修改响应内容)httpResponse.setHeader("Custom-Header", "Value");}@Overridepublic void destroy() {// 清理资源System.out.println("Filter destroyed");}
    }
    
  2. 注册过滤器

    过滤器在 Spring Boot 中可以通过 FilterRegistrationBean 注册。通过在 @Configuration 注解的配置类中进行注册,可以为过滤器指定过滤路径、初始化参数等。

    @Configuration
    public class WebConfig {@Beanpublic FilterRegistrationBean<MyFilter> loggingFilter() {FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();registrationBean.setFilter(new MyFilter());registrationBean.addUrlPatterns("/api/*"); // 配置过滤路径return registrationBean;}
    }
    
📌 过滤器常见应用场景
  1. 全局处理 Cookie 和 Session

    过滤器在处理请求时,可以非常方便地操作 Cookie 或 Session。比如检查用户是否登录,或者获取用户的认证信息。

    @Component
    public class AuthFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest) request;HttpServletResponse httpResponse = (HttpServletResponse) response;// 检查 Session 是否包含用户信息HttpSession session = httpRequest.getSession(false);if (session == null || session.getAttribute("user") == null) {// 如果未登录,则重定向到登录页面httpResponse.sendRedirect("/login");return;}// 继续传递请求chain.doFilter(request, response);}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void destroy() {}
    }
    
  2. 修改 HTTP 响应

    过滤器还可以修改 HTTP 响应,例如为响应添加自定义的 HTTP 头,或者修改响应内容。

    例如:在响应中添加自定义的 Header 信息

    @Component
    public class ResponseHeaderFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {HttpServletResponse httpResponse = (HttpServletResponse) response;// 为响应添加自定义的 Header 信息httpResponse.setHeader("X-Custom-Header", "This is a custom header");// 继续将请求传递到下一个过滤器或目标资源chain.doFilter(request, response);}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void destroy() {}
    }
    
  3. 跨域(CORS)问题解析与解决方案

    跨域资源共享(CORS) 是指一个域名下的网页可以通过 HTTP 请求访问另一个域名下的资源。在前后端分离的应用中,跨域问题是常见的。为了解决跨域问题,可以通过过滤器设置适当的 HTTP 头来允许跨域访问。

    跨域请求解决方案:

    通过过滤器,在 HTTP 响应中加入 CORS 相关的头部,允许指定域名的访问。

    @Component
    public class CorsFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {HttpServletResponse httpResponse = (HttpServletResponse) response;HttpServletRequest httpRequest = (HttpServletRequest) request;// 设置允许跨域的域名,* 代表所有域名httpResponse.setHeader("Access-Control-Allow-Origin", "*");httpResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");httpResponse.setHeader("Access-Control-Allow-Headers", "Origin, Content-Type, Accept, Authorization");httpResponse.setHeader("Access-Control-Allow-Credentials", "true");// 如果是预检请求,则直接返回 200 状态码if ("OPTIONS".equalsIgnoreCase(httpRequest.getMethod())) {httpResponse.setStatus(HttpServletResponse.SC_OK);return;}// 继续请求链chain.doFilter(request, response);}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void destroy() {}
    }
    

    解决方案解析:

    • Access-Control-Allow-Origin:指定哪些域名可以访问资源,* 代表允许所有域名访问。

    • Access-Control-Allow-Methods:允许的 HTTP 请求方法,如 GET, POST 等。

    • Access-Control-Allow-Headers:允许客户端发送的请求头。

    • Access-Control-Allow-Credentials:是否允许客户端发送认证信息(如 Cookies)。

📌 小结
  • 过滤器(Filter) 是一种强大的工具,能够在 Servlet 容器级别进行请求和响应的全局处理。

  • 过滤器的应用非常广泛,包括处理 Session 和 Cookie、修改响应、解决 CORS 问题等。

  • 使用过滤器时,开发者可以灵活地控制 HTTP 请求和响应,尤其适用于跨域请求、日志记录、安全防护等场景。

通过合理的过滤器配置和使用,可以有效地提升 Web 应用的功能性和安全性。

结语

通过这一期的内容,我们全面探讨了 Spring Web MVC 的核心机制,包括 获取 Cookie/SessionHTTP 响应的处理。掌握这些基础概念,对于构建健壮的 Web 应用至关重要。

在学习如何从客户端获取 CookieSession 时,我们了解了如何利用 @CookieValue 注解获取客户端存储的 Cookie 信息,以及如何使用 Session 管理用户状态。同时,我们深入探讨了如何通过 拦截器过滤器 优化请求处理和增强安全性,提升应用的灵活性和可维护性。

在解析 HTTP 响应 的部分,我们详细阐述了如何通过 @ResponseBodyResponseEntity 控制响应的内容、状态码以及 HTTP 头的定制。此外,我们还通过 JSONHTML富文本渲染 等具体例子展示了如何将后端数据返回给前端,并确保数据安全性,防止 XSS 攻击等问题。

这些知识不仅加深了我们对 Spring Web MVC 工作机制的理解,也为构建高效、灵活且安全的 Web 应用奠定了坚实的基础。无论是处理静态资源、动态页面,还是对复杂的 HTTP 响应进行精细控制,掌握这些概念和技能都能帮助你在开发中更加得心应手。

随着对这些核心概念的熟悉,后续的进阶学习将进一步提升你对 Web 应用架构的理解与实践能力。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com