获取form-data的数据——apache.commons.fileupload

travel.corechan.cn

最近刚入门java后台,用原生java写的项目,记录一下其中遇到的问题以及解决——图片上传。

post方法详细

概述

不知道现在技术最常用的方案是啥,我看了许多文章才知道,原来我用了这么多的post方法接数据,其实post上传数据光是格式就有许多种:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • application/json
  • text/xml

这个是参考大佬的博客看到的:四种常见的POST提交数据方式 写的很详细。

看了这篇文章我才知道原来之前我没管前端的哥们儿发的啥,我都是用req.getParameter(“”)接的数据,能接到数据而且甚至不用decode就能正常显示也不是没道理的,post请求默认就是发的x-www-form-urlencoded。文字就说了encoded咯。

form-data实战

首先感谢另一位大佬关于form-data的讲解:
Java中,当表单含有文件上传时,提交数据的如何读取

这里使用了apache.commons.fileupload.jar的包,据说是比较常用的方案。如果想了解不引包怎么解决问题,我这篇博客没啥用。

不引包的话需要在request.getInputStream,然后去解析数据流,自己造轮子比较容易出错,在这里表示不推荐。

具体操作我写了个demo,注释比较详细

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

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.util.Enumeration;
import java.util.List;

@WebServlet(urlPatterns = "/test")
public class TestServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //允许跨域访问
        resp.setHeader("Access-Control-Allow-Origin","*");
        //设置各种过滤器
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("UTF-8");
        //输出请求的类型
        System.out.println(req.getContentType());
        //这一段是获取参数并且输出参数名和值,用的是常规方法
        Enumeration parameterNames = req.getParameterNames();
        resp.getWriter().println("------这是parameter部分------");
        while (parameterNames.hasMoreElements()) {
            String name = parameterNames.nextElement();
            resp.getWriter().println(name + "\t" + req.getParameter(name));
        }
        //处理form-data
        boolean isMultipart = ServletFileUpload.isMultipartContent(req);
        //首先要new一个专门生产FileItem的工厂,fileitem是通过调包解析请求数据后,数据存储的对象
        DiskFileItemFactory factory = new DiskFileItemFactory();
        //设置临时文件大小(有时候可能传的文件太大,需要使用临时文件)
        factory.setSizeThreshold(1024 * 1024);
        //设置临时文件存放的位置
        factory.setRepository(new File("testcore"));
        //工厂相关的参数设置完成后,以工厂为模版,new一个upload实例
        ServletFileUpload upload = new ServletFileUpload(factory);
        if (isMultipart) {
            try {
                //用upload实例解析request,并将解析的结果放在List里面
                //每一个FileItem实际就是form-data中的键值对
                List items = upload.parseRequest(req);
                resp.getWriter().println("------这是form-data部分------");
                //遍历items
                for (FileItem item : items) {
                    //判断当前item是不是表单域(也就是表单域中的文字信息)
                    if (item.isFormField()) {
                        //获取这个键值对的键和值,并输出
                        String name = item.getFieldName();
                        String value = item.getString();
                        resp.getWriter().println(name + "\t" + value);
                    } else {
                        //如果不是表单域,则说明这是个文件,获取文件的相关信息并输出
                        String name = item.getName();
                        String field = item.getFieldName();
                        long size = item.getSize();
                        String type = item.getContentType();
                        String url = "/testcore/" + name;
                        resp.getWriter().println(field + "\t" + type + "\t" + size + "b\t" + url);
                        //既然已经拿到文件了(文件在内存里),那么就把它写到硬盘里吧
                        File file = new File(getServletConfig().getServletContext().getRealPath("testcore"), name);
                        if (!file.getParentFile().exists()) {
                            if (file.getParentFile().mkdir())
                                //写入硬盘
                                item.write(file);
                        } else
                            //写入硬盘
                            item.write(file);
                        //打印文件在硬盘里的绝对路径
                        System.out.println(file.getAbsolutePath());
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

总结

form-data有几个要注意的点:

  • form-data发到后台上的数据是不会帮你encode的,毕竟文件就是二进制流,完全没有encode的必要性。所以在form-data里发文字之前请前端的同学先urlencode一下
  • java后台处理文件内容,如果保存的位置需要新建文件夹,记得要先mkdir,不然会尴尬的报错“找不到文件位置”,具体来说就是这样,先是错误的示范:
//错误的示范
//假设我文件要存在后台根目录的testcore文件夹下的savepath文件夹中,以savename为文件名
File file=new File("/testcore/"+savepath,savename);
fileItem.write(file);
//正确的示范
File file=new File("/testcore/"+savepath,savename);
//先判断存这个文件的目录存不存在,存在就好咯,直接写入硬盘
if(file.getParentFile.exist())
    fileItem.write(file);
else
    //如果不存在,就创建这个目录,如果创建成功,就写入硬盘
    if(file.getParentFile.mkdir())
        fileItem.write(file);
    //万一创建不成功……就抛出异常什么的,这个就自行处理吧

撒花完结

你可能感兴趣的:(java后台)