我正在使用Spring Boot版本=' 1.4.0.RC1'使用Spring Boot Stormpath 1.0.2。
我正在尝试使用多部分文件上传,但MultipartFile在控制器中始终为null。
当我使用@RequestPart(" file")时,信息:"status":400,"error":"Bad Request","exception":"org.springframework.web.multipart.support.MissingServletRequestPartException","message":"Required request part 'file' is not present"
当我使用@RequestPart(name =" file",required = false)时,该部分始终为空。
但是,如果我向控制器添加一个HttpServletRequest参数,我可以直接从请求获取文件部分,所以我知道它实际存在。
这是控制器,在下面的代码checkNotNull(part)
总是成功,checkNotNull(imageFile)
总是失败:
@PostMapping("{username}/profilePhoto")
public ResponseEntity<?> saveProfilePhoto(@PathVariable("username") String username,
@RequestPart(name = "file", required = false) MultipartFile imageFile,
HttpServletRequest request) {
try {
Part part = request.getPart("file");
checkNotNull(part);
checkNotNull(imageFile);
} catch (IOException | ServletException ex) {
throw InternalServerErrorException.create();
}
// Transfer the multipart file to a temp file
File tmpFile;
try {
tmpFile = File.createTempFile(TMP_FILE_PREFIX, null);
imageFile.transferTo(tmpFile);
} catch (IOException ex) {
log.error("Failed to create temp file", ex);
throw InternalServerErrorException.create();
}
// Execute the use case
updateUserProfilePhoto.execute(username, tmpFile);
// Delete the temp file
FileUtils.deleteQuietly(tmpFile);
return ResponseEntity.status(HttpStatus.CREATED).build();
}
我的集成测试使用了改造:
@Multipart
@POST("users/{username}/profilePhoto")
Call<Void> uploadProfilePhoto(@Path("username") String username,
@Part("file") RequestBody profilePhoto);
...
@Test
public void saveProfilePhoto_shouldSavePhoto() throws IOException {
// Given
String usernamme = usernames[0];
Resource testImageResource = context.getResource("classpath:images/test_image.jpg");
File imageFile = testImageResource.getFile();
RequestBody body = RequestBody.create(okhttp3.MediaType.parse("image/*"), imageFile);
// When
Response<Void> response = getTestApi().uploadProfilePhoto(usernamme, body).execute();
// Then
assertThat(response.code()).isEqualTo(201);
}
我正在使用自动配置,所以我唯一的自定义配置类配置Stormpath:
@Configuration
public class SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.apply(stormpath());
}
}
更新: 这是传出请求。我不确定如何在多部分解析器本身中启用日志记录。
2016-08-18 14:44:14.714 DEBUG 13088 --- [ main] c.t.server.web.testutil.TestConfig$1 : --> POST http://localhost:8080/users/user1/profilePhoto http/1.1
2016-08-18 14:44:14.714 DEBUG 13088 --- [ main] c.t.server.web.testutil.TestConfig$1 : Content-Type: multipart/form-data; boundary=fe23ef21-3413-404c-a260-791c6921b2c6
2016-08-18 14:44:14.715 DEBUG 13088 --- [ main] c.t.server.web.testutil.TestConfig$1 : Content-Length: 181212
2016-08-18 14:44:14.715 DEBUG 13088 --- [ main] c.t.server.web.testutil.TestConfig$1 : Accept: application/json
2016-08-18 14:44:14.715 DEBUG 13088 --- [ main] c.t.server.web.testutil.TestConfig$1 : Authorization: Bearer [token]
2016-08-18 14:44:14.715 DEBUG 13088 --- [ main] c.t.server.web.testutil.TestConfig$1 :
2016-08-18 14:44:14.735 DEBUG 13088 --- [ main] c.t.server.web.testutil.TestConfig$1 : --fe23ef21-3413-404c-a260-791c6921b2c6
Content-Disposition: form-data; name="file"
Content-Transfer-Encoding: binary
Content-Type: image/*
Content-Length: 180999
file data
--fe23ef21-3413-404c-a260-791c6921b2c6--
2016-08-18 14:44:14.762 DEBUG 13088 --- [ main] c.t.server.web.testutil.TestConfig$1 : --> END POST (181212-byte body)
有关正在发生的事情的任何想法?
答案 0 :(得分:3)
默认情况下,您必须启用Spring Multipart Resolver Spring不启用多部分功能。
默认情况下,Spring没有多部分处理,因为有些开发人员 想要自己处理多部分。您启用Spring multipart 通过向Web应用程序添加多部分解析程序来处理 上下文。
对于您的配置类,您需要添加以下bean:
@Bean
public MultipartResolver multipartResolver() {
return new CommonsMultipartResolver();
}
*更新* 由于我之前的回答根据评论不正确。这是一个我能够成功运行的更新示例。
@SpringBootApplication
public class StackoverflowWebmvcSandboxApplication {
public static void main(String[] args) {
SpringApplication.run(StackoverflowWebmvcSandboxApplication.class, args);
}
@Controller
public class UploadPhoto {
@PostMapping("{username}/profilePhoto")
public ResponseEntity<String> saveProfilePhoto(@PathVariable("username") String username,
@RequestPart(name = "file", required = false) MultipartFile imageFile, HttpServletRequest request) {
String body = "MultipartFile";
if (imageFile == null) {
body = "Null MultipartFile";
}
return ResponseEntity.status(HttpStatus.CREATED).body(body);
}
}
}
这是一个非常基本的测试,没有特殊的东西。然后我创建了一个邮递员请求,这是示例curl调用:
curl -X POST -H "Cache-Control: no-cache" -H "Postman-Token: 17e5e6ac-3762-7d45-bc99-8cfcb6dc8cb5" -H "Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW" -F "file=@" "http://localhost:8080/test/profilePhoto"
响应为MultipartFile
,意味着它不为空,并且在该行上进行调试显示该变量已填充了我上传的图像。
答案 1 :(得分:1)
我发现问题是我使用Retrofit构建请求的方式。
Spring的多部分解析器要求文件的文件名出现在部件的content-disposition字段中。如果没有这个,它就不会将文件添加到多部分请求中。
根据此处的信息:https://futurestud.io/blog/retrofit-2-how-to-upload-files-to-server,我的API界面应为:
@Multipart
@POST("users/{username}/profilePhoto")
Call<Void> uploadProfilePhoto(@Path("username") String username,
@Part MultipartBody.Part profilePhoto);
然后在我的测试中打电话时:
// Given
String usernamme = usernames[0];
Resource testImageResource = context.getResource("classpath:images/test_image.jpg");
File imageFile = testImageResource.getFile();
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), imageFile);
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", imageFile.getName(), requestFile);
// When
Response<Void> response = testApi.uploadProfilePhoto(usernamme, filePart).execute();
答案 2 :(得分:0)
您必须启用Spring Multipart Resolver,因为默认情况下,Spring不会启用多部分功能。
默认情况下,Spring没有多部分处理,因为有些开发人员 想要自己处理多部分。您启用Spring multipart 通过向Web应用程序添加多部分解析程序来处理 上下文。
对于您的配置类,您需要添加以下bean:
@Bean
public MultipartResolver multipartResolver() {
return new StandardServletMultipartResolver();
}
由于Spring boot 1.4+使用servlet 3.0+,我们可以利用StandardServletMultipartResolver
代替经典CommonsMultipartResolver
答案 3 :(得分:0)
请参阅此网址中的答案: Spring Boot multipart upload getting null file object
基本上你必须避免使用multipart的默认Spring配置,并避免在请求标题中设置Content-type或boundary。
答案 4 :(得分:0)
检查application.properties中是否存在以下行:
spring.http.multipart.enabled = true