【Spring-MVC AJAX文件上传】
前言
准备筹划一个自己的个人网站,初步的架构设计采用SSH(Spring-MVC,Spring,Hibernate),在这里
顺便记录一下设计和开发过程,以备参考。后续会陆续更新文档,如有任何问题,欢迎各位不吝指出,共
同学习。
环境
开发环境 | 版本 |
---|---|
eclipse | 4.3.2 |
maven | 3.2.1 |
Spring-MVC | 3.2.3.RELEASE |
Spring | Spring |
Hibernate | 3.2.5 |
文件上传是很多项目都会使用到的功能,SpringMVC当然也提供了这个功能。不过本人不建议在项目中
通过form表单来提交文件上传,这样做的局限性很大。对于文件上传等类似的功能,推荐使用第三方的
插件(或者自己写的插件)来实现,这样可以减轻服务端的压力,同时呈现的页面效果也会更好,而且
可插拔,扩展性好。
在这里使用AJAX来上传文件,为了方便,使用了第三方的插件uploadify(http://www.uploadify.com/),
这个插件展示效果很好,还提供了丰富的功能,在下面的内容中会简单介绍,有兴趣的朋友可以到官网
去看下文档,简单易用。
这里依然借助了SpringMVC的文件上传功能,不过十三哥建议还是不要这样做,这里纯粹是为了介绍
SpringMVC的文件上传而已。
还是希望能使用完整的前后端结合的文件上传插件,把文件上传的功能独立出来。这样页面上就只显示
一个已上传的文件在服务端的保存地址,这个地址对应于数据库表中的URL字段。这样显示文件列表的
时候,服务端也只是从表中取出一系列的URL,再交由读文件的插件去读文件,这将会是非常好的一个
设计了。
使用SpringMVC的文件上传功能,需要引入相应的jar包,配置文件解析器。
【添加处理文件上传的jar包】
pom.xml添加commons-io和commons-fileupload的依赖
commons-io commons-io 2.4 commons-fileupload commons-fileupload 1.3
【springMVC-servlet.xml配置文件解析器】
另外,大家也会发现,SpringMVC的Resolver(解析器)是个很关键的东西,需要什么样的处理,就引入
什么样的解析器就行了。
【Controller代码】
package com.xbs.ready.ssh.controller;
import com.alibaba.fastjson.JSON;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
/**
* 文件上传的Controller
*
* @author ssg
*/
@Controller
@RequestMapping("upload")
public class FileUploadController {
private static final String FILE_PATH = "C:/uploaddir";
@RequestMapping(value = "one", method = RequestMethod.POST)
@ResponseBody
public String uploadFile(HttpServletRequest request, HttpServletResponse
response) throws IOException {
//String fileName = (String)request.getAttribute("filename");
MultipartHttpServletRequest multipartRequest =
(MultipartHttpServletRequest) request;
Iterator fileNames = multipartRequest.getFileNames();
MultipartFile multipartFile = multipartRequest.getFile(fileNames.next());
//如果使用firebug,或者chrome的开发者工具,可以看到,这个文件上传工具发送了两个文件名
//分别是:name="Filedata"; filename="AVScanner.ini"
//用这两个文件名获得文件内容都可以,只不过第一个没有后缀,需要自己处理
//第二个是原始的文件名,但是这个文件名有可能是上传文件时的全路径
//例如 C:/testssh/a.log,如果是全路径的话,也需要处理
String fileAlias = multipartFile.getName();
System.out.println("Spring MVC获得的文件名:" + fileAlias);
//获得文件原始名称
String name = multipartFile.getOriginalFilename();
String filePath = FILE_PATH + "/" + name;
saveFile(filePath, multipartFile.getBytes());
Map resultMap = new HashMap(5);
resultMap.put("result", "success");
resultMap.put("filePath", filePath);
return JSON.toJSONString(resultMap);
}
//保存文件的方法
public void saveFile(String filePath, byte[] content) throws IOException {
BufferedOutputStream bos = null;
try {
File file = new File(filePath);
//判断文件路径是否存在
if (!file.getParentFile().exists()) {
//文件路径不存在时,创建保存文件所需要的路径
file.getParentFile().mkdirs();
}
//创建文件(这是个空文件,用来写入上传过来的文件的内容)
file.createNewFile();
bos = new BufferedOutputStream(new FileOutputStream(file));
bos.write(content);
} catch (FileNotFoundException e) {
throw new FileNotFoundException("文件不存在。");
} finally {
if (null != bos) {
bos.close();
}
}
}
}
【HTML代码】
html文件路径:.../webapp/views/upload.html
文件上传
访问
访问路径:http://localhost:8080/sshdemo/views/upload.html
(或者通过访问Controller,然后跳转回这个页面,不过不建议这样做,尽量不去
打扰服务端)
uploadify介绍
这里只简要介绍上面使用的几个参数,其余的可以参照官方文档(http://www.uploadify.com/documentation/)
uploader:服务端处理上传文件的路径
"uploader": "http://localhost:8080/sshdemo/upload/one"
method:访问方式,post,get(这个访问方式要与服务的访问方式一致,否则405)
"method": "post"
progressData:上传进度,有percentage(百分比)和speed(进度条)两个值
"progressData": "percentage"
swf:动画文件的路径,因为要演示上传进度,所以需要动画(这个文件在官网的zip包里有,可以直接
使用)
"swf": "http://localhost:8080/sshdemo/static/flash/uploadify.swf"
buttonText:上传按钮的名字
"buttonText": "选择要上传的文件"
multi:是否可一次上传多个文件,true:可以,false:不可以(默认false)
"multi": true
fileSizeLimit:文件大小的限制(这里指单个文件),单位可以有B,KB,MB,和GB,默认是KB,
不过建议显式指定,方便理解;这个参数设置也可以代替在后台的配置文件中指定可上传文件的大小
"fileSizeLimit": "100KB"
queueSizeLimit:可上传文件的个数,如果不指定那么没有上限,建议指定的好
"queueSizeLimit": 5
successTimeout:上传文件后,多长时间服务端没有响应就意为上传成功,单位是秒(这时可能服务端
出错了,但是服务端处理的时间超过了这里设置的时间,那么插件会认为上传成功了)
"successTimeout": 60
onUploadSuccess:上传文件成功后,触发的事件
@Param file:上传成功的那个文件对象 @Param data:服务端返回的数据,这个例子中返回的是JSON数据 @Param response:服务端的响应,true 或者 false(注意:如果服务端在超过了 successTimeout之后返回了false,那么插件依然会返回true) "onUploadSuccess": function(file, data, response) { alert('The file ' + file.name + ' was successfully uploaded with a response of ' + response + ':' + data); }
onUploadError:上传文件失败后,触发的事件
@Param file:上传的文件对象 @Param errorCode:错误代码(这个代码是插件返回的,不是服务端) @Param errorMsg:错误信息(插件返回的错误信息) @Param errorString:详细的错误信息 "onUploadError": function(file, errorCode, errorMsg, errorString) { alert('The file ' + file.name + ' could not be uploaded: ' + errorString); }
onSelectError:选择上传文件出错时(例如 queueSizeLimit=5,但是选择了6个文件),可以触发这个
事件;文件上传失败时,也可以触发这个事件
@Param file:上传的文件对象 @Param errorCode:错误代码(QUEUE_LIMIT_EXCEEDED,FILE_EXCEEDS_SIZE_LIMIT, ZERO_BYTE_FILE,INVALID_FILETYPE) @Param errorMsg:错误信息 "onSelectError": function() { alert('The file ' + file.name + ' returned an error and was not added to the queue.'); }
这里就介绍这几个参数了,官网还有好多参数,触发事件,方法等,等以后用到了再介绍吧。