美文网首页javaWeb学习JavaJavaweb
javaweb 文件上传(fileupload) 下载

javaweb 文件上传(fileupload) 下载

作者: lvlvforever | 来源:发表于2016-10-20 20:04 被阅读144次

    1 文件上传

    html中通过<input type="file"/>可以向服务器上传文件。不过后台需要手动解析请求,比较复杂,所以可以使用smartupload或apache的fileupload组件进行文件的上传。smartupload据网友测试,在上传大文件时不稳定,所以还是使用fileupload的吧,毕竟apache出品。

    本例子中使用的jar包:

    1. commons-fileupload-1.3.2.jar
    2. commons-io-2.5.jar(fileupload依赖)

    前端jsp页面:

        <div class="upload">
            <form action="UploadFileServlet" method="POST" enctype="multipart/form-data">
                上传文件:<input type="file" name="uploadFile">
            <input type="submit" value="upload">上传
            <input type="reset" value="reset">重置
            </form>
            
        </div>
    

    其中有几个需要注意的点:

    1. form表单的enctype必须为"multipart/form-data"。
    2. <input type="file" name="uploadFile"/> 中必须有name属性,因为在fileupload中会根据fieldName解析上传的文件。
    3. method必须为POST方法。
    4. 如果多文件上传的话,file类型的name必须为不同的名称。

    服务端需要建立一个UploadFileServlet来处理请求。
    关键的doPost方法:

    protected void doPost(HttpServletRequest request,
                HttpServletResponse response) throws ServletException, IOException {
            // TODO Auto-generated method stub
    
            // 首先检测是否是文件上传,主要依据enctype的值来判定
            if (!ServletFileUpload.isMultipartContent(request)) {
                PrintWriter writer = response.getWriter();
                writer.write("Error 不是文件上传,表单必须包含 enctype='multipart/form-data'");
                writer.flush();
                writer.close();
                return;
            }
    
            DiskFileItemFactory factory = new DiskFileItemFactory();
            // 设置在内存中的缓存大小,如果超过了则保存到临时文件。
            factory.setSizeThreshold(MEMORY_THRESHOLD);
            System.err.println(System.getProperty("java.io.tmpdir"));
            // 设置临时文件夹的目录
            factory.setRepository(new File(System.getProperty("java.io.tmpdir")));
            ServletFileUpload upload = new ServletFileUpload(factory);
            // 设置单个文件大小的最大值
            upload.setFileSizeMax(MAX_FILE_SIZE);
            // 设置上传文件总量的最大值,包括所有文件和表单的总和
            upload.setSizeMax(MAX_REQUEST_SIZE);
            File uploadDir = new File(UPLOAD_PATH);
            if (!uploadDir.exists()) {
                uploadDir.mkdir();
            }
            try {
                // 解析request
                List<FileItem> formItems = upload.parseRequest(request);
                if (formItems != null && formItems.size() > 0) {
                    for (FileItem item : formItems) {
                        // 如果不是普通的formField则就是上传的文件
                        if (!item.isFormField()) {
                            String fileName = item.getName();
                            File storeFile = new File(UPLOAD_PATH + File.separator
                                    + fileName);
                            System.err.println(storeFile.getAbsolutePath());
                            item.write(storeFile);
                            item.delete();
    
                        } else {
                            System.err.println(item.getString());
                        }
                    }
                }
                request.setAttribute("message", "成功");
                request.getRequestDispatcher("result.jsp").forward(request,
                        response);
    
            } catch (Exception e) {
                // TODO: handle exception
                request.setAttribute("message", e.getMessage());
                request.getRequestDispatcher("result.jsp").forward(request,
                        response);
                e.printStackTrace();
                return;
            }
        }
    
    

    这样即可实现文件的上传。

    需要改进的地方
    1. 没有上传进度
    2. 限制文件大小
    3. 限制文件类型

    对于第2点,可以利用fileupload的抛出异常解决。

    catch(FileUploadBase.FileSizeLimitExceededException e){
                request.setAttribute("message", "单个文件大小超过限制");
                request.getRequestDispatcher("result.jsp").forward(request,
                        response);
                e.printStackTrace();
                return;
            
            } catch(FileUploadBase.SizeLimitExceededException e){
                request.setAttribute("message", "上传文件总大小超过限制");
                request.getRequestDispatcher("result.jsp").forward(request,
                        response);
                e.printStackTrace();
                return;
            
            }
    

    对于第3点,可以在页面用js进行校验。

    
        <form action="UploadFileServlet" method="POST"
            enctype="multipart/form-data" onsubmit="return check_file()">
            上传文件:<input type="file" name="uploadFile" id="uploadFile"> <input
                type="submit" value="upload">上传 <input type="reset"
                value="reset">重置
    
        </form>
        <script>
            function check_file() {
                var fileName = document.getElementById("uploadFile").value;
                var suffix = fileName.substr(fileName.lastIndexOf(".") + 1);
                if (suffix !== "exe") {
                    alert("只能上传exe文件");
                    return false;
                }
    
            }
        </script>
    

    对于第1点,fileupload可以添加监听器,监听上传进度。

    //设置上传进度的监听器
            ProgressListener progressListener = new ProgressListener() {
                public void update(long pBytesRead, long pContentLength, int pItems) {
                    System.out.println("We are currently reading item " + pItems);
    
                    if (pContentLength == -1) {
                        System.out.println("So far, " + pBytesRead
                                + " bytes have been read.");
    
                    } else {
                        System.out.println("So far, " + pBytesRead + " of "
                                + pContentLength + " bytes have been read.");
                        uploadPercent = (double) pBytesRead / pContentLength;
                        System.err.println(uploadPercent);
    
                    }
    
                }
            };
            upload.setProgressListener(progressListener);
    

    虽然服务端添加了监听器,可以在console或者Log里打印上传进度,但我们想要的是让用户看到上传进度。所以需要把进度返回给用户。
    要解决的问题主要有两个:

    1. 进度信息如何保存
    2. 前台如何获取
      其中的一种方案是利用session。我们将上传进度保存在session里,前台通过ajax方法定时获取上传的进度,因为每个用户是一个session,不同的用户session不同。这样当不同的用户同时上传文件时,依然可以正确的获得上传进
      度,不会获取到其他用户上传文件的进度。
      具体首先有一个简单的保存上传进度的实体类:
    public class UploadStatus {
        private double percent;
    
        public double getPercent() {
            return percent;
        }
    
        public void setPercent(double percent) {
            this.percent = percent;
        }
    }
    

    然后有一个监听的类,实现了ProgressListener接口

    public class UploadListener implements ProgressListener{
        private UploadStatus status;
        public  UploadListener(UploadStatus status) {
            
            // TODO Auto-generated constructor stub
            this.status = status;
        }
        @Override
        public void update(long pBytesRead, long pContentLength, int pItems) {
            
            // TODO Auto-generated method stub
            double uploadPercent = (double) pBytesRead / pContentLength;
            status.setPercent(uploadPercent);
        }
    
    }
    

    在doPost方法中:

    //设置上传进度的监听器
            UploadStatus status = new UploadStatus();
            UploadListener listener = new UploadListener(status);
            upload.setProgressListener(listener);
            request.getSession(true).setAttribute("uploadStatus", status);
    

    最后在doGet方法中,返回上传进度。

    protected void doGet(HttpServletRequest request,
                HttpServletResponse response) throws ServletException, IOException {
            // TODO Auto-generated method stub
            response.setContentType("text/html");
            response.setCharacterEncoding("UTF-8");
            response.setHeader("Cache-Control", "no-store");
            response.setDateHeader("Expires", 0);
            response.setHeader("Pragrma", "no-cache");
            PrintWriter writer = response.getWriter();
            UploadStatus status = (UploadStatus)(request.getSession().getAttribute("uploadStatus"));
            if(status != null){
                writer.write("上传进度:" + status.getPercent());
            }else{
                writer.write("没有上传信息");
            }
            writer.flush();
            writer.close();
        }
    
    

    当用户上传时可以访问doGet方法即可获取进度。
    前台页面可以这样写:
    其中form的target属性可以防止页面跳转。

    <body>
    <iframe width=0 height=0 name="uploadFrame"></iframe>
        <form action="UploadFileServlet" method="POST"
            enctype="multipart/form-data" target="uploadFrame" onsubmit="getStatus()">
            上传文件:<input type="file" name="uploadFile" id="uploadFile"> <input
                type="submit" value="upload">上传 <input type="reset"
                value="reset">重置
    
        </form>
        <span>上传进度:</span><span id="progress"></span>
        <script src="jquery-1.11.2.js"></script>
        <script>
        var finished ;
            function check_file() {
                var fileName = document.getElementById("uploadFile").value;
                var suffix = fileName.substr(fileName.lastIndexOf(".") + 1);
                if (suffix !== "exe") {
                    //alert("只能上传exe文件");
                    //return false;
                }
                finished = false;
                return true;
    
            }
            function getStatus(){
                finished = false;
                console.log("finished = " + finished)
    
                showStatus();
            }
            
            function showStatus(){
                console.log("showstatus finished = " + finished)
    
                if(finished === true) return;
                $.ajax({
                    url:'UploadFileServlet',
                    type:'GET',
                    success:function(data){
                        $('#progress').text(data);
                        if(data == '1.0'){
                            finished = true;
                        }
                            
                    },
                    error:function(data){
                        alert(data);
                    }
                
                });
                setTimeout(showStatus,1000);
            }
            
        </script>
    </body>
    

    最后 完整的程序UploadFile.zip

    2 文件下载

    文件下载相对比较简单

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // TODO Auto-generated method stub
            String id = request.getParameter("id");
            //app.properties 路径
            DFileItem dao = new DFileItem();
            String basePath = request.getSession().getServletContext().getRealPath("");
            String configPath = basePath+Constants.CONFIG_PATH;
            String uploadPath = Configuration.getInstance(configPath).getProperty(Constants.FILE_STORAGE_PATH);
            FileItem item = dao.queryFileItem(id);
            if(item == null){
                PrintWriter writer = response.getWriter();
    
                writer.write("文件已经被删除");
                writer.close();
                return;
            }
            
            String name = item.getFileName();
            response.setContentType("application/octet-stream");
            String downloadName = URLEncoder.encode(name,"UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-Disposition", "attachment;filename*=utf-8'zh_cn'"+downloadName);
            File file = new File(uploadPath+item.getUploadTime());
            response.setContentLength((int)file.length());
            FileInputStream in = new FileInputStream(file);
            OutputStream out = response.getOutputStream();
            byte[] buffer = new byte[8192];
            int len = 0;
            while((len = in.read(buffer)) != -1){
                out.write(buffer, 0, len);
            }
            out.flush();
            out.close();
            in.close();
        }
    

    注意response 的contentType和header的设置即可。
    最终一个完整的文件上传下载的例子FileServer

    相关文章

      网友评论

        本文标题:javaweb 文件上传(fileupload) 下载

        本文链接:https://www.haomeiwen.com/subject/lugvyttx.html