RestTemplate 上传文件

在调用第三方Api服务的时候,如果涉及到文件上传,就需要自己通过 Http 客户端发起 Multipart 请求来上传文件。 在 Spring 应用中比较流行的 Http 客户端就是 RestTemplate。本文将会指导你如何用 RestTemplate 发起 Multipart 请求来上传文件。 服务端 在服务端创建一个用于测试的 FileUploadController, 它接受来自客户端的 Multipart 文件请求,并且响应文件的相关信息。 package cn.springdoc.demo.controller; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.MediaType; import org.springframework.util.StreamUtils; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import jakarta.servlet.http.HttpServletResponse; @RestController @RequestMapping("/upload") public class FileUploadController { private static final Logger log = LoggerFactory.getLogger(FileUploadController.class); /** * 文件上传 * @param file * @param response * @return * @throws IOException */ @PostMapping(consumes = MediaType.

Spring Modulith 简介

1、简介 模块化单体(Modular Monolith)是一种架构风格,在这种风格中,我们的源代码按照模块的概念进行结构化。对于许多组织来说,模块化单体是一个很好的选择。它有助于保持一定程度的独立性,这有助于我们在需要时过渡到微服务架构。 Spring Modulith 是 Spring 的一个实验项目,可用于模块化单体应用程序。此外,它还支持开发人员构建结构合理、领域一致的 Spring Boot 应用程序。 在本教程中,我们将讨论 Spring Modulith 项目的基础知识,并举例说明如何实际使用它。 2、模块化单体架构 我们有不同的选择来构建应用程序的代码。传统上,我们围绕基础设施设计软件解决方案。但是,当我们围绕业务设计应用程序时,就能更好地理解和维护系统。模块化单体架构就是这样一种设计。 模块化单体架构因其简单性和可维护性而越来越受到架构师和开发人员的青睐。如果我们将领域驱动设计(DDD)应用于现有的单体应用程序,就可以将其重构为模块化单体架构: 我们可以通过确定应用程序的领域和定义有界上下文,将单体的核心拆分成模块。 让我们来看看如何在 Spring Boot 框架内实现模块化单体应用程序。Spring Modulith 包含一系列库,可帮助开发人员构建模块化 Spring Boot 应用程序。 3、Spring Modulith 基础 Spring Modulith 可帮助开发人员使用由领域(domain)驱动的模块,并支持对这种模块化进行验证和文档化。 3.1、Maven 依赖 首先,让我们在 pom.xml 的 <dependencyManagement> 部分导入 spring-modulith-bom 依赖: <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.experimental</groupId> <artifactId>spring-modulith-bom</artifactId> <version>0.5.1</version> <scope>import</scope> <type>pom</type> </dependency> </dependencies> </dependencyManagement> 此外,我们还需要一些 Spring Modulith 核心依赖: <dependency> <groupId>org.springframework.experimental</groupId> <artifactId>spring-modulith-api</artifactId> </dependency> <dependency> <groupId>org.springframework.experimental</groupId> <artifactId>spring-modulith-starter-test</artifactId> <scope>test</scope> </dependency> 3.2、模块 Spring Modulith 的主要概念是模块。模块是将 API 暴露给其他模块的功能单元。此外,它还有一些不允许其他模块访问的内部实现。当我们设计应用程序时,我们会为每个域(domain)考虑一个模块。

使用 Spring Boot Cli 编码密码

1、概览 Spring Boot CLI 是一个 Spring Boot 工具,用于从命令运行和测试 Spring Boot 应用。该工具提供了一个非常有用的密码编码功能,主要目的是避免暴露明文形式的密码。 在本教程中,我们将深入 Spring Security 的世界,学习如何使用 Spring Boot CLI 对密码进行编码。 2、密码编码 密码编码是一种将密码以二进制格式表示并保存在存储介质上的简单方法。我们可以使用 Spring Security 对密码进行编码,也可以通过 Spring Boot CLI 进行编码。 2.1、Spring Security PasswordEncoder Spring Security 提供了 PasswordEncoder 接口,并且预置了很多实现,如 StandardPasswordEncoder 和 BCryptPasswordEncoder。 此外,Spring Security 建议使用基于强大算法和随机生成盐值的 BCryptPasswordEncoder。在框架的早期版本中,可以使用 MD5PasswordEncoder 或 SHAPasswordEncoder 类,但由于其算法的弱点,它们现在已被弃用,这两个类强制开发者将盐作为构造函数参数传递。而 BCryptPasswordEncoder 将在内部生成随机盐,BCryptPasswordEncoder 生成的字符串大小为 60 个字符。 而 StandardPasswordEncoder 类则基于 SHA-256 算法。 显然,在第三方系统中创建的用户密码必须按照 Spring Security 中选择的编码类型进行编码,这样才能成功进行身份认证。 2.2、Spring Boot CLI Password Encoder Spring Boot CLI 提供了许多命令,其中之一就是 encodepassword。该命令允许对密码进行编码,以便与 Spring Security 配合使用。简单地说,Spring Boot Cli 可以使用这种简单的 encodepassword 命令直接将原始密码转换为加密密码:

Spring 中的 “自注入”

1、概览 自注入是指 Spring Bean 将自身作为依赖注入。它使用 Spring 容器获取自身的引用,然后使用该引用执行某些操作。 在这个简短的教程中,我们将了解如何在 Spring 中使用自注入。 2、自注入的场景 自注入最常见的用例是在需要将切面应用于自引用的方法或类时,绕过 Spring AOP 的限制 假设我们有一个执行某些业务逻辑的 service 类,需要调用自身的一个方法作为该逻辑的一部分: @Service public class MyService { public void doSomething() { // ... doSomethingElse(); } @Transactional public void doSomethingElse() { // ... } } 不过,当我们运行应用程序时,可能会发现 @Transactional 并未生效。这是因为 doSomething() 方法直接调用了 doSomethingElse(),从而绕过了 Spring 代理。 为了解决这个问题,我们可以使用自注入获取 Spring 代理的引用,然后通过该代理调用方法。 3、使用 @Autowired 自注入 在 Spring 中,我们可以通过在 Bean 的字段、构造器参数或 setter 方法上使用 @Autowired 注解来进行自注入。 下面是一个在字段上使用 @Autowired 的示例: @Component public class MyBean { @Autowired private MyBean self; public void doSomething() { // 在这里使用 self 引用 } } 通过构造器参数自注入。

在 Spring Boot 中使用 H2 异常:JdbcSQLSyntaxErrorException

1、概览 在 Spring Boot 中使用 h2 作为内存数据库的时候遇到异常:org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement expected “identifier”。 本文将会介绍出现 org.h2.jdbc.JdbcSQLSyntaxErrorException 的原因以及解决方案。 2、原因 通常,H2 会抛出 JdbcSQLSyntaxErrorException 来提示 SQL 语句中的语法错误。其中,“expected identifier” 信息表明 SQL 期望一个合适的 标识符,而我们没有给出。 导致这种异常的最常见原因是使用保留关键字作为标识符。 例如,使用关键字 table 来命名特定的 SQL 表就会导致 JdbcSQLSyntaxErrorException。 另一个原因是在 SQL 语句中缺少或错用了关键字。 3、重现异常 作为开发者,我们经常使用 user 一词来表示用户表。不幸的是,它在 H2 中是一个 保留关键字。 为了重现异常,我们将故意使用关键字 user。 因此,首先让我们添加一个基本的 SQL 脚本来初始化 H2 数据库并为其添加数据: INSERT INTO user VALUES (1, 'admin', 'p@ssw@rd'); INSERT INTO user VALUES (2, 'user', 'userpasswd'); 接下来,我们将创建一个实体(Entity)类来映射 user 表:

使用 Spring Security 通过 Header 认证服务之间的调用

1、概览 身份认证是微服务安全的基础。我们可以通过各种方式实现身份认证,如使用基于用户的凭证、证书或 token。 在本教程中,我们将学习如何使用 Spring Security 实现服务间的通信认证。 2、自定义身份认证简介 在某些情况下,使用 Oauth2 或存储在数据库中的密码可能并不可行,因为私有微服务不需要基于用户的交互。然而,我们仍然应该保护应用程序免受任何无效请求的影响。 在这种情况下,我们可以设计一种简单的身份认证技术,使用自定义 header。应用程序将根据预先配置的请求头认证请求。 我们还应在应用程序中启用 TLS,以确保 header 在网络传输中的安全。 我们可能还需要确保一些端点不需要进行任何身份认证,例如 health 或 error 端点。 3、示例应用 假如,我们需要用几个 REST API 构建一个微服务。 3.1、Maven 依赖 首先,我们将创建一个 Spring Boot Web 项目,添加 spring-boot-starter-web 和 spring-boot-starter-test 依赖。 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> 3.2、实现 REST Controller 我们的应用有两个端点,一个端点可通过 secret header 访问,另一个端点可被网络中的所有用户访问。 首先,在 APIController 中实现 /hello 端点: @GetMapping(path = "/api/hello") public String hello(){ return "hello"; } 然后,我们将在 HealthCheckController 类中实现 /health 端点:

Spring Boot Jdbctemplate 指南

Spring Boot 对 JDBC 的支持 Spring 的 JdbcTemplate 在 DataSource 的基础上提供了执行数据库操作的高级抽象。配合 Spring 的声明式事务,能以很简单的方式管理数据库事务,而无需编写模板式的代码。 Spring Boot 通过自动配置机制简化了 DataSource、TransactionManager 等的配置。 让我们看看如何使用 JdbcTemplate 对 PostgreSQL 数据库执行 CRUD 操作。 首先,访问 https://start.springboot.io/,选择 JDBC API、PostgreSQL Driver 和 Testcontainers starter,创建 Spring Boot 应用程序。 假设,我们正在开发一个管理书签(bookmarks)的简单应用。因此,我们将创建包含 id、title、url 和 created_at 列的 bookmarks 表。 初始化数据源 Spring Boot 提供了一种方便的数据库初始化机制。我们可以在 src/main/resources 下创建 schema.sql 和 data.sql 文件,这些文件将在启动应用程序时自动执行。不过,只有在使用 HSQL、H2 等内存数据库时,才会默认启用自动脚本执行功能,否则就会禁用。 我们可以在 src/main/resources/application.properties 文件中添加以下属性来启用脚本初始化。 spring.sql.init.mode=always 现在,让我们创建 src/main/resources/schema.sql 文件,如下所示: create table if not exists bookmarks ( id bigserial not null, title varchar not null, url varchar not null, created_at timestamp, primary key (id) ); 要插入一些示例数据,请创建 src/main/resources/data.

Spring Cache 使用 SCAN 来批量删除缓存

在 Spring Boot 应用中使用 Spring Cache 管理缓存时,可以通过调用 @CacheEvict(allEntries=true) 注解的方法来批量删除当前缓存(cacheNames) 下的所有缓存项目。如下: package cn.springdoc.demo.cache; import org.springframework.cache.annotation.CacheEvict; import org.springframework.stereotype.Component; @Component public class FooCahe { // 清除 “foo” 命名空间下的所有缓存项目 @CacheEvict(cacheNames = "foo", allEntries = true) public void clear () { } } 如果你的 Spring Cache 使用的缓存实现是 Redis,那么默认情况下它会使用 KEYS [pattern] 指令来获取、删除所有匹配的缓存项目。 测试方法如下: package cn.springdoc.demo; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import cn.springdoc.demo.cache.FooCahe; @SpringBootTest(classes = SpringdocCacheApplication.class) class SpringdocCacheApplicationTests { static final Logger logger = LoggerFactory.

在 Spring Boot 3 中自定义 WebFlux 异常

1、概览 在本教程中,我们将探索 Spring 框架中不同的错误响应格式。我们还将了解如何使用自定义属性抛出和处理 RFC7807 ProblemDetail,以及如何在 Spring WebFlux 中抛出自定义异常。 2、Spring Boot 3 中的异常响应格式 让我们来了解一下开箱即用的各种错误响应格式。 默认情况下,Spring Framework 提供了实现 ErrorAttributes 接口的 DefaultErrorAttributes 类,用于在出现未处理的错误时生成错误响应。在默认错误的情况下,系统会生成一个 JSON 响应,提供了一些详细的信息: { "timestamp": "2023-04-01T00:00:00.000+00:00", "status": 500, "error": "Internal Server Error", "path": "/api/example" } 虽然该错误响应包含一些关键属性,但可能对排除问题没有帮助。幸运的是,我们可以通过在 Spring WebFlux 应用程序中创建 ErrorAttributes 接口的自定义实现来修改默认行为。 从 Spring Framework 6 ProblemDetail 开始,支持 RFC7807 规范的表示。ProblemDetail 包含一些定义错误细节的标准属性,还提供了扩展细节以进行自定义的选项。支持的属性如下所示: type(string) - 标识问题类型的 URI 参考地址。 title(string) - 问题类型简述。 status(number) - HTTP 状态码。 detail(string) - 应包含异常的详细信息。 instance(string) - 一个 URI 参考地址,用于标识问题的具体原因。例如,它可以指向导致问题的属性。 除了上述标准属性外,ProblemDetail 还包含一个 Map<String, Object>,用于添加自定义参数,以提供有关问题的更详细信息。

在非 Spring Boot 应用中整合 Spring Boot Actuator

1、概览 Spring Boot 项目 是 Spring 框架的扩展,它提供的功能有助于创建基于 Spring 的独立应用程序,并支持云原生开发。 有时,我们并不想使用 Spring Boot,例如在将 Spring Framework 整合到 Jakarta EE 应用程序时,但我们仍然希望受益于生产就绪功能,如指标和健康检查,即所谓的 “可观察性”。(可在 “Spring Boot 3 和 Observability(可观察性)” 一文中找到详细信息)。 可观察性功能由 Spring Boot Actuator 提供,它是 Spring Boot 的一个子项目。在本文中,我们将了解如何将 Actuator 整合到非 Spring Boot 的应用程序中。 2、项目配置 如果不使用 Spring Boot,我们就需要处理应用打包和服务器运行时配置的问题,还需要自己将 配置外部化,当然,本文并不会涉及这些内容。由于我们不能直接使用 Spring Boot 的 Starter 依赖(本例中为 spring-boot-starter-actuator),因此我们需要在 application context 中手动添加必要的 Bean。 我们可以手动配置,也可以使用自动配置。因为 Actuator 的配置相当复杂,而且没有任何详细的文档说明,所以我们应该选择自动配置。这是我们需要 Spring Boot 的原因之一,因此我们不能完全排除 Spring Boot。 2.1、添加项目依赖 要集成 Actuator,我们需要 Spring-boot-actuator-autoconfigure 依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-actuator-autoconfigure</artifactId> <version>3.0.6</version> </dependency> 这也将通过传递依赖 spring-boot-actuator、spring-boot 和 spring-boot-autoconfigure。