javaweb 文件上传(fileupload) 下载

来源:互联网 发布:truelicense源码包 编辑:程序博客网 时间:2024/06/15 04:27

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的设置即可。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 被骗给人冲q币了怎么办 支付宝账户异常无法领取红包怎么办 微信q币支付错了怎么办 王者荣耀不小心把点卷用了怎么办 微信绑定的qq号密码忘记了怎么办 微信红包实名认证没银行卡怎么办 手机烂了换新手机微信支付宝怎么办 支付宝转账给别人号码没用了怎么办 微信转账验证码收不到怎么办 陌生网友生日叫我发红包怎么办 微信群的群主不小心推出群该怎么办 支付宝验证码被别人知道了怎么办 微信解除银行卡绑定零钱清零怎么办 qq号被盗了理财通的钱怎么办 工行转错账号的钱被冻结怎么办 微信20w限额满了怎么办 通过qq号申请微信被盗了怎么办 微信号被盗手机绑定被改怎么办 腾讯视频激活码兑换达到限制怎么办 虚拟服务购买自动每月扣q币怎么办 微信被骗充值Q币怎么办 微信给别人充q币怎么办 k歌别人送的k币怎么办 忘记了qq号码但记得密码怎么办 q自己的活干完了该怎么办 在应用宝下载的游戏搜不到了怎么办 衣服有图片在淘宝找不到同款怎么办 淘宝卖家小儿说质量不合格怎么办 订单显示显示已签收没收到货怎么办 网上买过的东西查不到订单号怎么办 亚航的组合机票飞机延误怎么办 在微信上面对面红包被骗了钱怎么办 人欠我钱不给我怎么办 微信号被骗走然后骗了朋友钱怎么办 微信手机充值不到帐怎么办 中银香港密码器坏了怎么办 香港恒生银行的编码器丢了怎么办 淘宝拍下订单发货物流不显示怎么办 wish查到仿品审核变慢怎么办 淘宝卖家订单号错误无法修改怎么办 顺丰快递运单号微信扫描取消怎么办