首先是导入jar包:
web.xml:
1 <servlet> 2 <servlet-name>mvc-dispatcher</servlet-name> 3 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 4 <init-param> 5 <param-name>contextConfigLocation</param-name> 6 <param-value>/WEB-INF/configs/mvc-dispatcher-servlet.xml</param-value> 7 </init-param> 8 <load-on-startup>1</load-on-startup> 9 </servlet> 10 <servlet-mapping> 11 <servlet-name>mvc-dispatcher</servlet-name> 12 <!-- mvc-dispatcher 拦截所有的请求 --> 13 <url-pattern>*.g</url-pattern> 14 </servlet-mapping>
mvc-dispatcher-servlet.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:p="http://www.springframework.org/schema/p" 5 xmlns:context="http://www.springframework.org/schema/context" 6 xmlns:mvc="http://www.springframework.org/schema/mvc" 7 xmlns:tx="http://www.springframework.org/schema/tx" 8 xmlns:aop="http://www.springframework.org/schema/aop" 9 xsi:schemaLocation=" 10 http://www.springframework.org/schema/beans 11 http://www.springframework.org/schema/beans/spring-beans.xsd 12 http://www.springframework.org/schema/context 13 http://www.springframework.org/schema/context/spring-context.xsd 14 http://www.springframework.org/schema/mvc 15 http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd 16 http://www.springframework.org/schema/tx 17 http://www.springframework.org/schema/tx/spring-tx.xsd 18 http://www.springframework.org/schema/aop 19 http://www.springframework.org/schema/aop/spring-aop.xsd"> 20 21 <!-- 激活 22 @Required 23 @Autowired,jsr250's 24 @PostConstruct, 25 @PreDestroy and @ Resource等标注 26 --> 27 <context:annotation-config /> 28 <!-- 29 DispatcherServlet上下文,只搜索@Controller标注的类,不搜索其他标注的类 30 --> 31 <context:component-scan base-package="com.test"> 32 <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 33 </context:component-scan> 34 35 <!-- 36 37 HandlerMapping无需配置,Spring MVC可以默认启动 38 --> 39 <!-- 40 扩充了注解驱动,可以将请求参数绑定到控制器参数 41 启用基于annotation的handlerMapping. 42 --> 43 <!-- <mvc:annotation-driven /> --> 44 <mvc:annotation-driven> 45 <mvc:message-converters register-defaults="true"> 46 <bean class="org.springframework.http.converter.StringHttpMessageConverter"> 47 <constructor-arg> 48 <bean class="java.nio.charset.Charset" factory-method="forName"> 49 <constructor-arg value="UTF-8" /> 50 </bean> 51 </constructor-arg> 52 </bean> 53 54 <bean class="org.springframework.http.converter.StringHttpMessageConverter"> 55 <!-- 控制RequestBody返回值乱码 --> 56 <property name="supportedMediaTypes" value = "text/plain;charset=UTF-8" /> 57 </bean> 58 59 </mvc:message-converters> 60 </mvc:annotation-driven> 61 <!-- 62 静态资源处理,css,js,imgs 63 --> 64 <mvc:resources location="/resources/" mapping="/resources/**"/> 65 66 67 <!-- 视图解析器 --> 68 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 69 <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> 70 <property name="prefix" value="/WEB-INF/jsps/" /> 71 <property name="suffix" value=".jsp" /> 72 </bean> 73 74 <!-- 配置上传文件代码,导入commons-fileupload-1.2.2.jar,commons-io-2.4.jar 75 200*1024*1024即200M resolveLazily属性启用是为了推迟文件解析,以便捕获文件大小异常 76 --> 77 <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> 78 <!-- 上传的最大限制 --> 79 <property name="maxUploadSize" value="209715200" /> 80 <!-- 默认编码 --> 81 <property name="defaultEncoding" value="UTF-8" /> 82 <!-- 上传文件的解析 --> 83 <property name="resolveLazily" value="true" /> 84 </bean> 85 86 <!-- 整合json,导入jackson-core-asl-1.1.2.jar,jackson-mapper-asl-1.1.2.jar 87 配置ViewResolver. 88 可以用多个ViewResolver.使用order属性排序.InternalResourceViewResolver放在最后 89 --> 90 <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> 91 <property name="order" value="1" /> 92 <property name="mediaTypes"> 93 <map> 94 <entry key="json" value="application/json" /> 95 <entry key="xml" value="application/xml" /> 96 <entry key="htm" value="text/html" /> 97 </map> 98 </property> 99 <property name="defaultViews"> 100 <list> 101 <!-- JSON View --> 102 <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"></bean> 103 </list> 104 </property> 105 <property name="ignoreAcceptHeader" value="true" /> 106 </bean> 107 </beans>
UploadController.java
1 @Controller 2 @RequestMapping(value = "/mvc") 3 public class UploadController {
/** 上传目录名*/
private static String uploadFolderName = "uploadFiles";
/** 允许上传的扩展名*/
private static String [] extensionPermit = {"txt","jpg","xls","zip"};
4 /** 5 * 上传文件 6 * @param file 7 * @return 8 * @throws IOException 9 */ 10 @RequestMapping(value="/upload",method=RequestMethod.POST) 11 public String doUploadFile(@RequestParam("file") MultipartFile file) throws IOException{ 12 if(!file.isEmpty()){ 13 System.out.println("提示:"+file.getOriginalFilename()); 14 FileUtils.copyInputStreamToFile(file.getInputStream(), new File("d:\upload\",System.currentTimeMillis()+file.getOriginalFilename())); 15 } 16 return "success"; 17 } 18 }
最终这个文件会被上传到d:upload里面,可是我们想把代码上传到项目文件夹里面,做一些修改.
@Controller @RequestMapping(value = "/mvc") public class UploadController {
/** 上传目录名*/
private static final String uploadFolderName = "uploadFiles";
/** 允许上传的扩展名*/
private static String [] extensionPermit = {"txt","jpg","xls","zip"};
@RequestMapping(value = "/upload", method = RequestMethod.POST) public @ResponseBody String fileUpload(@RequestParam("file") CommonsMultipartFile file, HttpSession session, HttpServletRequest request, HttpServletResponse response) throws Exception{ String curProjectPath = session.getServletContext().getRealPath("/"); String saveDirectoryPath = curProjectPath + "/" + uploadFolderName; File saveDirectory = new File(saveDirectoryPath); logger.debug("Project real path [" + saveDirectory.getAbsolutePath() + "]"); // 判断文件是否存在 if (!file.isEmpty()) { String fileName = file.getOriginalFilename(); String fileExtension = FilenameUtils.getExtension(fileName); if(!Arrays.asList(extensionPermit).contains(fileExtension)){ throw new Exception("No Support extension."); } FileUtils.copyInputStreamToFile(file.getInputStream(), new File(saveDirectoryPath,System.currentTimeMillis()+file.getOriginalFilename())); } logger.info("UploadController#fileUpload() end"); return "{'status':200,'msg':'上传成功'}"; } }
运行后,在tomcat的项目目录里就可以找到新建的文件了.
后台代码编写完毕了,现在编写前台.
首先准备jquery,和ajaxfileupload.js
下载下来的ajaxfileupload.js需要做相应的修改,才能接收上传成功后从服务器返回的数据,
修改后才能和现在高版本的jquery相兼容.
具体改了哪些地方就不啰嗦了.我把改过的最终代码全部贴上来.
ajaxfileupload.js
1 jQuery.extend({ 2 3 4 createUploadIframe: function (id, uri) { 5 //create frame 6 var frameId = 'jUploadFrame' + id; 7 var iframeHtml = '<iframe id="' + frameId + '" name="' + frameId + '" style="position:absolute; top:-9999px; left:-9999px"'; 8 if (window.ActiveXObject) { 9 if (typeof uri == 'boolean') { 10 iframeHtml += ' src="' + 'javascript:false' + '"'; 11 12 } 13 else if (typeof uri == 'string') { 14 iframeHtml += ' src="' + uri + '"'; 15 16 } 17 } 18 iframeHtml += ' />'; 19 jQuery(iframeHtml).appendTo(document.body); 20 21 return jQuery('#' + frameId).get(0); 22 }, 23 createUploadForm: function (id, fileElementId, data) { 24 //create form 25 var formId = 'jUploadForm' + id; 26 var fileId = 'jUploadFile' + id; 27 var form = jQuery('<form action="" method="POST" name="' + formId + '" id="' + formId + '" enctype="multipart/form-data"></form>'); 28 if (data) { 29 for (var i in data) { 30 if (data[i].name != null && data[i].value != null) { 31 jQuery('<input type="hidden" name="' + data[i].name + '" value="' + data[i].value + '" />').appendTo(form); 32 } else { 33 jQuery('<input type="hidden" name="' + i + '" value="' + data[i] + '" />').appendTo(form); 34 } 35 } 36 } 37 var oldElement = jQuery('#' + fileElementId); 38 var newElement = jQuery(oldElement).clone(); 39 jQuery(oldElement).attr('id', fileId); 40 jQuery(oldElement).before(newElement); 41 jQuery(oldElement).appendTo(form); 42 43 44 45 //set attributes 46 jQuery(form).css('position', 'absolute'); 47 jQuery(form).css('top', '-1200px'); 48 jQuery(form).css('left', '-1200px'); 49 jQuery(form).appendTo('body'); 50 return form; 51 }, 52 53 ajaxFileUpload: function (s) { 54 // TODO introduce global settings, allowing the client to modify them for all requests, not only timeout 55 s = jQuery.extend({}, jQuery.ajaxSettings, s); 56 var id = new Date().getTime() 57 var form = jQuery.createUploadForm(id, s.fileElementId, (typeof (s.data) == 'undefined' ? false : s.data)); 58 var io = jQuery.createUploadIframe(id, s.secureuri); 59 var frameId = 'jUploadFrame' + id; 60 var formId = 'jUploadForm' + id; 61 // Watch for a new set of requests 62 if (s.global && !jQuery.active++) { 63 jQuery.event.trigger("ajaxStart"); 64 } 65 var requestDone = false; 66 // Create the request object 67 var xml = {} 68 if (s.global) 69 jQuery.event.trigger("ajaxSend", [xml, s]); 70 // Wait for a response to come back 71 var uploadCallback = function (isTimeout) { 72 var io = document.getElementById(frameId); 73 try { 74 if (io.contentWindow) { 75 xml.responseText = io.contentWindow.document.body ? io.contentWindow.document.body.innerHTML : null; 76 xml.responseXML = io.contentWindow.document.XMLDocument ? io.contentWindow.document.XMLDocument : io.contentWindow.document; 77 78 } else if (io.contentDocument) { 79 xml.responseText = io.contentDocument.document.body ? io.contentDocument.document.body.innerHTML : null; 80 xml.responseXML = io.contentDocument.document.XMLDocument ? io.contentDocument.document.XMLDocument : io.contentDocument.document; 81 } 82 } catch (e) { 83 jQuery.handleError(s, xml, null, e); 84 } 85 if (xml || isTimeout == "timeout") { 86 requestDone = true; 87 var status; 88 try { 89 status = isTimeout != "timeout" ? "success" : "error"; 90 // Make sure that the request was successful or notmodified 91 if (status != "error") { 92 // process the data (runs the xml through httpData regardless of callback) 93 var data = jQuery.uploadHttpData(xml, s.dataType); 94 // If a local callback was specified, fire it and pass it the data 95 if (s.success) 96 s.success(data, status); 97 98 // Fire the global callback 99 if (s.global) 100 jQuery.event.trigger("ajaxSuccess", [xml, s]); 101 } else 102 jQuery.handleError(s, xml, status); 103 } catch (e) { 104 status = "error"; 105 jQuery.handleError(s, xml, status, e); 106 } 107 108 // The request was completed 109 if (s.global) 110 jQuery.event.trigger("ajaxComplete", [xml, s]); 111 112 // Handle the global AJAX counter 113 if (s.global && ! --jQuery.active) 114 jQuery.event.trigger("ajaxStop"); 115 116 // Process result 117 if (s.complete) 118 s.complete(xml, status); 119 120 jQuery(io).unbind() 121 122 setTimeout(function () { 123 try { 124 jQuery(io).remove(); 125 jQuery(form).remove(); 126 127 } catch (e) { 128 jQuery.handleError(s, xml, null, e); 129 } 130 131 }, 100) 132 133 xml = null 134 135 } 136 } 137 // Timeout checker 138 if (s.timeout > 0) { 139 setTimeout(function () { 140 // Check to see if the request is still happening 141 if (!requestDone) uploadCallback("timeout"); 142 }, s.timeout); 143 } 144 try { 145 146 var form = jQuery('#' + formId); 147 jQuery(form).attr('action', s.url); 148 jQuery(form).attr('method', 'POST'); 149 jQuery(form).attr('target', frameId); 150 if (form.encoding) { 151 jQuery(form).attr('encoding', 'multipart/form-data'); 152 } 153 else { 154 jQuery(form).attr('enctype', 'multipart/form-data'); 155 } 156 jQuery(form).submit(); 157 158 } catch (e) { 159 jQuery.handleError(s, xml, null, e); 160 } 161 162 jQuery('#' + frameId).load(uploadCallback); 163 return { abort: function () { } }; 164 165 }, 166 167 uploadHttpData: function (r, type) { 168 var data = !type; 169 if (!type) 170 data = r.responseText; 171 if (type == "xml") 172 data = r.responseXML; 173 //data = type == "xml" || data ? r.responseXML : r.responseText; 174 // If the type is "script", eval it in global context 175 if (type == "script") 176 jQuery.globalEval(data); 177 // Get the JavaScript object, if JSON is used. 178 if (type == "json") { 179 ////////////Fix the issue that it always throws the error "unexpected token '<'"/////////////// 180 data = r.responseText; 181 var start = data.indexOf(">"); 182 if (start != -1) { 183 var end = data.indexOf("<", start + 1); 184 if (end != -1) { 185 data = data.substring(start + 1, end); 186 } 187 } 188 /////////////////////////////////////////////////////////////////////////////////////////////// 189 eval("data = " + data); 190 } 191 // evaluate scripts within html 192 if (type == "html") 193 jQuery("<div>").html(data).evalScripts(); 194 195 return data; 196 }, 197 198 handleError: function (s, xhr, status, e) { 199 // If a local callback was specified, fire it 200 if (s.error) { 201 s.error.call(s.context || s, xhr, status, e); 202 } 203 204 // Fire the global callback 205 if (s.global) { 206 (s.context ? jQuery(s.context) : jQuery.event).trigger("ajaxError", [xhr, s, e]); 207 } 208 } 209 })
html代码:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>上传页面三</title> <script type="text/javascript" src="static/js/jquery-1.7.2.js"></script> <script type="text/javascript" src="static/js/ajaxfileupload.js"></script> </head> <body> <h2>JQuery ajaxfileupload文件上传</h2> <div id="loading" style="display: none;">正在上传.....</div> 用户信息: <br /> 姓名: <input id="name" name="name" type="text"> <br /> 附件: <input id="fileToUpload" name="file" type="file" class="input"> <br /> <input type="button" onclick="ajaxFileUpload()" value="上传"> <br /> <script type="text/javascript"> function ajaxFileUpload() { $('#loading').show(); $.ajaxFileUpload({ url : 'mvc/upload.g', secureuri : false, fileElementId : 'fileToUpload', dataType : 'json',//此时指定的是后台需要返回json字符串,前端自己解析,可以注释掉.后台直接返回map data : { name : $('#name').val() }, success : function(data, status) { alert("success"); console.log(data); $('#loading').hide(); }, error : function(data, status, e) { $('#loading').hide(); //这里处理的是网络异常,返回参数解析异常,DOM操作异常 alert("上传发生异常"); } }) } </script> </body> </html>
好,结束.
当你程序跑起来的时候,打开控制台你是看不到ajax提交请求的.因为ajaxFileupload.js上传的 原理是:form表单+iframe提交的.
服务器端返回的数据最终会进入到iframe里面的.通过修改ajaxFileUpload.js把这个数据从ifram中解析出来.
这个过程可以在success里加个alert,阻止脚本执行,来观察到.当success执行完毕后,form和iframe被删除.
可以结合前面的上传博客来更好地理解这里.