简体   繁体   English

从 React 和 Spring Boot 上传 CSV 文件

[英]Upload CSV file from React and Spring Boot

Maybe anybody knows how to solve the problem of uploading files to the back-end.也许有人知道如何解决上传文件到后端的问题。 Send file from Postman looks like But after upload from React, I have exception like this:从 Postman 发送文件看起来像但是从 React 上传后,我有这样的异常:

2020-11-09 18:17:38.829 DEBUG 10764 --- [nio-8081-exec-7] osweb.servlet.DispatcherServlet : POST "/api/employees/save-from-csv", parameters={masked} 2020-11-09 18:17:38.829 DEBUG 10764 --- [nio-8081-exec-7] swsmmaRequestMappingHandlerMapping : Mapped to com.bank.controller.EmployeeController#uploadFile(MultipartFile, Model) 2020-11-09 18:17:38.831 DEBUG 10764 --- [nio-8081-exec-7] .wsmmaServletInvocableHandlerMethod : Could not resolve parameter [0] in public org.springframework.http.ResponseEntity<com.bank.message.ResponseMessage> com.bank.controller.EmployeeController.uploadFile(org.springframework.web.multipart.MultipartFile,org.springframework.ui.Model) throws java.io.IOException: Required request part 'file' is not present 2020-11-09 18:17:38.831 DEBUG 10764 --- [nio-8081-exec-7] .mmaExceptionHandlerExceptionResolver : Using @ExceptionHandler com.bank.exceptions.FileUploadExceptionAdvice#handleException(Exception, WebRequest) 2020-11-09 18:17:38.832 DEBUG 10764 --- [nio-8081-exec- 2020-11-09 18:17:38.829 DEBUG 10764 --- [nio-8081-exec-7] osweb.servlet.DispatcherServlet : POST "/api/employees/save-from-csv", parameters={masked} 2020 -11-09 18:17:38.829 DEBUG 10764 --- [nio-8081-exec-7] swsmmaRequestMappingHandlerMapping:映射到 com.bank.controller.EmployeeController#uploadFile(MultipartFile, Model) 2020-11-09 18:17: 38.831 调试 10764 --- [nio-8081-exec-7] .wsmmaServletInvocableHandlerMethod:无法解析公共 org.springframework.http.ResponseEntity<com.bank.message.ResponseMessage> com.bank.controller.EmployeeController 中的参数 [0] .uploadFile(org.springframework.web.multipart.MultipartFile,org.springframework.ui.Model) 抛出 java.io.IOException:所需的请求部分“文件”不存在 2020-11-09 18:17:38.831 DEBUG 10764 - -- [nio-8081-exec-7] .mmaExceptionHandlerExceptionResolver :使用@ExceptionHandler com.bank.exceptions.FileUploadExceptionAdvice#handleException(Exception, WebRequest) 2020-11-09 18:17:38.832 DEBUG 10764 --- [nio-8081 -执行- 7] oswsmmaHttpEntityMethodProcessor : No match for [application/json, text/plain, /], supported: [] 2020-11-09 18:17:38.833 WARN 10764 --- [nio-8081-exec-7] .mmaExceptionHandlerExceptionResolver : Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present] 2020-11-09 18:17:38.837 DEBUG 10764 --- [nio-8081-exec-7] osweb.servlet.DispatcherServlet : Completed 400 BAD_REQUEST 7] oswsmmaHttpEntityMethodProcessor : [application/json, text/plain, /] 不匹配, 支持: [] 2020-11-09 18:17:38.833 WARN 10764 --- [nio-8081-exec-7] .mmaExceptionHandlerExceptionResolver :已解决 [org.springframework.web.multipart.support.MissingServletRequestPartException:所需的请求部分“文件”不存在] 2020-11-09 18:17:38.837 DEBUG 10764 --- [nio-8081-exec-7] osweb。 servlet.DispatcherServlet : 已完成 400 BAD_REQUEST

This code for sending a file from React form :此代码用于从 React 表单发送文件:

class UploadFiles extends Component{

state = {
    file : ''
};

componentDidMount = () => {
    const {file} = this.props;
    this.setState({ file })
};

uploadFile = ({target : {files}}) => {
    console.log(files[0]);
    let data = new FormData();
    data.append('file', files);


    axios.post("/api/employees/save-from-csv", data)
        .then(res => {console.log(res)})
};

render(){
    return(
        <div className="container">
            <div className="row">
                <div className="col-md-6">
                    <div className="form-group files color">
                        <label>Upload Your File </label>
                        <input type="file" onChange={this.uploadFile}/>
                    </div>
                </div>
            </div>
        </div>
    )
}}

Service服务

public void csvToEmployees(@RequestParam("file") MultipartFile file, Model model) {
    // validate file
    if (file.isEmpty()) {
        model.addAttribute("message", "Please select a CSV file to upload.");
        model.addAttribute("status", false);
    } else {

        try (Reader reader = new BufferedReader(new InputStreamReader(file.getInputStream()))) {

            CsvToBean csvToBean = new CsvToBeanBuilder(reader)
                    .withType(Employee.class)
                    .withIgnoreLeadingWhiteSpace(true)
                    .build();

            List users = csvToBean.parse();
            employeeRepository.saveAll(users);

            model.addAttribute("users", users);
            model.addAttribute("status", true);

        } catch (Exception ex) {
            model.addAttribute("message", "An error occurred while processing the CSV file.");
            model.addAttribute("status", false);
        }
    }

}

Controller控制器

 @PostMapping("/employees/save-from-csv")
public ResponseEntity<ResponseMessage> uploadFile(@RequestParam("file") MultipartFile file, Model model) throws IOException {
    ResponseEntity<ResponseMessage> result = null;
    boolean finished = false;
    String message = "";

    if (CSVHelper.hasCSVFormat(file)) {
        try {
            service.csvToEmployees(file, model);
            message = "Uploaded the file successfully: " + file.getOriginalFilename();
            result = ResponseEntity.status(HttpStatus.OK).body(new ResponseMessage(message));
            finished = true;
        } catch (Exception e) {
            message = "Could not upload the file: " + file.getOriginalFilename() + "!";
            message += e;
            result = ResponseEntity.status(HttpStatus.UNPROCESSABLE_ENTITY).body(new ResponseMessage(message));
            finished = true;
        }
    }
    if (!CSVHelper.hasCSVFormat(file)){

        message = "File is empty!";
        result = ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ResponseMessage(message));
    }
    if (!finished) {
        message = "Please upload a csv file!";
        result = ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseMessage(message));
    }
    return result;
}

CSVHelper CSVHelper

public class CSVHelper {

    public static boolean hasCSVFormat(MultipartFile file) {

        String TYPE = "text/csv";
        return TYPE.equals(file.getContentType());
    }

    public static List<Employee> csvToEmployees(InputStream is) {
        try (BufferedReader fileReader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
             CSVParser csvParser = new CSVParser(fileReader,
                     CSVFormat.DEFAULT.withFirstRecordAsHeader().withIgnoreHeaderCase().withTrim());) {

            List<Employee> employees = new ArrayList<>();

            Iterable<CSVRecord> csvRecords = csvParser.getRecords();

            for (CSVRecord csvRecord : csvRecords) {
                Employee employee = new Employee(
                        Long.parseLong(csvRecord.get("Id")),
                        csvRecord.get("Name"),
                        Long.parseLong(csvRecord.get("DepartmentId")),
                        Double.parseDouble(csvRecord.get("Salary")),
                        csvRecord.get("City"),
                        csvRecord.get("Street"),
                        csvRecord.get("BankName"),
                        csvRecord.get("CardNumber")
                );

                employees.add(employee);
            }

            return employees;
        } catch (IOException e) {
            throw new RuntimeException("fail to parse CSV file: " + e.getMessage());
        }
    }

}

UnitTest单元测试

@Test
    public void saveEmployeesFromCSV() throws Exception {
        String url = "/api/employees/save-from-csv";


        String csvBuilder = "name,departmentId,salary,city,street,bankName,cardNumber\n" +
                "Maxim,1,3855,Madrid,Street,Bank York,NY98675432100\n";
        InputStream is = new ByteArrayInputStream(csvBuilder.getBytes());

        MockMultipartFile mockFile = new MockMultipartFile("file", "employees.csv", "text/csv", is);

        MockHttpServletResponse responseMessage = mvc.perform(MockMvcRequestBuilders.multipart(url)
                .file(mockFile)
                .param("file", "employees2.csv"))
                .andReturn()
                .getResponse();
        assertEquals(responseMessage.getStatus(), 200);
    }

Ok so This took me some time, although it's a very small mistake you made.好的,这花了我一些时间,虽然这是你犯的一个很小的错误。

In your react code, you set the array of files, that is passed as file in your FormData .在您的反应代码中,您设置了文件数组,该数组在您的FormData作为file传递。

The correct thing to do here is to only set one File of the array as content for the FormData :这里正确的做法是只将数组的一个 File 设置为FormData内容:

uploadFile = ({target : {files}}) => {
    console.log(files[0]);
    let data = new FormData();
    data.append('file', files[0]); <- this here is where the error was


    axios.post("/api/employees/save-from-csv", data)
        .then(res => {console.log(res)})
};

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

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