教程

使用 Podman Desktop 容器化 Spring Boot 应用

1、概览 本文将带你了解如何使用 Podman Desktop 对 Spring Boot 应用进行容器化。Podman 是一种容器化工具,它允许我们在不需要守护进程的情况下管理容器。 Podman Desktop 是一款具有图形用户界面(GUI)的桌面应用,用于使用 Podman 管理容器。 为了演示其用法,我们要创建一个简单的 Spring Boot 应用,构建容器镜像,并使用 Podman Desktop 运行容器。 2、安装 Podman Desktop 我们需要在本地计算机上 安装 Podman Desktop 才能开始使用。它适用于 Windows、macOS 和 Linux 操作系统。下载安装程序后,按照安装说明在机器上安装 Podman Desktop 即可。 以下是设置 Podman Desktop 的几个重要步骤: 机器上应已安装 Podman。如果没有安装,Podman Desktop 会提示并为我们安装。 Podman 准备就绪后,系统会提示我们启动 Podman 虚拟机。我们可以选择默认设置,也可以根据需要自定义设置。在运行容器之前,这是必须的。 此外,对于 Windows,需要启用/安装 WSL2(Windows Subsystem for Linux),然后才能运行 Podman。 在安装过程结束时,我们应该有一个正在运行的 Podman 虚拟机,并可以使用 Podman Desktop 进行管理。 可以在 “Dashboard”(仪表盘)部分看到: 3、创建 Spring Boot 应用 创建一个小型 Spring Boot 应用。该应用有一个 REST Controller,当我们访问 /hello 端点时,它返回一条 "Hello, World!

Spring Boot 测试 CORS 跨域配置

1、简介 跨源资源共享(Cross-Origin Resource Sharing,CORS)是一种安全机制,允许网页从一个源访问另一个源的资源。它由浏览器强制执行,以防止网站向不同域发出未经授权的请求。 在使用 Spring Boot 构建 Web 应用时,必须正确测试 CORS 配置,以确保应用能安全地与授权的源交互,同时阻止未经授权的源。 通常情况下,我们只有在应用部署后才会发现 CORS 问题。通过尽早测试 CORS 配置,可以在开发过程中发现并解决这些问题,从而节省时间和精力。 本文将带你了解讨如何使用 MockMvc 编写有效的测试来验证 CORS 配置。 关于 Spring Boot 中 CORS 跨域配置的详细内容,你可以参阅 “在 Spring 应用中处理 CORS 跨域” 和 “Spring 和 CORS 跨域” 这两篇文章。 2、Spring Boot 配置 CORS 在 Spring Boot 应用中配置 CORS 有多种方法。在本文中,我们使用 Spring Security 并自定义 CorsConfigurationSource: private CorsConfigurationSource corsConfigurationSource() { CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.setAllowedOrigins(List.of("https://baeldung.com")); corsConfiguration.setAllowedMethods(List.of("GET")); corsConfiguration.setAllowedHeaders(List.of("X-Baeldung-Key")); corsConfiguration.setExposedHeaders(List.of("X-Rate-Limit-Remaining")); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.

解决异常 PSQLException: Operator Does Not Exist: Character Varying = UUID

1、简介 本文将带你了解 JPA 与 PostgreSQL 交互时出现 PSQLException 异常:“Operator Does Not Exist: Character Varying = UUID” 的原因,以及如何处理和避免该异常。 2、异常原因 PostgreSQL 区分 Character Varying(字符串)和 UUID 数据类型。这种区分要求在这些类型之间进行比较时进行 显式类型转换。因此,当我们尝试直接将 UUID 值与字符串(VARCHAR)列进行比较时,PostgreSQL 会抛出异常,因为它缺乏用于这种特定类型比较的操作符。 举个例子,有一个 User 实体,其 varchar 列为 uuid: @Entity @Table(name = "User_Tbl") public class User{ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(columnDefinition = "varchar") private UUID uuid; // Gette / Setter 方法省略 } 当尝试使用 UUID 值查询数据库时,会出现异常: // UUID UUID testId = UUID.fromString("c3917b5b-18ed-4a84-a6f7-6be7a8c21d66"); User user = new User(); user.

Java 枚举、JPA 和 PostgreSQL 枚举

1、简介 本文将带你了解 Java 枚举、JPA 和 PostgreSQL 枚举的概念,以及如何将它们结合使用,在 Java 枚举和 PostgreSQL 枚举之间创建无缝映射。 2、Java 枚举 Java 枚举(Enum)是一种特殊类型的类,用于表示一组固定数量的常量。枚举用于定义一组具有底层类型(如字符串或整数)的命名值。当我们需要定义一组在应用中具有特定含义的命名值时,枚举非常有用。 下面是一个 Java 枚举的示例: public enum OrderStatus { PENDING, IN_PROGRESS, COMPLETED, CANCELED } 在本例中,OrderStatus 枚举定义了四个常量。这些常量可以在我们的应用中用来表示订单的状态。 3、使用 @Enumerated 注解 在 JPA 中使用 Java 枚举时,需要用 @Enumerated 来注解枚举字段,以指定如何将枚举值存储到数据库中。 首先,定义一个名为 CustomerOrder 的实体类,并用 @Entity 进行注解,以标记其用于 JPA 持久化: @Entity public class CustomerOrder { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Enumerated() private OrderStatus status; // 其他的字段和方法省略 } 默认情况下,JPA 将枚举值存储为整数(Integer),代表枚举常量的序号位置(ordinal())。例如,上文中的 OrderStatus 枚举值 PENDING、IN_PROGRESS、COMPLETED 和 CANCELED,默认行为将分别把它们存储为整数 0、1、2 和 3。由此产生的数据库表将有一个小 int 类型的状态列,其值为 0 至 3:

在 Spring 中使用 Logbook 记录 HTTP 请求和响应

1、概览 Logbook 是一个可扩展的 Java 库,可为不同的客户端和服务器端提供完整的请求和响应日志。它允许开发人员记录应用接收或发送的任何 HTTP 流量。这可用于日志分析、审计或分析流量问题。 本文将带了解如何在 Spring Boot 中整合 Logbook,以及如何使用 Logbook 记录 HTTP 请求和响应。 2、依赖 在 Spring Boot 中添加 logbook-spring-boot-starter 依赖: <dependency> <groupId>org.zalando</groupId> <artifactId>logbook-spring-boot-starter</artifactId> <version>3.9.0</version> </dependency> 你可以在 Maven Central 中找到最新版本的 Logbook。 3、配置 Logbook 与 Spring Boot 应用中的 logback 日志配合使用。 我们需要在 logback-spring.xml 和 application.properties 文件中添加配置。 在 pom.xml 中添加 Logbook 库后,Spring Boot 就会自动配置 Logbook 库,我们需要做的就是在 application.properties 文件中添加日志级别: logging.level.org.zalando.logbook.Logbook=TRACE 启用 TRACE 日志级别,即可记录 HTTP 请求和响应。 此外,还要在 logback-spring.xml 文件中添加了 Logbook 配置: <logger name="org.zalando.logbook" level="INFO" additivity="false"> <appender-ref ref="RollingFile"/> </logger> 添加完成后,就可运行应用了。每次 HTTP 请求调用后,Logbook 都会将请求和响应记录到 logback-spring.

Spring Data JPA 检索最大值(Max Value)

1、简介 本文将带你了解如何使用 Spring Data JPA 检索数据列中的最大值(Max Value)。 2、示例 首先,添加 spring-boot-starter-data-jpa 依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> 然后,定义一个简单的 Employee 实体表示员工: @Entity public class Employee { @Id @GeneratedValue private Integer id; private String name; private Long salary; // 工资 // 构造函数、Getter、Setter 方法省略 } 接下来,看看有哪些方法可以检索出所有员工中薪水(salary)列的最大值。 3、使用 Repository 的派生查询 Spring Data JPA 提供了一个强大的机制,可以使用 Repository 方法来定义自定义查询。其中之一是派生查询,它允许我们通过声明方法名来实现SQL查询。 创建 Employee 实体类的 Repository 接口: public interface EmployeeRepository extends JpaRepository<Employee, Integer> { Optional<Employee> findTopByOrderBySalaryDesc(); } 如上,我们实现了一个方法 findTopByOrderBySalaryDesc,该方法使用查询派生机制生成相应的 SQL。根据方法名,它将按照工资(salary)降序对所有员工进行排序,然后返回第一个员工,即工资最高的员工。 该方法会返回一个加载了所有属性的实体。如果我们只想检索一个工资(salary)值,可以使用投影查询: 创建 EmployeeSalary 投影接口:

在 Golang 中实现类似于 Spring 中的模板事务

事务(TRANSACTION),是指一组操作的集合,这些操作要么全部成功,要么全部失败。其目的是在出现错误、系统崩溃或其他意外情况下,保证数据的一致性和完整性。 事务通常具有以下四个重要的特性,这些特性被统称为 ACID 属性: Atomicity(原子性): 定义: 事务中的所有操作要么全部完成,要么全部不完成,任何一个操作失败都会导致整个事务的失败,并且事务的所有操作都会被回滚(撤销)。 示例: 银行转账操作,如果从一个账户扣款后无法在另一个账户中存款,那么整个操作将回滚,不会执行任何更改。 Consistency(一致性): 定义: 事务只能把数据库从一种一致状态转换到另一种一致状态。在事务开始之前和结束之后,数据库的完整性约束没有被破坏。 示例: 在一个事务中插入数据时,如果插入的数据违反了数据库的完整性约束(例如唯一约束),那么这个事务将失败,数据库将保持一致状态。 Isolation(隔离性): 定义: 事务的执行是隔离的,多个事务并发执行时,一个事务的执行不会受到其他事务的干扰。隔离性确保了并发事务的执行结果与按顺序执行的结果相同。 示例: 两个用户同时购买同一件商品,隔离性确保每个用户看到的库存是正确的,避免超卖的情况。 Durability(持久性): 定义: 一旦事务提交,其结果将永久保存在数据库中,即使系统崩溃也不会丢失。 示例: 即使在事务提交后立即发生系统崩溃,事务的结果也会保存在数据库中,重启系统后数据依然存在。 以 MYSQL 关系型数据库为例,事务的使用如下: -- 开始事务 BEGIN TRANSACTION; -- TODO 执行业务 1 -- TODO 执行业务 2 -- TODO 执行业务 3 -- .... -- 提交事务 COMMIT; -- 或者,回滚事务 ROLLBACK; 其中,BEGIN TRANSACTION、COMMIT 以及 ROLLBACK 都是事务固定的模板代码,当代的大多数框架都会自动帮我们进行处理。 Spring 对事务的支持 Spring 对关系型数据库中的事务提供强大的支持,包括声明式事务、TransactionTemplate 模板事务等等。 @Transactional 声明式事务 实际开发中,最常用的就是通过 @Transactional 注解来声明事务方法。事务方法会在执行开始前自动开始事务,在方法结束后自动提交事务,在执行过程中如果遇到异常则自动回滚事务。 import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service @Transactional // 为 public 方法开启事务 public class FooService { public void service () { // TODO 在事务中执行业务 } } 在类上注解 @Transactional,则会为当前类中所有 public 方法开启声明式事务。也可以单独注解在方法上,则会覆盖类上的 @Transactional 定义。

Java 中的向上转型和向下转型

1、简介 了解如何处理 Java 类型层次结构中的对象对于编写灵活和可维护的代码至关重要。在这个领域中,两个基本概念是向上转型(Upcasting)和向下转型(Downcasting)。 本文将带你深入了解这些概念,探索它们之间的区别,以及它们在 Java 中的原理。 2、Java 中的类型转换 Java 是一种面向对象的编程语言(Object Oriented Programming,OOP),允许在其类型系统中将一种类型转换为另一种类型。转换是将一种类类型的引用转换为另一种类类型的过程。具体来说,Java 中主要有两种类型的转换:向上转型(Upcasting)和向下转型(Downcasting)。 假设我们有一个类的层次结构,其中 Dog 是 Animal 的子类。下图显示了向上转型(Upcasting)和向下转型(Downcasting)在这个层次结构中的工作原理: 向上转型(Upcasting)箭头从 Dog 类移动到 Animal 类,显示了子类引用(Dog)如何泛化为父类引用(Animal)。而,向下转型(Downcasting)箭头从 Animal 类返回 Dog 类,显示父类引用(Animal)如何再次被指定为子类引用(Dog)。 但是,如果尝试使用 Animal 引用实例化 Dog 对象,则会因类型不兼容而导致编译错误。 Dog dog = new Animal(); //异常 ClassCastException 3、Java 向上转型 向上转型(Upcasting)是指将子类引用转换为父类引用。这种类型的转换是隐式的,在处理多态性时经常使用它。 向上转型(Upcasting)允许我们将一个子类的对象当作一个父类的对象来处理: class Animal { public void makeSound() { System.out.println("Animal sound"); } } class Dog extends Animal { public void makeSound() { System.out.println("Bark"); } public void fetch() { System.

Jackson 序列化和反序列化 java.sql.Blob

1、简介 本文将带你了解如何使用 Jackson 序列化和反序列化 java.sql.Blob 对象。 java.sql.Blob 表示 Java 中的二进制大对象(Binary Large Object,Blob),可以存储大量二进制数据。在使用 Jackson 处理 JSON 序列化和反序列化时,处理 Blob 对象可能比较棘手,因为 Jackson 并不直接支持它们。不过,我们可以创建自定义的序列化器(Serializer)和反序列化器(Deserializer)来处理 Blob 对象。 2、依赖和示例项目 首先,在 pom.xml 中添加 jackson-databind 依赖: <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.3</version> </dependency> 然后,创建一个简单的 User POJO,其中包含 id、name 和 Blob 类型的 profilePicture(图片数据): public class User { private int id; private String name; private Blob profilePicture; // 构造函数,Getter/Setter 省略 } 3、定义 Blob 序列化器 定义一个序列化器(Serializer),将 User 的 profilePicture 属性转换为 Base64 编码的二进制字符串: @JacksonStdImpl public class SqlBlobSerializer extends JsonSerializer<Blob> { @Override public void serialize(Blob value, JsonGenerator gen, SerializerProvider serializers) throws IOException { try { byte[] blobBytes = value.

使用 Spring WebClient 和 WireMock 进行集成测试

1、简介 Spring WebClient 是一款非阻塞、响应式的 HTTP 客户端,而 WireMock 是一个强大的用于模拟基于 HTTP 的 API 的工具。 2、依赖和示例 首先,需要在 Spring Boot 项目中添加必要的依赖。 在 pom.xml 中添加 spring-boot-starter-flux(WebClient) 和 spring-cloud-starter-wiremock(WireMock Server)依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-contract-wiremock</artifactId> <version>4.1.2</version> <scope>test</scope> </dependency> 假设,我们的应用需要调用外部天气 API,以获取给定城市的天气数据。 定义 WeatherData POJO: public class WeatherData { private String city; private int temperature; private String description; // 构造函数、Getter/Setter 方法省略 我们要使用 WebClient 和 WireMock 进行集成测试,以测试这个功能。 3、使用 WireMock API 进行集成测试 首先用 WireMock 和 WebClient 设置 Spring Boot 测试类: