教程

使用 Spring ResponseEntity 处理 HTTP 响应

1、概览 本文将带你了解如何使用 ResponseEntity 设置 HTTP 响应的 Body、Status 和 Header。 2、ResponseEntity ResponseEntity 表示整个 HTTP 响应:状态码、Header 和 Body。因此,可以用它来完全配置 HTTP 响应。只需从端点返回它,Spring 就会处理接下来的所有事情。 ResponseEntity 是一个泛型类。因此,可以使用任何类型作为响应体: @GetMapping("/hello") ResponseEntity<String> hello() { return new ResponseEntity<>("Hello World!", HttpStatus.OK); } 通过编程式,可以针对不同情况返回不同的 HTTP 状态码: @GetMapping("/age") ResponseEntity<String> age( @RequestParam("yearOfBirth") int yearOfBirth) { if (isInFuture(yearOfBirth)) { return new ResponseEntity<>( "Year of birth cannot be in the future", HttpStatus.BAD_REQUEST); // 400 } return new ResponseEntity<>( "Your age is " + calculateAge(yearOfBirth), HttpStatus.OK); // 200s } 还可以设置 HTTP 响应头:

Spring Boot 日志配置

1、概览 本文将带你了解 Spring Boot 应用中的日志配置。 2、初始设置 通过 Spring Initializr 初始化一个 Spring Boot 应用: 创建唯一的类 LoggingController: @RestController public class LoggingController { Logger logger = LoggerFactory.getLogger(LoggingController.class); @RequestMapping("/") public String index() { logger.trace("A TRACE Message"); logger.debug("A DEBUG Message"); logger.info("An INFO Message"); logger.warn("A WARN Message"); logger.error("An ERROR Message"); return "Howdy! Check out the Logs to see the output..."; } } 启动应用后,只需访问 http://localhost:8080/,就能触发这些日志输出。 3、日志零配置 就日志记录而言,Spring Boot 唯一必须的依赖是 Apache Commons Logging。它是由 Spring 的 spring-jcl 模块提供的。 如果使用的是 Spring Boot Starter(几乎总是使用 Spring Boot Starter),就根本不用担心导入 spring-jcl 的问题。这是因为每个 Starter,比如 spring-boot-starter-web,都依赖于 spring-boot-starter-logging,它已经导入了 spring-jcl。

Spring 中的 @RequestParam 注解

1、概览 本文将带你了解 Spring 中 @RequestParam 注解的用法。 简单地说,可以使用 @RequestParam 从请求中提取查询参数、表单参数甚至是多个参数。 2、示例端点 假设我们有一个端点 /api/foos,它接受一个名为 id 的查询参数: @GetMapping("/api/foos") @ResponseBody public String getFoos(@RequestParam String id) { return "ID: " + id; } 在本例中,使用 @RequestParam 来提取 id 查询参数。 通过 GET 请求来调用 getFoos: http://localhost:8080/spring-mvc-basics/api/foos?id=abc ---- ID: abc 接下来,看看注解的属性:name、value、required 和 defaultValue。 3、指定请求参数名称 在上一个示例中,变量名和参数名都是相同的。 如果变量名称和参数名称不同,可以使用 name 属性配置 @RequestParam 名称: @PostMapping("/api/foos") @ResponseBody public String addFoo(@RequestParam(name = "id") String fooId, @RequestParam String name) { return "ID: " + fooId + " Name: " + name; } 也可以使用 @RequestParam(value = "id") 或直接使用 @RequestParam("id")。

Spring Boot 中的数据校验

1、概览 Spring Boot 通过 Hibernate Validator(Bean Validation 的实现)对数据验证提供了强大的支持。 本文将通过一个实际的 REST 应用带你了解如何在 Spring Boot 中校验数据。 2、Maven 依赖 在 pomx.ml 中添加 spring-boot-starter-web、spring-boot-starter-jpa 和 H2 database 依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>2.1.214</version> <scope>runtime</scope> </dependency> 从 Boot 2.3 开始,还需要明确添加 spring-boot-starter-validation 依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> 3、示例 Domain 类 定义一个 JPA 实体类,User: @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; @NotBlank(message = "Name is mandatory") private String name; @NotBlank(message = "Email is mandatory") private String email; // 构造函数、Set、Set 方发省略 } User 实体类很简单,它展示了如何使用 Bean Validation 的约束来限制 name 和 email 字段。

Spring Data JPA 获取最后一条记录

1、概览 本文将带你了解使用 Spring Data JPA 获取最后一条记录的多种方式。 2、初始设置 首先,创建并初始化要查询的表。 创建一个 Post 实体类: @Entity public class Post { @Id private Long id; private String title; private LocalDate publicationDate; // get、set 方法 } @Entity 表示注解的类代表数据库中的一个表。@Id 注解定义了主键。 为了简单起见,这里使用的是 H2 内存数据库。 添加一个基本的 SQL 脚本,创建 Post 类对应的 post 表: DROP TABLE IF EXISTS post; CREATE TABLE post( id INT PRIMARY KEY, title VARCHAR(200), publication_date DATE ) 接着,添加一些数据: INSERT INTO post (id, title, publication_date) VALUES(1, 'Facebook post', '2020-11-10'); INSERT INTO post (id, title, publication_date) VALUES(2, 'Instagram post', '2020-12-24'); INSERT INTO post (id, title, publication_date) VALUES(3, 'Twitter post', '2023-01-10'); INSERT INTO post (id, title, publication_date) VALUES(4, 'tiktok post', '2023-03-18'); INSERT INTO post (id, title, publication_date) VALUES(5, 'Pinterest post', '2023-09-09'); 如你所见,最后一条记录的 ID 是 5。

Spring Cloud OpenFeign 入门

1、概览 本文将带你了解 Spring Boot 应用中的声明式 REST 客户端 - Spring Cloud OpenFeign。 Feign 通过可插拔的注解支持(包括 Feign 注解和 JAX-RS 注解)使编写 Web 客户端更加容易。 此外,Spring Cloud 还增加了对 Spring MVC 注解和使用与 Spring Web 中相同的 HttpMessageConverter 的支持。 使用 Feign 的一个好处是,除了接口定义外,无需编写任何调用服务的代码。 2、依赖 首先,创建 Spring Boot Web 项目,并在 pom.xml 文件中添加 spring-cloud-starter-openfeign 依赖: <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> 此外,还需要添加 spring-cloud-dependencies 依赖: <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> 你可以在 Maven Central 上找到 spring-cloud-starter-openfeign 和 spring-cloud-dependencies 的最新版本。 3、Feign 客户端 接着,需要将 @EnableFeignClients 添加到 main 类中:

Spring 重新加载 Properties 属性

1、概览 本文将带你了解如何在 Spring 中重新加载 Properties 配置属性。 2、Spring 读取 Properties Spring 有几种不同的方式来访问 Properties: Environment - 可以注入 Environment,然后使用 Environment#getProperty 来读取给定的属性。Environment 包含不同的属性源,如系统属性(System Properties)、-D 参数和 application.properties(或者 .yml) 等。还可以使用 @PropertySource 将额外的属性源添加到 Environment 中。 Properties - 可以将 properties 文件加载到 Properties 实例中,然后在 Bean 中通过调用 properties.get("property") 使用它。 @Value - 可以使用 @Value(${'property'}) 注解在 Bean 中注入特定属性。 @ConfigurationProperties - 可以使用 @ConfigurationProperties 在 Bean 中加载层次化的属性。。 3、重新加载外部属性文件 要在运行时更改文件中的属性(Properties),应该将该文件放在 Jar 之外的某个地方。然后使用命令行参数 -spring.config.location=file://{文件路径} 告诉 Spring 文件的位置。或者,也可以将其放在 application.properties 中。 对于基于磁盘文件的 Properties,可以开发一个端点或定时任务来读取文件并更新 Properties。 Apache 的 commons-configuration 是一个用于重新加载属性文件的库。可以使用 PropertiesConfiguration 和不同的 ReloadingStrategy 。

自定义 Spring Cloud Gateway 过滤器(Filter)

1、概览 上一篇文章《Spring Cloud Gateway 教程》中介绍了 Spring Cloud Gateway 网关框架。本文将带你了解如何在 Spring Cloud Gateway 中自定义 Filter。以及如何在 Filter 中修改请求和响应数据。 2、项目设置 创建一个基本应用,并将其用作 API 网关。 2.1、Maven 配置 在使用 Spring Cloud 时,往往通过 <dependencyManagement> 来管理组件的版本: <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR4</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> 添加 Spring Cloud Gateway,无需指定使用的实际版本: <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> 最新的 Spring Cloud 版本可通过 Maven Central 中找到。当然,需要注意使用的 Spring Cloud 版本需要与 Spring Boot 版本兼容。 2.2、API 网关配置 假设 API 服务在本地 8081 端口运行,在 /resource 端点暴露了一个简单的字符串资源。 接下来,配置网关,把请求代理到该服务。简而言之,当请求网关的 URI 路径中带有 /service 前缀的请求时,网关将把请求转发给该服务。

Reactor WebFlux 与虚拟线程(Virtual Thread)的对比

1、概览 本文将带你了解 Java 19 的 虚拟线程 和 Reactor Webflux 的基本工作原理以及它们的优缺点。 2、代码示例 假如我们开发的是一个电商后台,有如下 “负责计算和发布添加到购物车中的商品价格” 的函数。 class ProductService { private final String PRODUCT_ADDED_TO_CART_TOPIC = "product-added-to-cart"; private final ProductRepository repository; private final DiscountService discountService; private final KafkaTemplate<String, ProductAddedToCartEvent> kafkaTemplate; // 构造函数 public void addProductToCart(String productId, String cartId) { Product product = repository.findById(productId) .orElseThrow(() -> new IllegalArgumentException("not found!")); Price price = product.basePrice(); if (product.category().isEligibleForDiscount()) { BigDecimal discount = discountService.discountForProduct(productId); price.setValue(price.getValue().subtract(discount)); } var event = new ProductAddedToCartEvent(productId, price.

使用 Zuul 作为代理访问 Spring REST 服务

1、概览 本文将带你了解如何在 UI (前端)应用中使用 Zuul 作为代理与 Spring REST 服务通信,使用 Zuul 代理的目的是为了统一处理 CORS 和 Same Origin Policy 问题。 Zuul 是 Netflix 基于 JVM 的路由和服务器端负载均衡器。Spring Cloud 与嵌入式 Zuul 代理进行了很好的集成。 2、Maven 配置 首先,在 UI 应用的 pom.xml 中添加 Spring Cloud Zuul 依赖: <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> <version>2.2.0.RELEASE</version> </dependency> 最新版本可在 此处 找到。 3、Zuul Properties 接着,在 application.yml 中对 Zuul 进行配置: zuul: routes: foos: path: /foos/** url: http://localhost:8081/spring-zuul-foos-resource/foos 如上: 代理了资源服务器 Foos UI 应用上所有以 /foos/ 开头的请求都将转发到 Foos 资源服务器 http://loclahost:8081/spring-zuul-foos-resource/foos/ 4、API API 是一个简单的 Spring Boot 应用,监听 8081 端口。