文件上传下载

利用 Servlet 实现文件的上传的下载

一、文件上传

1.前端代码:

(1).基于表单的上传如果在表单中使用表单元素浏览器在解析表单时,会自动生成一个输入框和一个按钮,输入框可供用户填写本地文件的文件名和路径名,按钮可以让浏览器打开一个文件选择框供用户选择文件,此时表单要加上 enctype 属性

(2).JS 动态生成文件框:点击 “添加文件” 按钮,可以添加一个文件框而且可以删除。

jsp代码:


    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
    <script type="text/javascript" src = "../js/jquery.min.js"></script>
    <script type="text/javascript">
        $(function(){
            var i = 2;
            $("#addFile").click(function(){

                $("#tr").before("<tr class = 'file'><td>File"+i+":</td>"+
                    "<td><input type = 'file' name = 'file"+i+"'/></td></tr>" +
                    "<tr class = 'desc'><td>Desc"+i+":</td>"+
                    "<td><input type = 'text' name = 'desc"+i+"'/></td>" +
                    "<td><button id = 'delete"+ i +"' type = 'button'>删除</button></td></tr>");
                i++;

                $("#delete" + (i-1)).click(function(){
                    var tr = $(this).parent().parent();//获取 delete 按钮所在的 tr 对象
                    tr.prev("tr").remove();           //获取 delete 按钮所在的 tr 对象的前一个 tr 对象并移除
                    tr.remove();

                    //对 i 重新排序
                    $(".file").each(function(index){//index 从 0 开始,遍历 file 集合修改对应属性值
                        var n = index + 1;
                        $(this).find("td:first").text("File" + n + ":");
                        $(this).find("td:nth-child(2) input").attr("name","file"+ n +"");
                    });
                    $(".desc").each(function(index){
                        var n = index + 1;
                        $(this).find("td:first").text("Desc" + n + ":");
                        $(this).find("td:nth-child(2) input").attr("name","desc" + n);
                        //对删除按钮也要进行重新编号
                        $(this).find("td:last button").attr("id","delete" + n);
                    });

                    i--;
                });
            });
        })
    </script>
    </head>
    <body>
        <font color="red">${message }</font>
        <form action="FileUploadServlet" method="post" enctype="multipart/form-data">
            <table>
                <tr class = "file">
                    <td>File1:</td>
                    <td><input type = "file" name = "file1"/></td>
                </tr>
                <tr class = "desc">
                    <td>Desc1:</td>
                    <td><input type = "text" name = "desc1"/></td>
                </tr>
                <tr id = "tr">
                    <td><input type = "submit" value = "上传"/></td>
                    <td><button id = "addFile" type = "button">添加文件</button></td>
                </tr>
            </table>
        </form>
    </body>
    </html>

2.后台代码:

(1).上传文件的属性文件:upload.properties

  文件能够上传的扩展名以及不能超过的大小(字节)。


    <!-- 以下文件能够上传 --!>
    exts=pptx,docx,doc,xls,xlsx

     <!-- 单个文件不能超过 1M --!>
    file.max.size=1048576

     <!-- 文件总大小不能超过 5M --!>
    total.file.max.size=5242880


(2).上属性文件 Bean 类:FileUploadProperties.java

  单例模式,从上面的 upload.properties 文件中提取出信息,以供后面使用。


    import java.util.HashMap;
    import java.util.Map;

    /**
     * 
     * 单例模式,只需获取一次就可以了。
     */
    public class FileUploadProperties {

        private Map<String, String> properties = new HashMap<>();
        private FileUploadProperties(){}
        private static FileUploadProperties instance = new FileUploadProperties();

        public static FileUploadProperties getInstance(){
            return instance;
        }

        public void addProperty(String propertyName,String propertyValue){
            properties.put(propertyName, propertyValue);
        }

        public String getPropertty(String propertyName){
            return properties.get(propertyName);
        }
    }

(3).监听器:FileUploadListener.java

  当项目运行起来,立即从属性文件中获取信息加载到 FileUploadProperties 类中,这部分工作可由 Listener 完成。


    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Map;
    import java.util.Properties;

    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import javax.servlet.annotation.WebListener;

    @WebListener
    public class FileUploadListener implements ServletContextListener {


        public FileUploadListener() {
        }

        public void contextDestroyed(ServletContextEvent arg0)  { 
             // TODO Auto-generated method stub
        }
        /**
         * 当服务器启动的时候运行该方法,加载信息。
         */
        public void contextInitialized(ServletContextEvent arg0)  { 
             InputStream in = getClass().getClassLoader().getResourceAsStream("/upload.properties");
             Properties properties = new Properties();
             try {
                    properties.load(in);
                    for (Map.Entry<Object, Object> pro: properties.entrySet()) {
                        String propertyName = (String) pro.getKey();
                        String propertyValue = (String) pro.getValue();

                        FileUploadProperties.getInstance().addProperty(propertyName, propertyValue);
                    }

                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }

(4).文件实体类:FileUploadBean.java

  将上传的文件进行封装,方便后面使用。



    import java.io.InputStream;

    public class FileUploadBean {

        private Integer id;
        private String fileName;    //文件名
        private String filePath;    //文件路径
        private String fileDesc;    //文件描述
        private long fileSize;      //文件大小
        private InputStream in;     //文件的输入流

        public FileUploadBean() {
            super();
            // TODO Auto-generated constructor stub
        }
        public FileUploadBean(String fileName, String filePath, String fileDesc, long fileSize, InputStream in) {
            super();
            this.fileName = fileName;
            this.filePath = filePath;
            this.fileDesc = fileDesc;
            this.fileSize = fileSize;
            this.in = in;
        }
        public Integer getId() {
            return id;
        }
        public void setId(Integer id) {
            this.id = id;
        }
        public String getFileName() {
            return fileName;
        }
        public void setFileName(String fileName) {
            this.fileName = fileName;
        }
        public String getFilePath() {
            return filePath;
        }
        public void setFilePath(String filePath) {
            this.filePath = filePath;
        }
        public String getFileDesc() {
            return fileDesc;
        }
        public void setFileDesc(String fileDesc) {
            this.fileDesc = fileDesc;
        }
        public long getFileSize() {
            return fileSize;
        }
        public void setFileSize(long fileSize) {
            this.fileSize = fileSize;
        }
        public InputStream getIn() {
            return in;
        }
        public void setIn(InputStream in) {
            this.in = in;
        }
    }

(5).Servlet 类:FileUploadServlet.java

  当表单设置 enctype=”multipart/form-data” 时表示表单以二进制传输数据,此时不能在通过request.getParameter(“file”) 获取文件,需要通过 commons-fileupload-1.3.1.jar 来获取文件。

  1. FileItemFactory 文件上传工厂类(把每一个请求表单项封装为一个个FileItem对象)
  2. ServletFileUpload 文件上传核心类,可以获取所有的FileItem对象

    1. Boolean isMultipartContent(request);判断表单类型,文件上传表单但会true
    2. upload.setFileSizeMax(fileSizeMax);设置单个上传文件的最大值
    3. upload.setSizeMax(sizeMax);设置总上传文件大总的最大值
    4. upload.setHeaderEcoding(“UTF-8”);设置上传文件名的编码
  3. FileItem 封装了普通表单项的值以及文件上传表单元素的值

    1. item.getFiledName();获取上传表单元素的名称
    2. item.getString();获取上传数据;
    3. item.getString(“UTF-8”);获取上传数据,处理中文
    4. item.getContentType();获取上传文件类型[文件上传项]
    5. item.getInputStream();获取文件流[文件上传项]
    6. item.getName();获取文件名[文件上传项]
    7. item.write(file);把数据写到file文件
    8. item.delete();删除临时文件

    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.UnsupportedEncodingException;
    import java.sql.Connection;
    import java.sql.SQLException;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import java.util.Random;
    import java.util.UUID; 
    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.commons.fileupload.FileItem;
    import org.apache.commons.fileupload.FileUpload;
    import org.apache.commons.fileupload.FileUploadException;
    import org.apache.commons.fileupload.disk.DiskFileItemFactory;
    import org.apache.commons.fileupload.servlet.ServletFileUpload;
    import org.apache.commons.io.FileUtils;
    import org.junit.Test;
    import cn.edu.pzhu.cg.bean.Student;
    import cn.edu.pzhu.cg.db.JDBCTools;

    @WebServlet("/app2/FileUploadServlet")
    public class FileUploadServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;
        private static final String FILE_PATH = "d:\\Test\\files";

        public FileUploadServlet() {
            super();
            // TODO Auto-generated constructor stub
        }


        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //要请求的页面
            String path = null;

            try {
                ServletFileUpload upload = getServletFileUpload();

                //解析请求获取 FileItem 集合
                List<FileItem> list = upload.parseRequest(request);
                //解析 FileItem 获取每个文件的相关信息,并将文件保存
                List<FileUploadBean> fileBeans = getFileBeans(list);

                //校验文件大小
                validateFileSize(fileBeans);

                //校验文件扩展名
                validateExtName(fileBeans);

                //上传文件
                uploadFile(fileBeans);

                //将文件信息写入数据库中
                saveFileUploadBeans(fileBeans);

                path = "success.jsp";

            } catch (Exception e) {
                e.printStackTrace();
                //如果发生异常,重新回到上传页面
                path = "upload.jsp";
                //保存异常信息
                request.setAttribute("message", e.getMessage());
            }
            //请求 path 页面
            request.getRequestDispatcher(path).forward(request, response);
        }

        /**
         * 
            * @Title: validateFileSize
            * @Description: TODO(校验文件大小,先校验每个文件大小是否超过规定大小,再校验总文件大小,将信息以异常的形式抛出)
            * @param @param fileBeans    参数
            * @return void    返回类型
            * @throws
         */
        private void validateFileSize(List<FileUploadBean> fileBeans) {
            String fileMaxSize = FileUploadProperties.getInstance().getPropertty("file.max.size");
            String totalFileMaxSize = FileUploadProperties.getInstance().getPropertty("total.file.max.size");

            int tempFileSize = Integer.parseInt(fileMaxSize)/1024/1024;
            int tempTotalFileSize = Integer.parseInt(totalFileMaxSize)/1024/1024;
            long total = 0;


            for (FileUploadBean file : fileBeans) {
                if(file.getFileSize() > Integer.parseInt(fileMaxSize)){
                    throw new cn.edu.pzhu.cg.app2.FileUploadException(file.getFileName() + " 文件大小超过 " + tempFileSize + " M");
                }
                total += Integer.parseInt(fileMaxSize);
            }

            if(total > Integer.parseInt(totalFileMaxSize)){
                throw new cn.edu.pzhu.cg.app2.FileUploadException("总文件文件大小超过 " + tempTotalFileSize + " M");
            }
        }


        /**
         *  文件上传成功后,将文件信息写入到数据库中,由于多条信息需要写入数据库中,这里要开启事务操作。
            * @Title: saveFileUploadBeans
            * @Description: TODO(这里用一句话描述这个方法的作用)
            * @param @param fileBeans    参数
            * @return void    返回类型
            * @throws
         */
        private void saveFileUploadBeans(List<FileUploadBean> fileBeans) {
            Connection conn = null;
            FileUploadDAO fileUploadDAO= new FileUploadDAO();

            try {
                conn = JDBCTools.getConnection();
                //开启事务,设置不自动提交
                conn.setAutoCommit(false);

                for (FileUploadBean file : fileBeans) {
                    fileUploadDAO.insert(conn, file.getFileName(),FILE_PATH,file.getFileDesc());
                }

                conn.commit();
            } catch (Exception e) {
                try {
                    conn.rollback();
                } catch (SQLException e1) {
                    e1.printStackTrace();
                }
                e.printStackTrace();
            } finally{
                JDBCTools.release(conn, null, null);
            }

        }

        /**
         *  将文件集合中的文件上传到磁盘中,
            * @Title: uploadFile
            * @Description: TODO(这里用一句话描述这个方法的作用)
            * @param @param fileBeans    参数
            * @return void    返回类型
            * @throws
         */
        private void uploadFile(List<FileUploadBean> fileBeans) {
            String fileName = null;
            File file = null;
            try {
                for(FileUploadBean fileUploadBean:fileBeans){
                    fileName = getFileName(fileUploadBean.getFileName());
                    fileUploadBean.setFileName(fileName);

                    file = new File(FILE_PATH,fileName);
                    FileUtils.copyInputStreamToFile(fileUploadBean.getIn(), file);
                }
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        }

        /**
         *  验证用户上传的文件与配置的后缀文件是否一致
            * @Title: validateExtName
            * @Description: TODO(这里用一句话描述这个方法的作用)
            * @param @param fileBeans
            * @param @return    参数
            * @return boolean    返回类型
            * @throws
         */
        private void validateExtName(List<FileUploadBean> fileBeans) {
            //配置文件中能够上传的文件扩展名
            String [] propertiesExtNames = FileUploadProperties.getInstance().getPropertty("exts").split(",");
            List<String> propertiesExtName = Arrays.asList(propertiesExtNames);


            for(FileUploadBean file:fileBeans){
                String fileName = file.getFileName();
                //判断文件扩展名是否在扩展名集合中,如果不在,抛出异常信息。
                if(!propertiesExtName.contains(fileName.substring(fileName.lastIndexOf(".") + 1))){
                    throw new cn.edu.pzhu.cg.app2.FileUploadException(fileName + " 文件扩展名不合法");
                }
            }

        }

        /**
         *  通过 FileItem 将文件以及相应信息提取出来并封装成 FileUploadBean 对象,将所有的 FileUploadBean 存放在集合中
            * @Title: getFileBeans
            * @Description: TODO(这里用一句话描述这个方法的作用)
            * @param @param list
            * @param @return    参数
            * @return List<FileUploadBean>    返回类型
            * @throws
         */
        private List<FileUploadBean> getFileBeans(List<FileItem> list) {
            List<FileUploadBean> fileBeans = new ArrayList<>();
            List<FileItem> files = new ArrayList<>();
            List<FileItem> descs = new ArrayList<>();
            String path = "d:\\Test\\files";


            for(FileItem item:list){

                if(item.isFormField()){
                    descs.add(item);
                }else{
                    files.add(item);
                }
            }

            for(int i = 0;i < files.size();i++){
                String fileName = files.get(i).getName();
                String fileDesc = null;
                InputStream in = null;
                long fileSize = 0;

                try {
                    fileDesc = descs.get(i).getString("UTF-8");

                    in = files.get(i).getInputStream();

                    fileSize = files.get(i).getSize();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                FileUploadBean fileUploadBean = new FileUploadBean(fileName, path, fileDesc,fileSize,in);
                fileBeans.add(fileUploadBean);
            }
            return fileBeans;
        }

        /**
         *  防止上传文件时发生文件名重复问题,为每个文件重生生成一个文件名,由系统时间 + 随机数 + 原文件名
            * @Title: getFileName
            * @Description: TODO(这里用一句话描述这个方法的作用)
            * @param @param name
            * @param @return    参数
            * @return String    返回类型
            * @throws
         */
        private String getFileName(String name) {
            String fileName;
            Random random = new Random();

            fileName = System.currentTimeMillis() + random.nextInt(1000000) + name;

            return fileName;
        }

        /**
         * 返回 ServletFileUpload 对象
            * @Title: getServletFileUpload
            * @Description: TODO(这里用一句话描述这个方法的作用)
            * @param @return    参数
            * @return ServletFileUpload    返回类型
            * @throws
         */
        private ServletFileUpload getServletFileUpload() throws Exception{
            DiskFileItemFactory factory = new DiskFileItemFactory();
            ServletFileUpload upload = new ServletFileUpload(factory);
    //      upload.setFileSizeMax(Integer.parseInt(fileMaxSize));
    //      upload.setSizeMax(Integer.parseInt(totalFileMaxSize));
            return upload;
        }


        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }

    }

二、文件下载

  文件下载需要设置响应流,告诉浏览器是个下载文件,交由用户处理。


    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

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

        public DownLoadFileServlet() {
            super();
            // TODO Auto-generated constructor stub
        }

        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            response.setCharacterEncoding("UTF-8");
            request.setCharacterEncoding("UTF-8");
            //通知浏览器这是个下载的文件
            response.addHeader("Content-type", "appllication/octet-stream");

            String path = request.getParameter("path");
            String fileName = request.getParameter("name");

            //通知浏览器不再由浏览器来自行处理(或打开)要下载的文件,而交由用户处理
            response.addHeader("Content-Disposition", "attachment;filename="+fileName);

            //获得文件输入流           
            InputStream in = new FileInputStream(path);
            OutputStream out = response.getOutputStream();

            byte[] buffer = new byte[1024];
            int len = 0;

            while((len = in.read()) != -1){
                out.write(buffer, 0, len);
            }
            //因为输出流要向客户端输出文件,所以这里不关闭,输出流。
            in.close();
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值