文件的上传,下载

文件上传

文件上传三要素
  • 提供form表单,method必须是post
  • form表单的enctype必须是multipart/form-data
  • 提供 input type=“file” 类型输入
文件上传的细节
  1. 为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下
  2. 为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名
  3. 为防止一个目录下面出现太多文件,要使用hash算法打散存储
  4. 要限制上传文件的最大值
  5. 限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法
以上传图片为例

从前端获取数据

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>文件上传</title>
</head>
<body>
    <h2>文件上传</h2>
    <%--条件:1.method必须是post  2.enctype="multipart/form-data"  提供input type="file"类型输入--%>
    <form action="${pageContext.request.contextPath}/upload" method="post" enctype="multipart/form-data">
        用户名:<input type="text" name="username"><br/>
        附件1:<input type="file" name="file1"><br/>
        附件2:<input type="file" name="file2"><br/>
        <input type="submit" value="提交"><br/>
    </form>
</body>
</html>

接收数据的Servlet

/**
 *
 * 注意:先添加注解
 * @MultipartConfig
 *      maxFileSize 单个文件大小
 *      maxRequestSize 所有文件大小
 */
@WebServlet(name = "UploadServlet", value = "/upload")
@MultipartConfig(maxFileSize = 5*1024*1024, maxRequestSize = 50*1024*1024)
public class UploadServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //解决乱码
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");

        //1. 把上传的图片放到安全的目录下  /WEB-INF 这个路径下不能访问,安全问题!!!
        String basepath = request.getServletContext().getRealPath("/WEB-INF/upload");
        File dir = new File(basepath);
        if (!dir.exists()){
            dir.mkdirs();
        }

        //2.遍历文件,获取文件,使用getParts,而不是用getParameter()
        Collection<Part> parts = request.getParts();
        if (parts != null) {
            for (Part part : parts) {
                //3.1判断是不是文件
                //所有名字   part.getName()
                //是文件类型的名字  part.getSubmittedFileName()
                if (part.getSubmittedFileName() == null){
                    //普通字段
                    System.out.println(part.getName() + " : " + request.getParameter(part.getName()));
                } else {
                    //文件名,不同的浏览器会有问题
                    //String fileName = part.getSubmittedFileName();

                    //3.2判断有没有未提交的数据
                    //如果有不选的,则跳过
                    String fileName = part.getSubmittedFileName();
                    if (fileName == ""){
                        continue;
                    }

                    //获取请求头,获取文件名
                    String header = part.getHeader("content-disposition");
                    //找到以filename=开头的位置,往后10位开始截取,真的文件名路径在 filename="xxxx",所以往后取10个,截取到倒数第二个
                    String path = header.substring(header.indexOf("filename=") + 10, header.length() - 1);
                    //取出真正的文件名
                    String filename = path.substring(path.lastIndexOf("\\") + 1);

                    //3.3判断是不是想要的数据类型
                    //获取文件的后缀
                    String ext = filename.substring(filename.lastIndexOf(".") + 1);
                    List<String> allows = Arrays.asList("jpg", "png", "bmp");
                    //判断是不是想要的图片类型
                    if (!allows.contains(ext)) {
                        response.getWriter().write("不支持文件类型" + filename);
                        return;
                    }

                    
                    //存入项目中!!!
                    part.write(UploadUtils.createNewPath(basepath, filename) + "/" + UploadUtils.createNewFilename(filename));
                    //删除缓存
                    part.delete();
                    System.out.println("上传成功");
                    //用到向浏览器写数据的时候,设置编码
                    response.getWriter().write("上传成功" + UploadUtils.createNewFilename(filename));
                }
            }
        }
    }

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

适用于所有浏览器,谷歌,IE,火狐…获取文件名

//获取请求头,获取文件名
String header = part.getHeader("content-disposition");
//找到以filename=开头的位置,往后10位开始截取,真的文件名路径在 filename="xxxx",所以往后取10个,截取到倒数第二个
String path = header.substring(header.indexOf("filename=") + 10, header.length() - 1);
//取出真正的文件名
String filename = path.substring(path.lastIndexOf("\\") + 1);
public class UploadUtils {

    //确定名称是唯一的
    public static String createNewFilename(String filename){

        //UUID(唯一值) 36位 中间有4个 -
        String s = UUID.randomUUID().toString().replace("-", "");
        //用于后期拼接
        return s + "_" + filename;
    }

    //用于打乱存储位置
    public static String createNewPath(String basepath,String filename){
        int hashCode = filename.hashCode();
        int dir1 = hashCode & 0xf;       //0-15
        int dir2 = (hashCode & 0xf0) >> 4;    //0-15

        String newpath = basepath + "/" + dir1 + "/" + dir2;
        File dir = new File(newpath);
        if (!dir.exists()){
            dir.mkdirs();
        }
        return newpath;
    }

    /**
     * 把图片(图片中不能有_)的处理过的名字当做key,真正的名字当做值,存入map集合
     * @param dir  遍历文件夹,找到所有图片
     * @param map 使用key保存带有UUID的文件名,用value保存没有UUID文件名
     */
    public static void listFiles(File dir, HashMap<String, String> map){
        File[] files = dir.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()){
                    listFiles(file, map);
                } else {
                    map.put(file.getName(), file.getName().split("_")[1]);
                }
            }
        }
    }
}

下载
@WebServlet(name = "FileListServlet", value = "/filelist")
public class FileListServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String basepath = request.getServletContext().getRealPath("/WEB-INF/upload");
        HashMap<String, String> filemaps = new HashMap<>();
        UploadUtils.listFiles(new File(basepath), filemaps);

        //把集合放入域
        request.setAttribute("filemaps", filemaps);
        //转发到前端展示
        request.getRequestDispatcher("/list.jsp").forward(request, response);

    }

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

放到页面展示

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>下载列表</title>
</head>
<body>
    <h1>下载列表</h1>
    <c:forEach var="entry" items="${filemaps}">
        ${entry.value}<a href="${pageContext.request.contextPath}/down?filename=${entry.key}">下载</a><br/>
    </c:forEach>
</body>
</html>

下载

@WebServlet(name = "DownServlet", value = "/down")
public class DownServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        //获取浏览器传来的路径,带uuid
        String uuid_filename = request.getParameter("filename");

        //获取到相同的参数,找到真实路径【巧妙获取真实路径】
        String filename = uuid_filename.split("_")[1];
        String basepath = request.getServletContext().getRealPath("/WEB-INF/upload");

        //获取路径
        String realpath = UploadUtils.createNewPath(basepath, filename);
        FileInputStream fis = new FileInputStream(realpath + "/" + uuid_filename);

        int len = -1;
        byte[] buf = new byte[1024];
        ServletOutputStream os = response.getOutputStream();
        //设置下载
        response.setHeader("content-disposition","attachment;filename" + URLEncoder.encode(filename, "utf-8"));
        while ((len = fis.read(buf)) != -1){
            os.write(buf, 0 ,len);
        }
        fis.close();
        os.close();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值