Spring Boot 处理 Multipart 文件上传请求

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.

在 Spring Boot 中上传文件到 Minio

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.

Spring 中的 @AliasFor 注解

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 {}; .

Spring 中的条件注解

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,如果参数缺失,是否应匹配该条件。

Spring Boot 启动异常:ApplicationContextException

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.

配置 Feign 的日志级别

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.

使用 Spring Boot + Freemarker 开发 i18n 国际化应用

i18n(Internationalization),即国际化。目的是为了使软件、应用或网站能够适应不同的语言、地区,用户可以选择他们熟悉的语言进行交互,为所有用户提供一致的体验。 本文将会带你了解如何使用 Spring Boot + Freemarker 实现国际化。 假设我们有一个登录页面,其中有 2 个输入框,分别用于输入 用户名 和 密码。对于使用不同语言的用户,需要显示不同的输入框名称。 创建项目 在 pom.xml 中添加 web 和 freemarker stater 依赖。 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> 配置 定义国际化资源文件 通常我们会把项目中需要国际化的内容定义在不同的 properties 文件中,通过 properties 文件名的后缀来表示资源的 语言 和 国别。 在 resources 目录下创建 i18n 目录,用于存放国际化资源文件。接着,在 i18n 目录中创建如下 3 个 properties 文件,如下: message.properties # message.properties 的内容 # 空着就行 message_en_US.properties # message_en_US.properties 的内容 # 英文 login.username=USERNAME login.password=PASSWORD message_zh_CN.properties # message_zh_CN.properties 的内容 # 中文 login.

在 Spring 应用中的 Service 层进行验证

1、概览 本文将带你了解如何在 Spring 应用的 Service 层中使用 Spring Validation 进行校验。 2、应用分层 Spring Web 应用通常分为如下几层: Consumer 层或 Web 层是 Web 应用程序的最上层。它负责解析用户的输入并提供适当的响应。其他层抛出的异常也必须由 Web 层处理。由于 Web 层是应用程序的入口点,因此它负责身份认证,是防止未授权用户的第一道防线。 在 Web 层之下是 Service 层。它充当事务屏障,同时承载应用和基础设施服务。Service 层的公共 API 由应用服务提供。它们通常作为事务边界,并负责授权事务。基础设施服务提供与外部工具(包括文件系统、数据库和电子邮件服务器)连接的 “管道代码”。这些方法通常被多个应用服务使用。 Web 应用的最底层是持久层。换句话说,它负责与数据存储进行交互。 3、Service 层的验证 Service 层是应用中的一个层,用于在 Controller 和持久层之间进行通信。此外,业务逻辑也存储在 Service 层中。其中特别包括验证逻辑。Model 状态用于 Controller 层和 Service 层之间的通信。 在业务层进行验证逻辑有其优点和缺点。Spring 的验证(和数据绑定)架构并不排除任何一种方式。验证未绑定在 Web 层,这易于本地化,并且允许使用任何可用的 Validator。 此外,客户端输入数据并不总是通过 REST Controller 处理,如果不在 Service 层进行验证,非法数据可能会通过,引发多个问题。 在这种情况下,可以使用标准的 Java JSR-303 验证方案。 4、示例 使用 Spring Boot 开发一个简单的用户注册应用。 4.1、Domain 只有 name、age、phone 和 password 属性:

Spring Boot 中的 Max-HTTP-Header-Size

1、概览 Spring Boot Web 应用默认包含一个预配置的嵌入式 Web 服务器。有时候需要对这个服务器进行一些定制来满足特殊的需求。 本文将会带你了解如何在 Spring Boot 应用中通过 max-http-header-size 配置属性来限制客户端的 Header 大小。 2、Max-HTTP-Header-Size Spring Boot 支持将 Tomcat、Undertow 和 Jetty 作为嵌入式服务器。通常,会在 Spring Boot 应用的 application.properties 文件或 application.yaml 文件中定义服务器配置。 大多数 Web 服务器对 HTTP 请求头有自己的大小限制。HTTP 请求头的值受服务器实现的限制。在 Spring Boot 应用中,可以使用 server.max-http-header-size 配置属性来配置最大允许的 HTTP Header 的大小 Tomcat 和 Jetty 的默认值为 8kB,而 Undertow 的默认值为 1MB。 在 application.properties 文件中添加该属性,修改最大 HTTP Header 大小: server.max-http-header-size=20000 同样,application.yaml 格式也是如此: server: max-http-header-size: 20000 从 Spring Boot 2.1 开始,可以使用 DataSize 格式的值:

使用 Spring Boot 和 GraalVM 构建原生镜像

1、概览 本年将带你了解原生镜像(Native Image)的相关知识,以及如何使用 Spring Boot 和 GraalVM 构建原生镜像应用。 本文使用的是 Spring Boot 3,但是在末尾会教你如何解决与 Spring Boot 2 的差异问题。 2、原生镜像 原生(本地)镜像是一种将 Java 代码构建为独立可执行文件的技术。该可执行文件包括应用程序类、其依赖项的类、运行时库类以及来自 JDK 的静态链接本地代码。JVM 被打包到原生镜像中,因此在目标系统上不需要任何 Java 运行环境,但构建产物依赖于平台。因此,需要为每个支持的目标系统进行一次构建,在使用 Docker 等容器技术时会更加简单,将容器构建为一个目标系统,可以部署到任何 Docker 运行时。 2.1、GraalVM 和 Native Image Builder 通用递归应用和算法语言虚拟机(Graal VM)是一个高性能的 JDK 发行版,专为 Java 和其他 JVM 语言编写,同时支持 JavaScript、Ruby、Python 和其他几种语言。它提供了一个原生镜像生成器(Native Image builder),这是一个从 Java 应用中生成原生代码并将其与 VM 一起打包成独立可执行文件的工具。Spring Boot Maven 和 Gradle Plugin 除了少数 例外情况(Mockito 目前不支持原生测试),正式支持该工具。 2.2、两个特性 在构建原生镜像时,会遇到两个典型特性。 Ahead-Of-Time(AOT)编译是将高级 Java 代码编译成本地可执行代码的过程。通常由 JVM 的即时编译器 (JIT) 在运行时进行编译,这样可以在执行应用程序时进行观察和优化。在 AOT 编译的情况下,这一优势就不复存在了。 通常,在进行 AOT(Ahead-of-Time)编译之前,可以选择进行一个单独的步骤,称为 AOT 处理,即从代码中收集元数据并提供给 AOT 编译器。将这两个步骤分开是有意义的,因为 AOT 处理可以是针对特定框架的,而 AOT 编译器更加通用。下面的图片给出了一个概览: