构建自己的 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.

JdbcTemplate 中废弃的 query(...) 和 queryForObject(...) 方法

1、概览 在 Spring Boot 2.4.x 以后,JdbcTemplate 中有几个方法注解了 @Deprecated,也就是说被废弃了: query(String sql, @Nullable Object[] args, ResultSetExtractor<T> rse) query(String sql, @Nullable Object[] args, RowCallbackHandler rch) query(String sql, @Nullable Object[] args, RowMapper<T> rowMapper) queryForObject(String sql, @Nullable Object[] args, RowMapper<T> rowMapper); queryForObject(String sql, @Nullable Object[] args, Class<T> requiredType) queryForList(String sql, @Nullable Object[] args, Class<T> elementType) 这些过时的方法都使用对象数组 Object[] args 传递参数。 JdbcTemplate 又提供了一些新的方法来代替它们,新方法使用了 “可变参数”,即 Varargs 传递参数。 本文接下来会讲解一下新旧方法的用法和区别。 2、数据库 使用 H2 内存数据库进行演示,假如我们有一张 student 表,如下: CREATE TABLE student ( student_id INT AUTO_INCREMENT PRIMARY KEY, student_name VARCHAR(255) NOT NULL, age INT, grade INT NOT NULL, gender VARCHAR(10) NOT NULL, state VARCHAR(100) NOT NULL ); -- Student 1 INSERT INTO student (student_name, age, grade, gender, state) VALUES ('John Smith', 18, 3, 'Male', 'California'); -- Student 2 INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Emily Johnson', 17, 2, 'Female', 'New York'); -- 其他 insert 语句 .

Spring Boot v3.1.4 发布

⭐ 新特性 在 JavaVersion 枚举中添加 TWENTY_ONE #37364 🐞 Bug 修复 当 SLF4J 和 Logback 在多线程中并行初始化时,由于 SubstituteLoggerFactory 被认为是一个竞争的 LoggerFactory 实现,启动可能会失败 #37484 使用 metadata-url 时,Saml2RelyingPartyAutoConfiguration 会忽略 sign-request #37482 在 DomainSocket 工具中泄漏文件描述符/套接字 #37460 在 WelcomePageHandlerMapping 中,无效的 Accept 头会产生 HTTP 500 #37457 PrivateKeyParser 不支持 ed448、XDH 和 RSA-PSS 密钥 #37422 使用 Gradle 8.3 并配置 Java 工具链语言版本时,“languageVersion is final and cannot be changed” #37380 当 @ConfigurationProperties 注解的记录有多个构造函数时,AOT 处理失败 #37336 使用 Gradle 和 dependency management 插件时,Spring Boot dependency management 对 ehcache 无效 #37270 SslStoreBundle 实现不是不可变的 #37222 解析因使用大写字母而无效的 OCI image 名称的速度非常慢 #37183 生成和消费不同的跟踪传播格式不起作用 #37178 使用除 secp384r1 之外的椭圆曲线时,使用 https 失败 #37169 在 3.