今天在写一个文件上传的时候遇到了 问题 ! 无论如何都检索不到有上传的文件。上传的结果都只有文件的路径,上传的文件夹内一直没有文件。琢磨了好长时间,才解决问题。
客户端。
- 首先,我们看下页面的代码。这里以上传图片的代码为例。
我使用的是 layui 的官方框架。
form 表单提交,带有附件的时候,需要设置 enctype="multipart/form-data" 图中已给出。
2. 紧接着,开始 使用 JQuery Ajax 对图片进行异步上传。
3. 这样后台就能够接收到带有附件表单上传的数据。
一、之前我经常使用的 AJAX 是这样的。
- 写一个简单的 ajax 访问:
$.ajax({
url:"", // 请求后台方法。
type:"get", // 请求方式
cache:false, // 控制是否缓存数据
async:false, // 控制同步还是异步
data:{
id:1
// 传入数据
},
success:function(data){
if(data != null && data != ""){
$(".showdata").html(data); // 从后台成功获取数据的回调函数
}
},
error:function(){
alert("网络错误,请重试 !!");
}
});
- 使用的时候 需要注意两点信息
- cache属性,默认是 true ,就是页面需要缓存。有些时候修改了值,但是值没变,都是由于缓存的原因。ajax 请求存在着许多缓存问题。
请求方式为 post 的时候,默认为 false ;请求方式为 get 的时候,默认为 true 。
- async属性,默认是 true,决定本次执行的 ajax 请求是异步的。
同步指的是:像后台代码一样,一行一行的执行。异步指的是:ajax 请求还没有执行完成就去执行下一句 js 。
- ajax 简单来说,就是请求后台,获取数据回调,然后页面展示。
二、但是 AJAX 文件上传更应该注意下面的内容。
- 经常用 ajax 的人都知道,ajax 的默认编码方式是 “application/x-www-form-urlencoded”,此编码方式只能编码文本类型的数据,因此 ajax 发送请求的时候,会把 data 序列化成一个个
String 类型的键值对
,大部门应用都可以满足。- 就是上述的原因,导致今天的错误。所以此序列化机制是文件上传的绊脚石。
- 我们需要做的是,(1)获取表单的内容,赋值给 ajax 的data;(2)阻止将参数转成String类型的键值对。
- FormData 是 html5 的接口,使用它一行代码便可以拿到整个表单的内容。
var form = new FormData(document.getElementById("mulform"));
// mulform 是表单的 id 。
- 设置 process 属性,阻止转成 String 类型的字符串。同时设置 ajax 的编码方式为false(contentType:fals),在 form 表单里已经设置了编码方式,ajax 的编码机制已经不需要。
$.ajax({
url : "../../addActivity.action",
type : "post", // 默认 对应的 cache:false
dataType : "json",
processData:false,
contentType:false,
data:form,
success : function(data){
location.reload();
},
error:function(){
top.layer.msg("网络错误,请重试 !!");
}
});
务必 使用 post 的请求方式,
。
contentType 的编码方式:
- application/x-www-form-urlencoded:String 类型的键值对。
- multipart/form-data:支持文件上传。
- application/json类型主要是传递json数据用到,层次比较深的数据。
- text/plain:窗体数据以纯文本形式进行编码,其中不含任何控件或格式字符。
2.1 其中的关键要素。
- contentType:(默认的编码方式 “application/x-www-form-urlencoded”)发送信息至服务器时内容编码类型。
- processData:(默认 true )默认情况下,通过 data 属性传进来的数据,都会转化成一个字符串,配合默认内容类型"application/x-www-form-urlencoded",如果要发送 DOM 树、文件内容或其他希望转换的信息,需要设置为 true 。
- FormData :利用 这个对象,我们可以通过 JavaScript 用一些键值对来模拟一系类表单控件,还可以异步上传一个 二进制文件。
2.2 这里补充一个既能获取文件,又能获取表单数据的方式
- 这里通过 new FormData 创建了 fileFrom 表单的对象。
- 下图就是断点停留的地方,可以看到文件与表单的内容都可以获取到的,只不过需要设置一下实体类中的文件路径。
服务器。
目前呢,我对上传文件的操作还只是初步了解,如果哪位大神有更好的方法,希望能够分享给我的啦。
需要两个 Jar 包。
1. commons-fileupload.jar 包文件。
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
2. commons-io.jar 包文件。
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
SpringMVC 配置文件解析器CommonsMultipartResolver
<!-- 多部分文件上传 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="104857600" />
<property name="maxInMemorySize" value="4096" />
<property name="defaultEncoding" value="UTF-8"></property>
</bean>
单文件接收 MultipartFile 以及 多文件接收 MutipartFile[]
- 对于MulipartFile,只需要这样就可以了:MultipartFile file, HttpServletRequest request
@RequestMapping("uploadFile")
public String fileUpload(MultipartFile file, HttpServletRequest request) throws IOException {
}
- 对于CommonsMultipartFile,需要@RequestParam(“file”) CommonsMultipartFile Filedata, HttpServletRequest request,不然不会进此方法。
@RequestMapping("uploadFile")
public String fileUpload(@RequestParam("file") CommonsMultipartFile Filedata, HttpServletRequest request) throws IOException {
}
通过流的方式上传文件
@RequestParam(“file”) 将name=file控件得到的文件封装成CommonsMultipartFile 对象
通过字节流的方式,读取文件 file.getInputStream(); ,之后通过 OutputStream 写在指定目录。
@RequestMapping("fileUpload")
public String fileUpload(@RequestParam("file") CommonsMultipartFile file) throws IOException {
// 文件上传的开始时间
long startTime=System.currentTimeMillis();
System.out.println("fileName:"+file.getOriginalFilename());
try {
//获取输出流
OutputStream os=new FileOutputStream("D:/"+new Date().getTime()+file.getOriginalFilename());
//获取输入流 CommonsMultipartFile 中可以直接得到文件的流
InputStream is = file.getInputStream();
int temp;
//一个一个字节的读取并写入
while((temp=is.read())!=(-1))
{
os.write(temp);
}
os.flush();
os.close();
is.close();
} catch (FileNotFoundException e) {
throw new Exception("异常:文件找不到");
}
long endTime=System.currentTimeMillis();
System.out.println("方法一的运行时间:"+String.valueOf(endTime-startTime)+"ms");
return "/success";
}
file.transferTo 方式上传文件
只需要规定文件上传文件的路径就可以对文件进行上传。
@RequestMapping("fileUpload2")
public String fileUpload2(@RequestParam("file") CommonsMultipartFile file) throws IOException {
long startTime=System.currentTimeMillis();
System.out.println("fileName:"+file.getOriginalFilename());
String path="D:/"+new Date().getTime()+file.getOriginalFilename();
File newFile=new File(path);
// file.transTo 方式上传文件,直接写文件
file.transferTo(newFile);
long endTime=System.currentTimeMillis();
System.out.println("方法二的运行时间:"+String.valueOf(endTime-startTime)+"ms");
return "/success";
}
使用 SpringMVC 同时上传文件与数据。
## 文本数据上传表单数据过大,使用 POST 提交
@RequestMapping(value="/upload" ,method=RequestMethod.POST)
public String test(User user,@RequestParam(value="uploadFile",required=false) MultipartFile uploadFile) throws Exception, IOException{
System.out.println("上传文件操作开始……");
String path = null; // 设置存储路径为空
if(!(uploadFile.isEmpty())){
System.out.println("上传的文件不为空,进行路径操作");
// 获取保存文件的绝对路径,存放到项目路径下。File.separator 是 io 文件下的字符串 \
String path = request.getSession().getServletContext().getRealPath("statics"+File.separator+"uploadfiles");
System.out.println("2.1 uploadFile path ===>"+path);
// 获取上传文件的文件名
String oldFileName = uploadFile.getOriginalFilename();//原文件名
System.out.println("2.2 uploadFile oldFileName ===>"+oldFileName);
// 获取文件名后缀
String suffix = oldFileName.substring(oldFileName.lastIndexof('.')); // 原文件名后缀
System.out.println("2.3 uploadFile suffix ===>"+suffix );
//设置文件大小的变量,KB是单位
int filesize = 5000000;
System.out.println("2.4 uploadFile filesize ===>"+uploadFile.getSize());
if(uploadFile.getSize() > filesize){
request.setAttribute("uploadFileError", "* 上传大小不得超过5000KB");
System.out.println("* 上传大小不得超过5000KB");
return "useradd";
}else if(prefix.equalsIgnoreCase("jpg")
|| prefix.equalsIgnoreCase("png")
|| prefix.equalsIgnoreCase("jpeg")){
// 上传格式正确,重新取得一个文件的路径。
String fileName = System.currentTimeMillis()+RandomUtils.nextInt(1000000)+".jpg";
System.out.println("2.5 new fileName===>"+uploadFile.getName());
// 新建一个文件,File API,这样就可以为文件重定义名字。
File targetFile = new File(path,fileName);
if(!targetFile.exists()){ // 判断文件是否存在,存在就上传覆盖了,
targetFile.mkdirs(); // 不存在就创建。
}
//保存
try{
// 上传
uploadFile.transferTo(targetFile);
}catch (Exception e){
e.printStackTrace();
request.setAttribute("uploadFileError", "* 上传失败! ");
System.out.println("* 上传失败! ");
return "useradd";
}
path = path+File.separator+fileName;
}else{
request.setAttribute("uploadFileError", "* 上传格式错误!");
System.out.println("* 上传格式错误!");
return "useradd";
}
}
user.setPicPath(path);
System.out.println("user is: "+user);
return "userlist";
}
- 其中 ,File 有固定的字符串可以使用。