圖片即文件,在jsp中文件上傳很簡單,一個type爲file的input,一個form指定enctype爲multipart/form-data,經過post提交到後臺利用apache的commons-fileupload.XXjar便可實現。EasyUI的filebox組件也是用來進行文件上傳的,但我這裏的業務需求不單單是圖片上傳,還有其餘文本框的提交,因此須要文件上傳後再點擊保存。界面展現圖片是在數據列表中,所以須要小圖,點擊圖片後再展現大圖。javascript
由於這裏支付截圖上傳後需跟另外一個支付流水的文本框一塊兒在form裏提交,所以須要多加一個文件上傳按鈕來先進行圖片的上傳:css
選好圖片後點擊圖片上傳:html
傳好後點擊保存,支付流水和截圖將一塊兒入庫。再看數據列表的展現:java
鼠標點擊小圖展現大圖:web
這裏上傳和展現就一塊兒說明了:ajax
先看html,首先datagrid中咱們設置列頭時執行支付截圖須要經過imgFormatter方法進行格式化:spring
<th field="payFlow" width="3%">支付流水</th> <th field="photoUrl" width="3%" data-options="formatter:imgFormatter">支付截圖</th>
再看點擊編輯時彈出的form:apache
<div id="dlg" class="easyui-dialog" style="width:560px;height:300px;padding:10px 20px" closed="true" buttons="#dlg-buttons"> <div class="ftitle">支付信息</div> <form id="fm" method="post" novalidate> <div class="fitem"> <label>支付流水:</label> <input name="payFlow" class="easyui-numberbox"> </div> <div class="fitem"> <label>支付截圖:</label> <input id="photoUrl" name="photoUrl"> </div> </form> </div> <div id="dlg-buttons"> <a href="javascript:void(0)" class="easyui-linkbutton c6" iconCls="icon-save" onclick="saveFile()" style="width:90px">圖片上傳</a> <a href="javascript:void(0)" class="easyui-linkbutton c6" iconCls="icon-ok" onclick="saveFlow()" style="width:90px">保存</a> <a href="javascript:void(0)" class="easyui-linkbutton" iconCls="icon-cancel" onclick="javascript:$('#dlg').dialog('close')" style="width:90px">取消</a> </div>
再看下js,展現圖片、上傳圖片和保存信息都在這裏:json
var url; var uploadPath; $(function () { $('#photoUrl').filebox({ prompt: '請選擇一張圖片...', width: '280px', buttonText: '點擊選擇圖片' }) $('#photoUrl').filebox({ onChange: function () { var fileObj = $("input[name='photoUrl']")[0]; var allowExtention = ".jpg,.bmp,.gif,.png,.jpeg"; var extention = fileObj.value.substring(fileObj.value.lastIndexOf(".") + 1).toLowerCase(); if (allowExtention.indexOf(extention) == -1) { $.messager.show({ // show error message title: '錯誤', msg: "只支持如下格式圖片:" + allowExtention + "." }); $('#photoUrl').filebox('reset'); $('#photoUrl').filebox('setValue', ""); $('#photoUrl').filebox('disableValidation'); } } }) }); function imgFormatter(value, row, index) { if ('' != value && null != value) { var imgResult = "<img onclick=download(\"" + value + "\") style='width:30px; height:30px;margin-left:3px;' src='" + value + "' title='點擊查看全圖'/>"; return imgResult; } } function download(img) { var imgTemp = "http://localhost:8888" + img; $('#dlgImg').dialog({ title: '展現全圖', width: 600, height: 500, resizable: true, closed: false, cache: false, modal: true }); $('#imgTemp').attr("src", imgTemp); } function editFlow() { var row = $('#dg').datagrid('getSelected'); if (row) { $('#dlg').dialog('open').dialog('setTitle', '編輯'); $('#fm').form('load', row); url = 'update_pay?id=' + row.id; } } function saveFile() { // 異步提交文件 $.ajaxFileUpload({ url: 'uploadFile', secureuri: false, fileElementId: $("input[name='photoUrl']").attr("id"), type: 'post', success: function (data) { var reg = /<pre.+?>(.+)<\/pre>/g; var temp = data.match(reg); temp = RegExp.$1; var data = eval('(' + temp + ')'); if (data.resultPath) { uploadPath = data.resultPath; $.messager.show({ // show error message title: '成功', msg: '圖片上傳成功.' }); } }, error: function () { $.messager.show({ // show error message title: '錯誤', msg: "圖片上傳失敗." }); } }); $('#photoUrl').filebox('reset'); $('#photoUrl').filebox('setValue', ""); $('#photoUrl').filebox('disableValidation'); } function saveFlow() { if (uploadPath) { url = url + '&photoUrl=' + uploadPath; } $('#fm').form('submit', { url: url, onSubmit: function () { return $(this).form('validate'); }, success: function (result) { var result = eval('(' + result + ')'); if (result.errorMsg) { $.messager.show({ title: '錯誤', msg: "保存失敗." }); } else { $('#dlg').dialog('close'); // close the dialog $('#dg').datagrid('reload'); // reload the user data } } }); }
頭文件裏引入ajaxfileupload.jstomcat
<script src="ajaxfileupload.js" type="text/javascript"></script>
ajaxfileupload.js直接放在靜態文件目錄下便可,固然你也能夠本身找地方,上面的引入路徑能匹配到便可:
jQuery.extend({ createUploadIframe: function (d, b) { var a = "jUploadFrame" + d; var c = '<iframe id="' + a + '" name="' + a + '" style="position:absolute; top:-9999px; left:-9999px"'; if (window.ActiveXObject) { if (typeof b == "boolean") { c += ' src="' + "javascript:false" + '"' } else { if (typeof b == "string") { c += ' src="' + b + '"' } } } c += " />"; jQuery(c).appendTo(document.body); return jQuery("#" + a).get(0) }, createUploadForm: function (a, j, d) { var h = "jUploadForm" + a; var c = "jUploadFile" + a; var b = jQuery('<form action="" method="POST" name="' + h + '" id="' + h + '" enctype="multipart/form-data"></form>'); if (d) { for (var e in d) { if (d[e].name != null && d[e].value != null) { jQuery('<input type="hidden" name="' + d[e].name + '" value="' + d[e].value + '" />').appendTo(b) } else { jQuery('<input type="hidden" name="' + e + '" value="' + d[e] + '" />').appendTo(b) } } } var f = jQuery("#" + j); var g = jQuery(f).clone(); jQuery(f).attr("id", c); jQuery(f).before(g); jQuery(f).appendTo(b); jQuery(b).css("position", "absolute"); jQuery(b).css("top", "-1200px"); jQuery(b).css("left", "-1200px"); jQuery(b).appendTo("body"); return b }, ajaxFileUpload: function (k) { k = jQuery.extend({}, jQuery.ajaxSettings, k); var a = new Date().getTime(); var b = jQuery.createUploadForm(a, k.fileElementId, (typeof (k.data) == "undefined" ? false : k.data)); var i = jQuery.createUploadIframe(a, k.secureuri); var h = "jUploadFrame" + a; var j = "jUploadForm" + a; if (k.global && !jQuery.active++) { jQuery.event.trigger("ajaxStart") } var c = false; var f = {}; if (k.global) { jQuery.event.trigger("ajaxSend", [f, k]) } var d = function (l) { var p = document.getElementById(h); try { if (p.contentWindow) { f.responseText = p.contentWindow.document.body ? p.contentWindow.document.body.innerHTML : null; f.responseXML = p.contentWindow.document.XMLDocument ? p.contentWindow.document.XMLDocument : p.contentWindow.document } else { if (p.contentDocument) { f.responseText = p.contentDocument.document.body ? p.contentDocument.document.body.innerHTML : null; f.responseXML = p.contentDocument.document.XMLDocument ? p.contentDocument.document.XMLDocument : p.contentDocument.document } } } catch (o) { jQuery.handleError(k, f, null, o) } if (f || l == "timeout") { c = true; var m; try { m = l != "timeout" ? "success" : "error"; if (m != "error") { var n = jQuery.uploadHttpData(f, k.dataType); if (k.success) { k.success(n, m) } if (k.global) { jQuery.event.trigger("ajaxSuccess", [f, k]) } } else { jQuery.handleError(k, f, m) } } catch (o) { m = "error"; jQuery.handleError(k, f, m, o) } if (k.global) { jQuery.event.trigger("ajaxComplete", [f, k]) } if (k.global && !--jQuery.active) { jQuery.event.trigger("ajaxStop") } if (k.complete) { k.complete(f, m) } jQuery(p).unbind(); setTimeout(function () { try { jQuery(p).remove(); jQuery(b).remove() } catch (q) { jQuery.handleError(k, f, null, q) } }, 100); f = null } }; if (k.timeout > 0) { setTimeout(function () { if (!c) { d("timeout") } }, k.timeout) } try { var b = jQuery("#" + j); jQuery(b).attr("action", k.url); jQuery(b).attr("method", "POST"); jQuery(b).attr("target", h); if (b.encoding) { jQuery(b).attr("encoding", "multipart/form-data") } else { jQuery(b).attr("enctype", "multipart/form-data") } jQuery(b).submit() } catch (g) { jQuery.handleError(k, f, null, g) } jQuery("#" + h).load(d); return { abort: function () { } } }, uploadHttpData: function (r, type) { var data = !type; if (!type) { data = r.responseText } if (type == "xml") { data = r.responseXML } if (type == "script") { jQuery.globalEval(data) } 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) } if (type == "html") { jQuery("<div>").html(data).evalScripts() } return data }, handleError: function (b, d, a, c) { if (b.error) { b.error.call(b.context || b, d, a, c) } if (b.global) { (b.context ? jQuery(b.context) : jQuery.event).trigger("ajaxError", [d, b, c]) } } });
經過ajaxfileupload.js進行異步調用獲取到的json響應會多一些文本(其實就是一個<pre>標籤),因此上面在點擊保存時saveFile()經過正則過濾才能真正拿到圖片路徑。
最後看下後臺,文件上傳Controller:
@ResponseBody @RequestMapping(value = "uploadFile", method = RequestMethod.POST) public Object uploadFile(@RequestParam(value = "photoUrl") MultipartFile file, HttpServletRequest request) { Map<String, Object> resultMap = new HashMap<>(); String error = null; // 獲取文件名 String fileName = file.getOriginalFilename(); // 根據文件後綴生成新的文件名 String type = fileName.substring(fileName.lastIndexOf(".") + 1); String newFileName = Utils.createFileName(type); fileName = newFileName != null ? newFileName : fileName; // 上傳文件並返回相對路徑 String resultPath = null; try { resultPath = flowService.uploadFile(file.getBytes(), filePath, fileName); } catch (Exception e) { LOGGER.error("--uploadFile-- error: {}", e); error = e.getMessage(); } if (error != null) { resultMap.put("errorMsg", error); } else { resultMap.put("resultPath", resultPath); } return resultMap; }
這裏MultipartFile是spring自帶的,在spring boot中咱們無需引入額外的jar包,看下導入的包路徑便可明瞭:
org.springframework.web.multipart.MultipartFile
再看調用的service:
/** * 上傳文件 * * @param file * @param filePath * @param fileName * @return * @throws Exception */ public String uploadFile(byte[] file, String filePath, String fileName) throws Exception { // 判斷文件目錄是否存在,不存在則新建 File targetFile = new File(filePath); if (!targetFile.exists()) { targetFile.mkdir(); } // 新文件路徑 String fullPath = filePath + "/" + fileName; FileOutputStream out = new FileOutputStream(fullPath); out.write(file); out.flush(); out.close(); // 入庫路徑 return fullPath.substring(fullPath.indexOf("/")); }
上傳是否是很簡單?但有兩點須要注意:一個是文件上傳大小限制,一個是文件存儲目錄必需要跟js中的展現url創建映射,這兩點都須要在application.properties中配置:
#圖片保存路徑
imgUpload.file.savePath=D:/imgUpload
#上傳文件大小設置10M,默認是1M
spring.servlet.multipart.maxFileSize=10485760
文件路徑在上面的Controller裏經過定義全局變量filePath,而filePath則是經過註解從application.properties獲取
@Value("${imgUpload.file.savePath}") private String filePath;
經過新增java配置來映射物理文件地址和web訪問url:
import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfigurer implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/imgUpload/**").addResourceLocations("file:D:/imgUpload/"); } }
我將存放在D盤的imgUpload映射給tomcat下webapps的/imgUpload,這樣在dataGrid中展現的/imgUpload/test.jpg(後臺入庫時存儲的圖片路徑)就能經過本機地址http://localhost:8888/imgUpload/test.jpg訪問到並展現出來了。