欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

文件上传下载

程序员文章站 2022-03-04 21:02:40
...

利用 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();
        }
    }

相关标签: servlet