spirgmvc+ajaxfileupload上传文件
springmvc在上传文件方面有一个MutilpartFile类,这个类中的有直接保存文件的功能。使用的时候首先需要引入commons-fileupload,然后在spirngmvc的配置文件中配置。
<!-- 上传文件拦截,设置最大上传文件大小 10M=10*1024*1024(B)=10485760 bytes -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760"/>
</bean>
之后,需要一个controller进行处理用户上传文件的请求。
package com.xueyou.ssm.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xueyou.ssm.utils.Base;
import com.xueyou.ssm.utils.SysContent;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Encoder;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
/**
* Created by wuxueyou on 16/10/3.
*/
@RestController
@RequestMapping(value = "/file", method = RequestMethod.POST, produces = "application/json;charset=UTF-8;")
public class FileUploadController {
@RequestMapping(value = "/upload",produces = "text/html;charset=UTF-8;")
private String fileUpload(MultipartFile file, Model model) {
Map<String, Object> resMap = new HashMap<>();
if (!file.isEmpty()) {
HttpServletRequest request = SysContent.getRequest();
String relativePathDir = "/ssmUpload/files";
String realPathDir = request.getSession().getServletContext().getRealPath(relativePathDir);
String fileSign = (new SimpleDateFormat("yyyyMMddHHmmssSSS")).format(Calendar.getInstance().getTime());
String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
String fileName = realPathDir + "/" + file.getName() + fileSign + suffix;
System.out.println(fileName);
File myDir = new File(realPathDir);
if (!myDir.exists()) {
myDir.mkdirs();
}
File uploadFile = new File(fileName);
try {
byte[] filebytes = file.getBytes();
file.transferTo(uploadFile);
resMap.put("resMsg", Base.MSG_SUCCESS);
resMap.put("resCode", Base.MSG_CODE_SUCCESS);
resMap.put("resFile", new BASE64Encoder().encode(filebytes));
resMap.put("resFilePath",relativePathDir + "/" + file.getName() + fileSign + suffix);
} catch (IOException e) {
e.printStackTrace();
}
} else {
resMap.put("resCode", Base.MSG_CODE_ERROR);
resMap.put("resMsg", Base.MSG_ERROR);
}
String resJson = "";
ObjectMapper mapper = new ObjectMapper();
try {
resJson = mapper.writeValueAsString(resMap);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return resJson;
}
}
其中获得HttpServletRequest和HttpServletResponse的方式请看 springmvc 得到HttpServletRequest、HttpServletResponse、HttpSession。
下面是前段代码,首先需要的就是ajaxfileupload.js(可以下载,但是可能有bug,推荐用本文中的这个)
/**
* Created by wuxueyou on 16/10/3.
*/
// JavaScript Document
jQuery.extend({
createUploadIframe: function (id, uri) {
//create frame
var frameId = 'jUploadFrame' + id;
if (window.ActiveXObject) {
//var io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />');
if (jQuery.browser.version == "9.0" || jQuery.browser.version == "10.0") {
var io = document.createElement('iframe');
io.id = frameId;
io.name = frameId;
} else if (jQuery.browser.version == "6.0" || jQuery.browser.version == "7.0" || jQuery.browser.version == "8.0") {
var io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />');
if (typeof uri == 'boolean') {
io.src = 'javascript:false';
}
else if (typeof uri == 'string') {
io.src = uri;
}
}
} else {
var io = document.createElement('iframe');
io.id = frameId;
io.name = frameId;
}
io.style.position = 'absolute';
io.style.top = '-1000px';
io.style.left = '-1000px';
document.body.appendChild(io);
return io;
},
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>');
var oldElement = jQuery('#' + fileElementId);
var newElement = jQuery(oldElement).clone();
jQuery(oldElement).attr('id', fileId);
jQuery(oldElement).before(newElement);
jQuery(oldElement).appendTo(form);
//add data
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 = s.id;
//var id = s.fileElementId;
var form = jQuery.createUploadForm(id, s.fileElementId, s.data);
var io = jQuery.createUploadIframe(id, s.secureuri);
var frameId = 'jUploadFrame' + id;
var formId = 'jUploadForm' + id;
if (s.global && !jQuery.active++) {
// Watch for a new set of requests
jQuery.event.trigger("ajaxStart");
}
var requestDone = false;
// Create the request object
var xml = {};
if (s.global) {
jQuery.event.trigger("ajaxSend", [xml, s]);
}
var uploadCallback = function (isTimeout) {
// Wait for a response to come back
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 (s.success) {
// ifa local callback was specified, fire it and pass it the data
s.success(data, status);
}
;
if (s.global) {
// Fire the global callback
jQuery.event.trigger("ajaxSuccess", [xml, s]);
}
;
} else {
jQuery.handleError(s, xml, status);
}
} catch (e) {
status = "error";
jQuery.handleError(s, xml, status, e);
}
;
if (s.global) {
// The request was completed
jQuery.event.trigger("ajaxComplete", [xml, s]);
}
;
// Handle the global AJAX counter
if (s.global && !--jQuery.active) {
jQuery.event.trigger("ajaxStop");
}
;
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 () {
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) {
form.encoding = 'multipart/form-data';
} else {
form.enctype = 'multipart/form-data';
}
jQuery(form).submit();
} catch (e) {
jQuery.handleError(s, xml, null, e);
}
/*if(window.attachEvent){
document.getElementById(frameId).attachEvent('onload', uploadCallback);
}
else{
document.getElementById(frameId).addEventListener('load', uploadCallback, false);
} */
jQuery('#' + frameId).load(uploadCallback);
return {
abort: function () {
}
};
},
uploadHttpData: function (r, type) {
var data = !type;
data = type == "xml" || data ? r.responseXML : r.responseText;
// ifthe type is "script", eval it in global context
if (type == "script") {
jQuery.globalEval(data);
}
// Get the JavaScript object, ifJSON is used.
if (type == "json") {
data = r.responseText;
var start = data.indexOf(">");
if (start != -1) {
var end = data.indexOf("<", start + 1);
if (end != -1) {
data = data.substring(start + 1, end);
}
}
eval("data = " + data);
}
// evaluate scripts within html
if (type == "html") {
jQuery("<div>").html(data).evalScripts();
}
return data;
},
/*handleError: function( s, xml, status, e ) {
// If a local callback was specified, fire it
if ( s.error )
s.error( xml, status, e );
// Fire the global callback
if ( s.global )
jQuery.event.trigger( "ajaxError", [xml, s, e] );
}*/
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]);
}
}
});
前台页面:
<%--
Created by IntelliJ IDEA.
User: wuxueyou
Date: 16/10/1
Time: 下午2:05
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>登录</title>
<script src="${pageContext.request.contextPath}/Component/angular.min-1.2.19.js"></script>
<script src="${pageContext.request.contextPath}/Component/angular-route.min-1.2.19.js"></script>
<script src="${pageContext.request.contextPath}/Component/angular-ui/angular-ui-router.min.js"></script>
<link href="${pageContext.request.contextPath}/Component/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<script src="${pageContext.request.contextPath}/Component/bootstrap/js/jquery-1.8.3.min.js"></script>
<script src="${pageContext.request.contextPath}/Component/ajaxfileupload.js"></script>
<script src="${pageContext.request.contextPath}/Component/bootstrap/js/bootstrap.min.js"></script>
<!--[if lte IE 9]>
<script src="${pageContext.request.contextPath}/Component/bootstrap/js/respond.min.js"></script>
<script src="${pageContext.request.contextPath}/Component/bootstrap/js/html5.js"></script>
<![endif]-->
<script src="${pageContext.request.contextPath}/js/base.js"></script>
<script src="${pageContext.request.contextPath}/js/common/fileupload.js"></script>
</head>
<body ng-app="fileupload" ng-controller="fileuploadController" class="container">
<h1>fileupload.jsp</h1>
<hr/>
select a file <input type="file" name="file" id="file">
<div id="resPath"></div>
<div id="fileimg"><img src="" style="width: 200px;height: 200px;border: solid #cccccc 1px;"/></div>
<button class="btn btn-primary" id="ajaxUpload">ajax上传</button>
</body>
</html>
前台js
/**
* Created by wuxueyou on 16/10/1.
*/
var fileuploadapp = angular.module('fileupload', [], function ($httpProvider) {
baseRequest($httpProvider);
});
fileuploadapp.controller('fileuploadController', function ($scope) {
$scope.test = "aabbcc";
$('#resPath').text(' ');
$('#ajaxUpload').click(function () {
$.ajaxFileUpload({
url:BASE_URL + '/file/upload',
securityuri:false,
fileElementId:'file',
dataType:'json',
success:function(data,status){
if(data != null){
if(data.resCode == 1){
alert('上传成功!');
$('#resPath').text(data.resFilePath);
$('#fileimg').empty();
$('#fileimg').append('<img src="data:image/png;base64,'+ data.resFile + '" style="width: 200px;height: 200px;border: solid #cccccc 1px;"/>');
//$('#fileimg').attr("src","data:image/png;base64," + data.resFile);
}else{
alert('上传失败!');
$('#resPath').text(' ');
$('#fileimg').empty();
$('#fileimg').append('<img src="data:image/png;base64,'+ 'error' + '" style="width: 200px;height: 200px;border: solid #cccccc 1px;"/>');
//$('#fileimg').attr("src","data:image/png;base64,--");
}
}
},
error: function (data, status) {
alert('error');
}
})
});
});
下面是运行效果,还有一点问题,就是IE8,上传图片完成后,图片不能显示出来。
需要注意的是ie8 ajaxfileupload支持的jquery最高不能超过1.9。如果超过,会报错。如果不考虑ie8那么无所谓了。
附:下面是解决IE8下不显示图片的问题。首先是上传后,能够在浏览器中访问图片资源,然后是在ie中加载图片的时候,不要使用base64编码的方式,因为图片过大的话,会出现错误。下面是代码:
/**
* Created by wuxueyou on 16/10/1.
*/
var fileuploadapp = angular.module('fileupload', [], function ($httpProvider) {
baseRequest($httpProvider);
});
fileuploadapp.controller('fileuploadController', function ($scope) {
$scope.test = "aabbcc";
$('#resPath').text(' ');
$('#ajaxUpload').click(function () {
$.ajaxFileUpload({
url: BASE_URL + '/file/upload',
securityuri: false,
fileElementId: 'file',
dataType: 'json',
timeout:30000,
success: function (data, status) {
if (data != null) {
if (data.resCode == 1) {
var path = BASE_URL + data.resFilePath;
$('#img').attr("src",path);
//ie8下,上传如果文件过大,渲染不出来
//$('#img').attr("src","data:image/jpg;base64," + data.resFile);
alert('上传成功!');
$('#resPath').text(data.resFilePath);
} else {
var errorPath = BASE_URL + '/img/404.jpg';
$('#img').attr("src",errorPath);
alert('上传失败!');
$('#resPath').text(' ');
}
}
},
error: function (data, status) {
alert('error');
}
});
});
});
附2:
最近在做项目的时候发现,一个界面中很多个上传控件,这个时候以为需要些好多后台,后来发现,只需要写一个后台。ajaxfileupload和后台中的代码对应是这样的:
界面上name属性和后台中Mutilpartfile file这个参数对应。也就是说前台是可以这样写的:
<input type="file" id="ccc" name="file"/>
然后在js中使用的时候
$ajaxFileUpload的时候,需要把fileElementId改为“ccc”即可。
这样就解决了单个页面中有多个文件上传控件,进行上传任务的问题了。