Upload file sử dụng Ajax Jquery và Apache Commons FileUpload

Chào mừng các bạn đã quay trở lại với thachleblog, như đã đề cập ở bài trước, sau khi đọc được file excel, mình cần tìm cách upload file lên server (server deploy app). Do đó, bài viết hôm nay mình sẽ giới thiệu với các bạn cách upload file sử dụng Apache Commons FileUpload. Qua bài viết này, các bạn sẽ hiểu được cách gửi một request có đính kèm 1 (hoặc nhiều) file lên server, đồng thời xử lý ghi file xuống server. Nào, chúng ta cùng bắt đầu nhé.

Để upload file lên server, việc đầu tiên ta cần sử dụng thẻ input file trong html để đính kèm file từ máy local vào request, tiếp theo là gửi request lên server.

<!DOCTYPE html>
<html lang="en">
  <head>
	<meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
    <meta name="description" content="">
    <meta name="author" content="">
 
    <title>Dashboard Template for Bootstrap</title>
    <!-- Bootstrap core CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  </head>
  <body>
   <div class="container-fluid" >   	  
      <div class="row" style="margin-top: 50px;">      
        <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">     
          <h2 class="sub-header">Import file</h2>
		  <form id="code" method="post" enctype="multipart/form-data" class="form-horizontal">
			<div class="input-group">
				<input id="file-upload" type="file" name="file-upload">
			</div>
		  </form><br>
		  <button type="button" id="btn-import" class="btn btn-default">Upload</button>		  
              </tbody>
            </table>
          </div>
        </div>
      </div>
    </div>
  </body>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
  <script type="text/javascript">  
	$(document).ready(function() {
		$("#btn-import").click(function() {
			var file = $('#file-upload').get()[0].files[0];
			var fileUpload = $('#file-upload').val();
			if(!file){
				alert("Vui lòng chọn file");
				return;
			}
			if (fileUpload && (fileUpload.indexOf('xlsx') === -1)) {
				alert("Vui lòng chọn file excel");
				return;
			}
 
			$.ajax({
				url: '/fileupload/ajax',
				type: 'POST',
				data: new FormData($('#code')[0]),
				processData: false,
				contentType: false
			}).done(function () {
				alert("Upload thành công");
			});
		});
	});	
  </script>
</html>
 
 
Code html demo cách sử dụng input file và gửi request  sử dụng Ajax Jquery

Lưu ý: ở đây mình sử dụng Ajax để gửi đến server request có đính kèm file excel sử dụng FormData, các bạn có thể tìm hiểu thêm về FormData tại đây. Chi tiết các bạn có thể đọc code ở trên (đính kèm 1 file).

Tiếp theo, ở phần server, chúng ta sẽ sử dụng Apache Commons FileUpload để xử lý request và lưu file xuống server

Các bạn có thể sử dụng maven hoặc download Apache Commons FileUpload tại đây. Lưu ý, để sử dụng Apache Commons FileUpload, cần tải thêm dependencies của nó là Apache Commons IO.

Implement:

package thach.le.fileupload;
 
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.eclipse.jetty.http.HttpStatus;
 
/**
 *
 * @author thachlp
 */
public class UploadFileController extends HttpServlet {
 
	private static final long serialVersionUID = 1L;
	private static final String UPLOAD_DIRECTORY = "/home/thachlp/Documents/";
 
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		resp.setStatus(HttpStatus.OK_200);
		// Check that we have a file upload request
		boolean isMultipart = ServletFileUpload.isMultipartContent(req);
 
		if (isMultipart) {
			// Create a factory for disk-based file items
			FileItemFactory factory = new DiskFileItemFactory();
			// Create a new file upload handler
			ServletFileUpload upload = new ServletFileUpload(factory);
			try {
				List<FileItem> fileItems = upload.parseRequest(req);
				String pathFile = "";
                                // loop for multi file
				for (FileItem item : fileItems) {
					if (!item.isFormField()) {
						pathFile = UPLOAD_DIRECTORY + File.separator + item.getName();
						item.write(new File(pathFile));
					}
				}
 
			} catch (Exception e) {
			}
		}
 
	}
}

Code demo cách xử lý request có đính kèm file và ghi file sử dụng Apache Commons FileUpload

Các bạn cần sửa lại đường dẫn thư mục cần lưu trữ file cho phù hợp.

Kết quả:

Upload file sử dụng Ajax Jquery và Apache Commons FileUpload

Link tải source code: https://github.com/thachlp/FileUpload
Tham khảo thêm: https://commons.apache.org/proper/commons-fileupload/using.html

Chia sẻ kinh nghiệm: sử dụng ajaxComplete()

Chào mừng các bạn đã quay trở lại với thachleblog, ở bài trước, mình đã demo cách load dữ liệu bằng cách call ajax. Bài viết hôm nay, mình sẽ giới thiệu với các bạn một tính năng khác của ajax đó là ajaxComplete(). Nhìn cái tên ajaxComplete() thôi các bạn cũng đoán được method này giải quyết vấn đề gì rồi phải không?

Đúng rồi đó, nhưng để hiểu hơn method này được dùng trong trường hợp nào. Các bạn hãy xem tình huống của mình nhé.

ajaxComplete()

Mình biết đến method này vào một ngày đẹp trời. Khi ánh nắng ban mai rọi qua khung cửa sổ, ngoài cành cây, bầy chim non hót véo von… :))). Mình develop một chức năng tương tự như ở ví dụ bài trước, cho phép user click vào button “tải thêm” thì data sẽ trả về. Sau khi nhận data trả về thì mình cần gọi method update để update chiều cao của panel chứa data. Đơn giản là cái bảng chứa dữ liệu cần tự động cập nhật theo lượng dữ liệu.

Đoạn code đó đại loại sẽ giống như này:

  1. $(".btnLoadMore").click(function() {
  2. loadMoreData(); get data from server
  3. update(); // update heigh panel
  4. });

Logic code rất easy, method update() cần chạy sau khi method loadMoreData() đã chạy xong. Mình code xong, deploy luôn. Kết quả, thật bất ngờ, data được lấy về nhưng cái panel chứa lại không update? Debug vào thì thấy cả 2 method đều chạy.

Fu*k, đơn giản vậy mà cũng không chạy, muốn chửi thề ghê. Ngồi xem lại code của method update(), rõ ràng là không có vấn đề gì. Thế mà tại sao code không chạy? Thế mà ngồi nghĩ vẩn vơ, debug cả tiếng đồng hồ…

Một ý nghĩ “exellent” chợt lóe lên. Có khi nào method loadMoreData() chưa chạy xong mà update() đã chạy không? Ngồi thử trên console của chrome và kết quả đúng là như dự đoán. Chỉ cần gọi method update() ngay sau khi method loadMoreData() hoàn thành thì kết quả như mong muốn.

Đã tìm ra nguyên nhân thì vấn đề đã được giải quyết hơn một nửa. Ngồi google 5 – 10′ là có cách giải quyết. JQuery trigger ajaxComplete() khi ajax request hoàn thành. Và kết quả là ta chỉ việc thêm vào đoạn code ở trên như sau:

  1. $(".btnLoadMore").click(function() {
  2. loadMoreData();
  3. $( document ).ajaxComplete(function( event,request, settings ) {
  4. update();
  5. });
  6. });

 

Kết quả cuối cùng, chạy ngon. Các bạn có thể xem thêm docs về ajaxComplete() tại đây.

Ngoài cách sử dụng ajaxComplete, ta cũng có thể update method ajax ở bài trước như sau:

  1. $.ajax({
  2. url: ,
  3. type: 'POST',
  4. data: params,
  5. async: true
  6. }).done(function (resp) {
  7. if (resp.err < 0) {
  8.  
  9. } else {
  10.  
  11. }
  12.  
  13. });

Ở trường hợp này, sử dụng ajaxcomplete hoặc ajax done đều sẽ cho kết quả tương tự.

Kết

Qua tình huống của mình, các bạn có thể thấy. Mấu chốt để giải quyết vấn đề thường là tìm ra nguyên nhân gây ra vấn đề. Chuyện còn lại thường rất đơn giản. Mình cũng đã từng gặp vấn đề tương tự, mất gần cả ngày debug để tìm ra đoạn code gây lỗi. Và cũng chỉ mất vài phút để sửa…

Hy vọng bài viết vừa rồi của mình sẽ giúp các bạn không chuyên về frontend biết thêm về một tính năng của JQuery ajax. Nếu bạn có kinh nghiệm gì hay, hãy chia sẻ vào comment bên dưới nhé, để chúng ta cùng rút kinh nghiệm.

Cảm ơn và hẹn gặp lại các bạn ở các bài viết sau.

Chúc tất cả cuối tuần vui vẻ.