JavaWeb項目實現文件上傳動態顯示進度


 很久沒有更新博客了,這段時間實在的忙的不可開交,項目馬上就要上線了,要修補的東西太多了。當我在學習JavaWeb文件上傳的時候,我就一直有一個疑問,網站上那些博客的圖片是怎么上傳的,因為當提交了表單之后網頁就跳轉了。后來我學習到了Ajax,我知道了瀏覽器可以異步的發送響應,這時我又有新的疑問,那就是在我上傳一些文件的時候,那些網站的上傳進度是怎么做到的,因為servlet直到上傳完成之后才完成響應。

  最近我們的項目中有一個地方中需要用到一個功能,當用戶點擊一個處理按鈕時,前台會實時的顯示后台處理動態,由於servlet一次只能接受一個請求,而且在servlet的生命周期結束時才會把響應數據發送到前台(這一點大家可以做個這樣的測試:

1 response.getWriter().print("hello");
2 Thread.sleep(10000);
3 response.getWriter().print("world");

,你們會發現前台在等待了約10s后收到了"helloworld")。所以我想到了一個方法:使用單例保存實時信息。具體的實現方法就是,當用戶點擊了處理按鈕時,在后台開啟一個線程進行處理,並且每進行到一步,就向單例中寫入當前狀態信息。然后編寫一個servlet,用於返回單例中的信息,前台循環發送請求,這樣就能實現實時顯示進度的效果。

  好了,啰嗦了這么多,下面進入正題,如何實現上傳文件動態顯示進度,其實思想和上面的功能是一致的,我將這個功能分為三個點:

  1. 單例:用於保存進度信息;
  2. 上傳servlet:用於上傳文件並實時寫入進度;
  3. 進度servlet:用於讀取實時進度信息;

  上代碼,前台:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style type="text/css">
    #progress:after {
        content: '%';
    }
</style>
</head>
<body>
    <h3>File upload demo</h3>
    <form action="TestServlet" method="post" enctype="multipart/form-data" id="dataForm">
        <input type="file" name="file" id="fileInput"> <br>
        <input type="submit" value="submit" id="submit">
    </form>
    <div id="progress"></div>
    <script type="text/javascript" src="scripts/jquery-1.9.1.min.js"></script>
    <script type="text/javascript">
    (function () {
        var form = document.getElementById("dataForm");
        var progress = document.getElementById("progress");
        
        $("#submit").click(function(event) {
            //阻止默認事件
            event.preventDefault();
            //循環查看狀態
            var t = setInterval(function(){
                $.ajax({
                    url: 'ProgressServlet',
                    type: 'POST',
                    dataType: 'text',
                    data: {
                        filename: fileInput.files[0].name,
                    },
                    success: function (responseText) {
                        var data = JSON.parse(responseText);
                        //前台更新進度
                        progress.innerText = parseInt((data.progress / data.size) * 100);
                    },
                    error: function(){
                        console.log("error");
                    }
                });
            }, 500);
            //上傳文件
            $.ajax({
                url: 'UploadServlet',
                type: 'POST',
                dataType: 'text',
                data: new FormData(form),
                processData: false,
                contentType: false,
                success: function (responseText) {
                    //上傳完成,清除循環事件
                    clearInterval(t);
                    //將進度更新至100%
                    progress.innerText = 100;
                },
                error: function(){
                    console.log("error");
                }
            });
            return false;
        });
    })();
    </script>
</body>
</html>

后台,單例:

import java.util.Hashtable;

public class ProgressSingleton {
    //為了防止多用戶並發,使用線程安全的Hashtable
    private static Hashtable<Object, Object> table = new Hashtable<>();
    
    public static void put(Object key, Object value){
        table.put(key, value);
    }
    
    public static Object get(Object key){
        return table.get(key);
    }
    
    public static Object remove(Object key){
        return table.remove(key);
    }
}

上傳servlet:

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.tomcat.util.http.fileupload.FileItem;
import org.apache.tomcat.util.http.fileupload.FileUploadException;
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
import org.apache.tomcat.util.http.fileupload.servlet.ServletRequestContext;

import singleton.ProgressSingleton;

@WebServlet("/UploadServlet")
public class UploadServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public UploadServlet() {
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        
        DiskFileItemFactory factory = new DiskFileItemFactory();
        factory.setSizeThreshold(4*1024);
        
        ServletFileUpload upload = new ServletFileUpload(factory);
        
        List<FileItem> fileItems;
        try {
            fileItems = upload.parseRequest(new ServletRequestContext(request));
            //獲取文件域
            FileItem fileItem = fileItems.get(0);
            //使用sessionid + 文件名生成文件號
            String id = request.getSession().getId() + fileItem.getName();
            //向單例哈希表寫入文件長度和初始進度
            ProgressSingleton.put(id + "Size", fileItem.getSize());
            //文件進度長度
            long progress = 0;
            //用流的方式讀取文件,以便可以實時的獲取進度
            InputStream in = fileItem.getInputStream();
            File file = new File("D:/test");
            file.createNewFile();
            FileOutputStream out = new FileOutputStream(file);
            byte[] buffer = new byte[1024];
            int readNumber = 0;
            while((readNumber = in.read(buffer)) != -1){
                //每讀取一次,更新一次進度大小
                progress = progress + readNumber;
                //向單例哈希表寫入進度
                ProgressSingleton.put(id + "Progress", progress);
                out.write(buffer);
            }
            //當文件上傳完成之后,從單例中移除此次上傳的狀態信息
            ProgressSingleton.remove(id + "Size");
            ProgressSingleton.remove(id + "Progress");
            in.close();
            out.close();
        } catch (FileUploadException e) {
            e.printStackTrace();
        }
        
        response.getWriter().print("done");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

進度servlet:

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONObject;
import singleton.ProgressSingleton;

@WebServlet("/ProgressServlet")
public class ProgressServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    public ProgressServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        
        String id = request.getSession().getId();
        String filename = request.getParameter("filename");
        //使用sessionid + 文件名生成文件號,與上傳的文件保持一致
        id = id + filename;
        Object size = ProgressSingleton.get(id + "Size");
        size = size == null ? 100 : size;
        Object progress = ProgressSingleton.get(id + "Progress");
        progress = progress == null ? 0 : progress; 
        JSONObject json = new JSONObject();
        json.put("size", size);
        json.put("progress", progress);
        response.getWriter().print(json.toString());
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

 效果圖:

 

現在人工智能非常火爆,很多朋友都想學,但是一般的教程都是為博碩生准備的,太難看懂了。最近發現了一個非常適合小白入門的教程,不僅通俗易懂而且還很風趣幽默。所以忍不住分享一下給大家

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM