文件上传


1. 文件上传注意事项

1、为保证服务器的安全,上传的文件应放在外界无法访问的目录下,如WEN-INF。

2、为防止同名文件产生覆盖现象,要为上传的文件产生一个唯一的文件名。

3、要限制上传文件的最大值。

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

2. 新建一个项目

  1. 新建一个空的java项目

  2. 在弹出的框里选择项目,然后选择jdk的版本和项目语言的版本。

  3. 在文件处新建模块

  4. 把web.xml的版本头更新

    <?xml version="1.0" encoding="UTF-8"?>
    
    
    
    

3. 用到的工具jar包

commons-io-2.6.jar

commons-fileupload-1.4.jar

maven pom.xml配置


    commons-io
    commons-io
    2.6



    commons-fileupload
    commons-fileupload
    1.4

4. 常用方法

//isFormFile方法用于判断FileItem类对象封装的数据是一个普通文本表单

//还是一个文件表单,如果时普通表单字段则返回true,否则返回false

boolean isField();

//getFieldName方法用于返回表单标签name属性的值

String getFieldName();

//getString方法用于将FileItem对象中保存的数据流内容以一个字符串返回

String getString();

//getName方法用于获得文件上传字段中的文件名。

String getName();

//以流的形式返回上传文件的数据内容。

InputStream getInputStream();

//delete方法用来清空FileItem类对象中存放的主体内容

//如果主体内容被保存在临时文件中,delete方法将删除该临时文件

void delete();

5. 文件上传Servlet

  1. 判断是否为上传文件的表单
  2. 创建文件保存地址和临时文件保存地址
  3. 创建DiskFileItemFactory对象,设置缓冲区大小,设置临时目录
  4. 创建ServletFileUpload对象(需传入DiskFileItemFactory对象)
  5. 通过ServletFileUpload对象设置文件上传进度监听
  6. 通过ServletFileUpload对象设置头文件编码格式避免乱码,设置单个文件大小,设置总文件大小
  7. 通过ServletFileUpload对象解析请求获取List列表
  8. 遍历List列表,用isFormField()方法判断每个FileItem对象是否为文件控件(是文件控件结果为false)
  9. 使用UUID解决文件名重复导致覆盖的问题
  10. 获取文件控件的输入流,传入文件保存地址,实现文件的上传
  11. 关闭流,清空临时文件
  12. 转发到前端页面
package com.feng.servlet;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;

public class FileServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //===========================1. 首先判断表单是否为上传文件的表单;==========================
        if (!ServletFileUpload.isMultipartContent(req)) {
            //普通表单=>终止方法;
            return;
        }

        String message = null;//传递给前端的信息

        try {
            //带文件的表单;

            //==========================2.1 创建上传文件的最终保存地址================================;
            String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
            //拿到上传文件时;若保存地址不存在就去创建保存目录;
            File uploadFile = new File(uploadPath);
            if (!uploadFile.exists()) {
                //创建目录;
                uploadFile.mkdir();
            }

            //===========================2.2使用缓存; 当文件过大时;先存为临时文件;========================
            String tempPath = this.getServletContext().getRealPath("/WEB-INF/temp");
            //拿到上传文件时;若保存地址不存在就去创建保存目录;
            File tempFile = new File(tempPath);
            if (!tempFile.exists()) {
                //创建临时目录;
                tempFile.mkdir();
            }

            //==============================3. 创建DiskFileItemFactory对象;=============================
            DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
            //设置缓冲区大小为 1M;大于这个缓冲区大小的文件,先存在临时文件目录里
            diskFileItemFactory.setSizeThreshold(1024 * 1024);
            //临时文件保存目录;
            diskFileItemFactory.setRepository(tempFile);

            //===============================4. 获取ServletFileUpload对象==================================
            //作用是处理上传文件数据,将表单的每一项输入封装为Fileltem对象;
            ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);

            //====================================5. 监听文件上传进度=======================================;
            servletFileUpload.setProgressListener(new ProgressListener() {
                //l:已上传的文件字节数; l1:要上传的文件的总字节数; i:上传第几个文件
                public void update(long l, long l1, int i) {
                    System.out.println("已经上传==>" + l + " -文件总大小==>" + l1 + "- 第"+i+"个文件");
                }
            });

            //=====================6. 通过ServletFileUpload对象设置头文件编码格式避免乱码,设置单个文件大小,设置总文件大小==================
            // 处理文件乱码;
            servletFileUpload.setHeaderEncoding("utf-8");
            //设置单个文件最大值; 3M
            servletFileUpload.setFileSizeMax(31 * 1024 * 1024);
            //设置总大小; 100M
            servletFileUpload.setSizeMax(100 * 1024 * 1024);

            //=======================7. 前端请求解析; 封装为fileItem对象的列表=================
            List fileItems = servletFileUpload.parseRequest(req);

            //======================8. 处理上传的文件================================
            for (FileItem fileItem : fileItems) {
                //判断是输入框还是上传文件的;
                //注意这个方法: 当返回 false 时才是文件类型的;
                if (fileItem.isFormField()) {
                    //获取其他标签框的name;
                    String name = fileItem.getName();
                    //处理乱码问题;(统一编码)
                    String value = fileItem.getString("utf-8");
                    System.out.println(name + "<--->" + value);
                } else {
                    //获取文件名;
                    String uploadName = fileItem.getName();
                    System.out.println("上传的文件名==>" + uploadName);

                    //对空文件名进行限制拦截;
                    if (uploadName == null || uploadName.trim().equals("")) {
                        continue;
                    }

                    //输入文件的名字;与后缀名;
                    String realName = uploadName.substring(uploadName.lastIndexOf("/") + 1);
                    String nameSuffix = uploadName.substring(uploadName.lastIndexOf(".") + 1);

                    System.out.println("文件名==>" + realName + "后缀文件类型=>" + nameSuffix);

                    //使用UUID生成的随机通用码保证文件唯一性;
                    String uploadFileID = UUID.randomUUID().toString();

                    //=================9. 使用UUID解决文件名重复导致覆盖的问题============
                    //文件真实地址加上uuid的通用码;
                    String realPath = uploadPath + "/" + uploadFileID;
                    File realFile = new File(realPath);
                    if (!realFile.exists()) {
                        //创建目录;
                        realFile.mkdir();
                    }

                    //===============================10. 获取文件控件的输入流,传入文件保存地址,实现文件的上传=========================;
                    InputStream inputStream = fileItem.getInputStream();
                    //输出流;
                    FileOutputStream out = new FileOutputStream(realPath + "/" + realName);
                    //创建传输的缓冲区;
                    byte[] bytes = new byte[1024];
                    int len = 0;
                    while ((len = inputStream.read(bytes)) > 0) {
                        out.write(bytes, 0, len);
                    }
                    //============11. 关闭流,清空临时文件==========
                    //关闭;释放资源;
                    out.close();
                    inputStream.close();
                    message = "<==上传成功==>";
                    //清除临时文件;
                    fileItem.delete();
                }
            }
        } catch (FileUploadException e) {
            message = "失败!!!";
            e.printStackTrace();
        }
        //========================12. 转发到前端页面=============
        //转发消息;
        req.setAttribute("message", message);
        req.getRequestDispatcher("info.jsp").forward(req, resp);
    }
}

以上内容参考自:狂神说java