web-dev-qa-db-ja.com

Spring Boot multipartfileは常にnull

Spring Boot Stormpath 1.0.2でSpring Bootバージョン= '1.4.0.RC1'を使用しています。

マルチパートファイルのアップロードを使用しようとしていますが、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)を使用すると、パートは常にnullになります。

ただし、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)
_

何が起こっているかについてのアイデアはありますか?

10
JabariP

問題は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
JabariP

Spring Multipart Resolver を有効にする必要があります。デフォルトでは、Springはマルチパート機能を有効にしていません。

一部の開発者はマルチパート自体を処理したいため、デフォルトでは、Springはマルチパート処理を行いません。マルチパートリゾルバーをWebアプリケーションのコンテキストに追加して、Springマルチパート処理を有効にします。

構成クラスに、次の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でした。これはnullではなく、その行でデバッグを実行すると、アップロードした画像が変数に入力されたことを示しています。

3
Shawn Clark

Spring Multipart Resolver を有効にする必要があります。デフォルトでは、Springはマルチパート機能を有効にしていません。

一部の開発者はマルチパート自体を処理したいため、デフォルトでは、Springはマルチパート処理を行いません。マルチパートリゾルバーをWebアプリケーションのコンテキストに追加して、Springマルチパート処理を有効にします。

構成クラスに、次のBeanを追加します。

@Bean
public MultipartResolver multipartResolver() {
    return new StandardServletMultipartResolver();
}

Spring Boot 1.4以降ではサーブレット3.0以降を使用しているため、従来のStandardServletMultipartResolverではなくCommonsMultipartResolverを利用できます。

1
rajadilipkolli

次の行がapplication.propertiesに存在するかどうかを確認します。

spring.http.multipart.enabled = true
0
Nazrul Kabir

このURLで私の回答を参照してください: Spring Boot multipart upload getting null file object

基本的に、マルチパートのデフォルトのSpring構成を回避し、リクエストヘッダーでContent-typeまたは境界を設定しないようにする必要があります。

0
Alexis Gamarra