JavaWeb上传原理和实现

1、介绍enctype

  • enctype 属性规定发送到服务器之前应该如何对表单数据进行编码。
  • enctype作用是告知服务器请求正文的MIME类型(请求消息头content-type的作用一样)

1、1 enctype的取值有三种

描述
application/x-www-form-urlencoded 在发送前编码所有字符(默认)
multipart/form-data 不对字符编码。每一个表单项分割为一个部件
text/plain 空格转换为 “+” 加号,但不对特殊字符编码。

1. 当enctype=’application/x-www-form-urlencoded’

这里写图片描述

2.当enctype=’multipart/form-data’

这里写图片描述
这里写图片描述
通过观察发现这个的请求体就发生了变化。这种请求体被称之为多部件请求体。
什么是多部件请求体:就是把每一个表单项分割为一个部件。
以请求头的content-type的boundary后面的一串随机字符串作为分割标识
普通表单项:

//name的意思是文本框里面name的属性值,而admin是我们输入的文本值
Content-Disposition: form-data; name="username"
admin

文件表单项

//filename的意思是:我们上传的文件名称,content-Type的意思是:MIME类型,asdasdas的意思是:文件里面的内容
Content-Disposition: form-data; name="upload"; filename="a.txt"
Content-Type: text/plain
asdasdas

3. 当enctype=’text/plain’

这里写图片描述
w3c称:空格会变成”+”加号,但是我这里没有发现,只有当get请求的时候,空格会变成”+”号
这里写图片描述

进入正题

完成上传需要满足3个必要的条件

  1. 提供form表单,method必须是post,因为get请求的传输数据一般为2kb,不同浏览器不一样。
  2. form表单属性enctype的必须是multipart/form-data
  3. 提供input type=”file”类的上传输入域

    大致实现原理:当enctype的值是multipart/form-data时,浏览器会把每个表单项进行分割,分割成不同的部件,以boundary的值为分割标识,这个标识的字符串是随机生成的,最后一个表单项的分割标识字符串末尾会多两个”- -“,代表结束。服务端用request.getHeader(“content-type”)获取分割字符串,然后进行解析。
    这里写图片描述

代码实现

一、开发环境搭建

准备两个第三方jar包
commons-io包
commons-upload包

代码实现

 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 判断表单的enctype值是不是"multipart/form-data"
        boolean isMultipartContent = ServletFileUpload
                .isMultipartContent(request);
        if (!isMultipartContent) {
            throw new RuntimeException("your form is not multipart/form-data");
        }
        // 创建一个DiskFileItemfactory工厂类
        DiskFileItemFactory factory = new DiskFileItemFactory();
        // 创建一个ServletFileUpload核心对象
        ServletFileUpload sfu = new ServletFileUpload(factory);
        // 解析request对象,并得到一个表单项的集合
        try {
            List<FileItem> fileItems = sfu.parseRequest(request);
            // 遍历表单项数据
            for (FileItem fileitem : fileItems) {
                if (fileitem.isFormField()) {
                    // 普通表单项
                    String fieldName = fileitem.getFieldName();
                    String fieldValue = fileitem.getString();
                    System.out.println(fieldName + "=====" + fieldValue);
                } else {
                    //上传表单项
                    //得到文件输入流
                    InputStream is = fileitem.getInputStream();
                    //创建文件存储目录
                    String directoryRealPath = this.getServletContext().getRealPath("WEB-INF/upload");
                    //创建文件路径
                    File storeDirectory = new File(directoryRealPath + File.separator + fileitem.getName());
                    //使用apache commons-io包,将输入流转成文件
                    FileUtils.copyInputStreamToFile(is, storeDirectory);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
posted @ 2018-06-02 11:11  诸秋白  阅读(2360)  评论(0编辑  收藏  举报