jsp+springmvc实现文件上传、图片上传和及时预览图片
1、多文件上传:http://blog.csdn.net/a1314517love/article/details/24183273
2、单文件上传的简单示例:http://blog.csdn.net/cheung1021/article/details/7084673
3、springMVC+ajaxfileupload异步上传图片并及时预览
http://www.codeweblog.com/springmvc-ajaxfileupload%E5%BC%82%E6%AD%A5%E4%B8%8A%E4%BC%A0%E5%9B%BE%E7%89%87%E9%A2%84%E8%A7%88-%E8%A3%81%E5%89%AA%E5%B9%B6%E4%BF%9D%E5%AD%98%E5%9B%BE%E7%89%87/
个人实践:
一、对1中的第二种方法的实现:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@taglib uri="http://www.springframework.org/tags/form" prefix="form" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>${pageTitle }</title> <link href="/Public/media/css/new/page.css" rel="stylesheet" type="text/css" /> </head> <body> <form action="${pageContext.request.contextPath}/workConfig/upload" method="post" enctype="multipart/form-data"> name:<input name="name" type="text" ><br /> <input name="file" type="file" ><br /> <input name="file2" type="file" ><br /> <input name="file3" type="file" ><br /> <input name="file4" type="file" ><br /> <input type="submit" value="提交"> </form> </body> </html>
package com.leslie.controller; import java.io.File; import java.io.IOException; import java.util.Iterator; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.commons.CommonsMultipartResolver; import org.springframework.web.servlet.ModelAndView; import com.leslie.User; @Controller @RequestMapping("/workConfig") public class SJWorkConfigController { private Logger log = LoggerFactory.getLogger(SJWorkConfigController .class); @RequestMapping(value = "/upload") public ModelAndView upload(@Valid @ModelAttribute User user, BindingResult br, HttpServletRequest request, HttpServletResponse response) throws IllegalStateException, IOException { // 创建一个通用的多部分解析器 CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver( request.getSession().getServletContext()); // 判断 request 是否有文件上传,即多部分请求 if (multipartResolver.isMultipart(request)) { // 转换成多部分request MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request; // 取得request中的所有文件名 Iterator<String> iter = multiRequest.getFileNames(); while (iter.hasNext()) { // 记录上传过程起始时的时间,用来计算上传时间 // int pre = (int) System.currentTimeMillis(); // 取得上传文件 MultipartFile file = multiRequest.getFile(iter.next()); if (file != null) { // 取得当前上传文件的文件名称 String myFileName = file.getOriginalFilename(); // 如果名称不为“”,说明该文件存在,否则说明该文件不存在 if (myFileName.trim() != "") { System.out.println(myFileName); // 重命名上传后的文件名 String fileName = "demoUpload" + file.getOriginalFilename(); // 定义上传路径 String path = "E:/test/" + fileName; File localFile = new File(path); file.transferTo(localFile); } } // 记录上传该文件后的时间 // int finaltime = (int) System.currentTimeMillis(); // System.out.println(finaltime - pre); } } ModelAndView mv = new ModelAndView(); mv.addObject("message", request.getParameter("name").toString()); mv.setViewName("hello"); return mv; } // @RequestMapping(value = "/upload") // public ModelAndView upload(DefaultMultipartHttpServletRequest request) { // CommonsMultipartFile file = (CommonsMultipartFile) // request.getFile("file"); // // 这里的file就是前台页面的name // if (file.isEmpty()) { // return null; // } // // 获取路径,生成完整的文件路径 // String fileName = "E:/test/"+"demoUpload" + file.getOriginalFilename(); // File uploadFile = new File(fileName); // try { // // 上传 // FileCopyUtils.copy(file.getBytes(), uploadFile); // } catch (IOException e) { // e.printStackTrace(); // } // ModelAndView mv = new ModelAndView(); // mv.addObject("message",request.getParameter("name").toString()); // mv.setViewName("hello"); // return mv; // } }
1、1中的方法比较通用,且一次能上传多个文件。
2、虽然request的类型是MultipartHttpServletRequest,但仍可继续使用request.getParameter来正常取表单中的非Multipart内容,
这样就可以将图片和普通表单内容一次提交了。
二、对3中方法的实现
注:3文中不但实现了图片上传和预览,并且有使用js切图的功能。由于我使用java在后台切图,所以只使用了它的文件上传预览功能。
前台页面代码:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>${pageTitle }</title> <link href="/Public/media/css/new/page.css" rel="stylesheet" type="text/css" /> <style type="text/css"> .errormsg { font-family: "微软雅黑"; color: #F30; } </style> </head> <body> <div class="outer"> <div class="pathdiv"> ${currentMenuDesc } <div class="tableDivTitleButtonDiv"> <a href="${backToURL}"><input type="button" class="tableDivTitleButtonDivButton" value="返回" /></a> </div> </div> <div class="infoTitle">${pageTitle }</div> <form:form action="${formActionURL}" method="post" commandName="work"> <div class="formDiv"> <table width="1020" border="0"> <tr> <form:input path="worksId" type="hidden" /> <form:input path="designerId" type="hidden" /> <form:input path="worksImg1" type="hidden" /> <form:input path="worksImg2" type="hidden" /> <form:input path="worksImg3" type="hidden" /> <td align="right">作品名称:</td> <td align="left"><form:input path="worksName" /><span class="errormsg"><form:errors path="worksName" /></span></td> </tr> <tr> <td align="right">作品说明:</td> <td align="left"><form:textarea path="worksRemark" cols="30" rows="10" /><span class="errormsg"><form:errors path="worksRemark" /></span></td> </tr> <tr> <td align="right">作品图1:</td> <td align="left"> <input name="realPicFile" id="realPicFile" type="file" onchange="ajaxFileUpload()"/> <img src="/Public/media/image/loading2.gif" id="loading" style="display: none;"> <img id="realPic" src="/Public/showimgbj.jpg"/> <span class="errormsg"> <form:errors path="worksImg1" /> </span> </td> </tr> <tr> <td align="right">作品图2:</td> <td align="left"><input name="" type="file" /><img id="img2" src="" /><span class="errormsg"><form:errors path="worksImg2" /></span></td> </tr> <tr> <td align="right">作品图3:</td> <td align="left"><input name="" type="file" /><img id="img3" src="" /><span class="errormsg"><form:errors path="worksImg3" /></span></td> </tr> <tr> <td></td> <td><input name="" type="submit" value="提交" /></td> </tr> </table> </div> </form:form> </div> <div id="errorMsgDiv"></div> <script src="/Public/media/js/jquery-1.10.1.min.js" type="text/javascript"></script> <script src="/Public/media/js/jquery-migrate-1.2.1.min.js" type="text/javascript"></script> <script src="/Public/media/js/bootstrap.min.js" type="text/javascript"></script> <script src="/Public/media/js/jquery.gritter.js" type="text/javascript"></script> <script src="/Public/media/js/app.js" type="text/javascript"></script> <script src="/Public/media/css/new/ajaxfileupload.js" type="text/javascript"></script> <script> jQuery(document).ready(function() { App.init(); // initlayout and core plugins }); </script> <script> function ajaxFileUpload() { var file = $("#realPicFile").val(); if(!/\.(gif|jpg|jpeg|png|JPG|PNG)$/.test(file)){ Error("不支持的图片格式.图片类型必须是.jpeg,jpg,png,gif格式."); return false; } $.ajaxFileUpload({ url : '${pageContext.request.contextPath}/workConfig/uploadOnePic?inputId=realPicFile', secureuri : false, fileElementId : 'realPicFile', dataType : 'content', success : function(data, status){ $("#realPic").attr("src", data); }, error : function(data, status, e){ alert(e); //Error(e); } }); return false; } </script> </body> </html>
后台controller代码(不包括切图):
package com.leslie.controller; import java.io.File; import java.io.IOException; import java.util.Iterator; import java.util.List; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; import org.apache.commons.lang3.exception.ExceptionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.commons.CommonsMultipartResolver; import org.springframework.web.servlet.ModelAndView; import com.leslie.model.DesignerWorks; import com.leslie.model.MemberDesigner; import com.leslie.model.User; import com.leslie.service.DesignerService; import com.leslie.util.ConstantsUtil; import com.leslie.validator.DesignerWorksValidator; @Controller @RequestMapping("/workConfig") public class SJWorkConfigController { @RequestMapping("/uploadOnePic") @ResponseBody public String fileUpload(String inputId, MultipartHttpServletRequest request) { try { MultipartFile realPicFile = request.getFile(inputId); if (realPicFile != null) { // 取得当前上传文件的文件名称 String myFileName = realPicFile.getOriginalFilename(); // 如果名称不为“”,说明该文件存在,否则说明该文件不存在 if (myFileName.trim() != "") { System.out.println(myFileName); // 重命名上传后的文件名 String fileName = "demoUpload" + realPicFile.getOriginalFilename(); // 定义上传路径 String path = "D:/program files/apache-tomcat-8.0.33/webapps/Public/upload/images/" + fileName; String pathReturn = "/Public/upload/images/" + fileName; File localFile = new File(path); realPicFile.transferTo(localFile); return pathReturn; } } } catch (Exception e) { // LOG.error("upload header picture error : ", e); } return null; } }
过程概述:用户点选了文件选择器的按钮以后,浏览器弹出选择文件的对话框,当用户选定了某张图片并确定以后,会触发文件选择器的onchange事件,我们在onchange事件里调用ajaxfileupload将文件选择器
选中的文件提交到后台处理,后台通过request拿到文件以后,可以裁剪,可以保存,可以做很多事情,然后将保存以后的文件的url路径返回给前台ajaxfileupload,ajaxfileupload拿到文件路径以后,将页面中
相应的img标签的src属性改成文件路径,然后这张图片就在页面中显示出来了。
说明:
1、ajaxfileupload的功能只是将文件提交到后台,真正对图片进行保存、裁切等处理的还是后台程序。
2、ajaxfileupload的dataType属性一般为"json",但我在使用json类型时报错,后台返回给前台数据以后走到了error分支,弹出“syntexError:unexpeted token”。网上搜了一下,有高人通过修改
ajaxfileupload源码解决了问题(原文地址:http://liwx2000.iteye.com/blog/1540321),但我在实践中按它的办法修改问题依然存在,于是我将类型改为content就搞定了,正确返回了文件的路径
并走入了success分支。
3、在保存文件时定义了两个文件路径,path指的是图片在服务器本地保存的绝对路径,pathReturn指的是用户在浏览器上看到的图片的src路径,此处需要注意,如果将path直接返回,
页面上是看不到图片的。
4、ajaxfileupload.js的下载:http://www.cnblogs.com/kissdodog/archive/2012/12/15/2819025.html
三、后记
按照二中的办法,似乎一切顺风顺水波澜不惊,但却有一个问题无法解决:虽然使用ajaxfileupload成功完成了图片的上传和及时预览,但文件选择器(<input type="file")在选中了图片以后却始终无法显示
图片的url,一直显示“未选择文件”,这似乎是ajaxfileupload的一个bug。最后我使用了一个折中的办法,将文件选择器隐藏,使用一个普通的按钮,当它被点击时触发文件选择器的onclick事件。下面重新给出整理以后的代码。
jsp代码
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>${pageTitle }</title> <link href="/Public/media/css/new/page.css" rel="stylesheet" type="text/css" /> <style type="text/css"> .errormsg { font-family: "微软雅黑"; color: #F30; } </style> </head> <body> <div class="outer"> <div class="pathdiv"> ${currentMenuDesc } <div class="tableDivTitleButtonDiv"> <a href="${backToURL}"><input type="button" class="tableDivTitleButtonDivButton" value="返回" /></a> </div> </div> <div class="infoTitle">${pageTitle }</div> <form:form action="${formActionURL}" method="post" commandName="work"> <div class="formDiv"> <table width="1020" border="0"> <tr> <form:input path="worksId" type="hidden" /> <form:input path="designerId" type="hidden" /> <form:input id = "hiddenImgValue1" path="worksImg1" type="hidden" /> <form:input id = "hiddenImgValue2" path="worksImg2" type="hidden" /> <form:input id = "hiddenImgValue3" path="worksImg3" type="hidden" /> <td align="right">作品名称:</td> <td align="left"><form:input path="worksName" /><span class="errormsg"><form:errors path="worksName" /></span></td> </tr> <tr> <td align="right">作品说明:</td> <td align="left"><form:textarea path="worksRemark" cols="30" rows="10" /><span class="errormsg"><form:errors path="worksRemark" /></span></td> </tr> <tr> <td align="right">作品图1:</td> <td align="left"> <img src="/Public/media/image/loading2.gif" id="loading" style="display: none;"> <img id="realPic1" src="/Public/showimgbj.jpg"/> <input name="realPicFile1" id="realPicFile1" type="file" onchange="ajaxFileUpload('realPicFile1','realPic1','hiddenImgValue1')" style='display:none'/> <input type=button onclick="upImg('realPicFile1')" value="上传" /> <span class="errormsg"> <form:errors path="worksImg1" /> </span> </td> </tr> <tr> <td align="right">作品图2:</td> <td align="left"> <img src="/Public/media/image/loading2.gif" id="loading" style="display: none;"> <img id="realPic2" src="/Public/showimgbj.jpg"/> <input name="realPicFile2" id="realPicFile2" type="file" onchange="ajaxFileUpload('realPicFile2','realPic2','hiddenImgValue2')" style='display:none'/> <input type=button onclick="upImg('realPicFile2')" value="上传" /> <span class="errormsg"> <form:errors path="worksImg2" /> </span> </td> </tr> <tr> <td align="right">作品图3:</td> <td align="left"> <img src="/Public/media/image/loading2.gif" id="loading" style="display: none;"> <img id="realPic3" src="/Public/showimgbj.jpg"/> <input name="realPicFile3" id="realPicFile3" type="file" onchange="ajaxFileUpload('realPicFile3','realPic3','hiddenImgValue3')" style='display:none'/> <input type=button onclick="upImg('realPicFile3')" value="上传" /> <span class="errormsg"><form:errors path="worksImg3" /> </span> </td> </tr> <tr> <td></td> <td><input name="" type="submit" value="提交" /></td> </tr> </table> </div> </form:form> </div> <div id="errorMsgDiv"></div> <script src="/Public/media/js/jquery-1.10.1.min.js" type="text/javascript"></script> <script src="/Public/media/js/jquery-migrate-1.2.1.min.js" type="text/javascript"></script> <script src="/Public/media/js/bootstrap.min.js" type="text/javascript"></script> <script src="/Public/media/js/jquery.gritter.js" type="text/javascript"></script> <script src="/Public/media/js/app.js" type="text/javascript"></script> <script src="/Public/media/css/new/ajaxfileupload.js" type="text/javascript"></script> <script> jQuery(document).ready(function() { App.init(); // initlayout and core plugins }); </script> <script> function upImg(fileID){ $("#"+fileID).click(); } function ajaxFileUpload(fileID,imgID,hiddenImgValue) { /*var file = $("#"+hiddenImgValue).val(); if(!/\.(jpg|png|JPG|PNG)$/.test(file)){ Error("不支持的图片格式.图片类型必须是.jpg,png格式."); return false; }*/ $.ajaxFileUpload({ url : '${pageContext.request.contextPath}/workConfig/uploadOnePic?inputId='+fileID, secureuri : false, fileElementId : fileID, dataType : 'json', success : function(data, status){ $("#"+imgID).attr("src", data.result); $("#"+hiddenImgValue).val(data.result); //$(this).val(data.result); //console.log($('#realPicFile')); }, error : function(data, status, e){ alert(e); //Error(e); } }); return true; } </script> </body> </html>
controller代码
@RequestMapping("/uploadOnePic") @ResponseBody public AjaxResultDomain fileUpload(String inputId, MultipartHttpServletRequest request) { try { // 拿到文件 MultipartFile realPicFile = request.getFile(inputId); // 准备好路径参数 String uploadImagesSavePath = pathUtil.getYgbhUploadImagesDiskFolderPath(request); String urlRootPath = pathUtil.getYgbhUploadImagesUrlFolderPath(); List<MultipartFile> files = new ArrayList<MultipartFile>(); files.add(realPicFile); // 保存+压缩 String fileName = MultipartFileUtil.saveAndConstrictMultipartFiles(files, uploadImagesSavePath, urlRootPath) .get(0); String fileUrl = urlRootPath + fileName; AjaxResultDomain d = new AjaxResultDomain(); d.setResult(fileUrl); return d; } catch (Exception e) { e.printStackTrace(); } return null; }
注意,ajax拿到后台返回的值data以后,使用data.result给图片地址赋值而不是直接用data赋值。原因是,如果后台直接将图片地址作为String字符串返回给前台的话,js会将图片地址辨认为是一个正则表达式并报错。
所以,对付js这么灵活的东西,能绕开就绕开,否则坑很深。不跟它纠结,直接用一个object返回来,然后取object的属性。