SQLite 是一种嵌入式关系型数据库管理系统(RDBMS),使用 C 语言开发,以其简单性、轻量级和零配置而闻名。不需要独立的服务器,可以直接嵌入到应用中。支持事务,支持各种编程语言。是移动应用和嵌入式系统的首选数据库解决方案。
本文将会带你了解如何在 Spring Boot 中配置和使用 SQLite。
创建 Spring Boot 应用 创建一个示例 Spring Boot 应用。在 pom.xml 添加 spring-boot-starter-jdbc 和 SQLite 驱动 sqlite-jdbc 依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.xerial</groupId> <artifactId>sqlite-jdbc</artifactId> </dependency> sqlite-jdbc 已经被 Spring Boot 纳入了版本控制,所以在项目继承了 spring-boot-starter-parent 的情况下,添加此依赖不用声明版本号。
配置属性 在 application.yaml 中配置如下属性:
spring: datasource: type: com.zaxxer.hikari.HikariDataSource driver-class-name: org.sqlite.JDBC url: "jdbc:sqlite:D:\\app.db" 使用默认的数据源实现 HikariDataSource。通过 driver-class-name属性指定 SQLite 的驱动类。url 配置指定了 SQLite 数据库文件的位置,可以是相对路径或者绝对路径。如果文件不存在,会被创建。
测试 得益于 Spring Boot 对数据源开箱即用的支持,完成上述配置后,SQLite 数据库已经就绪可以使用了。
创建测试类:
import java.time.LocalDateTime; import java.
1、概览 在云上构建分布式应用时,需要考虑到服务故障,这通常会涉及到重试。
Spring WebFlux 提供了一些失败后重试的工具。
本文将会带你了解如何在 Spring WebFlux 添加和配置重试功能。
2、用例 本文使用一个 MockWebServer 来模拟外部系统暂时不可用,然后又变为可用的情况。
连接到 REST 服务的组件:
@Test void givenExternalServiceReturnsError_whenGettingData_thenRetryAndReturnResponse() { mockExternalService.enqueue(new MockResponse() .setResponseCode(SERVICE_UNAVAILABLE.code())); mockExternalService.enqueue(new MockResponse() .setResponseCode(SERVICE_UNAVAILABLE.code())); mockExternalService.enqueue(new MockResponse() .setResponseCode(SERVICE_UNAVAILABLE.code())); mockExternalService.enqueue(new MockResponse() .setBody("stock data")); StepVerifier.create(externalConnector.getData("ABC")) .expectNextMatches(response -> response.equals("stock data")) .verifyComplete(); verifyNumberOfGetRequests(4); } 3、添加重试 Mono 和 Flux API 中内置了两个关键的 retry 操作。
3.1、使用 retry retry 可以防止应用立即返回错误,并重新订阅指定次数:
public Mono<String> getData(String stockId) { return webClient.get() .uri(PATH_BY_ID, stockId) .retrieve() .bodyToMono(String.class) .retry(3); } 无论 Web 客户端返回什么错误,都会重试最多三次。
3.2、使用 retryWhen retryWhen 方法可用来创建一个可配置的重试策略:
1、概览 在设计 RESTful API 的时候,往往会纠结于到底是用 PUT 还是 POST 请求?
本文将会带你了解在 RESTful API 中 PUT 和 POST 请求之间的区别以及它们的应用场景。
2、PUT 与 POST 在典型的 REST 架构中,客户端以 HTTP 方法的形式向服务器发送请求,以创建、检索、修改或删除资源。虽然可以使用 PUT 和 POST 来创建资源,但它们在预期应用方面有很大的不同。
根据 RFC 2616 标准,POST 方法应该用于请求服务器将所附实体作为现有资源(由请求 URI 标识)的子级接受。这意味着使用 POST 方法调用将在资源集合下创建一个子资源。
相反,PUT 方法应该用于请求服务器将所附实体存储在请求的 URI 下。如果请求 URI 指向服务器上的现有资源,则提供的实体将被视为现有资源的修改版本。因此,PUT 方法调用要么创建一个新资源,要么更新现有资源。
这两种方法的另一个重要区别是,PUT 是一种幂等方法,而 POST 不是。例如,多次调用 PUT 方法将创建或更新同一资源。相比之下,多次 POST 请求将导致多次创建同一资源。
3、示例应用 使用 Spring Boot 创建一个简单的 RESTful Web 应用来演示 PUT 和 POST 请求的区别。
3.1、Maven 依赖 需要在 pom.xml 中添加 Spring Web、Spring Data JPA 和 H2 内存数据库依赖:
1、概览 本文将会带你了解 Spring MVC HandlerInterceptor 和 Servlet Filter 之间的区别和各自的应用场景。
2、Filter Filter 是 Web 服务器的一部分,而不是 Spring 框架的组件。对于传入请求,可以使用 Filter 来操作甚至阻止请求到达任何 Servlet。反之亦然,也可以阻止响应到达客户端。
Spring Security 就是使用 Filter 进行身份认证和授权的一个很好的例子。要配置 Spring Security,只需添加一个 Filter,即 DelegatingFilterProxy。这样,Spring Security 就能拦截所有进出流量。这就是 Spring Security 可以在 Spring MVC 之外使用的原因。
2.1、创建 Filter 创建一个实现 jakarta.servlet.Filter 接口的 Filter 实现类:
public class LogFilter implements Filter { private Logger logger = LoggerFactory.getLogger(LogFilter.class); @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { logger.info("Hello from: " + request.
1、简介 本文将带你了解如何在 Spring Boot 项目中处理 Multipart 文件上传请求。
Multipart 请求可以包含多个独立的请求体部分,通常用于文件上传。除了文件以外,还可以同时上传表单、JSON、XML 等等数据。
2、使用 @ModelAttribute 一个简单的示例,使用表单发送包含了员工姓名和文件的数据。
创建 Employee 类:
public class Employee { private String name; private MultipartFile document; } 然后,使用 Thymeleaf 渲染表单:
<form action="#" th:action="@{/employee}" th:object="${employee}" method="post" enctype="multipart/form-data"> <p>name: <input type="text" th:field="*{name}" /></p> <p>document:<input type="file" th:field="*{document}" multiple="multiple"/> <input type="submit" value="upload" /> <input type="reset" value="Reset" /></p> </form> 注意,需要将表单的 enctype 属性声明为 multipart/form-data。
最后,创建一个接受表单数据(包括 Multipart 文件)的方法:
@RequestMapping(path = "/employee", method = POST, consumes = { MediaType.
Minio 是一个用 Golang 开发的开源的对象存储服务器,它基于 Amazon S3 协议,提供了简单而强大的存储解决方案。可以在本地部署或云环境中使用。也支持分布式部署,并具有高可用性和容错性。
本文将会带你了解如何在 Linux 中通过 Docker 的方式来安装、配置 Minio,以及如何在 Spring Boot 应用中通过 Minio 官方 SDK 上传文件资源到 Minio 服务器。
安装 Minio 在 Linux 下,使用 Docker 的方式安装 Minio 最简单。首先确保你在服务器上安装了 Docker,并且需要 root 用户来执行下面的安装过程。
首先,创建存放文件资源的目录:
mkdir -p ~/minio/data 上述命令在 $HOME 目录下创建了 /minio/data 文件夹,用于存放资源。
接着,使用 Docker 运行 Minio 容器:
docker run \ -d \ -p 9000:9000 \ -p 9090:9090 \ --name minio-server \ -v ~/minio/data:/data \ -e "MINIO_ROOT_USER=admin" \ -e "MINIO_ROOT_PASSWORD=minio858896" \ quay.
1、概览 本文将会带你了解 Spring 中的 @AliasFor 注解。
首先介绍一些框架中的使用示例,最后看看如何在自定义注解中使用 @AliasFor。
2、注解 @AliasFor 自 4.2 版起成为框架的一部分。多个 Spring 核心注解已更新为包含此注解。
可以将其用于装饰单个注解中的属性,或者在由元注解组成的注解中使用。元注解是可以应用于其他注解的注解。
在同一个注解中,使用 @AliasFor 来声明属性的别名,这样就可以交替使用它们。或者,可以在组合注解中使用 @AliasFor 来覆盖元注解中的属性。换句话说,当使用 @AliasFor 在组合注解中装饰属性时,它会覆盖其元注解中的指定属性。
许多核心 Spring 注解,如 @Bean、@ComponentScan、@Scope、@RequestMapping 和 @RestController 现在都使用 @AliasFor 来配置其内部属性别名。
@AliasFor 注解的定义如下:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented public @interface AliasFor { @AliasFor("attribute") String value() default ""; @AliasFor("value") String attribute() default ""; Class<? extends Annotation> annotation() default Annotation.class; } 既可以隐式地使用这个注解,也可以显式地使用它。隐式使用仅限于注解内部的别名。相比之下,显式使用还可以用于元注解中的属性。
3、注解中的显示别名 参考 Spring 的核心注解 @ComponentScan:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Repeatable(ComponentScans.class) public @interface ComponentScan { @AliasFor("basePackages") String[] value() default {}; @AliasFor("value") String[] basePackages() default {}; .
1、简介 本文将带你了解 Spring 中的 @Conditional 注解。它用于根据特定条件来控制 Bean 的创建和注册。
2、声明条件 首先来看看在哪些情况下可以使用条件注解。
最常见的用法是包含或排除整个配置类:
@Configuration @Conditional(IsDevEnvCondition.class) class DevEnvLoggingConfiguration { } 或者是一个 Bean:
@Configuration class DevEnvLoggingConfiguration { @Bean @Conditional(IsDevEnvCondition.class) LoggingService loggingService() { return new LoggingService(); } } 如上,这样就可以根据特定条件(如环境类型或特定需求)来调整应用的行为。在上例中,只为开发环境初始化了额外的 LoggingService。
另一种方式是直接在组件类上放置条件。
@Service @Conditional(IsDevEnvCondition.class) class LoggingService { // ... } 可以将上述示例应用于任何使用 @Component、@Service、@Repository 或 @Controller 注解声明的 Bean。
3、预定义条件注解 Spring 自带一组预定义的条件注解。
首先,看看如何根据配置的属性值来创建组件:
@Service @ConditionalOnProperty( value="logging.enabled", havingValue = "true", matchIfMissing = true) class LoggingService { // ... } 第一个属性 value 指定了要匹配的配置属性。第二个属性 havingValue 定义了该条件所需的值。最后,matchIfMissing 属性告诉 Spring,如果参数缺失,是否应匹配该条件。
1、概览 本文将会带你了解在 Spring Boot 启动时出现 ApplicationContextException 异常的原因,以及解决办法:
ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean 2、可能的原因 异常信息,“由于缺少 ServletWebServerFactory Bean,无法启动 ServletWebServerApplicationContext” 说明了一切。ApplicationContext 中没有配置 ServletWebServerFactory Bean。
该异常主要出现在 Spring Boot 无法启动 ServletWebServerApplicationContext 时。为什么会这样?因为 ServletWebServerApplicationContext 使用包含的 ServletWebServerFactory Bean 来启动自身。
一般来说,Spring Boot 通过 SpringApplication.run 方法来启动 Spring 应用。
SpringApplication 类会根据应用类型(如,Web 应用),尝试创建正确的 ApplicationContext。
用于确定是否是 Web 应用的算法来自于一些依赖,如 spring-boot-starter-web。缺少这些依赖,可能是导致异常的原因之一。
另一个原因是 Spring Boot 启动类中缺少 @SpringBootApplication 注解。
3、重现异常 创建一个示例应用,故意在 main 类上不添加 @SpringBootApplication 注解。
public class MainEntryPoint { public static void main(String[] args) { SpringApplication.
1、概览 本文将带你了解如何在 Spring Boot 中配置 Feign 客户端的日志级别。
2、Feign 客户端 Feign 是一个声明式的 HTTP 客户端,通过注解来处理模板代码。只需提供一个带注解的接口,运行时会根据注解定义创建实际的实现。
3、日志配置 要启用日志记录,需要将应用中包含 Feign 客户端的类或包的日志记录级别设置为 DEBUG。
给一个类设置日志级别:
logging.level.<packageName>.<className> = DEBUG 如果 Feign 接口都在同一个包下,也可以直接为整个 package 设置日志级别:
logging.level.<packageName> = DEBUG 接着,需要设置 feign 客户端的日志级别。注意,上一步只是启用日志记录。
有四种日志级别可供选择:
NONE:无日志记录(默认) BASIC:记录基本信息,包括请求方法和 URL 以及响应状态码和执行时间 HEADERS:记录基本信息以及请求和响应的 Header FULL:记录请求和响应的 Header、Body 和元数据 可以通过 Java 配置类或在 properties 文件中进行配置。
3.1、Java 配置 声明一个配置类 FeignConfig:
public class FeignConfig { @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } } 然后,把配置类设置到 Feign 客户端接口 FooClient 中:
@FeignClient(name = "foo-client", configuration = FeignConfig.