HTTP上传文件并动态提供上传进度做法(后台JAVA)

当用户点击一个上传按钮时,前台会实时的显示后台处理动态。

由于servlet一次只能接受一个请求,而且在servlet的生命周期结束时才会把响应数据发送到前台。所以对于前端来说,至少需要两个API才能实现这一功能。一个API用来实现上传文件,另一个API实时获取上传的进度。

那么后台的做法:当用户点击了处理按钮时,在后台开启一个线程进行处理,并且每进行到一步,就向单例中写入当前状态信息。然后编写一个servlet,用于返回单例中的信息,前台循环发送请求,这样就能实现实时显示进度的效果。

简单说,可以将这个功能分为三个点:

  1. 进度对象(单例模式):用于保存进度信息;
  2. 上传servlet:用于上传文件并实时写入进度;
  3. 进度servlet:用于读取实时进度信息;

直接上后台代码,下面是进度类,采用单例模式:

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);
    }

}

最后上传一个前端代码来测试:

<!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>

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,针对您的问题,我可以给你提供以下Java代码示例,用于FTP上传大文件并打印上传进度信息: ``` import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; public class FTPUploader { private FTPClient ftpClient; public FTPUploader(String host, String user, String password) throws IOException { ftpClient = new FTPClient(); ftpClient.connect(host); ftpClient.enterLocalPassiveMode(); ftpClient.login(user, password); ftpClient.setFileType(FTP.BINARY_FILE_TYPE); } public void uploadFile(String localFilePath, String remoteFilePath) throws IOException { File localFile = new File(localFilePath); BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(localFile)); ftpClient.storeFile(remoteFilePath, inputStream); inputStream.close(); } public void uploadFileWithProgress(String localFilePath, String remoteFilePath) throws IOException { File localFile = new File(localFilePath); BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(localFile)); long fileSize = localFile.length(); long uploadedSize = 0; byte[] buffer = new byte[4096]; int bytesRead = -1; while ((bytesRead = inputStream.read(buffer)) != -1) { ftpClient.appendFile(remoteFilePath, new BufferedInputStream(new ByteArrayInputStream(buffer, 0, bytesRead))); uploadedSize += bytesRead; System.out.println("Uploaded " + uploadedSize + " bytes out of " + fileSize); } inputStream.close(); } public void disconnect() throws IOException { if (ftpClient.isConnected()) { ftpClient.logout(); ftpClient.disconnect(); } } } ``` 以上代码使用了 Apache Commons Net 库提供的 FTPClient 类,实现了 FTP 上传文件的功能。其中,uploadFile 方法用于上传小文件,而 uploadFileWithProgress 方法用于上传大文件并打印上传进度信息。 注意:在使用该代码时,需要将以下代码中的 `host`、`user` 和 `password` 替换为您的 FTP 服务器相关的信息。 ``` FTPUploader uploader = new FTPUploader("host", "user", "password"); uploader.uploadFileWithProgress("local_file_path", "remote_file_path"); uploader.disconnect(); ``` 希望这个代码示例可以帮助到您。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值