Spring MVC中文件上传和下载

文件上传

文件上传需将表格的提交方式设为"POST",并且将enctype设为"multipart/form-data",以二进制的方式提交数据。
spring mvc中可通过MultipartResolver监听每个请求,如有上传的文件,则把请求封装为MultipartHttpServletRequest,通过封装的请求可以获取上传的文件信息和上传的文件。
实际使用可直接将MultipartFile作为控制器中请求处理方法的参数,MultipartFile是一个接口,其实现类为CommonsMultipartFile,通过MultipartFile封装的方法也可获取文件相关信息。

注意:spring mvc默认没有装配MultipartResolver,因此要使用文件上传功能,可在上下文中配置基于Apache CommonsFileUpload实现的CommonsMultipartResolver,同时要加入相关的commons-fileupload.jar包。

public interface MultipartFile extends InputStreamSource {
String getName();//获得上传文件在表单中的域名
String getOriginalFilename();//获得上传文件的原名
String getContentType();//获得提交的内容类型
boolean isEmpty();//判断是否有上传的文件
long getSize();//上传文件的大小
byte[] getBytes() throws IOException;//获得上传文件的字节数组

@Override
InputStream getInputStream() throws IOException;
void transferTo(File dest) throws IOException, IllegalStateException;//获得上传文件的输入流

}

下面是封装的工具类:

package com.yc.utils;


import static java.util.Calendar.MONTH;
import static java.util.Calendar.YEAR;


import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;


import javax.servlet.http.HttpServletRequest;


import org.springframework.web.multipart.MultipartFile;


/**
 * Spring MVC文件上传的帮助类,对基于Apache Commons
 * FileUpload实现的CommonsMultipartResolver得到的MultipartFile进行处理
 * 
 * @author 刘亚楼
 *
 */
public class MVCFileUpload {
/**
* 访问的相对路径
*/
public static final String RELATIVE_PATH = "RelativePath";
/**
* 文件保存的绝对路径
*/
public static final String ABSOLUTE_PATH = "AbsolutePath";
/**
* 文件的原名
*/
public static final String ORIGINAL_FILENAME = "OriginalFileName";
/**
* 文件保存的前缀形式为yyyyMMddHHmmssSS
*/
public static final String PREFIX_DATE = "date";
/**
* 文件保存的前缀形式为uuid编号
*/
public static final String PREFIX_UUID = "uuid";
// 文件保存目录
private String saveDir = "images";
// 文件前缀形式可为date或uuid
private String prefixForm = PREFIX_DATE;


public MVCFileUpload() {
super();
}


public MVCFileUpload(String prefixForm) {
super();
this.prefixForm = prefixForm;
}


public String getSaveDir() {
return saveDir;
}


public void setSaveDir(String saveDir) {
this.saveDir = saveDir;
}


public String getPrefixForm() {
return prefixForm;
}


public void setPrefixForm(String prefixForm) {
this.prefixForm = prefixForm;
}


/**
* 处理表单域名相同的多个文件<br/>
* 将上传的文件保存到服务器<br/>
* 默认路径为 <b>D:\TomcatInstalling\apache-tomcat-7.0.79\webapps\images\年\月\日<b>

* @param request
* @param files
* @throws IllegalStateException
* @throws IOException
*/
public List<Map<String, String>> transferMultiFilesWithSameField(HttpServletRequest request, MultipartFile[] files)
throws IllegalStateException, IOException {
List<Map<String, String>> fileList = new ArrayList<Map<String, String>>();
if (files != null && files.length > 0) {
String basePath = getSaveBasePath(request);
for (MultipartFile file : files) {
if (!file.isEmpty()) {
Map<String, String> fileInfo = new HashMap<String, String>();
saveToServer(fileInfo, basePath, file);
fileList.add(fileInfo);
}
}
}
return fileList;
}


/**
* 处理表单域名不同的多个文件,将上传的文件保存到服务器<br/>
* 默认路径为 <b>D:\TomcatInstalling\apache-tomcat-7.0.79\webapps\images\年\月\日<b>

* @param request
* @param files
* @return
* @throws IOException
*/
public Map<String, String> transferMultiFilesWithDistinctField(HttpServletRequest request, MultipartFile... files)
throws IOException {
Map<String, String> fileInfo = new HashMap<String, String>();
if (files != null && files.length > 0) {
String basePath = getSaveBasePath(request);
for (MultipartFile file : files) {
if (!file.isEmpty()) {
saveToServer(fileInfo, basePath, file);
}
}
}
return fileInfo;
}


// 获得文件存储的基础路径
private String getSaveBasePath(HttpServletRequest request) {
Calendar c = Calendar.getInstance();
String path = request.getServletContext().getRealPath("/");
File rootPath = new File(path).getParentFile();
File basePath = new File(rootPath.getAbsolutePath(),
saveDir + File.separator + c.get(YEAR) + File.separator + (c.get(MONTH) + 1));
if (!basePath.exists()) {
basePath.mkdirs();
}
return basePath.getAbsolutePath();
}


/**
* 将上传的文件存到服务器并将文件相关信息记录到map中,可通过表单中文件的域名加MVCFileUpload的静态变量访问

* @param fileInfo
* @param basePath
* @param file
* @throws IOException
*/
private void saveToServer(Map<String, String> fileInfo, String basePath, MultipartFile file) throws IOException {
if (!file.isEmpty()) {
// 表单中文件域名
String fieldName = file.getName();
// 文件前缀
String prefix = generateFilePrefix();
// 文件原名
String fileName = file.getOriginalFilename();
// 文件后缀
String suffix = fileName.substring(fileName.indexOf("."));
File dest = new File(basePath, prefix + suffix);
// 存入服务器
file.transferTo(dest);
Calendar c = Calendar.getInstance();
// 访问的相对路径
String relativePath = "../" + saveDir + "/" + c.get(YEAR) + "/" + (c.get(MONTH) + 1) + "/" + prefix
+ suffix;
// 访问的绝对路径
String absolutePath = dest.getAbsolutePath();
fileInfo.put(fieldName + RELATIVE_PATH, relativePath);
fileInfo.put(fieldName + ABSOLUTE_PATH, absolutePath);
fileInfo.put(fieldName + ORIGINAL_FILENAME, fileName);
}
}


// 生成保存的文件前缀
private String generateFilePrefix() {
String prefix = "";
if (prefixForm.equalsIgnoreCase(PREFIX_DATE)) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSS");
prefix = sdf.format(new Date());
} else if (prefixForm.equalsIgnoreCase(PREFIX_UUID)) {
UUID uuid = UUID.randomUUID();
prefix = uuid.toString().replaceAll("-", "");
} else {
throw new IllegalArgumentException("前缀模式不支持");
}
return prefix;
}
}

不通过表单提交也可通过Ajax实现文件上传,这里要借助于ajaxfileupload.js,通过一个隐藏的iframe创建表单实现文件上传

jQuery
.extend({

createUploadIframe : function(id, uri) {
// create frame
var frameId = 'jUploadFrame' + id;
var iframeHtml = '<iframe id="'
+ frameId
+ '" name="'
+ frameId
+ '" style="position:absolute; top:-9999px; left:-9999px"';
if (window.ActiveXObject) {
if (typeof uri == 'boolean') {
iframeHtml += ' src="' + 'javascript:false' + '"';


} else if (typeof uri == 'string') {
iframeHtml += ' src="' + uri + '"';

}
}
iframeHtml += ' />';
jQuery(iframeHtml).appendTo(document.body);


return jQuery('#' + frameId).get(0);
},
createUploadForm : function(id, fileElementId, data) {
// create form
var formId = 'jUploadForm' + id;
var fileId = 'jUploadFile' + id;
var form = jQuery('<form  action="" method="POST" name="'
+ formId + '" id="' + formId
+ '" enctype="multipart/form-data"></form>');
if (fileElementId != null && fileElementId.length > 0) {
for(var i=0;i<fileElementId.length;i++){
var feid=fileElementId[i];//'pic','pic2','pic3'
var oldElement = jQuery('#' + feid);
var newElement = jQuery(oldElement).clone();
jQuery(oldElement).attr('id', "jUploadFile"+new Date().getTime());
jQuery(oldElement).before(newElement);
jQuery(oldElement).appendTo(form);
}
}

/** *** 增加参数的支持 **** */
if (data) {
for ( var i in data) {
$(
'<input type="hidden" name="' + i + '" value="'
+ data[i] + '" />').appendTo(form);
}
}
// set attributes
jQuery(form).css('position', 'absolute');
jQuery(form).css('top', '-1200px');
jQuery(form).css('left', '-1200px');
jQuery(form).appendTo('body');
return form;
},
ajaxFileUpload : function(s) {
// TODO introduce global settings, allowing the client to modify
// them for all requests, not only timeout
s = jQuery.extend({}, jQuery.ajaxSettings, s);
var id = new Date().getTime();
// ADD s.data
var form = jQuery.createUploadForm(id, s.fileElementId, s.data);
var io = jQuery.createUploadIframe(id, s.secureuri);
var frameId = 'jUploadFrame' + id;
var formId = 'jUploadForm' + id;
// Watch for a new set of requests
if (s.global && !jQuery.active++) {
jQuery.event.trigger("ajaxStart");
}
var requestDone = false;
// Create the request object
var xml = {}
if (s.global)
jQuery.event.trigger("ajaxSend", [ xml, s ]);
// Wait for a response to come back
var uploadCallback = function(isTimeout) {
var io = document.getElementById(frameId);
try {
if (io.contentWindow) {
xml.responseText = io.contentWindow.document.body ? io.contentWindow.document.body.innerHTML
: null;
xml.responseXML = io.contentWindow.document.XMLDocument ? io.contentWindow.document.XMLDocument
: io.contentWindow.document;
} else if (io.contentDocument) {
xml.responseText = io.contentDocument.document.body ? io.contentDocument.document.body.innerHTML
: null;
xml.responseXML = io.contentDocument.document.XMLDocument ? io.contentDocument.document.XMLDocument
: io.contentDocument.document;
}
} catch (e) {
jQuery.handleError(s, xml, null, e);
}
if (xml || isTimeout == "timeout") {
requestDone = true;
var status;
try {
status = isTimeout != "timeout" ? "success"
: "error";
// Make sure that the request was successful or
// notmodified
if (status != "error") {
// process the data (runs the xml through
// httpData regardless of callback)
var data = jQuery.uploadHttpData(xml,
s.dataType);
// If a local callback was specified, fire it
// and pass it the data
if (s.success)
s.success(data, status);


// Fire the global callback
if (s.global)
jQuery.event.trigger("ajaxSuccess", [ xml,
s ]);
} else
jQuery.handleError(s, xml, status);
} catch (e) {
status = "error";
jQuery.handleError(s, xml, status, e);
}
// The request was completed
if (s.global)
jQuery.event.trigger("ajaxComplete", [ xml, s ]);
// Handle the global AJAX counter
if (s.global && !--jQuery.active)
jQuery.event.trigger("ajaxStop");
// Process result
if (s.complete)
s.complete(xml, status);
jQuery(io).unbind()
setTimeout(function() {
try {
jQuery(io).remove();
jQuery(form).remove();

} catch (e) {
jQuery.handleError(s, xml, null, e);
}

}, 100)

xml = null

}
}
// Timeout checker
if (s.timeout > 0) {
setTimeout(function() {
// Check to see if the request is still happening
if (!requestDone)
uploadCallback("timeout");
}, s.timeout);
}
try {
var form = jQuery('#' + formId);
jQuery(form).attr('action', s.url);
jQuery(form).attr('method', 'POST');
jQuery(form).attr('target', frameId);
if (form.encoding) {
jQuery(form).attr('encoding', 'multipart/form-data');
} else {
jQuery(form).attr('enctype', 'multipart/form-data');
}
jQuery(form).submit();

} catch (e) {
jQuery.handleError(s, xml, null, e);
}

jQuery('#' + frameId).load(uploadCallback);
return {
abort : function() {
}
};

},

/** handleError 方法在jquery1.4.2之后移除了,此处重写改方法 * */
handleError : function(s, xhr, status, e) {
// If a local callback was specified, fire it
if (s.error) {
s.error.call(s.context || s, xhr, status, e);
}
// Fire the global callback
if (s.global) {
(s.context ? jQuery(s.context) : jQuery.event).trigger(
"ajaxError", [ xhr, s, e ]);
}
},
uploadHttpData : function(r, type) {
var data = !type;
data = type == "xml" || data ? r.responseXML : r.responseText;
// If the type is "script", eval it in global context
if (type == "script") {
jQuery.globalEval(data);
}
// Get the JavaScript object, if JSON is used.
if (type == "json") {

var result = data.substring(data.indexOf("{"), data
.indexOf("}") + 1);
data = eval("(" + result + ")");
}
// evaluate scripts within html
if (type == "html") {
jQuery("<div>").html(data).evalScripts();
}
return data;
}
})
下面是上传的js代码

var person = {
uname : $("#uname").val(),
upass : $("#upass").val(),
diploma : $("#diploma").val(),
};
$.ajaxFileUpload({
type : "POST",
secureuri : true,
fileElementId : ["pic","pic2","pic3"],//上传文件的表单域名
url : "test.jsp",
data : person,
dataType : "json",
success : function(data, status) {
}
});

文件下载

文件下载比较简单,直接在页面给出一个超链接,该链接href属性等于要下载文件的文件名,就可以实现下载了。但是如果该文件的文件名为中文名,在某些早期的浏览器上就会导致下载失败。如果使用最新的Firefox、Opera、Chrome、Safari则都可以正常下载了。但对于可打开的文件如文本、图片等等,浏览器会直接打开。因此这里我们使用ResponseEntity对象作为请求处理方法的返回值。

在Spring MVC中可使用ResponseEntity<T>(继承自HttpEntity)代表响应的实体,HttpEntity可以访问请求和响应头。下面是请求处理方法:

@RequestMapping("/download.action")

public ResponseEntity<byte[]> download(String fileName) throws IOException {
String path = System.getProperty("user.home");
File file = new File(path, "Pictures" + File.separator + fileName);
// 实现了MultiValueMap,代表请求头或者响应头
HttpHeaders responseHeader = new HttpHeaders();
// 浏览器对可打开的文件如:图片或文本文件,会自行打开。通过设置Content-Disposition属性为attachment,浏览器会弹出对话框提示打开还是保存,不会默认打开。
// 即使打开也会使用其它程序,如记事本
responseHeader.setContentDispositionFormData("attachment", fileName);
// 设置响应类型为application/octet-stream(二进制流数据,最常见的文件下载)
responseHeader.setContentType(MediaType.APPLICATION_OCTET_STREAM);
// 使用FileUtils读取文件,返回一个ResponseEntity对象(由内容,响应头信息,状态码组成),HttpStatus.CREATED代表创建新资源
return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file), responseHeader, HttpStatus.CREATED);
}

猜你喜欢

转载自blog.csdn.net/lingbomanbu_lyl/article/details/78989029
今日推荐