Spring Boot 整合 Redisson

Redisson 是一个功能十分强大的 Redis Java 客户端,它提供了丰富的功能和API,支持同步和异步操作,以及 RxJava 和响应式编程模型。Redisson 提供了50多个基于 Redis 的 Java 对象和服务,包括 分布式锁、原子计数器、分布式集合(Set、Map、List、Queue) 等高级功能。它还还支持本地缓存和 RPC 调用等功能,是开发分布式应用和使用 Redis 的理想选择。 总之,Redisson 所提供的功能已经远远超出了一个 Redis 客户端的范畴,Redis 官方也 推挤使用它 作为 Java 的 Redis 客户端。 之前我们介绍过 如何在 Spring Boot 中整合、使用 Redis。我们用到了 Spring Data Redis 组件,这是由 Spring 提供的抽象,可以使用 Jedis、Lettuce 等客户端作为实现。 Redisson 官方提供了一个 redisson-spring-boot-starter 组件,它正是 Spring Data Redis 抽象的实现,也就是说,我们可以直接使用 redisson-spring-boot-starter 无缝替换 spring-boot-starter-data-redis。 本文将会带你了解如何在 Spring Boot 中通过 redisson-spring-boot-starter 整合、使用 Redisson。 整合 Redisson 添加依赖 添加 redisson-spring-boot-starter 依赖即可。 <!-- https://mvnrepository.com/artifact/org.redisson/redisson-spring-boot-starter --> <dependency> <groupId>org.

Spring OpenFeign 的异常处理

1、概览 微服务间的 HTTP API 调用可能会出现异常。在 Spring Boot 中使用 OpenFeign 时,默认会把下游服务的 “Not Found” 等异常全部当做 “Internal Server Error” 响应给客户端。这并不是异常的最佳处理方式,幸而,Spring 和 OpenFeign 都提供了一些机制,允许我们自定义异常处理。 本文将带你了解,Spring Boot 和 OpenFeign 默认的异常传播、处理机制,以及如何实现自定义的异常处理。 2、默认的异常传播策略 2.1、Feign 中默认的异常传播 Feign 使用 ErrorDecoder.Default 内部实现类进行异常处理。每当 Feign 收到任何非 2xx 状态码时,都会将其传递给 ErrorDecoder 的 decode 方法。 如果 HTTP 响应有 Retry-After 头信息,decode 方法就会返回 RetryableException,否则就会返回 FeignException。 重试时,如果请求在默认重试次数之后仍然失败,则会返回 FeignException。 decode 方法将 HTTP 方法 key 和响应存储在 FeignException 中。 2.2、Spring Rest Controller 中的默认异常传播 只要 RestController 收到任何未处理的异常,它就会向客户端返回 500 Internal Server Error(内部服务器错误)响应。 该异常响应包含时间戳、HTTP 状态码、异常信息和路径等信息:

构建自己的 Spring Initializr 服务

Spring Initializr 是 Spring 官方提供的一个用于快速创建和初始化 Spring 项目的在线工具。它可以让开发人员选择所需的 Spring 模块、版本、语言(Java、Kotlin 或 Groovy)和构建工具(Maven 或 Gradle),并生成一个基本的项目结构。现在大多数 IDE 都对 Spring Initializr 提供了支持! 官方的 Spring Initializr 服务(start.spring.io)部署在海外,在国内访问经常出现各种连网络接失败的问题。好在 Spring Initializr 是一个开源的项目,我们可以用它来构建自己的 Spring Initializr 服务。 Spring Initializr Github 仓库:https://github.com/spring-io/start.spring.io 构建 Spring Initializr 服务 Clone 项目 需要先在机器上安装 git 软件。 git clone https://github.com/spring-io/start.spring.io.git 该仓库下有三个工程,我们只关心其中2个: start-client 前端工程,使用 React 开发。 start-site 后端工程,是一个 Spring Boot 应用。 执行构建 项目使用 maven 构建,且提供了 mvnw(Maven Wrapper) 脚本,它是一个用于管理和运行 Maven 项目的工具。它的作用是在没有全局安装 Maven 的情况下,通过自动下载和配置特定版本的 Maven 来确保项目的构建和运行环境一致性。也就是说 不需要在本地安装 Maven,通过此脚本即可完成构建。 进入项目根目录,执行如下命令进行自动构建:

Swagger 中的 @Operation 和 @ApiResponse 注解

1、概览 本文将带你了解 Swagger 中 @Operation 和 @ApiResponse 注解的主要区别和应用场景。 2、用 Swagger 生成文档 Swagger 是一套围绕 OpenAPI 规范构建的开源工具,用于描述整个 API,如暴露的端点、操作、参数、验证方法等。 Swagger 提供了 @Operation 和 @ApiResponse 注解,用于描述 REST API,以及 REST API 的响应。 定义一个示例 Controller: @RestController @RequestMapping("/customers") class CustomerController { private final CustomerService customerService; public CustomerController(CustomerService customerService) { this.customerService = customerService; } @GetMapping("/{id}") public ResponseEntity<CustomerResponse> getCustomer(@PathVariable("id") Long id) { return ResponseEntity.ok(customerService.getById(id)); } } 3、@Operation @Operation 注解用于描述单个操作。 @Operation(summary = "Gets customer by ID", description= "Customer must exist") @GetMapping("/{id}") public ResponseEntity<CustomerResponse> getCustomer(@PathVariable("id") Long id) { return ResponseEntity.

Spring Security 中 permitAll() 和 anonymous() 的区别

1、概览 Web 应用中,有些资源只能被已登录(认证)的的用户访问。有些资源,可以被匿名用户访问。而有些资源,甚至只能被匿名用户访问,已登录的用户不能访问。 本文将带你了解 Spring Security 中 HttpSecurity 的 permitAll() 和 anonymous() 方法之间的区别以及如何通过这两个方法实现上述的权限设计。 2、权限设计 假如,我们有一个电商网站,权限设计如下: 匿名用户和已登录的用户均可查看网站上的商品。 需要审计匿名用户和已登录用户请求。 匿名用户可以访问用户注册页面,已经登录的用户则不能访问。 只有已登录的用户才能查看其购物车。 3、Controller 和 WebSecurity 配置 定义 Controller: @RestController public class EcommerceController { @GetMapping("/private/showCart") public @ResponseBody String showCart() { return "Show Cart"; } @GetMapping("/public/showProducts") public @ResponseBody String listProducts() { return "List Products"; } @GetMapping("/public/registerUser") public @ResponseBody String registerUser() { return "Register User"; } } 接下来在 EcommerceWebSecruityConfig 类中实现上述权限设计: @Configuration @EnableWebSecurity public class EcommerceWebSecurityConfig { @Bean public InMemoryUserDetailsManager userDetailsService(PasswordEncoder passwordEncoder) { UserDetails user = User.

在 Spring Boot 中整合、使用 Redis

Redis 是一款开源的,使用 C 开发的高性能内存 Key/Value 数据库,支持 String、Set、Hash、List、Stream 等等数据类型。它被广泛用于缓存、消息队列、实时分析、计数器和排行榜等场景。基本上是当代应用中必不可少的软件! Spring Boot 对 Redis 提供了开箱即用的组件:spring-boot-starter-data-redis。通过这个 starter,我们只需要几行简单的配置就可以快速地在 Spring Boot 中整合、使用 Redis。 Spring Boot 整合 Redis Maven 依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> 除了 spring-boot-starter-data-redis 外,还添加了 commons-pool2 依赖,是因为我们需要使用到连接池。 配置属性 只需要在 application.yaml | properties 中配置如下常用的基本属性即可: spring: data: redis: # 连接地址 host: "localhost" # 端口 port: 6379 # 数据库 database: 0 # 用户名,如果有 # username: # 密码,如果有 # password: # 连接超时 connect-timeout: 5s # 读超时 timeout: 5s # Lettuce 客户端的配置 lettuce: # 连接池配置 pool: # 最小空闲连接 min-idle: 0 # 最大空闲连接 max-idle: 8 # 最大活跃连接 max-active: 8 # 从连接池获取连接 最大超时时间,小于等于0则表示不会超时 max-wait: -1ms 注意,如果你使用的是 spring boot 2.

Swagger:同一状态码返回不同的 Response 对象

1、概览 本文介绍了如何在 API 规范中,为同一个响应定义多个不同的对象,以及如何使用该规范生成 Java 代码和 Swagger 文档。 2、问题陈述 定义两个对象(object)。 Car 对象的属性是 owner 和 plate,两者都是 String。 Bike 对象的属性是 owner 和 speed,speed 是一个 Integer。 它们在 OpenAPI 中的描述如下: Car: type: object properties: owner: type: string plate: type: string Bike: type: object properties: owner: type: string speed: type: integer 我们想描述一个 /vehicle 端点,它将接受 GET 请求,并能返回一个 Car 或一个 Bike。 类似于如下描述: paths: /vehicle: get: responses: '200': # 返回 Car 或 Bike 接下来介绍在 OpenAPI 2 和 3 规范中的不同实现方式。

Feign Client 异常处理

1、概览 在 Feign 客户端 中,可以使用 ErrorDecoder 或者 FallbackFactory 来处理异常。 2、Maven 依赖 创建一个 Spring Boot 项目,添加 spring-cloud-starter-openfeign 依赖,该 starter 已经包含了 feign-core 依赖。 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>3.1.3</version> </dependency> 如果你想自定义要使用的 feign-core 的版本,你也可以手动在 pom.xml 文件中添加 feign-core 依赖: <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-core</artifactId> <version>11.9.1</version> </dependency> 3、使用 ErrorDecoder 处理异常 通过自定义 ErrorDecoder 来处理异常,可以在出现异常时返回自定义的异常。 如下: public class RetreiveMessageErrorDecoder implements ErrorDecoder { private final ErrorDecoder errorDecoder = new Default(); @Override public Exception decode(String methodKey, Response response) { ExceptionMessage message = null; try (InputStream bodyIs = response.

在 Spring Boot 中使用 AOP 和 SpEL 记录操作日志

通常,我们在 Spring Boot 应用中都是用过 AOP 和自定义注解的方式来记录请求日志、操作日志等。 这种方式记录到的日志数据,都是固定的模板数据。如:XXX 删除了用户、XXX 新增了用户、XXX 查询了用户列表 等等。 如果我们想要在日志内容中添加更多的业务信息,如:XXX 删除了用户 ID = xxx 的记录,那么可以通过使用 AOP 和 SpEL 表达式来实现。 SpEL 表达式简介 SpEL(Spring Expression Language) 是 Spring 中的表达式语言,用于在运行时评估和处理表达式。它提供了一种灵活的方式来访问和操作对象的属性、方法和其他表达式。SpEL可以用于配置文件、注解、XML 配置等多种场景,用于实现动态的、可配置的行为。它支持常见的表达式操作,如算术运算、逻辑运算、条件判断、集合操作等,并且可以与 Spring 框架的其他功能整合使用。 通俗理解就是,可以在 Spring 应用中使用 String 定义表达式,在表达式中可以创建、定义对象。以及访问对象的属性、方法,进行逻辑运算等等。最后得到表达式的输出结果! 一个简单的例子如下: import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.EvaluationContext; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; public class Main { public static void main(String[] args) { // 执行上下文 EvaluationContext context = new StandardEvaluationContext(); context.setVariable("param", "World"); // 设置参数到上下文 // 解析器 ExpressionParser parser = new SpelExpressionParser(); // 使用解析器,解析 SpEL 表达式 // 该表达式中定义了字符串 'Hello ' 常量,并且调用它的 .

Spring Boot 接收数组参数

普通的数组 定义一个简单的 Controller,它接收一个 String[] 类型的数组参数,如下: @RestController @RequestMapping("/demo") public class DemoController { @GetMapping public Object demo (@RequestParam("hobby") String[] hobby) { return hobby; } } Spring Boot 可以直接把以逗号分割的参数封装为集合、数组,例如: $ curl "localhost:8080/demo?hobby=chang,tiao,rap" ["chang","tiao","rap"] 其他框架、程序不一定会根据逗号进行分割。更优雅的方式,也是通用的方式应该是多次声明同名参数,例如: $ curl "localhost:8080/demo?hobby=chang&hobby=tiao&hobby=rap" ["chang","tiao","rap"] 数组也可以替换为 Collection 接口,Spring 都会正确地处理。特别是在一些需要对数组参数去重的场景,推荐使用 Set 作为参数,如下: @GetMapping public Object demo (@RequestParam("hobby") Set<String> hobby) { return hobby; } 发起请求,这一次 rap 值重复传递了 3 次: $ "localhost:8080/demo?hobby=chang&hobby=tiao&hobby=rap&hobby=rap&hobby=rap" ["chang","tiao","rap"] 得益于 Set 自带去重的特性,所以最终 hobby 集合中重复的 rap 值,只保留了一个。 使用 Set 作为参数的时候,默认使用的实现是 java.