Java文件上传

本文转载自 文件上传与 Angular

最近项目需要使用 Angular,对于初学 Angular 的我只能硬着头皮上了,项目中有一个需求是文件上传,磕磕绊绊之下也实现了,将实现过程中学习到的一些知识记录下来以备将来查阅。

与表单数据编码相关的知识



通常,我们使用 HTML 的标签 <form> 来为用户输入创建一个表单,使用 <input type="file"> 作为文件上传的控件。

要将表单的数据发送给后台,不仅要通过指定 <form> 的属性 method 来确定发送数据的 HTTP 方法而且需要通过指定 <form> 的属性 enctype 来确定对发送数据的编码方式。

下面对这两个属性进行简单说明。

表单 form 的属性 method

<form> 的属性 method 规定用于发送 form-data 的 HTTP 方法,其值可以为 get 或者 postget 请求会将表单的数据编码后以 name1=value1&name2=value2 的形式附加到请求的 url 后面进行发送。post 请求会将表单的数据进行编码之后置于请求体中进行发送。

本文接下来的讨论主要基于 post 请求方式。

表单 form 的属性 enctype

<form> 标签的属性 entype 用来规定在发送表单数据之前应该如何对其进行编码,其实就是用来指定请求的编码类型。

enctype属性有 3 个取值,在 w3school 中对于其取值的描述如下:

取值 描述
application/x-www-form-urlencoded 空格转换为 "+" 加号,特殊符号转换为 ASCII HEX 值
multipart/form-data 不对字符编码。在使用包含文件上传控件的表单时,必须使用该值
text/plain 空格转换为 "+" 加号,但不对特殊字符编码

其中 application/x-www-form-urlencoded 是默认采用的编码的方式,如果表单 <form> 中有用到文件上传的控件,就要手动指定编码为 multipart/form-data

下面分别对上述这几种编码方式进行举例(均基于 post 请求方式)

  • 编码为 application/x-www-form-urlencoded 的情况

首先,构造一个表单:

<form method="post" action="/" enctype="application/x-www-form-urlencoded">
  <input type="text" name="name1" placeholder="name1">
  <input type="text" name="name2" placeholder="name2">
  <input type="submit">
</form>

在输入框内分别输入 i‘m name1 和 [email protected] ,根据编码规则,提交表单的时候,表单数据会被编码成 name1=i%27m+name1&name2=name%402 置于请求体中进行传递,在 chrome 浏览器中执行结果也正如预期所示。

以 application/x-www-form-urlencoded 编码来发送的表单数据

  • 编码为 multipart/form-data 的情况

编码为 multipart/form-data 的情况又有所不同,先来看看示例代码的结果。

示例代码:

<form method="post" action="/" enctype="multipart/form-data">
  <input type="text" name="name1" placeholder="name1">
  <input type="text" name="name2" placeholder="name2">
  <input type="file" name="inputfile">
  <input type="submit">
</form>

在输入框内分别输入 i‘m name1 和 [email protected] ,再选择一个名为 testfile.txt 的文件上传,可以在 chrome 中看到发送的请求如下:

以 multipart/form-data 编码来发送的表单数据

注意图片中的红框部分,Content-Type 值为 multipart/form-data; boundary=----WebKitFormBoundaryBdpfgMg4VKAZat6C ,其中多了一个叫做 boundary 的字段,它是由浏览器随机生成的一个字符串,作为表单数据的分割边界来使用的,在服务器端会根据这个 boundary 边界字段来解析表单数据。

可以明显看到,以边界分割的每一段均对应于一项表单数据,每项数据均包含有一个 Content-Disposition 字段和一个 name 字段,而对于上传的文件则会多一个指定上传文件名字的 filename 的属性和上传文件的类型的 Content-Type 字段,由于例子中上传的文件是 .txt 格式的文件,因此 Content-Type 的值为 text/plain,有关文件的扩展名和 Content-Type 的对照表可以看这里

  • 编码为 text/plain 的情况
    这种情况与编码为 application/x-www-form-urlencoded 的情况类似,唯一的差别就在于 text/plain 不对特殊字符进行编码。

文件上传的 Angular 实现


基于 FormData 的实现

实现的思路:通过 File API 获取控件中上传的文件,利用 FormData 类型构造表单数据上传。

基本知识:File API 和 FormData 类型
  • File API

File API(文件API)为Web 开发人员提供一种安全的方式来访问用户计算机中的文件,并更好地对这些文件执行操作。

具体来讲,File API 在表单中的文件输入字段的基础上,又添加了一些直接访问文件信息的接口。HTML5 在 DOM 中为文件输入元素添加了一个 files 集合。在通过文件输入字段选择了一或多个文件时,files 集合中将包含一组 File 对象,每个 File 对象对应着一个文件。

构造一个文件上传的表单,通过如下 jQuery 代码:

$("input[type=‘file‘]")[0].files

在 chrome 浏览器控制台中可以看到获得的信息如下:

可以看到选取的文件 testfile.txt 的相关信息,因此可以通过上述方式来获得上传的文件。

关于 File API 的更多叙述可以在这里获得。

  • FormData 类型

FormData 是在 XMLHttpRequest Level 2 中定义的,为序列化表单以及创建与表单格式相同的数据(用于通过XHR 传输)提供了便利。

下面这段对于 FormData 对象的描述引用自 MDN,更多关于 FormData 类型的叙述可以在这里获得。

XMLHttpRequest Level 2 添加了一个新的接口 FormData. 利用FormData 对象,我们可以通过 JavaScript 用一些键值对来模拟一系列表单控件,我们还可以使用 XMLHttpRequest 的 send() 方法来异步的提交这个"表单". 比起普通的 ajax, 使用 FormData 的最大优点就是我们可以异步上传一个二进制文件.

可见,我们可以使用 FormData 对象来模拟实现文件上传时候提交的表单数据,而构造提交的数据是通过 FormData 的方法 append() 实现的,它用于给当前 FormData 对象添加一个键/值对。

Angular 实现

有了上面所说的实现思路和基础知识,现在可以着手进行代码的实现了。

  • 首先,编写一个指令用来获取上传文件的 File 对象。

代码如下:

.directive( "fileModel", [ "$parse", function( $parse ){
  return {
    restrict: "A",
    link: function( scope, element, attrs ){
      var model = $parse( attrs.fileModel );
      var modelSetter = model.assign;

      element.bind( "change", function(){
        scope.$apply( function(){
          modelSetter( scope, element[0].files[0] );
          // console.log( scope );
        } )
      } )
    }
  }
}])

这个指令的使用方式如下:

<input type="file" file-model="fileToUpload">

对于 <input> 元素,在它们失去焦点且 value 值改变时会触发 change 事件,因此我们在指令的 link 函数中监听元素上的 change 事件,在事件响应函数中获取用户上传的文件信息,并且将该文件赋值给 $scope 对象中与指令 fileModel 绑定的属性(上例中为 fileToUpload)。

可以运行例子中的代码,选择一个文件 filetest.txt,打印出赋值后的 $scope 对象如下:

将获取的上传文件赋给 $scope 对象

如红框所示,$scope 的属性 fileToUpload 即是上传的文件 filetest.txt 的信息。

  • 然后,编写一个服务用于发送上传文件的 multipart/form-data 请求。

代码如下:

.service( "fileUpload", ["$http", function( $http ){
  this.uploadFileToUrl = function( file, uploadUrl ){
    var fd = new FormData();
    fd.append( "file", file )
    $http.post( uploadUrl, fd, {
      transformRequest: angular.identity,
      headers: { "Content-Type": undefined }
    })
    .success(function(){
      // blabla...
    })
    .error( function(){
      // blabla...
    })
  }
}])

在服务 fileUpload 的方法 uploadFileToUrl 中,通过 FormData 的 append() 方法将上传的文件序列化为表单数据,然后通过 $http.post() 方法发送给后台。

Angular 默认的 transformRequest 方法会尝试序列化我们的 FormData 对象,因此此处我们使用 angular.identity 函数来覆盖它;另外,angular 在发送 POST 请求的时候使用的默认 Content-Type 是 application/json,因此此处需要调整为 undefined,这时浏览器会自动的帮我们设置成 multipart/form-data 的编码方式,同时还会生成一个合适的 boundary,如果手动设置成 multipart/form-data 的话就不会生成 boundary 字段了。

  • 最后,在控制器的合适地方发送这个请求。

现在我们已经获得了上传的文件的相关信息,也有一个用于发送该文件的服务,那么只要在控制器中定义一个用于发送的函数,然后在合适的时机调用它即可将文件上传到后台去了。

举个例子,在控制器的 $scope 里面定义一个发送请求的函数 sendFile

.controller( "myCtrl", [ "$scope", "fileUpload", function( $scope, fileUpload ){
  $scope.sendFile = function(){
    var url = "/server",
        file = $scope.fileToUpload;
    if ( !file ) return;
    fileUpload.uploadFileToUrl( file, url );
  }
}])

然后我们可以定义一个按钮,当用户点击这个按钮的时候就会将上传的文件发送出去。

<button type="button" ng-click="sendFile()">Submit</button>

结果是这样的:

通过 FormData 上传文件的请求

兼容性

由于 FormData 只兼容 IE10+ ,因此上述方法也只是在 IE10+ 中可以使用。

如果你的应用需要兼容 IE8 ,老老实实封装一个含有 iframe 的指令即可,请接着往下看。

含有 iframe 的实现

指令代码如下

.directive( "iframeFileUpload", [function(){
  var inner = "<div>";
      inner +=    "<form action=\"/server\" method=\"post\" enctype=\"multipart/form-data\" target=\"uploadIframe\">";
      inner +=        "<input type=\"file\" name=\"filename\">";
      inner +=        "<input type=\"submit\">";
      inner +=      "</form>";
      inner +=      "<iframe id=\"uploadIframe\" name=\"uploadIframe\" style=\"display:none\"></iframe>";
      inner +=    "</div>";
  return{
    restrict: "A",
    template: inner,
    // or
    // templateUrl: "components/iframeFileUpload.html",
    replace: true,
    scope: {},
    link: function( scope, element, attrs ){
      // blabla...
    }
  }
}])

调用方式大概是这样的:

<div iframe-file-upload></div>
时间: 2024-10-01 02:49:29

Java文件上传的相关文章

Java文件上传的几种方式

文件上传与文件上传一样重要.在Java中,要实现文件上传,可以有两种方式: 1.通过Servlet类上传 2.通过Struts框架实现上传 这两种方式的根本还是通过Servlet进行IO流的操作. 一.通过Servlet类上传 1.编写Sevlet类 package com.chanshuyi.upload; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.

java文件上传-原始的Servlet方式

前言: 干了这几个项目,也做过几次文件上传下载,要么是copy项目以前的代码,要么是百度的,虽然做出来了,但学习一下原理弄透彻还是很有必要的.刚出去转了一圈看周围有没有租房的,在北京出去找房子是心里感觉最不爽的时候,没有归属感,房租还不便宜,RT,不能好高骛远,还是脚踏实地一点一点学技术吧,终将有一日,工资会涨的. java文件上传 传统的文件上传,不用jquery插件的话,就是用form表单提交,项目里用过uploadify,可以异步上传文件,原理我也没研究.现在说传统的form表单上传文件.

Java 文件上传 MultipartFile与ServletFileUpload

参考这个:https://www.cnblogs.com/liuyangv/p/8298997.html Java文件上传 MultipartFile 1. 配置MultipartResolver defaultEncoding="UTF-8"               是请求的编码格式,默认为iso-8859-1maxUploadSize="1048576"            是上传文件的大小,单位为字节uploadTempDir="fileUpl

java文件上传下载

文件上传首先要引入两个核心包 commons-fileupload-1.2.1.jar commons-io-1.4.jar 下面是对文件上传和下载的一些代码做的一个简单封装,可以方便以后直接使用[使用时将封装好的jar包直接导入工程中即可使用] 上传文件核心代码 1 package com.lizhou.fileload; 2 3 import java.io.File; 4 import java.io.FileOutputStream; 5 import java.io.IOExcepti

java 文件上传下载--基于ajaxFileUpload+struts2

jQuery插件ajaxFileUpload可以实现ajax文件上传,使用非常简单. 下面做一个简单的demo(以上传图片为例),实现图片上传,图片显示,图片下载 注:以下的代码是在项目的基础上进行开发.css样式文件.包路径等未做修改. 1. ajaxFileUpload文件下载地址http://www.phpletter.com/Demo/AjaxFileUpload-Demo/ 2.自行引入jquery.js.ajaxFileUpload.js文件 jsp核心代码: [html] view

java文件上传模块

今天做了一下java的简单的文件上传,使用的是commons-fileupload-1.3.1.jar.依赖于commons-io-2.4.jar.所以在导入包的时候也需要导入这个commons-io-2.4.jar.至于版本之间的关系,我并没有好好的去看,我使用的这两个还是很很友好合作的. 使用这两个包来上传文件到服务器端,是比较简单的.大致的就分为两个部分,一个是html页面部分的设置,一个是servlet部分的代码. html页面 1 <form action="uploadFile

java文件上传与下载

不多说,直接上实例代码!!! 我使用的是idea工具,maven管理. 首先,在pom.xml引入上传文件所需要的包. <!--fileupload--> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </depe

java文件上传-使用apache-fileupload组件

目前文件上传的(框架)组件:Apache----fileupload .Orialiy – COS – 2008() .Jsp-smart-upload – 200M. 用fileupload上传文件: 需要导入第三方包: Apache-fileupload.jar – 文件上传核心包. Apache-commons-io.jar – 这个包是fileupload的依赖包.同时又是一个工具包. 使用springmvc,解决烦人的post乱码问题,新建maven项目: maven依赖: <depe

java文件上传Demo

说到文件上传我们要做到: 1.引入两个包:commons-fileupload-1.2.1.jar和commons-io-1.3.2.jar 2.将form改为上传文件模式:enctype="multipart/form-data" 3.开始编写相关代码 这里会用到几个关键的类:磁盘文件工厂DiskFileItemFactory : 创建servlet文件上传类:ServletFileUpload 还有几个重要的方法:DiskFileItemFactory类用于将以临时文件形式保存在磁

28、java文件上传下载、邮件收发

文件上传下载 前台: 1. 提交方式:post 2. 表单中有文件上传的表单项: <input type="file" /> 3. 指定表单类型: 默认类型:enctype="application/x-www-form-urlencoded" 文件上传类型:multipart/form-data FileUpload 文件上传功能开发中比较常用,apache也提供了文件上传组件! FileUpload组件: 1. 下载源码 2. 项目中引入jar文件