首页 > 学院 > 开发设计 > 正文

文件上传和下载

2019-11-15 01:12:25
字体:
来源:转载
供稿:网友
文件上传和下载1. 文件上传1.1 快速入门1.1.1提供上传页面,upload.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html>  <head>  </head>  <body>  <!--   1. 表单提交方式post  2. 表单的enctype="multipart/form-data"  1. 表单要上传文件输入项type="file"   -->  <form method="post" enctype="multipart/form-data" action="/upload/upload">      上传人: <input type="text" name="name"><br/>      请上传图片:<input type="file" name="file"><br>      <input type="submit" value="上传">  </form>  </body></html> 
1.1.2编写servlet处理提供的数据

fileupload组件工作流程

  • DiskFileItemFactory
  • 工厂得到servletFileupload解析器
  • servletFileupload关联 request
  • 解析器将form映射为FileItem
  • isFormField判断Item是普通字段还是文件.true表示是普通字段```import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;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.FileUploadException;import org.apache.commons.fileupload.disk.DiskFileItemFactory;import org.apache.commons.fileupload.servlet.ServletFileUpload;

/**

  • 完成文件上传 */public class UploadServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { / 由于form的enctype属性原因,以下代码获取不了上传数据: String * name=request.getParameter("name"); String * file=request.getParameter("file"); ServletInputStream in = * request.getInputStream(); */

    // apache提供了开源的commons-fileupload组件,只需要在工程中导入使用// 1.导入commons-fileupload-1.2.1.jar,commons-io-1.4.jar到lib// 2.拿到工厂DiskFileItemFactory factory = new DiskFileItemFactory();// 3.拿到解析器对象ServletFileUpload uploader = new ServletFileUpload(factory);// 4.关联到requestList<FileItem> list;try {    list = uploader.parseRequest(request);    for (FileItem fileItem : list) {        if (fileItem.isFormField()) {            // 普通的输入项            // 获得普通输入项字段的名称            String fieldName = fileItem.getFieldName();            // 获得普通输入项字段的名称对应的值            String fieldValue = fileItem.getString();        } else {            // 文件上传输入项            // 获得上传文件名字            String name = fileItem.getName();            // 获得上传文件输入流            InputStream in = fileItem.getInputStream();            OutputStream out = new FileOutputStream("D://" + name);            int len = 0;            byte[] buf = new byte[1024];            while ((len = in.read(buf)) != -1) {                out.write(buf, 0, len);            }            in.close();            out.close();        }    }} catch (Exception e) {    // TODO Auto-generated catch block    e.PRintStackTrace();}

    }

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

##### 1.2 文件上传若干需要注意的细节 1. 文件上传时普通的输入项中文的乱码问题java//这里使用UTF-8进行解码String fieldValue=fileItem.getString("UTF-8");2. 上传时中文文件名称乱码java//设置解析事,中文文件名解析的码表uploader.setHeaderEncoding("UTF-8");3. 上传的时候,表单必须设置三个值.判断文件上传的时候,提交的数据是否是文件上传的表单java//判断是否文件上传的表单if(!ServletFileUpload.isMultipartContent(request)){ //说明不是文件上传的表单,下面的代码不再执行 request.setAttribute("message", "对不起,您的表单不符合规范,请检查表单属性设置..."); request.getRequestDispatcher("/upload.jsp").forward(request, response); return;}4. 限定上传文件的大小.java//限定上传文件的大小uploader.setFileSizeMax(102410242);//以kb为单位,限制单个文件大小uploader.setSizeMax(1024102420);//限制总的文件大小20M当超过大小限制时,就会抛出异常.就可以捕获异常javacatch (FileUploadBase.FileSizeLimitExceededException e) { // 单个文件大小超过限制 request.setAttribute("message", "对不起,上传单个文件大小超过限制..."); request.getRequestDispatcher("/upload.jsp").forward(request, response); } catch (FileUploadBase.SizeLimitExceededException e) { // 总的文件大小超过限制 request.setAttribute("message", "对不起,总的文件大小超过限制..."); request.getRequestDispatcher("/upload.jsp").forward(request, response); }5. 限制上传的文件类型java//将允许的文件类型准备好String[] extensions={".jpg",".bmp",".png"};如果不合法javaboolean flag = false;for (String ex : extensions) { if (name.endsWith(ex)) { flag = true; break; }}if (!flag) { // 文件类型不合法,需要给用户友好信息 request.setAttribute("message", "对不起,文件类型不合法..."); request.getRequestDispatcher("/upload.jsp").forward( request, response); return;}6. 针对不同浏览器解决文件上传名称的问题javaString name = fileItem.getName();// 有些浏览器获得的name是E:/1.bmp// 这个索引是最后一个/所在索引位置int lastIndex = name.lastIndexOf("/");if (lastIndex != -1) { name = name.substring(lastIndex + 1);}7. 解决文件上传时,同名文件被覆盖问题.为了解决这个问题,生成文件名字要唯一,可以使用java提供的UUID的类.生成一个随机128值.java//生成不同名文件名,避免覆盖问题 name=UUID.randomUUID().toString().replace("-", "")+"_"+name;8. 上传的内容是恶意内容,网站被攻击 将上传文件放在一个特定文件夹下,不让外界直接访问.上传文件放在WEB-INF目录下保护起来.java//获得WEB-INF目录下upload文件夹的路径 String filePath=getServletContext().getRealPath("/WEB-INF/upload"); InputStream in = fileItem.getInputStream(); FileOutputStream out = new FileOutputStream(new File(filePath,UUIDName));

9. 避免上传文件夹文件过多,导致打开文件夹出现性能上问题,比如文件过多,打开较慢需要设计一套算法,保障上传文件分散放在多级目录

1.每隔一段时间创建一个文件夹,然后放上传的文件2.哈希算法,根据hash值二进制每隔4位的值创建一层目录.javaprivate String generatedRandomDir(String filePath, String uUIDName) { int hashCode = uUIDName.hashCode(); int dir1 = hashCode & 0xf;// 一级目录 int dir2 = (hashCode >> 4) & 0xf;// 二级目录 String path = filePath + File.separator + dir1 + File.separator + dir2; File file = new File(path); if (!file.exists()) { file.mkdirs(); } return path; }10. 上传时设置监听器监听上传进度javaProgressListener progressListener = new ProgressListener() { private long megaBytes = -1;

            public void update(long pBytesRead, long pContentLength,                    int pItems) {                long mBytes = pBytesRead / 1000000;                if (megaBytes == mBytes) {                    return;                }                megaBytes = mBytes;                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.");                }            }        };        // 设置监听器一定在解析之前设置        uploader.setProgressListener(progressListener);

11. 为了加快上传速度,可以设置临时缓冲区大小以及上传时临时文件存放位置.上传完成后,临时文件给删掉.java//设置临时缓存区大小factory.setSizeThreshold(102412042);//2M//设置上传时,临时文件的位置factory.setRepository(new File(getServletContext().getRealPath("/tmp")));java//删除临时文件,该方法放在流关闭之后fileItem.delete();

 实现代码

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

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.FileUploadBase;import org.apache.commons.fileupload.ProgressListener;import org.apache.commons.fileupload.disk.DiskFileItemFactory;import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class Upload2Servlet extends HttpServlet { /** * 文件上传,需要注意的问题 */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 将允许的文件类型准备好 String[] extensions = { ".jpg", ".bmp", ".png" };

    // 判断是否文件上传的表单    if (!ServletFileUpload.isMultipartContent(request)) {        // 说明不是文件上传的表单,下面的代码不再执行        request.setAttribute("message", "对不起,您的表单不符合规范,请检查表单属性设置...");        request.getRequestDispatcher("/upload.jsp").forward(request,                response);        return;    }    try {        DiskFileItemFactory factory = new DiskFileItemFactory();        //设置临时缓存区大小        factory.setSizeThreshold(1024*1204*2);//2M        //设置上传时,临时文件的位置        factory.setRepository(new File(getServletContext().getRealPath("/tmp")));        ServletFileUpload uploader = new ServletFileUpload(factory);        // 限定上传文件的大小        uploader.setFileSizeMax(1024 * 1024 * 2);// 以kb为单位,限制单个文件大小        uploader.setSizeMax(1024 * 1024 * 20);// 限制总的文件大小20M        // 设置解析事,中文文件名解析的码表        uploader.setHeaderEncoding("UTF-8");        // 设置监听器,监听上传进度        // 这里的update方法不定时被解析器调用到,        // pBytesRead:上传文件已经解析多少        // pContentLength:上传单个文件总的大小        // pItems:当前上传的是第几个Item        ProgressListener progressListener = new ProgressListener() {            private long megaBytes = -1;            public void update(long pBytesRead, long pContentLength,                    int pItems) {                long mBytes = pBytesRead / 1000000;                if (megaBytes == mBytes) {                    return;                }                megaBytes = mBytes;                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.");                }            }        };        // 设置监听器一定在解析之前设置        uploader.setProgressListener(progressListener);        List<FileItem> list = uploader.parseRequest(request);        for (FileItem fileItem : list) {            if (fileItem.isFormField()) {                String fieldName = fileItem.getFieldName();                // 这里使用UTF-8进行解码                String fieldValue = fileItem.getString("UTF-8");            } else {                String name = fileItem.getName();                // 有些浏览器获得的name是E:/1.bmp.针对不同浏览器解决上传时文件名称问题                // 这个索引是最后一个/所在索引位置                int lastIndex = name.lastIndexOf("//");                if (lastIndex != -1) {                    name = name.substring(lastIndex + 1);                }                boolean flag = false;                for (String ex : extensions) {                    if (name.endsWith(ex)) {                        flag = true;                        break;                    }                }                if (!flag) {                    // 文件类型不合法,需要给用户友好信息                    request.setAttribute("message", "对不起,文件类型不合法...");                    request.getRequestDispatcher("/upload.jsp").forward(                            request, response);                    return;                }                // 获得WEB-INF目录下upload文件夹的路径                String filePath = getServletContext().getRealPath(                        "/WEB-INF/upload");                // 生成不同名文件名,避免覆盖问题                String UUIDName = UUID.randomUUID().toString()                        .replace("-", "")                        + "_" + name;                // 生成随机文件夹,保存上传文件                filePath = generatedRandomDir(filePath, UUIDName);                InputStream in = fileItem.getInputStream();                FileOutputStream out = new FileOutputStream(new File(                        filePath, UUIDName));                int len = 0;                byte[] buf = new byte[1024];                while ((len = in.read(buf)) != -1) {                    out.write(buf, 0, len);                }                in.close();                out.close();                //删除临时文件,该方法放在流关闭之后                fileItem.delete();            }        }    } catch (FileUploadBase.FileSizeLimitExceededException e) {        // 单个文件大小超过限制        request.setAttribute("message", "对不起,上传单个文件大小超过限制...");        request.getRequestDispatcher("/upload.jsp").forward(request,                response);    } catch (FileUploadBase.SizeLimitExceededException e) {        // 总的文件大小超过限制        request.setAttribute("message", "对不起,总的文件大小超过限制...");        request.getRequestDispatcher("/upload.jsp").forward(request,                response);    } catch (Exception e) {        e.printStackTrace();    }}private String generatedRandomDir(String filePath, String uUIDName) {    int hashCode = uUIDName.hashCode();    int dir1 = hashCode & 0xf;// 一级目录    int dir2 = (hashCode >> 4) & 0xf;// 二级目录    String path = filePath + File.separator + dir1 + File.separator + dir2;    File file = new File(path);    if (!file.exists()) {        file.mkdirs();    }    return path;}public void doPost(HttpServletRequest request, HttpServletResponse response)        throws ServletException, IOException {    doGet(request, response);}public static void main(String[] args) {    System.out.println(UUID.randomUUID().toString().replace("-", ""));}

}

#### 2. 文件下载1. 告诉浏览器以下载方式打开要访问的数据

//设置content-diposition:attachement:filename=1.txt2. 将下载的文件当作一个流与response.getOutputStream关联起来.javaInputStream in=new FileInputStream("d:/aa/bb/1.txt");OutputStream out=response.getOutStream();----IO流拷贝```

3.综合练习,完成文件上传和下载

要求:

  1. 数据库保存上传文件信息
  2. 使用上传组件

步骤:

  1. 搭建环境,组合工程(包结构,数据库,必要的jar包,封装数据的java类)
  • 准备好数据库 sql create database upload_download; use upload_download; create table upfiles ( id varchar(100) primary key, uuidname varchar(80), filename varchar(80), savepath varchar(150), uploadtime timestamp,//数据库自动将当前时间插入 description varchar(255), username varchar(10) );
  • 导入jar包

  • 准备封装数据的javaBean java package com.domain; import java.sql.Timestamp; /** create table upfiles ( id varchar(100) primary key, uuidname varchar(80), filename varchar(80), savepath varchar(150), uploadtime timestamp, description varchar(255), username varchar(10) ); */ public class UpFile { private String id; private String uuidname;//上传文件的名称,文件的uuid名 private String filename;//上传文件的真实名称 private String savepath;//上传文件的路径 private Timestamp uploadtime;//上传时间 private String description;//文件描述 private String username;//上传人 public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUuidname() { return uuidname; } public void setUuidname(String uuidname) { this.uuidname = uuidname; } public String getFilename() { return filename; } public void setFilename(String filename) { this.filename = filename; } public String getSavepath() { return savepath; } public void setSavepath(String savepath) { this.savepath = savepath; } public Timestamp getUploadtime() { return uploadtime; } public void setUploadtime(Timestamp uploadtime) { this.uploadtime = uploadtime; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } }

3.1 文件下载
package com.web; import java.io.IOException; import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException;import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException;import org.apache.commons.fileupload.servlet.ServletFileUpload; import service.UpfileService; import com.domain.UpFile;import com.utils.WebUtils; public class UploadServlet extends HttpServlet {     public void doGet(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        // 判断是否是文件上传的request        if (!ServletFileUpload.isMultipartContent(request)) {            // 说明不是文件上传的表单,下面的代码不再执行            request.setAttribute("message", "对不起,您的表单不符合规范,请检查表单属性设置...");            request.getRequestDispatcher("/upload.jsp").forward(request,                    response);            return;        }         // 封装一个方法,完成文件上传        UpFile upFile;        try {            upFile = WebUtils.doFileUpload(request);        } catch (FileSizeLimitExceededException e) {            request.setAttribute("message", "对不起,上传单个文件大小超过限制...");            request.getRequestDispatcher("/upload.jsp").forward(request,                    response);            return;        } catch (SizeLimitExceededException e) {            request.setAttribute("message", "对不起,总的文件大小超过限制.....20M.");            request.getRequestDispatcher("/upload.jsp").forward(request,                    response);            return;        }        // 判断upFile是否为空,为空不执行后面语句        if (upFile == null) {            return;        }        System.out.println(upFile);         UpfileService ups = new UpfileService();         ups.upload(upFile);        // 上传成功,给用户友好提示        response.setContentType("text/html;charset=utf-8");        response.getWriter().print(                "上传成功<a href='" + request.getContextPath()                        + "/upload.jsp'>再次上传</a>");    }     public void doPost(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        doGet(request, response);    } }
package com.utils; import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.util.List;import java.util.UUID; import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.BeanUtils;import org.apache.commons.fileupload.FileItem;import org.apache.commons.fileupload.FileUploadBase;import org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException;import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException;import org.apache.commons.fileupload.ProgressListener;import org.apache.commons.fileupload.disk.DiskFileItemFactory;import org.apache.commons.fileupload.servlet.ServletFileUpload; import com.domain.UpFile; public class WebUtils {     public static UpFile doFileUpload(HttpServletRequest request) throws FileSizeLimitExceededException, SizeLimitExceededException  {        UpFile upFile = new UpFile();         try {            // 拿到工厂            DiskFileItemFactory factory = new DiskFileItemFactory();             // 设置临时缓存区大小            factory.setSizeThreshold(1024 * 1204 * 2);// 2M            // 设置上传时,临时文件的位置            factory.setRepository(new File(request.getsession()                    .getServletContext().getRealPath("/tmp")));             ServletFileUpload uploader = new ServletFileUpload(factory);            // 限定上传文件的大小            uploader.setFileSizeMax(1024 * 1024 * 2);// 以kb为单位,限制单个文件大小            uploader.setSizeMax(1024 * 1024 * 20);// 限制总的文件大小20M             // 设置解析事,中文文件名解析的码表            uploader.setHeaderEncoding("UTF-8");             // 设置监听器,监听上传进度             // 这里的update方法不定时被解析器调用到            // pBytesRead:上传文件已经解析多少            // pContentLength:上传单个文件总的大小            // pItems:当前上传的是第几个Item            ProgressListener progressListener = new ProgressListener() {                private long megaBytes = -1;                 public void update(long pBytesRead, long pContentLength,                        int pItems) {                    long mBytes = pBytesRead / 1000000;                    if (megaBytes == mBytes) {                        return;                    }                    megaBytes = mBytes;                    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.");                    }                }            };            // 设置监听器一定在解析之前设置            uploader.setProgressListener(progressListener);            List<FileItem> list = uploader.parseRequest(request);            for (FileItem fileItem : list) {                if (fileItem.isFormField()) {                    String fieldName = fileItem.getFieldName();                    // 这里使用UTF-8进行解码                    String fieldValue = fileItem.getString("UTF-8");                    // 使用beanUtils封装java类                    // beanUtils封装数据,要求目标javaBean字段名称与表单提交过来的数据的名称一样,否则封装不上                    BeanUtils.setProperty(upFile, fieldName, fieldValue);                 } else {                    String filename = fileItem.getName();                    // 有些浏览器获得的name是E:/1.bmp.针对不同浏览器解决上传时文件名称问题                     // 这个索引是最后一个/所在索引位置                    int lastIndex = filename.lastIndexOf("//");                    if (lastIndex != -1) {                        filename = filename.substring(lastIndex + 1);                    }                     // 获得WEB-INF目录下upload文件夹的路径                    String savepath = request.getSession().getServletContext()                            .getRealPath("/WEB-INF/upload");                     // 生成不同名文件名,避免覆盖问题                    String uuidname = UUID.randomUUID().toString()                            .replace("-", "")                            + "_" + filename;                    // 生成随机文件夹,保存上传文件,避免性能问题                    savepath = generatedRandomDir(savepath, uuidname);                    InputStream in = fileItem.getInputStream();                    FileOutputStream out = new FileOutputStream(new File(                            savepath, uuidname));                    int len = 0;                    byte[] buf = new byte[1024];                    while ((len = in.read(buf)) != -1) {                        out.write(buf, 0, len);                    }                    in.close();                    out.close();                     // 删除临时文件                    fileItem.delete();                    upFile.setFilename(filename);                    upFile.setId(UUID.randomUUID().toString());                    upFile.setUuidname(uuidname);                    upFile.setSavepath(savepath);                }            }            return upFile;        } catch (FileUploadBase.FileSizeLimitExceededException e) {            throw e;        } catch (FileUploadBase.SizeLimitExceededException e) {            throw e;         } catch (Exception e) {            e.printStackTrace();            return null;        }    }     private static String generatedRandomDir(String savepath, String uuidname) {        int hashCode = uuidname.hashCode();        int dir1 = hashCode & 0xf;// 一级目录        int dir2 = (hashCode >> 4) & 0xf;// 二级目录        String path = savepath + File.separator + dir1 + File.separator + dir2;        File file = new File(path);        if (!file.exists()) {            file.mkdirs();        }         return path;    }} 

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表