简体   繁体   English

Java 8 - 读取和存储在 REST 服务中收到的文件的最佳方式

[英]Java 8 - Best way to read and store a file received in REST service

I want to have an application where user can upload a csv file in front-end (Angular).我想要一个应用程序,用户可以在其中上传前端(Angular)的 csv 文件。 I want a rest service to read it and then store the file as a BLOB into Oracle database.我想要一个休息服务来读取它,然后将文件作为 BLOB 存储到 Oracle 数据库中。

For the REST service, I will receive a MultipartFile object:对于 REST 服务,我将收到一个 MultipartFile 对象:

@PostMapping(value = "/upload")
public String processUploadFile(@RequestParam MultipartFile file) {
    // Call to a service 
}

For the entity, it will be something like this:对于实体,它将是这样的:

@Entity
@DynamicUpdate
@Table(name = "FILE_UPLOAD")
public class FileUploadEntity implements Serializable {

    @Id
    @Column(name = "ID")
    private Long id;

    @Column(name = "BLOB")
    @Lob
    private Blob blob;
    
    // ...
}

I saw that I have getInputStream() and getBytes() methods.我看到我有 getInputStream() 和 getBytes() 方法。

What is the best and optimized way to read the CSV file line by line to do a treatment and then to store it if the treatment is in success without error please?逐行读取 CSV 文件进行处理然后在处理成功且没有错误的情况下存储它的最佳和优化方法是什么?

In order to process csv file, line by line, you could use any out of the following libraries:为了逐行处理 csv 文件,您可以使用以下库中的任何一个:

<dependency>
    <groupId>com.opencsv</groupId>
    <artifactId>opencsv</artifactId>
</dependency>

or或者

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-csv</artifactId>
</dependency>

Let's imagine that your csv line represents some DTO object YourDtoClass .假设您的 csv 行代表某个 DTO 对象YourDtoClass Example with usage of those libraries (make sure to customize according to your needs):使用这些库的示例(确保根据您的需要进行自定义):

import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvParser;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
import com.opencsv.CSVParserBuilder;
import com.opencsv.ICSVParser;
...

@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public void processUploadFile(@RequestParam MultipartFile file) throws IOException {
    // option #1. using `opencsv` library
    ICSVParser parser = new CSVParserBuilder()
            .withQuoteChar(ICSVParser.DEFAULT_QUOTE_CHARACTER)
            .build();
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(file.getInputStream(), UTF_8));
    bufferedReader.lines()
            .forEach(line -> {
                // process line...
                log.info("line has been processed");
            });

    // option #2. using `jackson-dataformat-csv` library
    List<YourDtoClass> list = readCsv(YourDtoClass.class, file.getInputStream());
}

public <T> List<T> readCsv(Class<T> clazz, InputStream stream) throws IOException {
    CsvMapper mapper = new CsvMapper();
    CsvSchema schema = mapper.schemaFor(clazz)
            .withoutHeader()
            .withColumnSeparator(CsvSchema.DEFAULT_COLUMN_SEPARATOR)
            .withArrayElementSeparator(CsvSchema.DEFAULT_ARRAY_ELEMENT_SEPARATOR)
            .withNullValue(StringUtils.EMPTY)
            .withoutEscapeChar();
    return mapper
            .readerFor(clazz)
            .with(CsvParser.Feature.TRIM_SPACES)
            .with(CsvParser.Feature.SKIP_EMPTY_LINES)
            .with(schema)
            .<T>readValues(stream)
            .readAll();
}

// your csv line represents this DTO class
class YourDtoClass {
    private String name;
    private String surname;
    // ...
}

And if you need to persist csv file into database, you could convert InputStream into byte array and persist it to database .如果您需要将 csv 文件持久化到数据库中,则可以将 InputStream 转换为字节数组并将其持久化到数据库中

Actually, InputStream can't be processed twice, but there are some workarounds, and one of them - store InputStream into a temporary file, and after that, you could read data from temp file multiple times.实际上, InputStream不能被处理两次,但有一些解决方法,其中之一 - 将InputStream存储到一个临时文件中,之后,您可以多次从临时文件中读取数据。

File tempFile = File.createTempFile(prefix, suffix);
FileUtils.copyInputStreamToFile(inputStream, tempFile); // from `org.apache.commons.io`

and after operating on temp file, make sure that you remove it.在对临时文件进行操作后,请确保将其删除。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM