• Java Web总结十八之一文件的上传和下载


    一、实现Web开发中的文件上传功能,需完成如下两步操作:

      1、在web页面中添加上传输入项。

      2、在Servlet中读取上传文件的数据,并保存到本地硬盘中。

    二、如何在web页面中添加上传输入项?

      1、<input type="file">标签用于在web页面中添加文件上传输入项,设置文件上传输入项时须注意:

        1)必须设置input输入项的name属性,否则浏览器将不会发送上传文件的数据。

        2)必须把form的enctype属性值设为multipart/form-data。设置该值后,浏览器在上传文件时,将把文件数据附带在http请求消息体中,并使用MIME协议对上传的文件进行描述,以方便接收方对上传数据进行解析和处理。

    三、在web开发中实现文件上传功能,通常使用commons-fileupload组件实现。使用commons-fileupload组件实现文件上传,需要导入该组件相应的支撑jar包:

      1、commons-fileupload-1.3.1.jar

      2、commons-io-2.4.jar

    四、上传文件的细节:

      1、中文乱码的问题

        1)普通字段的中文乱码问题:FileItem.getString("UTF-8"),FileItem表示上传表单中的表单项内容。

        2)上传字段的中文乱码问题:ServletUploadFile.setHeaderEncoding("UTF-8");

      2、临时文件的删除问题

        1)通过FileItem.delete()

        2)一定要在关闭IO流之后

      3、在同一个目录下上传相同文件名的问题

        1)将文件名拼接一个唯一标识符,即UUID

      4、单个目录下文件过多的问题

        1)采用位运算解决单个目录文件过多

        2)思路:

      5、为安全将上传的文件放入客户端无法直接访问的目录中的问题

        1)将上传的文件,放置到/WEB-INF/upload/目录下

      6、重构思想

        1)做到重用性

      7、自定义封装上传文件工具类的问题

      8、上传文件的大小问题

      9、上传多个文件的问题

      10、上传多个文件的界面问题

    五、显示下载文件列表

      1)递归方式查询可供下载的文件,一定要有出口条件。

      2)使用Map<UUID文件名,真实文件名>收集可供下载的文件

      3)使用<c:url>和<c:param>对中文名进行URL编码

    六、下载文件

      1、对传过来的中文编码进行URL解码

      2、通过UUID文件名,反向查到该文件所在的真实目录

    七、文件上传下载与数据库结合

      1、在将上传文件保存的同时,写往数据库表,一个上传文件对应一条记录,确保uuidFileName双方一致。

    八、上传和下载代码

    1、文件目录图

    2、UpDao.java

    package com.gnnuit.web.dao;
    
    import java.sql.SQLException;
    
    import org.apache.commons.dbutils.QueryRunner;
    
    import com.gnnuit.web.domain.Up;
    import com.gnnuit.web.util.JdbcUtil;
    
    //向数据库添加up对象
    public class UpDao {
        public void addUp(Up up) throws SQLException {
            QueryRunner qr = new QueryRunner(JdbcUtil.getDataSource());
            String sql = "insert into up(username,realFileName,uuidFileName) values(?,?,?)";
            qr.update(sql, new Object[] { up.getUsername(), up.getRealFileName(),
                    up.getUuidFileName() });
        }
    }

    3、Up.java

    package com.gnnuit.web.domain;
    
    public class Up {
        private int id;
        private String username;
        private String realFileName;
        private String uuidFileName;
    
        public Up() {
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getRealFileName() {
            return realFileName;
        }
    
        public void setRealFileName(String realFileName) {
            this.realFileName = realFileName;
        }
    
        public String getUuidFileName() {
            return uuidFileName;
        }
    
        public void setUuidFileName(String uuidFileName) {
            this.uuidFileName = uuidFileName;
        }
    }

    4、User.java

    package com.gnnuit.web.domain;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import org.apache.commons.fileupload.FileItem;
    
    //封装上传文件的内容
    public class User {
        // 上传用户
        private String username;
        // 上传的文件
        private List<FileItem> upfileList = new ArrayList<FileItem>();
    
        public User() {
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public List<FileItem> getUpfileList() {
            return upfileList;
        }
    
        public void setUpfileList(List<FileItem> upfileList) {
            this.upfileList = upfileList;
        }
    }

    5、NoUpfileException.java

    package com.gnnuit.web.exception;
    
    public class NoUpfileException extends Exception{
    
        private static final long serialVersionUID = 1L;
    
    }

    6、UpfileSizeException.java

    package com.gnnuit.web.exception;
    
    public class UpfileSizeException extends Exception{
    
    
        private static final long serialVersionUID = 1L;
    
    }

    7、UpfileTypeException.java

    package com.gnnuit.web.exception;
    
    public class UpfileTypeException extends Exception{
    
        private static final long serialVersionUID = 1L;
    
    }

    8、DownLoadServlet.java

    package com.gnnuit.web.servlet.download;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.net.URLEncoder;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import com.gnnuit.web.util.UploadUtil;
    
    public class DownLoadServlet extends HttpServlet {
    
        private static final long serialVersionUID = 1L;
    
        public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            // 获取传过来的UUID文件名,参数带有中文,需要做处理
            String uuidFileName = request.getParameter("fileName");
            byte[] buf = uuidFileName.getBytes("ISO8859-1");
            uuidFileName = new String(buf, "UTF-8");
    
            // 根据UUID文件名获取真实文件名
            int index = uuidFileName.lastIndexOf("_");
            String realFileName = uuidFileName.substring(index + 1);
    
            // 设置弹出下载框
            String uploadPath = this.getServletContext().getRealPath(
                    UploadUtil.uploadPath);
            String uuidFilePath = UploadUtil.makeUuidFilePath(uploadPath,
                    uuidFileName);
            response.setHeader("Content-Disposition", "attachment; filename="
                    + URLEncoder.encode(realFileName, "UTF-8"));
    
            // 开始下载
            FileInputStream fis = new FileInputStream(new File(uuidFilePath + "/"
                    + uuidFileName));
            OutputStream out = response.getOutputStream();
            int len = 0;
            buf = new byte[1024];
            while ((len = fis.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
            fis.close();
            out.close();
        }
    
    }

    9、FileListServlet.java

    package com.gnnuit.web.servlet.download;
    
    import java.io.File;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import com.gnnuit.web.util.UploadUtil;
    
    public class FileListServlet extends HttpServlet {
    
        private static final long serialVersionUID = 1L;
    
        public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            String uploadPath = this.getServletContext().getRealPath(
                    UploadUtil.uploadPath);
            Map<String, String> map = new HashMap<>();// key代表UUID文件名,value代表真实文件名
            getFiles(uploadPath, map);
            request.setAttribute("map", map);
            request.getRequestDispatcher("/download.jsp")
                    .forward(request, response);
        }
    
        // 获取下载目录的所有文件
        private void getFiles(String uploadPath, Map<String, String> map) {
            File file = new File(uploadPath);
            if (file.isFile()) {
                // 是文件,不是目录
                String uuidFileName = file.getName();
                int index = uuidFileName.lastIndexOf("_");
                String realFileName = uuidFileName.substring(index + 1);
                map.put(uuidFileName, realFileName);
            } else {
                // 是目录
                File[] files = file.listFiles();
                for (File f : files) {
                    getFiles(f.getPath(), map);
                }
            }
        }
    
    }

    10、UploadServlet.java

    package com.gnnuit.web.servlet.upload;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import com.gnnuit.web.dao.UpDao;
    import com.gnnuit.web.domain.Up;
    import com.gnnuit.web.domain.User;
    import com.gnnuit.web.exception.NoUpfileException;
    import com.gnnuit.web.exception.UpfileSizeException;
    import com.gnnuit.web.exception.UpfileTypeException;
    import com.gnnuit.web.util.UploadUtil;
    
    public class UploadServlet extends HttpServlet {
    
        private static final long serialVersionUID = 1L;
    
        public void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            try {
                User user = UploadUtil.doUpload(request);
                String uploadPath = this.getServletContext().getRealPath(
                        UploadUtil.uploadPath);
                List<Up> upList = new ArrayList<>();
                // 写入硬盘
                UploadUtil.doSave(user, uploadPath, upList);
                //写入数据库
                UpDao dao = new UpDao();
                for (Up up : upList) {
                    dao.addUp(up);
                }
                request.setAttribute("message", "上传文件成功");
                request.getRequestDispatcher("/WEB-INF/message.jsp").forward(
                        request, response);
            } catch (UpfileSizeException e) {
                e.printStackTrace();
                request.setAttribute("message", "上传文件大小限制在200K以内");
                request.getRequestDispatcher("/WEB-INF/message.jsp").forward(
                        request, response);
            } catch (UpfileTypeException e) {
                e.printStackTrace();
                request.setAttribute("message", "只能上传JPG格式的文件");
                request.getRequestDispatcher("/WEB-INF/message.jsp").forward(
                        request, response);
            } catch (NoUpfileException e) {
                e.printStackTrace();
                request.setAttribute("message", "无上传文件");
                request.getRequestDispatcher("/WEB-INF/message.jsp").forward(
                        request, response);
            } catch (Exception e) {
                e.printStackTrace();
                request.setAttribute("message", "上传文件失败");
                request.getRequestDispatcher("/WEB-INF/message.jsp").forward(
                        request, response);
            }
    
        }
    
    }

    11、up.sql

    use mydb3;
    drop table if exists up;
    create table if not exists up(
        id int primary key auto_increment,
        username varchar(20) not null,
        realFileName varchar(20) not null,
        uuidFileName varchar(100) not null
    );

    12、JdbcUtil.java

    package com.gnnuit.web.util;
    
    import java.sql.Connection;
    import java.sql.SQLException;
    
    import javax.sql.DataSource;
    
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    
    public final class JdbcUtil {
        private static ComboPooledDataSource cpds;
        static {
            cpds = new ComboPooledDataSource();
        }
    
        // 获取数据源
        public static DataSource getDataSource() {
            return cpds;
        }
    
        // 取得连接
        public static Connection getMySqlConnection() throws SQLException {
            return cpds.getConnection();
        }
    
        // 关闭连接
        public static void close(Connection conn) throws SQLException {
            if (conn != null) {
                conn.close();
            }
        }
    }

    13、UploadUtil.java

    package com.gnnuit.web.util;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.util.List;
    import java.util.UUID;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    
    import org.apache.commons.fileupload.FileItem;
    import org.apache.commons.fileupload.disk.DiskFileItemFactory;
    import org.apache.commons.fileupload.servlet.ServletFileUpload;
    
    import com.gnnuit.web.domain.Up;
    import com.gnnuit.web.domain.User;
    import com.gnnuit.web.exception.NoUpfileException;
    import com.gnnuit.web.exception.UpfileSizeException;
    
    public final class UploadUtil {
        // 取得上传使用的临时和真实目录
        public static final String tempPath = "/WEB-INF/temp";
        public static final String uploadPath = "/WEB-INF/upload";
    
        // 取得真实文件名
        public static String getRealFileName(String realFileName) {
            int index = realFileName.lastIndexOf("\");
            if (index >= 0) {
                // IE6浏览器
                realFileName = realFileName.substring(index + 1);
            }
            return realFileName;
        }
    
        // 取得uuid文件名
        public static String makeUuidFilePath(String uploadPath, String uuidFileName) {
            String uuidFilePath = null;
            int code = uuidFileName.hashCode();// 8
            int dir1 = code & 0xF;// 3
            int dir2 = code >> 4 & 0xF;// A
            File file = new File(uploadPath + "/" + dir1 + "/" + dir2);
            // 如果该目录未存在
            if (!file.exists()) {
                // 一次性创建N层目录
                file.mkdirs();
            }
            uuidFilePath = file.getPath();
            return uuidFilePath;
        }
    
        // 取得upload/目录下的分散目录
        public static String makeUuidFileName(String realFileName) {
            return UUID.randomUUID().toString() + "_" + realFileName;
        }
    
        // 文件复制
        public static void doSave(InputStream is, String uuidFileName,
                String uuidFilePath) {
            OutputStream os = null;
            try {
                os = new FileOutputStream(uuidFilePath + "/" + uuidFileName);
                byte[] buf = new byte[1024];
                int len = 0;
                while ((len = is.read(buf)) > 0) {
                    os.write(buf, 0, len);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (is != null) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (os != null) {
                    try {
                        os.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        // 将上传文件封装成JavaBean对象中
        public static User doUpload(HttpServletRequest request) throws Exception {
            User user = new User();
            // 创建上传文件工厂
            DiskFileItemFactory factory = new DiskFileItemFactory();
            // 设置内存中缓存区的大小,默认10K
            factory.setSizeThreshold(100 * 1024);
            // 设置上传文件临时存放的目录
            String tempPath = request.getSession().getServletContext()
                    .getRealPath(UploadUtil.tempPath);
            factory.setRepository(new File(tempPath));
            // 创建上传文件对象[核心]
            ServletFileUpload upload = new ServletFileUpload(factory);
            // 设置上传文件的中文编码方式
            upload.setHeaderEncoding("UTF-8");
            // 客户端上传文件是否使用MIME协议,
            boolean flag = ServletFileUpload.isMultipartContent(request);
            if (!flag) {
                // 不是以MIME协议上传文件
                throw new ServletException();
            } else {
                /*
                 * 是以MIME协议上传的文件,解析request中的所有上传内容每个内容封装成一个对象FileItem,
                 * FileItem代表普通字段和上传字段二类
                 */
                List<FileItem> fileItemList = upload.parseRequest(request);
                for (FileItem fileItem : fileItemList) {
                    if (fileItem.isFormField()) {
                        String fieldValue = fileItem.getString("UTF-8");
                        user.setUsername(fieldValue);
                    } else {
                        // 必定是上传字段
    
                        // 如果无上传文件
                        if (fileItem.getSize() == 0) {
                            throw new NoUpfileException();
                        }
    
                        // 只能上传JPG文件
                        /*String realFileName = UploadUtil.getRealFileName(fileItem
                                .getName());
                        if (!realFileName.endsWith("jpg")) {
                            throw new UpfileTypeException();
                        }*/
    
                        // 只有上传<=200K的文件
                        if (fileItem.getSize() > 200 * 1024) {
                            throw new UpfileSizeException();
                        }
    
                        // 封装到JavaBean
                        user.getUpfileList().add(fileItem);
    
                    }
                }// end of for loop
            }
            return user;
        }
    
        public static void doSave(User user, String uploadPath, List<Up> upList)
                throws Exception {
            // 取得该用户上传的所有文件集合
            List<FileItem> fileItemList = user.getUpfileList();
            // 迭代每个文件,并上传
            for (FileItem fileItem : fileItemList) {
                // 创建Up对象
                Up up = new Up();
                up.setUsername(user.getUsername());
                // 取得输入流
                InputStream is = fileItem.getInputStream();
                // 取得真实文件名
                String realFileName = fileItem.getName();
                realFileName = UploadUtil.getRealFileName(realFileName);
                // 取得UUID文件名
                String uuidFileName = UploadUtil.makeUuidFileName(realFileName);
                // 取得UUID文件路径
                String uuidFilePath = UploadUtil.makeUuidFilePath(uploadPath,
                        uuidFileName);
                // 保存
                UploadUtil.doSave(is, uuidFileName, uuidFilePath);
                // 收集Up信息
                up.setUuidFileName(uuidFileName);
                up.setRealFileName(realFileName);
                upList.add(up);
                // 删除临时文件
                fileItem.delete();
            }
    
        }
    }

    14、c3p0-config.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <c3p0-config>
        <default-config>
            <property name="driverClass">com.mysql.jdbc.Driver</property>
            <property name="user">root</property>
            <property name="password">root</property>
            <property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/mydb3</property>
        </default-config>
    </c3p0-config>

    15、message.jsp

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      
      <body>
        ${message }
      </body>
    </html>

    16、download.jsp

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      
      <body>
        <table align="center" border="1">
            <tr>
                <th>文件列表</th>
                <th>操作</th>
            </tr>
            <c:forEach var="entry" items="${map }">
                <tr>
                    <td>${entry.value }</td>
                    <td>
                        <c:url var="myURL" value="/DownLoadServlet">
                            <c:param name="fileName" value="${entry.key }"></c:param>
                        </c:url>
                        <a href="${myURL }" >下载</a>
                    </td>
                </tr>
            </c:forEach>
        </table>
      </body>
    </html>

    17、upload.jsp

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
          <script type="text/javascript">
              var time=0;
              function addDiv(addButton) {
                var outDiv=document.getElementById("outDiv");
                var divElement= document.createElement("div");
                var inputElement=document.createElement("input");
                inputElement.type="file";
                inputElement.name="filename";
                var inputElement2=document.createElement("input");
                inputElement2.type="button";
                inputElement2.value="删除";
                inputElement2.onclick=function(){
                    var parentNode= this.parentNode.parentNode;
                    parentNode.removeChild(this.parentNode);
                    time--;
                    if(time<5){
                        addButton.disabled=false;
                    }
                };
                divElement.appendChild(inputElement);
                divElement.appendChild(inputElement2);
                outDiv.appendChild(divElement);
                time++;
                if(time==5){
                    addButton.disabled=true;
                }
            }
          </script>
      </head>
      <body>
        <form action="${pageContext.request.contextPath }/UploadServlet" method="post" enctype="multipart/form-data">
            <table border="1" align="center">
                <tr>
                    <td>上传用户</td>
                    <td><input type="text" name="username"/></td>
                </tr>
                <tr>
                    <td>上传文件</td>
                    <td>
                        <div id="outDiv">
                        
                        </div>
                        <%--<input type="file" name="filename"/> --%>
                        <input type="button" value="添加" onclick="addDiv(this)"/>
                    </td>
                </tr>
                <tr>
                    <td colspan="2" align="center">
                        <input type="submit" value="提交"/>
                    </td>
                </tr>
                
                <tr>
                    <td colspan="2" align="center">
                        <a href="${pageContext.request.contextPath }/FileListServlet">显示下载文件列表</a>
                    </td>
                </tr>
            </table>
        </form>
      </body>
    </html>
  • 相关阅读:
    5.16
    4.29
    二十节 作业
    作业
    作业
    控件
    选择排序
    百钱买百鸡
    用颜色变色变换来调整图像的对比度和亮度
    图像的裁剪
  • 原文地址:https://www.cnblogs.com/FlySheep/p/3719599.html
Copyright © 2020-2023  润新知