Java:使用 REST 服务下载 CSV 文件

标签 java spring rest csv spring-mvc

我正在尝试从 REST 端点下载 csv 文件。这就是我正在尝试的。

@ApiOperation(value = "export",
        notes = "Export Cache details for a given criteria")
@ApiImplicitParams({

})
@ApiResponses(value = {
        @ApiResponse(code = 400, message = "Bad Request"),
        @ApiResponse(code = 404, message = "Not Found"),
        @ApiResponse(code = 500, message = "Internal Server Error") })
@RequestMapping(method = RequestMethod.GET, value = "/export")
public ResponseEntity export( HttpServletRequest request )
{
    CacheDataManager cacheResultHandler = new CacheDataManager();
    InputStreamResource inputStreamResource = null;
    HttpHeaders httpHeaders = new HttpHeaders();
    long contentLengthOfStream;

    try
    {
        inputStreamResource = cacheResultHandler.exportCacheResults( request );
        httpHeaders.set( HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + "test.csv" );

        contentLengthOfStream = inputStreamResource.contentLength();
        httpHeaders.setContentLength( contentLengthOfStream );
    }
    catch ( IOException e )
    {
        e.printStackTrace();
    }

    return new ResponseEntity( inputStreamResource, httpHeaders, HttpStatus.OK );

}

我的导出功能。

@Override
public InputStreamResource export( HttpServletRequest request )
{
    StringBuilder sb = new StringBuilder();
    StringBuilder fileName = new StringBuilder( VALIDATION_REPORT );

    sb.append( "Column A" );
    sb.append( "," );
    sb.append( "Column B" );
    sb.append( "\n" );

    try
    {

            sb.append( "TEST A");
            sb.append( ',' );
            sb.append( "TEST B" );
            sb.append( '\n' );



        fileName.append( "_" ).append( sdf.format( new Date() ) ).append( ".csv" );
        return CsvFileWriter.csvFileWrite( fileName.toString(), sb );

    }
    catch ( Exception e )
    {
        e.printStackTrace();

    }

    return null;
}

CsvFileWriter.java

package it.app.ext.dashboard.util;

import org.springframework.core.io.InputStreamResource;

import java.io.*;

public class CsvFileWriter
{

public static InputStreamResource csvFileWrite( String fileName, StringBuilder content ) throws FileNotFoundException
{
    File file = null;
    PrintWriter pw = null;
    try
    {
        file = new File( fileName );
        pw = new PrintWriter( file );
        pw.write( content.toString() );
    }
    catch ( FileNotFoundException e )
    {
        e.printStackTrace();
    }
    finally
    {
        pw.flush();
        pw.close();
    }

    InputStream inputStream = new FileInputStream( file );

    return new InputStreamResource( inputStream );
}

}

正在使用 tomcat/bin 文件夹中的内容生成文件,但发生异常。

java.lang.IllegalStateException: InputStream has already been read - do not use InputStreamResource if a stream needs to be read multiple times.

我想在调用此端点后下载 .csv 文件。

如有任何建议,我们将不胜感激。

谢谢你

最佳答案

说明:

您首先获得了 inputStream:

contentLengthOfStream =inputStreamResource.contentLength();

然后Spring的returnValueHandlers又得到了inputStream:

新的 ResponseEntity( inputStreamResource, httpHeaders, HttpStatus.OK ).

但是被inputStreamResource包裹的inputStream只能使用一次:

/**
 * This implementation throws IllegalStateException if attempting to
 * read the underlying stream multiple times.
 */
public InputStream getInputStream() throws IOException, IllegalStateException {
    if (this.read) {
        throw new IllegalStateException("InputStream has already been read - " +
                "do not use InputStreamResource if a stream needs to be read multiple times");
    }
    this.read = true;
    return this.inputStream;
}

解决方案:您可以从inputStream中获取字节并返回带有字节的ResponseEntity。

@ApiOperation(value = "export",
        notes = "Export Cache details for a given criteria")
@ApiImplicitParams({

})
@ApiResponses(value = {
        @ApiResponse(code = 400, message = "Bad Request"),
        @ApiResponse(code = 404, message = "Not Found"),
        @ApiResponse(code = 500, message = "Internal Server Error") })
@RequestMapping(method = RequestMethod.GET, value = "/export")
public ResponseEntity export( HttpServletRequest request )
{
    CacheDataManager cacheResultHandler = new CacheDataManager();
    InputStreamResource inputStreamResource = null;
    InputStream inputStream = null;
    byte[] byteArray = new byte[0];
    HttpHeaders httpHeaders = new HttpHeaders();

    try
    {
        inputStreamResource = cacheResultHandler.exportCacheResults( request );
        httpHeaders.set( HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + "test.csv" );

        //convert inputStream to bytes
        inputStream = inputStreamResource.getInputStream();
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        int nRead;
        byte[] data = new byte[1024];
        while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
            buffer.write(data, 0, nRead);
        }

        buffer.flush();
        byteArray = buffer.toByteArray();

        httpHeaders.setContentLength(byteArray.length);
    }
    catch ( IOException e )
    {
        e.printStackTrace();
    }

    return new ResponseEntity( byteArray, httpHeaders, HttpStatus.OK );

}

建议:使用 Apache Commons IO将InputStream转换为字节。需要添加lib依赖,这可以使您的代码变得简洁

byte[] byteArray = IOUtils.toByteArray(inputStream);

关于Java:使用 REST 服务下载 CSV 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44536141/

相关文章:

java - "The requested resource does not support http method ' GET '"- 但我 'm not using C# or asp.net, I' 是发出请求的人

java - 这是我使用 DynamoDBMapper.BatchGetItemException 的方法 getUnprocessedKeys() 获取未处理键列表的方式吗?

java - 帮助制定为期 2 周的 Spring 和 OSGi 学习计划

rest - REST 架构中的分页

json - 将 MarkLogic EVAL REST 服务输出作为 JSON 返回

java - 将散列电子邮件上传到服务器

java - 如何使用 AES_DECRYPT 更新 jtable

java - 如何从文本文件中获取值

java - 鉴于参数名称在编译过程中丢失,Spring如何通过参数名称 Autowiring ?

java - 将变量的值设置为 application.properties 文件中的一个属性