Loading

06、文件上传下载

一、引言

1.1、场景

  在项目中,文件的上传和下载是常见的功能。很多程序或者软件中都经常使用到文件的上传和下载。

  邮箱中有附件的上传和下载

  OA办公系统中有附件材料的上传

二、文件上传

2.1、概念

  当用户在前端页面点击文件上传后,用户上传的文件数据提交给服务器端,实现保存。

2.2、文件上传实现步骤

2.2.1、提交方式

  提供form表单,method必须是post。因为post请求无数据限制。

<form method="post"> </form>

2.2.2、提交数据格式

  表单的enctype属性值必须为multipart/form-data

  以多段的形式进行拼接提交。以二进制流的方式来处理表单数据,会把指定的文件内容封装进请求参数中。

<form enctype="multipart/form-data" method="post"></form>

2.2.3、提供组件

  提供file表单组件,提供给用户上传文件

<form enctype="multipart/form-data" method="post">
    上传用户:<input type="text" name="username "><br />
    上传文件1:<input type="file" name="file1"><br />
    <input type=" submit" value="提交">
</form>

2.2.4、Controller编写

  在Servlet 3.0及其以上版本的容器中进行服务器端文件上传的编程,是围绕着注解类型MultipartConfig和javax. servlet.http.Part接口进行的。处理已上传文件的Servlet必须以@MultipartConfig进行注解。

@WebServlet(name = "UploadController", value = "/uploadController")
@MultipartConfig(maxFileSize = 1024 * 1024 * 100, maxRequestSize = 1024 * 1024 * 200)
public class UploadController extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置乱码
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html ; charset=utf-8");

        //通过getPart方法获取文件组件
        Part file1 = request.getPart("file1");

        //获取上传文件保存路径(真实路径)
        String uploadPath = request.getServletContext().getRealPath("WEB-INF/upload");
        System.out.println(uploadPath);

        //创建文件夹对象
        File file = new File(uploadPath);

        //如果文件夹不存在,新建
        if (!file.exists()) {
            file.mkdirs();
        }


        //如果上传的文件不是空,进行保存
        if (file1 != null) {
            file1.write(uploadPath + File.separator + file1.getSubmittedFileName());
        }

        response.getWriter().println("上传成功!" + file1.getSubmittedFileName());

    }

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

2.3、文件上传细节注意

  上述的代码虽然可以成功将文件上传到服务器的指定目录当中,但是文件上传功能有许多需要注意的小细节问题。

2.3.1、安全问题

  为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下。

2.3.2、文件覆盖

  当上传重名的文件时,为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名。

    //使用UUID生成唯一标识码,拼接上图片的名称。
    public static String newFileName(String filename){
        return UUID.randomUUID().toString().replaceAll("-","")+"_"+filename;
    }

2.3.3、散列存储

  为防止一个目录下面出现太多文件,要使用hash算法生成二级、三级目录,散列存储上传的文件。

    //生成二级、三级目录
    public static String newFilePath(String basepath,String filename){
        int hashCode = filename.hashCode();
        int path1 = hashCode & 15;//二级目录  与运算 0~15
        int path2 = (hashCode>>4) & 15;//三级目录  0~15
        String newPath = basepath+"\\"+path1+"\\"+path2;
        File file = new File(newPath);
        if(!file.exists()){
            file.mkdirs();
        }
        return newPath;
    }

 

2.3.4、文件类型限制

  要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。

        //4.文件上传
        //生成唯一文件名
        String oldName = part.getSubmittedFileName();

        List<String> nameList = new ArrayList<>();
        nameList.add(".jpg");
        nameList.add(".png");
        nameList.add(".jpeg");

        String extName = oldName.substring(oldName.lastIndexOf("."));
        if(!nameList.contains(extName)){
            response.getWriter().println(oldName+"不符合文件上传的规则!");
            return;
        }

2.4、多文件上传

@WebServlet(name = "MoreUploadController",value = "/moreUpload")
@MultipartConfig(maxFileSize = 1024*1024*100,maxRequestSize = 1024*1024*200)
public class MoreUploadController extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        // 得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
        String basePath = request.getServletContext().getRealPath("/WEB-INF/upload");
        File file = new File(basePath);
        if(!file.exists()){
            file.mkdirs();
        }
        //获得表单提交的所有数据
        Collection<Part> parts = request.getParts();

        for (Part part : parts) {
            // 获取文件提交的名字
            String filename = part.getSubmittedFileName();
            if(filename!=null){
                // 文件
                if(filename.trim().equals("")){
                    continue;
                }
                // 获得包含UUID的文件名
                String newName = UploadUtils.newFileName(filename);
                // 获取分散后的路径
                String newPath = UploadUtils.newFilePath(basePath,filename);

                part.write(newPath+"\\"+newName);

            }else{//普通表单项
                String username = request.getParameter(part.getName());
                System.out.println(username);
            }
        }
    }

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

三、文件下载

3.1、概念

  我们要将Web应用系统中的文件资源提供给用户进行下载,首先我们要有一个页面列出上传文件目录下的所有文件,当用户点击文件下载超链接时就进行下载操作。

3.2、获取文件列表

3.2.1、DownLoadUtils

public class UploadUtils {

    //使用UUID生成唯一标识码,拼接上图片的名称。
    public static String newFileName(String filename){
        return UUID.randomUUID().toString().replaceAll("-","")+"_"+filename;
    }

    //生成二级、三级目录
    public static String newFilePath(String basepath,String filename){
        int hashCode = filename.hashCode();
        int path1 = hashCode & 15;//二级目录  与运算 0~15
        int path2 = (hashCode>>4) & 15;//三级目录  0~15
        String newPath = basepath+"\\"+path1+"\\"+path2;
        File file = new File(newPath);
        if(!file.exists()){
            file.mkdirs();
        }
        return newPath;
    }

}

3.2.2、FileListController

@WebServlet(name = "FileListController",value = "/fileList")
public class FileListController extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=utf-8");

        //集合,map,key=UUID   value=源文件名称
        HashMap<String,String> fileMap = new HashMap<>();
        String basePath = request.getServletContext().getRealPath("/WEB-INF/upload");
        DownLoadUtils.getFileList(new File(basePath),fileMap);

        request.setAttribute("fileMap",fileMap);
        request.getRequestDispatcher("/list.jsp").forward(request,response);
    }

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

3.3、下载

3.3.1、fileList.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>文件下载页面</title>
</head>
<body>
    <table>
        <tr>
            <th>文件名</th>
            <th>操作</th>
        </tr>
        <c:forEach items="${fileMap}" var="entry">
            <tr>
                <td>${entry.value}</td>
                <td><a href="${pageContext.request.contextPath}/downLoad?filename=${entry.key}">下载</a></td>
            </tr>
        </c:forEach>
    </table>
</body>
</html>

3.3.2、DownLoadController

@WebServlet(name = "DownLoadController",value = "/downLoad")
public class DownLoadController extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        String basePath = request.getServletContext().getRealPath("/WEB-INF/upload");
        //UUID文件名
        String uuidFilename = request.getParameter("filename");
        //通过_拆分,UUID和源文件名称
        String filename = uuidFilename.split("_")[1];
        //通过工具类,使用源文件名称获得散列存储的路径,就是下载的路径
        String downPath = UploadUtils.newFilePath(basePath,filename);

        //设置响应头,响应的文件类型和如何处理该文件  附件下载
        response.setHeader("content-disposition","attachment;filename="+ URLEncoder.encode(filename,"UTF-8"));
        FileInputStream is = new FileInputStream(downPath+"\\"+uuidFilename);
        ServletOutputStream sos = response.getOutputStream();
        byte[] buffer = new byte[1024*1024*100];
        int len = 0;
        while((len=is.read(buffer))!=-1){
            sos.write(buffer,0,len);
        }

        sos.close();
        is.close();

    }

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

 

posted @ 2021-08-07 15:22  菜鸟的道路  阅读(177)  评论(0)    收藏  举报