从 React 和 Spring Boot 上传 CSV 文件
Posted
技术标签:
【中文标题】从 React 和 Spring Boot 上传 CSV 文件【英文标题】:Upload CSV file from React and Spring Boot 【发布时间】:2021-03-01 12:10:33 【问题描述】:也许有人知道如何解决上传文件到后端的问题。 Send file from Postman looks like 但是从 React 上传后,我有这样的异常:
2020-11-09 18:17:38.829 DEBUG 10764 --- [nio-8081-exec-7] osweb.servlet.DispatcherServlet:POST“/api/employees/save-from-csv”,参数= masked 2020-11-09 18:17:38.829 调试 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 中的参数 [0] .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 调试 10764 --- [nio-8081-exec-7] .mmaExceptionHandlerExceptionResolver:使用 @ExceptionHandler com.bank.exceptions.FileUploadExceptionAdvice#handleException(Exception, WebRequest) 2020-11-09 18:17:38.832 调试 10764--- [nio-8081-exec-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
此代码用于从 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>
)
服务
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);
控制器
@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
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());
单元测试
@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);
【问题讨论】:
请发布您的端点代码,以便我们知道那里发生了什么 嗨,阿米尔!我已经编辑了代码 所以,据我测试,您的后端代码可以正常工作,我会尝试找出您的反应代码中的错误在哪里 【参考方案1】:好吧,这花了我一些时间,虽然这是你犯的一个很小的错误。
在您的反应代码中,您设置文件数组,在您的FormData
中作为file
传递。
这里正确的做法是只设置数组的一个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))
;
【讨论】:
以上是关于从 React 和 Spring Boot 上传 CSV 文件的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot 控制器 - 将 Multipart 和 JSON 上传到 DTO
从数据库H2错误spring boot thymeleaf上传和显示图像
Spring Boot 中的 CORS 与 Spring Security + React
使用 jQuery $.ajax 和 Spring Boot 上传图片的进度条