1

こんにちは、以下のようなコントローラークラスを作成しました。mongo db からファイルを取得してダウンロードしようとしています。

    organizationFileAttachmentService.setUser(getUser());
    GridFSDBFile file = organizationFileAttachmentService.getGridFSDBFileById(new ObjectId(id), "File");
    if (file != null) {
        byte[] content = organizationFileAttachmentService.findByIdAndBucket(new ObjectId(id), "File");
        try {
            int size = content.length;
            InputStream is = null;
            byte[] b = new byte[size];
            try {
                is = new ByteArrayInputStream(content);
                is.read(b);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (is != null)
                        is.close();
                } catch (Exception ex) {

                }
            }
            response.setContentType(file.getContentType());
            // String attachment =
            // "attachment; filename=\""+file.getFilename()+"\"";
            String attachment = "attachment; filename=" + file.getFilename();
            // response.setContentLength(new
            // Long(file.getLength()).intValue());
            response.setCharacterEncoding(file.getMD5());
            response.setHeader("content-Disposition", attachment);// "attachment;filename=test.xls"
            // copy it to response's OutputStream
            // FileCopyUtils.copy(is, response.getOutputStream());
            IOUtils.copy(is, response.getOutputStream());
            response.flushBuffer();
            is.close();
        } catch (IOException ex) {
            _logger.info("Error writing file to output stream. Filename was '" + id + "'");
            throw new RuntimeException("IOError writing file to output stream");
        }

しかし、ロードファイルをダウンロードできません。誰でも私を助けることができます。

4

2 に答える 2

4

見逃した方のために説明すると、Spring にはさまざまな組み込みのリソース ハンドラが用意されています。

http://docs.spring.io/spring/docs/3.2.5.RELEASE/spring-framework-reference/html/resources.html#resources-implementations

メソッドがそれらのいずれかを返す場合 (おそらく、あなたの場合は ByteArrayResource )、次のようにインターフェイスにいくつかの注釈が必要です。

@RequestMapping(value = "/foo/bar/{fileId}", 
    method = RequestMethod.GET, 
    produces = { MediaType.APPLICATION_OCTET_STREAM_VALUE })
@ResponseBody FileSystemResource downloadFile(Long fileId);

そうすれば、エンコーディングとヘッダーをいじる必要はありません。自分で巻く前に試してみることをお勧めします。

編集:上記はSpring 3.1.4でうまくいきました。3.2.x または 4.x では機能しなくなりました。以前は、produces = { MediaType.APPLICATION_OCTET_STREAM_VALUE } により Spring が適切なヘッダーを追加していましたが、現在はそれを制限として扱います。標準の Web ブラウザで URL にアクセスした場合、「application/octet-stream」の Accept ヘッダーは送信されません。したがって、Spring は 406 エラーを返します。再び機能させるには、そのようなメソッドを「produces」属性なしで書き直す必要があります。代わりに、メソッドの引数に HttpServletResponse を追加し、メソッド内にヘッダーを追加します。すなわち:

@RequestMapping(value = "/foo/bar/{fileId}", 
    method = RequestMethod.GET)
@ResponseBody FileSystemResource downloadFile(
            Long fileId, HttpServletResponse response) {
    ...
    response.setHeader( "Content-Disposition", "attachment;filename=" + fileName );
    ...
}

redux の編集: Spring Boot 1.1.8 経由で Spring 4.0.7 を使用するようになりました。produces = { MediaType.APPLICATION_OCTET_STREAM_VALUE }命令の設定が再び機能するようになりました。私が試したすべてのブラウザでは、その指示だけで十分なようです。ただし、 が設定されておらず、 のままになっていることもわかっていることに注意してContent-Dispositionくださいapplication/json。これはブラウザの問題ではないようですが、私は PHP クライアント アプリケーションでバグに遭遇しましたContent-Disposition。したがって、現在の解決策は上記の両方を行うことです。

于 2013-11-09T17:51:58.520 に答える
1

リクエストを GET に変更し、html のアンカー タグにリクエストを追加しました。Asloは私のコードを次のように変更しました

@RequestMapping(value = "/getFileById/{id}", method = RequestMethod.GET)
public @ResponseBody
void download(@PathVariable String id, HttpServletRequest request, HttpServletResponse response) throws IOException {
    organizationFileAttachmentService.setUser(getUser());
    GridFSDBFile file = organizationFileAttachmentService.getGridFSDBFileById(new ObjectId(id), "File");
    if (file != null) {
        try {
            response.setContentType(file.getContentType());
            response.setContentLength((new Long(file.getLength()).intValue()));
            response.setHeader("content-Disposition", "attachment; filename=" + file.getFilename());// "attachment;filename=test.xls"
            // copy it to response's OutputStream
            IOUtils.copyLarge(file.getInputStream(), response.getOutputStream());
        } catch (IOException ex) {
            _logger.info("Error writing file to output stream. Filename was '" + id + "'");
            throw new RuntimeException("IOError writing file to output stream");
        }
    }
}

今では私にとってはうまくいっています。

于 2013-11-14T14:41:06.767 に答える