JavaEE精选-FileUpload

简介: JavaEE精选-FileUpload

准备工作

1.需要form表单,input type=file 组件

2.form表单方法post

3.form表单必须要设置enctype=multipart/form-data,可以上传除了表单数据(文本)以外的数据

4.如果要使用JavaBean来封装的话,那么这个file属性的组件的name要和封装的对象中的属性相同

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/servlet/upload" enctype="multipart/form-data" method="post">
    <input type="text" name="username"><br>
    <input type="password" name="password"><br>
    <input type="file" name="image"><br>
    <input type="submit">
</form>
 </body>
</html>

此时注意,由于设置了enctype=multipart/form-data导致请求体报文的格式改变,那么就不能使用普通的读取方式了,否则会导致在二进制文件中写入字符而报错

------WebKitFormBoundaryrYApx85v3VoXeztu
Content-Disposition: form-data; name="username"
admin
------WebKitFormBoundaryrYApx85v3VoXeztu
Content-Disposition: form-data; name="password"
admin123
------WebKitFormBoundaryrYApx85v3VoXeztu
Content-Disposition: form-data; name="image"; filename="1.txt"
Content-Type: text/plain
hello  你好
------WebKitFormBoundaryrYApx85v3VoXeztu--

必须要剔除分隔符的部分,需要引入第三方组件来解决

使用组件完成文件上传

使用组件整体的思路:

  • 首先需要判断请求是否包含上传的文件,否则使用该组件没有意义
boolean multipartContent = ServletFileUpload.isMultipartContent(request);
  • 创建工厂,设置文件缓存,获取upload对象
DiskFileItemFactory factory = new DiskFileItemFactory();//创建工厂
ServletContext servletContext = getServletContext();//获取Context域,用于缓存
File repository = (File)servletContext.getAttribute("javax.servlet.context.tempdir");//创建一个缓存的中转站
factory.setRepository(repository);
ServletFileUpload upload = new ServletFileUpload(factory);//利用工厂创建一个upload对象,功能是帮我们处理请求报文中上传的部分
upload.setHeaderEncoding("utf-8");
  • 使用upload对象对请求报文进行解析,将每一个input框中的内容解析成FileItem,得到的是一个List
  • item实际上就是input中上传的文本参数或者是文件,根据不同的文件来实现具体的业务逻辑,分发给不同的方法来进行处理
try {
    List<FileItem> items = upload.parseRequest(request);//处理请求报文对象
    for (FileItem item : items) {
        //item本质上是页面上的input框中包含的文本、文件
        if (item.isFormField()){
            //如果是普通的表单数据,作出表单数据的处理
            processFormField(item);
        }else {
            //处理上传文件
            processUploadFile(item);
        }
    }
} catch (FileUploadException e) {
    e.printStackTrace();
}
private void processFormField(FileItem item) {
    //具体处理表单数据的方法
    String fieldName = item.getFieldName();//相当于获取请求参数中的key
    String value = null; //获取value
    try {
        value = item.getString("utf-8");//处理表单数据的中文乱码
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    System.out.println(fieldName+":"+value);
}
  • 处理上传数据
private void processUploadFile(FileItem item) {
        String fieldName = item.getFieldName();//文件属性名
        String fileName = item.getName();//文件名
//        String contentType = item.getContentType();//获取文件类型名mni
//        long size = item.getSize();//文件大小
//        boolean inMemory = item.isInMemory();//是否在内存中
        String realPath = getServletContext().getRealPath("image/" + fileName);//获取该文件要存放在服务器硬盘上的绝对路径
        File file = new File(realPath);
        if (!file.getParentFile().exists()){
            //如果该文件的父路径不存在,那么需要进行创建
            file.getParentFile().mkdirs();
        }
        try {
            item.write(file); //直接将该item写入硬盘
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

中文乱码

表单中文乱码

//表单中文乱码的解决方案
value = item.getString("utf-8");

setEncoding失效,因为此时文件的格式已经变了,之前都是key=value

上传的文件名中文乱码

//设置上传的文件名中文乱码
upload.setHeaderEncoding("utf-8");

将数据保存到Java Bean

思路:在具体分发的处理方法中,传入一个map对象,用于保存键值对,键可以设置为JAVA Bean中的属性名,值设置为一个object,用于保存具体的参数类型;最后在所有的Item处理完毕后,将map使用BeanUtils进行处理,就完成了封装

package com.fh.upload;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@WebServlet("/upload2")
public class UploadServlet2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
//        request.setCharacterEncoding("utf-8");
        boolean multipartContent = ServletFileUpload.isMultipartContent(request);//判断是否有上传的文件
        if (!multipartContent){
            //如果不存在该文件,那就直接返回
            System.out.println("你没有上传文件!");
            return;
        }
        DiskFileItemFactory factory = new DiskFileItemFactory();//创建工厂
        ServletContext servletContext = getServletContext();//获取Context域,用于缓存
        File repository = (File)servletContext.getAttribute("javax.servlet.context.tempdir");//创建一个缓存的中转站
        factory.setRepository(repository);
        ServletFileUpload upload = new ServletFileUpload(factory);//利用工厂创建一个upload对象,功能是帮我们处理请求报文中上传的部分
        upload.setHeaderEncoding("utf-8"); //解决上传文件名的中文乱码
        Map<String,Object> map = new HashMap<>();
        User user = new User();
        try {
            List<FileItem> items = upload.parseRequest(request);//处理请求报文对象
            for (FileItem item : items) {
                //item本质上是页面上的input框中包含的文本、文件
                if (item.isFormField()){
                    //如果是普通的表单数据,作出表单数据的处理
                    processFormField(item,map);
                }else {
                    //处理上传文件
                       processUploadFile(item,map);
                }
            }
        } catch (FileUploadException e) {
            e.printStackTrace();
        }
        try {
            BeanUtils.populate(user,map);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        getServletContext().setAttribute("user",user);//将user传到共享域
        response.setHeader("refresh","6;url="+request.getContextPath()+"/view");
    }
    private void processUploadFile(FileItem item, Map<String, Object> map) {
        String fieldName = item.getFieldName();//文件属性名
        String fileName = item.getName();//文件名
//        String contentType = item.getContentType();//获取文件类型名mni
//        long size = item.getSize();//文件大小
//        boolean inMemory = item.isInMemory();//是否在内存中
        String relativePath  = "image/"+fileName;
        String realPath = getServletContext().getRealPath(relativePath);//获取该文件要存放在服务器硬盘上的绝对路径
        File file = new File(realPath);
        if (!file.getParentFile().exists()){
            //如果该文件的父路径不存在,那么需要进行创建
            file.getParentFile().mkdirs();
        }
        try {
            item.write(file); //直接将该item写入硬盘
            map.put("img",relativePath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private void processFormField(FileItem item, Map<String, Object> map) {
        //具体处理表单数据的方法
        String fieldName = item.getFieldName();//相当于获取请求参数中的key
        String value = null; //获取value
        try {
            value = item.getString("utf-8");//处理表单数据的中文乱码
        } catch (UnsupportedEncodingException e)    {
            e.printStackTrace();
        }
        map.put(fieldName,value);
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }
}

工具类

package com.fh.upload;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class FileUploadUtil {
    public static Map<String, Object> parseRequest(HttpServletRequest request){
        //解析请求报文,终极目标是返回一个该请求报文中所有参数的列表,并完成文件上传的工作
        DiskFileItemFactory factory = new DiskFileItemFactory();//创建工厂
        ServletContext servletContext = request.getServletContext();//获取Context域,用于缓存
        File repository = (File)servletContext.getAttribute("javax.servlet.context.tempdir");//创建一个缓存的中转站
        factory.setRepository(repository);
        ServletFileUpload upload = new ServletFileUpload(factory);//利用工厂创建一个upload对象,功能是帮我们处理请求报文中上传的部分
        upload.setHeaderEncoding("utf-8"); //解决上传文件名的中文乱码
        Map<String,Object> map = new HashMap<>();
        try {
            List<FileItem> items = upload.parseRequest(request);//处理请求报文对象
            for (FileItem item : items) {
                //item本质上是页面上的input框中包含的文本、文件
                if (item.isFormField()){
                    //如果是普通的表单数据,作出表单数据的处理
                    processFormField(item,map);
                }else {
                    //处理上传文件
                    processUploadFile(item,map,request);
                }
            }
        } catch (FileUploadException e) {
            e.printStackTrace();
        }
        return map;
    }
    private static void processUploadFile(FileItem item, Map<String, Object> map, HttpServletRequest request) {
        String fieldName = item.getFieldName();//文件属性名
        String fileName = item.getName();//文件名
        fileName = UUID.randomUUID().toString() + "-" + fileName; //随机生成一个文件名,防止重复
        //对文件上传进行散列
        int hashCode = fileName.hashCode();
        String hexString = Integer.toHexString(hashCode); //生成一个16进制的哈希值,每一位都分别创建子目录,完成散列
        char[] chars = hexString.toCharArray();
        String basePath = fieldName; //总的一个父路径,所有下属的文件夹都放在这个父路径里,根据不同的文件类型生成
        for (char aChar : chars) {
            basePath = basePath + "/" + aChar;
        }
        String relativePath = basePath + "/" + fileName; //最终用文件总的父路径拼接文件名,那么就得到了文件要存放在硬盘上的相对路径
        //需要根据相对路径获取存储到服务器磁盘的绝对路径,显然需要一个request对象
        String realPath = request.getServletContext().getRealPath(relativePath);
        File file = new File(realPath);
        if (!file.getParentFile().exists()){
            //父路径不存在,那就创建
            file.getParentFile().mkdirs();
        }
        try {
            item.write(file);
            map.put(fieldName,relativePath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private static void processFormField(FileItem item, Map<String, Object> map) {
        String name = item.getFieldName();
        String value = null;
        try {
            //表单中文乱码的解决方案
            value = item.getString("utf-8");
            map.put(name, value);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}
目录
相关文章
|
编译器
【Bug】8086汇编学习
随笔 与汇编的灵活与底层所伴随的,是使用者极大的心智负担。 模块之间的隔离性很难控制。甚至多个子程序间的标号也不能相同,故子程序无法独立开发后直接集成。
328 5
|
1天前
|
存储 JavaScript 前端开发
JavaScript基础
本节讲解JavaScript基础核心知识:涵盖值类型与引用类型区别、typeof检测类型及局限性、===与==差异及应用场景、内置函数与对象、原型链五规则、属性查找机制、instanceof原理,以及this指向和箭头函数中this的绑定时机。重点突出类型判断、原型继承与this机制,助力深入理解JS面向对象机制。(238字)
|
2天前
|
安全 数据可视化 网络安全
安全无小事|阿里云先知众测,为企业筑牢防线
专为企业打造的漏洞信息收集平台
1300 2
|
3天前
|
云安全 人工智能
2025,阿里云安全的“年度报告”
拥抱AI时代,阿里云安全为你护航~
1447 2
|
10天前
|
机器学习/深度学习 安全 API
MAI-UI 开源:通用 GUI 智能体基座登顶 SOTA!
MAI-UI是通义实验室推出的全尺寸GUI智能体基座模型,原生集成用户交互、MCP工具调用与端云协同能力。支持跨App操作、模糊语义理解与主动提问澄清,通过大规模在线强化学习实现复杂任务自动化,在出行、办公等高频场景中表现卓越,已登顶ScreenSpot-Pro、MobileWorld等多项SOTA评测。
1406 7
|
11天前
|
人工智能 Rust 运维
这个神器让你白嫖ClaudeOpus 4.5,Gemini 3!还能接Claude Code等任意平台
加我进AI讨论学习群,公众号右下角“联系方式”文末有老金的 开源知识库地址·全免费
1285 16
|
4天前
|
人工智能 前端开发 API
Google发布50页AI Agent白皮书,老金帮你提炼10个核心要点
老金分享Google最新AI Agent指南:让AI从“动嘴”到“动手”。Agent=大脑(模型)+手(工具)+协调系统,可自主完成任务。通过ReAct模式、多Agent协作与RAG等技术,实现真正自动化。入门推荐LangChain,文末附开源知识库链接。
496 118
|
1天前
|
人工智能 自然语言处理 API
n8n:流程自动化、智能化利器
流程自动化助你在重复的业务流程中节省时间,可通过自然语言直接创建工作流啦。
290 3
n8n:流程自动化、智能化利器
|
3天前
|
机器学习/深度学习 测试技术 数据中心
九坤量化开源IQuest-Coder-V1,代码大模型进入“流式”训练时代
2026年首日,九坤创始团队成立的至知创新研究院开源IQuest-Coder-V1系列代码大模型,涵盖7B至40B参数,支持128K上下文与GQA架构,提供Base、Instruct、Thinking及Loop版本。采用创新Code-Flow训练范式,模拟代码演化全过程,提升复杂任务推理能力,在SWE-Bench、LiveCodeBench等基准领先。全阶段checkpoint开放,支持本地部署与微调,助力研究与应用落地。
389 1
|
2天前
|
安全 API 开发者
手把手带你使用无影 AgentBay + AgentScope 完成一站式智能体开发部署
阿里云无影 AgentBay 作为一个面向 AI 智能体开发的云端 GUI 沙箱服务,已集成至阿里巴巴通义实验室开源的 AgentScope 框架,助力开发者快速构建安全、高效的智能体应用。
233 1

热门文章

最新文章