24

大きな画像をRESTコントローラーにアップロード/ストリーミングしようとしています。RESTコントローラーはファイルを取得してデータベースに保存します。

@Controller
@RequestMapping("/api/member/picture")
public class MemberPictureResourceController {

  @RequestMapping(value = "", method = RequestMethod.POST)
  @ResponseStatus(HttpStatus.NO_CONTENT)
  public void addMemberPictureResource(@RequestBody InputStream image) {
    // Process and Store image in database
  }
}

これは、私が達成しようとしていることの機能しない例です(もちろん、または、InputStreamが機能していないと思います)。@RequestBodyを介して画像をストリーミング/読み取りたい。

私はどこでも検索しましたが、これを達成するための良い例を見つけることができません。ほとんどの人は、フォームを介して画像をアップロードする方法だけを尋ねているようですが、REST/RestTemplateを使用してアップロードすることはありません。これを手伝ってくれる人はいますか?

正しい方向へのヒントに感謝します。

よろしく、クリス

ソリューション

ここの下に、DirkとGigadotからの入力の後に私のために働いた解決策を投稿しようとしています。現時点では、両方のソリューションを検討する価値があると思います。最初はDirkの助けを借りて実用的な例を投稿し、次にGigadotの助けを借りて実例を作成しようとします。@RequestBodyを介してファイルをアップロードする方法を明示的に尋ねてきたので、Dirksの回答を正しいものとしてマークします。しかし、Gigadotのソリューションをテストすることにも興味があります。おそらく、より簡単で一般的に使用できるからです。

以下の例では、ファイルをMongoDBGridFSに保存します。

解決策1-Dirks推奨後の例

コントローラー(コメントでテストするためのcurlコマンドを使用):

/**
*
* @author charms
* curl -v -H "Content-Type:image/jpeg" -X PUT --data-binary @star.jpg http://localhost:8080/api/cardprovider/logo/12345
*/
@Controller
@RequestMapping("/api/cardprovider/logo/{cardprovider_id}")
public class CardproviderLogoResourceController {

  @Resource(name = "cardproviderLogoService")
  private CardproviderLogoService cardproviderLogoService;

  @RequestMapping(value = "", method = RequestMethod.PUT)
  @ResponseStatus(HttpStatus.NO_CONTENT)
  public void addCardproviderLogo(@PathVariable("cardprovider_id") String cardprovider_id,
      HttpEntity<byte[]> requestEntity) {
    byte[] payload = requestEntity.getBody();
    InputStream logo = new ByteArrayInputStream(payload);
    HttpHeaders headers = requestEntity.getHeaders();

    BasicDBObject metadata = new BasicDBObject();
    metadata.put("cardproviderId", cardprovider_id);
    metadata.put("contentType", headers.getContentType().toString());
    metadata.put("dirShortcut", "cardproviderLogo");
    metadata.put("filePath", "/resources/images/cardproviders/logos/"); 

    cardproviderLogoService.create1(logo, metadata);
  }
}

サービス(未完成ですがテストとして機能しています):

@Service
public class CardproviderLogoService {

  @Autowired
  GridFsOperations gridOperation;

  public Boolean create1(InputStream content, BasicDBObject metadata) {
    Boolean save_state = false;
    try {
      gridOperation.store(content, "demo.jpg", metadata);
      save_state = true;
    } catch (Exception ex) {
      Logger.getLogger(CardproviderLogoService.class.getName())
          .log(Level.SEVERE, "Storage of Logo failed!", ex);
    }
    return save_state;    
  }
}

解決策2-ギガドット推奨後の例

これについては、Springのマニュアルで説明されています: http ://static.springsource.org/spring/docs/3.2.1.RELEASE/spring-framework-reference/html/mvc.html#mvc-multipart

これは非常に簡単で、デフォルトですべての情報が含まれています。少なくともバイナリアップロードについては、このソリューションを採用すると思います。

投稿してくれてありがとう。大変感謝しております。

4

4 に答える 4

13

Springを使用しているように見えるので、HttpEntity(http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/http/HttpEntity.html)を使用できます。

それを使用すると、次のようなものが得られます(「ペイロード」を見てください)。

@Controller
public class ImageServerEndpoint extends AbstractEndpoint {

@Autowired private ImageMetadataFactory metaDataFactory;
@Autowired private FileService fileService;

@RequestMapping(value="/product/{spn}/image", method=RequestMethod.PUT) 
public ModelAndView handleImageUpload(
        @PathVariable("spn") String spn,
        HttpEntity<byte[]> requestEntity, 
        HttpServletResponse response) throws IOException {
    byte[] payload = requestEntity.getBody();
    HttpHeaders headers = requestEntity.getHeaders();

    try {
        ProductImageMetadata metaData = metaDataFactory.newSpnInstance(spn, headers);
        fileService.store(metaData, payload);
        response.setStatus(HttpStatus.NO_CONTENT.value());
        return null;
    } catch (IOException ex) {
        return internalServerError(response);
    } catch (IllegalArgumentException ex) {
        return badRequest(response, "Content-Type missing or unknown.");
    }
}

ここでは、RESTfullの「製品に画像を配置する」ためにPUTを使用しています。'spn'は製品番号であり、imagenameはfileService.store()によって作成されます。もちろん、画像をPOSTして画像リソースを作成することもできます。

于 2013-01-31T15:33:31.920 に答える
6

POSTリクエストを送信する場合、フォーム/パラメータ/ファイルをサーバーに送信するために使用できるエンコーディングには、との2種類がありapplication/x-www-form-urlencodedますmultipart/form-data。詳細については、こちらをご覧ください

application/x-www-form-urlencodedPOSTリクエストに大きなコンテンツがある場合は、通常Webブラウザがクラッシュするため(私の経​​験から)、使用することはお勧めできません。したがって、 multipart/form-dataをお勧めします。

multipart/form-dataマルチパートリゾルバーをディスパッチャーに追加すると、Springはコンテンツを自動的に処理できます。これを処理するためのSpringの実装は、apache-commons-fileuploadを使用して行われるため、このライブラリをプロジェクトに追加する必要があります。

実際にそれを行う方法の主な答えについては、すでにここにブログがありますhttp://viralpatel.net/blogs/spring-mvc-multiple-file-upload-example/

それが解決策を見つけるのに役立つことを願っています。RESTとは何かについて読みたいと思うかもしれません。少し混乱しているようですね。基本的に、URLが醜い場合でも、ほとんどすべてのhttpリクエストはRESTfulです。

于 2013-02-02T02:55:33.313 に答える
4

私は最近これを行いました。詳細はこちらをご覧ください。

ブラウザでは、ファイルAPIを使用してファイルを読み込み、Base64エンコーディングを使用してそのコンテンツをエンコードし、最後にエンコードされたコンテンツをjavascriptオブジェクトに割り当ててから投稿できます。

サーバーには、リクエストを処理するSpringControllerがあります。リクエスト本文をJavaオブジェクトに変換するjsonunmarshallingの一部として、画像バイトのbase64でエンコードされた値が標準のJava byte []に​​変換され、データベースにLOBとして格納されます。

画像を取得するために、別のSpring Controllerメソッドは、バイトを直接ストリーミングすることによって画像を提供できます。

上記のリンク先のブログ投稿では、画像を別のオブジェクトの一部として使用することを想定していますが、画像を直接操作する場合でも、原則は同じです。何か説明が必要な場合はお知らせください。

于 2013-01-31T02:37:57.177 に答える
0

リクエスト本文をInputStreamとして処理する場合は、リクエストから直接取得できます。

@Controller
@RequestMapping("/api/member/picture")
public class MemberPictureResourceController {

    @RequestMapping(value = "", method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void addMemberPictureResource(HttpServletRequest request) {
        try {
            InputStream is = request.getInputStream();
            // Process and Store image in database
        } catch (IOException e) {
            // handle exception
        }
    }
}
于 2020-07-08T23:01:35.443 に答える