VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > Java教程 >
  • 120_文件上传

准备工作

对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的。
一般采用Apache的开源工具common-fileupload这个文件上传组件。
common-fileupload是依赖于common-io这个包的,所以还需要下载这个包。

使用类介绍

文件上传注意事项

  1. 为保证服务器的安全,上传的文件应放在外界无法访问的目录下,如WEB-INF。
  2. 为防止同名文件产生覆盖现象,要为文件指定一个唯一的文件名。
  3. 要对上传文件的大小进行限制。
  4. 限制上传文件的类型,收到文件时,判断文件名是否合法。

需要用到的类详解

ServletFileUpload类

ServletFileUpload负责处理上传的文件数据,并将表单中的每个输入项封装成一个FileItem对象,在使用ServletFileUpload对象解析请求时需要DiskFileItemFactory对象。所以,我们需要在进行解析工作前构造好DiskFileItemFactory对象,通过ServletFileItem对象的构造方法或setFileItemFactory()设置ServletFileUpload对象的fileItemFactory属性。

FileItem类

在HTML页面中input必须要有name:<input type="file" name="fileName">
上传文件表单中如果包含一个文件上传项的话,这个表单的entype属性必须设置为multipart/form-data
浏览器的表单类型为multipart/form-data的话,服务器想获取数据就要通过流。

常用方法介绍

image.png
image.png

编写代码

maven库下载依赖包并引入

commons-fileupload-1.4.jar
commons-io-2.8.0.jar

image.png
image.png
出现问题提示:打包时不会打入lib目录下的jar,点击fix处理
image.png
处理成功
image.png
image.png

配置Tomcat

image.png

在gitee创建远程仓库并关联

创建远程仓库
image.png
创建本地仓库

Administrator@L87Y12K91TH8M2R MINGW64 /d/code/fileUpAndDown
$ git init
Initialized empty Git repository in D:/code/fileUpAndDown/.git/

Administrator@L87Y12K91TH8M2R MINGW64 /d/code/fileUpAndDown (main)
$ ll -a
total 24
drwxr-xr-x 1 Administrator 197121   0 Jun  2 23:25 ./
drwxr-xr-x 1 Administrator 197121   0 May 27 08:48 ../
drwxr-xr-x 1 Administrator 197121   0 Jun  2 23:25 .git/
drwxr-xr-x 1 Administrator 197121   0 Jun  2 23:26 .idea/
-rw-r--r-- 1 Administrator 197121 968 May 15 00:03 fileUpAndDown.iml
drwxr-xr-x 1 Administrator 197121   0 May 15 00:01 lib/
drwxr-xr-x 1 Administrator 197121   0 May 24 23:33 out/
drwxr-xr-x 1 Administrator 197121   0 May 14 23:56 src/
drwxr-xr-x 1 Administrator 197121   0 May 15 00:04 web/

Administrator@L87Y12K91TH8M2R MINGW64 /d/code/fileUpAndDown (main)

关联远程仓库,并拉取远程仓库文件

Administrator@L87Y12K91TH8M2R MINGW64 /d/code/fileUpAndDown (main)
$ git remote add origin git@gitee.com:wl3pbzhyq/fileUpAndDown.git

Administrator@L87Y12K91TH8M2R MINGW64 /d/code/fileUpAndDown (main)
$ git pull origin master
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (5/5), done.
remote: Total 5 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (5/5), 1.42 KiB | 7.00 KiB/s, done.
From gitee.com:wl3pbzhyq/fileUpAndDown
 * branch            master     -> FETCH_HEAD
 * [new branch]      master     -> origin/master

Administrator@L87Y12K91TH8M2R MINGW64 /d/code/fileUpAndDown (main)

配置忽略文件

# target
target/

# idea
.idea/
*.iml

image.png
提交main分支到远程仓库

D:\code\fileUpAndDown>git add .
warning: LF will be replaced by CRLF in out/artifacts/fileUpAndDown_war_exploded/WEB-INF/web.xml.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in out/artifacts/fileUpAndDown_war_exploded/index.jsp.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in web/WEB-INF/web.xml.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in web/index.jsp.
The file will have its original line endings in your working directory

D:\code\fileUpAndDown>git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   .gitignore
        new file:   .idea/vcs.xml
        new file:   lib/commons-fileupload-1.4.jar
        new file:   lib/commons-io-2.8.0.jar

D:\code\fileUpAndDown>git commit -m "初始化"
[main 0680e1f] 初始化
 31 files changed, 105 insertions(+)
 create mode 100644 .idea/vcs.xml
 create mode 100644 lib/commons-fileupload-1.4.jar
 create mode 100644 lib/commons-io-2.8.0.jar

D:\code\fileUpAndDown>git push --set-upstream origin main
Enumerating objects: 38, done.
Counting objects: 100% (38/38), done.
Delta compression using up to 4 threads
Compressing objects: 100% (27/27), done.
Writing objects: 100% (36/36), 662.53 KiB | 5.22 MiB/s, done.
Total 36 (delta 1), reused 0 (delta 0), pack-reused 0
remote: Powered by GITEE.COM [GNK-5.0]
remote: Create a pull request for 'main' on Gitee by visiting:
remote:     https://gitee.com/wl3pbzhyq/fileUpAndDown/pull/new/wl3pbzhyq:main...wl3pbzhyq:master
To gitee.com:wl3pbzhyq/fileUpAndDown.git
 * [new branch]      main -> main
Branch 'main' set up to track remote branch 'main' from 'origin'.

D:\code\fileUpAndDown>

编写表单

input必须要有name:<input type="file" name="fileName">
表单中如果包含文件上传项的话,这个表单的entype属性必须设置为multipart/form-data
浏览器的表单类型为multipart/form-data的话,服务器想获取数据就要通过流。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>

  <%--
  通过表单上传文件
  get:上传文件大小有限制
  post:上传文件大小没有限制
  表单中如果包含文件上传项的话,这个表单的entype属性必须设置为multipart/form-data
  浏览器的表单类型为multipart/form-data的话,服务器想获取数据就要通过流
  --%>
  <%--${pageContext.request.contextPath}获取服务器路径--%>
  <form action="${pageContext.request.contextPath}/upload.do" method="post" enctype="multipart/form-data">
    <p>上传用户:<input type="text" name="username"></p>
    <p><input type="file" name="file1"></p>
    <p><input type="file" name="file2"></p>
    <p><input type="submit"> | <input type="reset"></p>
  </form>

  </body>
</html>

image.png

编写文件上传Servlet,web.xml中注册

image.png

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>FileUploadServlet</servlet-name>
        <servlet-class>com.qing.servlet.FileUploadServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>FileUploadServlet</servlet-name>
        <url-pattern>/upload.do</url-pattern>
    </servlet-mapping>
</web-app>
package com.qing.servlet;

import org.apache.commons.fileupload.FileItem;
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.time.LocalDate;
import java.util.List;
import java.util.UUID;

public class FileUploadServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) {
        // 判断上传的表单是普通表单还是带文件的表单
        if (! ServletFileUpload.isMultipartContent(request)) {
            return; // 终止方法运行,这是一个普通表单
        }

        // 创建上传文件的保存目录,建议在WEB-INF路径下,安全,用户无法直接访问上传的文件
        String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
        File uploadDir = new File(uploadPath);
        if (! uploadDir.exists()) {
            uploadDir.mkdir(); // 创建文件上传目录
        }

        // 缓存,临时文件
        // 临时路径,假如文件超过了预期的大小,我们就把它放到一个临时目录中,过几天自动删除或者提醒用户转存为永久
        String tmpPath = this.getServletContext().getRealPath("/WEB-INF/tmp");
        File tmpDir = new File(tmpPath);
        if (! tmpDir.exists()) {
            tmpDir.mkdir(); // 创建临时目录
        }

        /*
        处理上传的文件,一般都需要通过流来获取,可以使用request.getInputStream(),原生态的文件上传流获取,十分麻烦
        建议使用Apache的文件上传组件来实现,common-fileupload,它需要依赖common-io组件
         */
        // 1.创建DiskFileItemFactory对象,负责处理文件上传路径或者大小限制
        DiskFileItemFactory factory = getDiskFileItemFactory(tmpDir);

        // 2.获取ServletFileUpload
        ServletFileUpload upload = getServletFileUpload(factory);

        // 3.处理上传的文件
        try {
            String msg = uploadParseRequest(request, uploadPath, upload);

            // Servlet请求转发消息
            request.setAttribute("msg",msg);
            request.getRequestDispatcher("info.jsp").forward(request,response);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (FileUploadException e) {
            e.printStackTrace();
        } catch (ServletException e) {
            e.printStackTrace();
        }

    }

    /**
     * 处理上传的文件
     * @param request
     * @param uploadPath
     * @param upload
     * @return
     * @throws IOException
     */
    private String uploadParseRequest(HttpServletRequest request, String uploadPath, ServletFileUpload upload) throws IOException, FileUploadException {
        StringBuilder msg = new StringBuilder();
        // 把前端请求解析,封装成一个FileItem对象(表单对象)
        List<FileItem> fileItems = upload.parseRequest(request);
        for (FileItem fileItem : fileItems) {
            // 判断表单是普通表单还是文件表单,普通表单返回true,文件表单返回false
            if (fileItem.isFormField()) {
                String name = fileItem.getFieldName();
                String vlaue = fileItem.getString("UTF-8");// 处理乱码
                System.out.println(name + ":" + vlaue);
            } else {
                System.out.println("=================处理文件==============================");
                String name = fileItem.getFieldName();
                String fileName = fileItem.getName();
                System.out.println(name + ":" + fileName);
                // 过滤文件名不合法的文件
                if (fileName == null || "".equals(fileName.trim())) {
                    continue;
                }
                // 获取文件后缀名,如果文件后缀名不是我们需要的文件类型,就直接return,告诉用户文件类型错误
                String fileExtName = fileName.substring(fileName.lastIndexOf(".") + 1);
                System.out.println("=================文件存放地址==============================");
                // 生成日期目录
                String datePath = LocalDate.now().toString();
                // 生成唯一目录
                String uuidPath = UUID.randomUUID().toString();
                // 组成文件实际路径
                String realPath = uploadPath + "/" + datePath + "/" + uuidPath;
                File realDir = new File(realPath);
                if (! realDir.exists()) {
                    // 注:创建多层目录使用mkdirs,mkdir只能创建一层目录
                    realDir.mkdirs();// 创建文件实际路径
                }
                System.out.println("=================文件传输==============================");
                // 获取文件上传输入流
                InputStream inputStream = fileItem.getInputStream();
                // 创建文件输出流
                FileOutputStream fos = new FileOutputStream(realPath + "/" + fileName);
                // 创建缓冲区
                byte[] buffer = new byte[1024 * 1024];
                // 判断是否读取完毕
                int len = 0;
                // 如果大于0,说明还存在数据
                while ((len = inputStream.read(buffer)) > 0) {
                    fos.write(buffer,0,len);
                }
                // 关闭流
                fos.close();
                inputStream.close();

                msg.append(fileName).append("文件上传成功!");
                fileItem.delete(); // 上传成功,清除临时文件
            }
        }
        return msg.toString();
    }

    /**
     * 获取ServletFileUpload
     * @param factory
     * @return
     */
    private ServletFileUpload getServletFileUpload(DiskFileItemFactory factory) {
        ServletFileUpload upload = new ServletFileUpload(factory);

        // 监听文件上传进度
        upload.setProgressListener(new ProgressListener() {
            @Override
            public void update(long read, long total, int i) {
                // read 已读取的文件大小
                // total 文件总大小
                System.out.println("总大小:" + total + ",已上传:" + read);
            }
        });

        // 处理乱码问题
        upload.setHeaderEncoding("UTF-8");
        // 设置单个文件的最大值
        upload.setFileSizeMax(1024 * 1024 * 10); // 10M
        // 设置总共能够上传文件的大小
        upload.setSizeMax(1024 * 1024 * 1000); // 1000M
        return upload;
    }

    /**
     * 创建DiskFileItemFactory对象,负责处理文件上传路径或者大小限制
     * @param tmpDir
     * @return
     */
    private DiskFileItemFactory getDiskFileItemFactory(File tmpDir) {
        DiskFileItemFactory factory = new DiskFileItemFactory();
        // 通过工厂设置一个缓冲区,当上传的文件大于缓冲区的时候,将它放到临时目录
        factory.setSizeThreshold(1024 * 1024); // 缓冲区大小为1M
        factory.setRepository(tmpDir); // 设置临时目录
        return factory;
    }
}

编写转发页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>

  ${msg}

  </body>
</html>

 
原文:https://www.cnblogs.com/wl3pb/p/14860069.html


相关教程