JavaWeb文件上传的实现

本文介绍文件上传过程中的关键处理技巧,包括确保服务器安全、解决中文乱码问题、防止重名文件覆盖、合理分目录存储、限制文件类型与大小、处理多文件上传、监听上传进度、避免重复上传等方面的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.如何保证服务器的安全

  • 我们要把上传的文件转移到通过静态资源访问不到的地方(放到WEB-INF下,nginx反向代理)
    2.中文乱问题
  • 首先要统编码,页面和服务器工程编码要统一
  • 用过滤器处理字符,达到统一编码的的目的
  • 跨域问题,过滤器可以使用
    3.重名文件被覆盖
  • uuid
  • 文件名+时间是不可取得(因为解决不了并发问题),时间+随机数
    4、如何分目录存储上传的文件
    • 根据具体业务来分文件夹。可以每天生成一个文件夹(为什么?)
      操作系统存储文件,每个文件夹存储文件的数据量是有极限的
      举例:先按用户、然后再按日期

5、限制用户上传的文件类型(不要简单地判断文件后缀)
1、实际上是要获取ContentType(),来判断这个文件类型

6、限制用户上传文件的大小(服务器端,不要等到上传完了才判断)
抓取异常信息来判断
FileSizeLimitException

7、删除临时文件的问题
临时文件对于我们的实际数据是没有什么意义的,它就相当于上传时的缓存
那么,上传完了以后,临时文件可以删掉,可以节省出一下磁盘空间

一定要在关闭流之后再删

8、多文件上传的问题
主要解决,没有文件上传,如何去判断
文件个数限制

9、如何监听上传进度(我相信很多人都没有去想办法解决过)
1、添加ServletUpload监听,重写update方法
2、实现接口ProgressListener(从服务端来监听文件上传进度,客户端是用定时器去不断地请求后台,获取上传进度)

10、如何避免已经上传的文件重复上传到服务器
计算文件的 MD5 值,文件的MD5值可以代表一个文件的唯一标示,如果两个文件的MD5值相等,可以认为文件是一致的; (已上传的文件的md5的值可以存储到数据库,每上传一个文件的时候对比下已上传的文件md5有没有在数据库中存在,上传完成再保存md5值,删除文件去删除数据库中的MD5值就行了)
代码实现
1.编写上传界面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%--
method
--%>
<form action="${pageContext.request.contextPath}/upload.do" enctype="multipart/form-data" method="post">
<p>上传用户:<input type="text" name="username"></p>
<p>选择文件:<input type="file" name="uploadfile"></p>
<p><input type="submit"></p>
</form>
</body>

在这里插入图片描述
在这里插入图片描述
2写servlet类

package com.wang.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.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 FileLoaderServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        //判断上传的文件时普通的表单的还是带文件的表单
        if (!ServletFileUpload.isMultipartContent(request)) {
            //如果是普通文件,我们可以直接返回
            return;
        }//如果通过了这个if,说明我我们的表单是带文件的上传的

        //创建上传文件的保存路径,建议在web-inf,安全,用户无法直访问上传的文件
        String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
        File uploadFile = new File(uploadPath);
        if (!uploadFile.exists()) {//如果目录不存在,创建这样一个目录;
            uploadFile.mkdir();
        }

        //临时文件
        String tmpPath = this.getServletContext().getRealPath("/WEB-INF/tmp");

        File file = new File(tmpPath);
        if (!file.exists()) {//如果不存在,就创建这样一个目录
            file.mkdir();
        }
        //处理上传文件,一般都需要通过流来获取,我们可以使用request。getInputStream(),原生态的文件上传流,十分麻烦

        //1.创建DiskFileItemFactory对象,处理文件上传路径或者大小限制的
        DiskFileItemFactory factory = getDiskFileItemFactory(file);
        //2.获取ServletFileUpload
        ServletFileUpload upload = getServletFileUpload(factory);

        //3.处理上传的文件
        String msg = uploadParseRequest(request, uploadPath, upload);
        //servlet请求转发消息
        request.setAttribute("msg",msg);
        request.getRequestDispatcher("info.jsp").forward(request,response);

        //监听文件上传速度
    }

    public DiskFileItemFactory getDiskFileItemFactory(File file) {
        DiskFileItemFactory factory = new DiskFileItemFactory();
        factory.setSizeThreshold(1024 * 1024);
        factory.setRepository(file);
        return factory;
    }
    private static ServletFileUpload getServletFileUpload(DiskFileItemFactory factory) {
        ServletFileUpload upload = new ServletFileUpload(factory);

        upload.setProgressListener(new ProgressListener() {
            @Override
            public void update(long pBytesRead, long pContentLength, int pItems) {
                System.out.println("总大小" + pContentLength + "以传上" + pBytesRead);

            }
        });
        upload.setHeaderEncoding("UTF-8");

        //设置总共能够上传文件的大小
        upload.setFileSizeMax(1024*1024*10);
        //设置总共能够上传文件的大小
        upload.setSizeMax(1024*1024*10);

        return upload;
    }

    private static String uploadParseRequest(HttpServletRequest request, String uploadPath, ServletFileUpload upload) throws IOException {
            String msg="";
        try {
            List<FileItem> fileItems = upload.parseRequest(request);
            for (FileItem fileItem : fileItems) {
                if (fileItem.isFormField()) {
                    String name = fileItem.getFieldName();
                    String value = fileItem.getString("UTF-8");
                    System.out.println(name + ":" + value);
                } else {
                    String uploadFilename = fileItem.getName();
                    System.out.println("上传的文件名" + uploadFilename);
                    if (uploadFilename.trim().equals("") || uploadFilename == null) {
                      continue;
                    }
                    //获得上传的文件名,/images/girl/projie.pang
                    String fileName = uploadFilename.substring(uploadFilename.lastIndexOf("/" )+1);
                    System.out.println(fileName);
                    String fileExtName = uploadFilename.substring(uploadFilename.lastIndexOf(".") + 1);

                    /*
                     * 如果文件后后缀名 fileExtName 不是我们所需要的
                     * 就直接return,不处理,告诉用户文件类型不对*/

                    System.out.println("文件信息,文件名:" + fileName + "文件类型" + fileExtName);
                    //可以试试用UUID(唯一识别的通用吗),保证文件唯一
                    String uuidFileName = UUID.randomUUID().toString();
                    //存到哪?
                    //文件真实存在的路径
                    String realPath = uploadPath + "/" + uuidFileName;
                    //给每个文件创建一个对应的文件夹
                    File realPathFile = new File(realPath);
                    if (!realPathFile.exists()) {
                        realPathFile.mkdir();
                    }
                    //获得文件上传的流
                    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="文件上传成功";
                    fileItem.delete();//上传成功,清除临时文件


                }
            }
        } catch (FileUploadException e) {
            e.printStackTrace();
        }
        return msg;
    }
}

3.写一个提示上传成功的jsp提示页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>提示信息</title>
</head>
<body>
${msg}
</body>
</html>

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值