簡體   English   中英

Java 8 - 讀取和存儲在 REST 服務中收到的文件的最佳方式

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

我想要一個應用程序,用戶可以在其中上傳前端(Angular)的 csv 文件。 我想要一個休息服務來讀取它,然后將文件作為 BLOB 存儲到 Oracle 數據庫中。

對於 REST 服務,我將收到一個 MultipartFile 對象:

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

對於實體,它將是這樣的:

@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;
    
    // ...
}

我看到我有 getInputStream() 和 getBytes() 方法。

逐行讀取 CSV 文件進行處理然后在處理成功且沒有錯誤的情況下存儲它的最佳和優化方法是什么?

為了逐行處理 csv 文件,您可以使用以下庫中的任何一個:

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

或者

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

假設您的 csv 行代表某個 DTO 對象YourDtoClass 使用這些庫的示例(確保根據您的需要進行自定義):

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;
    // ...
}

如果您需要將 csv 文件持久化到數據庫中,則可以將 InputStream 轉換為字節數組並將其持久化到數據庫中

實際上, InputStream不能被處理兩次,但有一些解決方法,其中之一 - 將InputStream存儲到一個臨時文件中,之后,您可以多次從臨時文件中讀取數據。

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

在對臨時文件進行操作后,請確保將其刪除。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM