一、问题描述
起因是当时我做项目的需求,既要上传音频文件,又有json字符串等普通数据。所以选用表单提交,但是方法的入参使用@RequestParam注解表单后,Postman测试接口死活不进方法。我也看到很多网友是这样注解表单的,都没有我这种情况。我就很困惑,但是放到param就不会报错,以下是我写的测试方法:
在Params传参正常
在Body传参就报错了
二、@RequestParam与@RequestPart的区别
1.@RequestParam注解
@RequestParam注解可以用于处理表单数据。但是表单类型为application/x-www-form-urlencoded,而且这个类型不能传输文件数据。@RequestParam注解通常用于处理HTTP请求中的参数,包括GET请求的查询参数和POST请求的表单参数。它可以从请求的查询字符串或表单数据中提取参数值,并将其绑定到控制器方法的参数上。
使用场景
- GET请求:在GET请求中,@RequestParam常用于处理URL中的查询参数。例如,一个URL可能是这样的:
http://localhost:8080/users?name=John&age=30。在这个例子中,name和age就是通过@RequestParam注解获取的参数。 - POST请求:在POST请求中,@RequestParam也可以用于处理
application/x-www-form-urlencoded类型的数据。这意味着在POST请求的Body部分,数据需要以键值对的形式提交,例如:name=John&age=30。这种情况下,@RequestParam同样可以用于提取这些参数。
配置参数
@RequestParam注解有几个配置参数:
- required:表示参数是否必须。默认为true,即参数必须存在。可以设置为false,表示参数可以不存在,此时如果参数不存在,方法的参数将为null而不是抛出异常。
- defaultValue:可以为参数设置一个默认值,当请求中没有该参数时,将使用这个默认值。
- value或name:指定请求中的参数名。
示例代码
下面是一个使用@RequestParam注解处理GET请求的示例:
@GetMapping("/users")
public String getUsers(@RequestParam(value = "name", required = false) String name,
@RequestParam(value = "age", defaultValue = "20") int age) {
return "Name: " + name + ", Age: " + age;
}
2.@RequestPart注解
RequestPart注解在Spring框架中的作用是处理multipart/form-data类型的请求,特别是用于文件上传和复杂的表单提交。它用于从multipart/form-data请求中提取某一部分的数据,并将其绑定到控制器方法的参数上。
使用场景
- 文件上传:当需要上传文件时,可以使用RequestPart注解将上传的文件绑定到MultipartFile类型的参数上。MultipartFile是Spring提供的一个接口,用于表示上传的文件。
- 复杂表单提交:当表单中包含多个部分,如文件和其他表单字段时,可以使用RequestPart注解分别提取这些部分的数据。
配置参数
@RequestPart注解有几个配置参数:
- name/value:指定multipart/form-data请求中的部分名称。这个名称应该与前端发送请求时指定的部分名称相匹配。
- required:指定该部分是否是必需的。默认为true,表示该部分是必需的。如果设置为false,则表示该部分是可选的,如果请求中未包含该部分,则不会抛出异常。
示例代码
以下是一个使用RequestPart注解处理文件上传和复杂表单提交的示例代码:
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@RestController
public class FileUploadController {
@PostMapping("/upload")
public String handleFileUpload(
@RequestPart("file") MultipartFile file) {
// 处理文件上传逻辑
return "文件上传成功";
}
}
三、问题原因
原因是我使用@RequestParam注解的时候,我的表单类型是multipart/form-data,最最重要的是我的是响应式代码,不支持@RequestParam来注解我表单数据。
四、解决办法
1.有文件和参数
方法一:看效果
@PostMapping("/upload")
public Mono<String> handleFileUpload(ServerWebExchange exchange) {
// 获取 multipart 数据
return exchange.getMultipartData()
.flatMap(multipartData -> {
// 获取文件数据
FilePart filePart = (FilePart) multipartData.getFirst("file");
if (filePart == null) {
return Mono.error(new ResponseStatusException(HttpStatus.BAD_REQUEST, "File is required"));
}
// 获取字符串数据(例如:username, description)
// 获取文本字段并读取其值
String username = extractFormFieldValue(multipartData, "username");
String description = extractFormFieldValue(multipartData, "description");
// 你可以在这里处理文件和其他表单字段
// 例如:保存文件,或者将数据保存到数据库
System.out.println("-----------------------------------------------------------Username: " + username);
System.out.println("------------------------------------------------------------Description: " + description);
// 处理文件数据(比如保存到磁盘)
return filePart.transferTo(new java.io.File("D:/" + filePart.filename()))
.then(Mono.just("File uploaded su***essfully"));
});
}
private String extractFormFieldValue(MultiValueMap<String, Part> multipartData, String fieldName) {
Part part = multipartData.getFirst(fieldName);
if (part instanceof FormFieldPart) {
FormFieldPart formFieldPart = (FormFieldPart) part;
return formFieldPart.value();
}
return null;
}
方法二:使用@RequestPart注解
2.如果只接收单个文件上传, 可以用 Mono<FilePart> 。
在 Java 中,使用 Mono<FilePart> 可以通过 Spring WebFlux 来处理单个文件的上传。Mono 是 Reactor 库中的一个类,表示一个异步的、单值的操作,而 FilePart 是一个接口,用于表示上传的文件部分。
步骤一:首先,确保你的项目中已经引入了 spring-boot-starter-webflux 和相关的依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
步骤二:创建一个简单的控制器,用于接收文件上传。
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Mono;
import org.springframework.web.server.ServerWebExchange;
import java.io.File;
import java.io.IOException;
@RestController
@RequestMapping("/upload")
public class FileUploadController {
@PostMapping
public Mono<ResponseEntity<String>> handleFileUpload(@RequestPart("file") Mono<FilePart> filePartMono) {
return filePartMono.flatMap(filePart -> {
// 保存文件到指定位置
String filePath = "path/to/your/file/directory/" + filePart.filename();
try {
// 将文件保存到磁盘
File file = new File(filePath);
filePart.transferTo(file).subscribe(); // 异步保存文件
// 返回成功响应
return Mono.just(ResponseEntity.ok("File uploaded su***essfully to " + filePath));
} catch (IOException e) {
// 处理异常
return Mono.just(ResponseEntity.status(500).body("Failed to upload file: " + e.getMessage()));
}
});
}
}
3.使用 ServerRequest 作为参数。通过 formData 接收。
Spring WebFlux 示例:
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ServerRequest;
import org.springframework.http.MediaType;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/example")
public class ExampleController {
// 通过 ServerRequest 获取表单数据
@PostMapping("/submit")
public Mono<String> handleFormData(ServerRequest request) {
return request.formData()
.flatMap(formData -> {
// 获取表单字段
String name = formData.getFirst("name"); // 获取 'name' 字段
String email = formData.getFirst("email"); // 获取 'email' 字段
return Mono.just("Received name: " + name + " and email: " + email);
});
}
}
解释:
-
ServerRequest是一个Spring WebFlux类,它代表了传入的HTTP请求。 -
formData()方法用于从请求中提取表单数据,它返回一个Mono<FormData>对象。 -
formData.getFirst("fieldName")用于获取特定表单字段的第一个值。
什么问题都可以评论区留言,看见都会回复的
如果你觉得本篇文章对你有所帮助的,把“文章有帮助的”打在评论区
多多支持吧!!!
点赞加藏评论,是对小编莫大的肯定。抱拳了!