【Java之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();
        }
    }
}
  • 28
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值