Khi triển khai chức năng tải tệp lên bằng Java, gặp phải vấn đề backend không thể nhận được dữ liệu tệp. Cụ thể như sau:
Phương thức xử lý tệp trong Controller được viết như sau:
/**
* Tải tệp lên
* @since 2018-05-22
* @return
*/
@ApiOperation(value="Tải tệp", notes = "Giao diện tải tệp")
@RequestMapping(value = "/tai-len", consumes = "multipart/form-data;charset=utf-8", produces = "text/plain;charset=utf-8", method = RequestMethod.POST)
public @ResponseBody ResponseEntity<String> taiLen(HttpServletRequest request) {
byte[] duLieuTep = null;
String hashTep = "";
HashMap<String, String> ketQua = new HashMap<>();
if (request instanceof MultipartHttpServletRequest) {
MultipartHttpServletRequest yeuCau = (MultipartHttpServletRequest) request;
List<MultipartFile> danhSachTep = yeuCau.getFiles("tep");
if(danhSachTep.size() > 0) {
for (MultipartFile tep : danhSachTep) {
/***/
}
ketQua.put("maTrangThai", "0000");
ketQua.put("thongBao", null);
ketQua.put("hashTep", hashTep);
}else{
ketQua.put("maTrangThai", "THAT_BAI");
ketQua.put("thongBao", "Không có tệp");
ketQua.put("hashTep", hashTep);
}
}
return ResponseEntity.ok(JSONUtils.toJSONString(ketQua));
}
Thử nghiệm bằng Postman thành công nhưng khi gọi từ chương trình khác thì danh sách tệp luôn trống:
List<MultipartFile> danhSachTep = yeuCau.getFiles("tep");
Kiểm tra nhiều cách như thay đổi Content-Type, thay đổi kiểu tham số thành MultipartFile... nhưng vẫn không nhận được tệp. Cuối cùng phát hiện vấn đề nằm ở tham số truyền vào phương thức getFiles() không khớp với tên trường tệp phía client.
Ví dụ frontend sử dụng HTML/JS:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Tải tệp</title>
<script type="text/javascript" src="tai_len.js"></script>
<script type="text/javascript" src="jquery-1.8.2.min.js"></script>
</head>
<body>
<form enctype = "multipart/form-data;charset=utf-8" name="form_tai_len" action="" method="POST">
<input type ="file" name="tep" id="tep"/><br/>
Ghi chú:<input type="text" name="du_lieu" id="du_lieu"/><br/>
<input type="button" value="Xác nhận" onclick="taiLen()"/><br/>
</form>
</body>
</html>
Và đoạn JS:
function taiLen() {
duLieu = document.getElementById("tep").files[0];
duLieuForm = new FormData();
duLieuForm.append("tep", duLieu);
$.ajax({
url:"http://xxx/file/tai-len",
type:"POST",
data:duLieuForm,
dataType:"text",
processData: false,
contentType: false,
success: function(ketQua){
alert(ketQua);
}
});
}
Tên trường "tep" trong frontend phải khớp với tham số truyền vào getFiles() ở backend, nếu không sẽ không nhận được tệp.
Lưu ý thêm về cấu hình giới hạn kích thước tệp trong Spring Boot. Mặc định là 1MB, vượt quá sẽ báo lỗi:
org.apache.tomcat.util.http.fileupload.FileUploadBase$FileSizeLimitExceededException: Trường tep vượt quá giới hạn 1048576 bytes
Để sửa, thêm cấu hình sau vào class Application:
/**
* Cấu hình tải tệp
* @return
*/
@Bean
public MultipartConfigElement cauHinhTep() {
MultipartConfigFactory factory = new MultipartConfigFactory();
// Giới hạn kích thước tệp
factory.setMaxFileSize("10240KB");
// Giới hạn tổng kích thước yêu cầu
factory.setMaxRequestSize("102400KB");
return factory.createMultipartConfig();
}
Các giá trị in đậm là kích thước mong muốn.