SPRING MVC 模式下base64编码格式实现多图片上传,删除

前提:

       在H5多图上传的场合,file框的filelist属性是不可编辑的,所以,无法通过修正filelist属性来达到将上传的多图中某一张图片删除。那么就可以使用另一种方式来达到目的即:base64编码格式。

背景知识:

       Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,大家可以查看RFC2045~RFC2049,上面有MIME的详细规范。Base64编码可用于在HTTP环境下传递较长的标识信息。例如,在Java Persistence系统Hibernate中,就采用了Base64来将一个较长的唯一标识符(一般为128-bit的UUID)编码为一个字符串,用作HTTP表单和HTTP GET URL中的参数。在其他应用程序中,也常常需要把二进制数据编码为适合放在URL(包括隐藏表单域)中的形式。此时,采用Base64编码具有不可读性,即所编码的数据不会被人用肉眼所直接看到。(引用自百度百科..)

       根据介绍,我们可以直接把用户上传的图片转变为字节代码存放在画面的隐藏文本框,通过编辑隐藏文本框的值来达到删除某一张图片的目的。

实现方式:

       具体可以通过代码段来参照:

<%@ page contentType="text/html;charset=UTF-8" %>
<%@ include file="/WEB-INF/views/include/taglib.jsp"%>商品管理rel="stylesheet" href="${ctxStatic}/common/multiplefileUpload.css" type="text/css" /> 第1张图片将会用做列表页面显示,最多可以上传5张
(建议图片尺寸640*400像素,图片小于1M的jpg、png格式图片)
style="display: none;" >
var tempInterval; var img_index_arr = [0,1,2,3,4];Array.prototype.remove = function(val) {var index = this.indexOf(parseInt(val));if (index > -1) {this.splice(index, 1);} }; $(function() {var delParent;var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串if (userAgent.indexOf("Chrome") > -1){$(".file").addClass("fileForChrome");$(".file").removeClass("file");}var defaults = { // fileType : [ "jpg", "png", "bmp", "jpeg" ], // 上传文件的类型fileType : [ "jpg", "png"], // 上传文件的类型fileSize : 1024 * 1024 * 1// 上传文件的大小 1M};$(".picindex").each(function() {img_index_arr.remove($(this).val());});/*** 判定选中的图片的合法性并添加到页面*/ function addPic(fileList, tempInterval, arrImgs, numUp, imgContainer){var flag = true;for(var i = 0 ; i < arrImgs.length ; i++){if (arrImgs[i].height <= 0 || arrImgs[i].width <= 0) {flag = false;break;}}if (flag) {if (fileList.length = 0) {alertx("未选择任何文件;");return;} else if (numUp < 5) { // 停止定时任务clearInterval(tempInterval);fileList = validateUpOnlyOne(fileList, arrImgs);for (var i = 0; i < fileList.length; i++) {var $section = $("
");$(".z_file").before($section);var $span = $("");$span.appendTo($section);var $img0 = $("").on("click", function(event) {event.preventDefault();event.stopPropagation();$(".works-mask").show();delParent = $(this).parent();});$img0.attr("src","/ehomebusiness/static/images/a7.png").appendTo($section);var img_index = img_index_arr[0];var $img = $("");$img.attr("src", "");$img.appendTo($section);var $textarea = $("");$textarea.appendTo($section);var $input3 = $("");$input3.appendTo($section);var $input4 = $("");$input4.appendTo($section);var reader = new FileReader();reader.readAsDataURL(fileList[i]);reader.onload = function(e) {if (document.getElementsByName("picList[0].imgBase64").length != 0&& document.getElementsByName("picList[0].imgBase64")[0].innerHTML == "") {document.getElementsByName("picList[0].imgBase64")[0].innerHTML = this.result;document.getElementsByName("imgName0")[0].src = this.result;} else if (document.getElementsByName("picList[1].imgBase64").length != 0&& document.getElementsByName("picList[1].imgBase64")[0].innerHTML == "") {document.getElementsByName("picList[1].imgBase64")[0].innerHTML = this.result;document.getElementsByName("imgName1")[0].src = this.result;} else if (document.getElementsByName("picList[2].imgBase64").length != 0&& document.getElementsByName("picList[2].imgBase64")[0].innerHTML == "") {document.getElementsByName("picList[2].imgBase64")[0].innerHTML = this.result;document.getElementsByName("imgName2")[0].src = this.result;} else if (document.getElementsByName("picList[3].imgBase64").length != 0&& document.getElementsByName("picList[3].imgBase64")[0].innerHTML == "") {document.getElementsByName("picList[3].imgBase64")[0].innerHTML = this.result;document.getElementsByName("imgName3")[0].src = this.result;} else if (document.getElementsByName("picList[4].imgBase64").length != 0&& document.getElementsByName("picList[4].imgBase64")[0].innerHTML == "") {document.getElementsByName("picList[4].imgBase64")[0].innerHTML = this.result;document.getElementsByName("imgName4")[0].src = this.result;}}img_index_arr.remove(img_index);}}setTimeout(function() {$(".up-section").removeClass("loading");$(".up-img").removeClass("up-opcity");}, 450);numUp = imgContainer.find(".up-section").length;if (numUp >= 5) {$(".fileForChrome").parent().hide();$(".file").parent().hide();}}}// 文本框CHANGE事件function fileChangeFunc(fileClass) {var idFile = $(fileClass).attr("id");var file = document.getElementById(idFile);var imgContainer = $(fileClass).parents(".z_photo"); // 存放图片的父亲元素var fileList = file.files; // 获取的图片文件var input = $(fileClass).parent();// 文本框的父亲元素// 遍历得到的图片文件var numUp = imgContainer.find(".up-section").length;var totalNum = numUp + fileList.length; // 总的数量if (fileList.length > 5 || totalNum > 5) {alertx("上传图片数目不可以超过5个,请重新选择"); // 一次选择上传超过5个// 或者是已经上传和这次上传的到的总数也不可以超过5个return;}// 获取所有图片var arrImgs = [];// 所有图片的集合for (var i = 0, file; file = fileList[i]; i++) {// 获取文件上传的后缀名var newStr = file.name.split("").reverse().join("");if (newStr.split(".")[0] != null) {var type = newStr.split(".")[0].split("").reverse().join("");if (jQuery.inArray(type, defaults.fileType) > -1) {var img = new Image;var imgUrl = window.URL.createObjectURL(fileList[i]);img.src = imgUrl;arrImgs.push(img);} else {alertx('您这个"' + file.name + '"上传类型不符合');// 为了重新触发新时间需要remove掉旧输入款生成新的removeInputAndCreate();}} else {alertx('您这个"' + file.name + '"没有类型, 无法识别');// 为了重新触发新时间需要remove掉旧输入款生成新的removeInputAndCreate();}}tempInterval = self.setInterval(function(){addPic(fileList, tempInterval, arrImgs, numUp, imgContainer)},200);}// 为了重新触发新时间需要remove掉旧输入款生成新的function removeInputAndCreate() {var file = $(".file");file.after(file.clone().val(""));file.remove();var fileForChrome = $(".fileForChrome");fileForChrome.after(fileForChrome.clone().val(""));fileForChrome.remove();$(".file").change(function() {fileChangeFunc(".file")});$(".fileForChrome").change( function() {fileChangeFunc(".fileForChrome")});}/* 点击图片的文本框 */$(".file").change(function() {fileChangeFunc(".file")});/* 点击图片的文本框 */$(".fileForChrome").change( function() {fileChangeFunc(".fileForChrome")});$(".z_photo").delegate(".close-upimg", "click", function() {$(".works-mask").show();delParent = $(this).parent();});$(".wsdel-ok").click(function() {$(".works-mask").hide();var numUp = delParent.siblings().length;if (numUp < 6) {delParent.parent().find(".z_file").css('display','inline-block').css('vertical-align', 'top');delParent.parent().find(".z_file").show();}if (typeof (delParent.find("textarea")[0]) == "undefined"|| delParent.find("textarea")[0].innerHTML == "") {// 第一个是图片叉号var path = delParent.find("img")[1].src;if (path.indexOf("/") > 0)// 如果包含有"/"号// 从最后一个"/"号+1的位置开始截取字符串{filename = delParent.find(".filename").val();document.getElementById("delImageName").value = document.getElementById("delImageName").value+ filename + ",";}}var del_index = delParent.find(".picindex").val();var temp_arr = [];temp_arr.push(parseInt(del_index));img_index_arr = temp_arr.concat(img_index_arr);img_index_arr = img_index_arr.sort();delParent.remove();});$(".wsdel-no").click(function() {$(".works-mask").hide();});// 文件大小长宽CHECKfunction validateUpOnlyOne(files, arrImgs) {var arrFiles = [];// 替换的文件数组// 在这里需要判断当前所有文件中// 类型符合,可以上传for(var i = 0 ; i < arrImgs.length ; i++){// file个数应与arrImgs中元素数相等var file = files[i];if (file.size >= defaults.fileSize) {alertx('您这个"' + file.name + '"图片大小超过1M。');// 为了重新触发新时间需要remove掉旧输入款生成新的removeInputAndCreate();} else if (arrImgs[i].height > 400) {alertx('您这个"' + file.name + '"图片高度超过400像素。');// 为了重新触发新时间需要remove掉旧输入款生成新的removeInputAndCreate();} else if (arrImgs[i].width > 640) {alertx('您这个"' + file.name + '"图片宽度超过640像素。');// 为了重新触发新时间需要remove掉旧输入款生成新的removeInputAndCreate();} else {arrFiles.push(file);}}return arrFiles;} });/*上传图片插件的样式*/ .img-box{margin-top: 40px; } .img-box .up-p{margin-bottom: 20px;font-size: 16px;color: #555; } .z_photo{padding: 18px;border:2px dashed #E7E6E6;/*padding: 18px;*/ } .z_photo .z_file{position: relative; } .z_file .file{width: 150px;height: 112.6px;opacity: 0;position: absolute;top: 0px;left: 0px;z-index: 100; } .z_photo .up-section{position: relative;margin-right: 20px;margin-bottom: 20px;display:inline-block; } .up-section .close-upimg{position: absolute;top: 6px;right: 8px;display: none;z-index: 10; } .up-section .up-span{display: block;width: 100%;height: 100%;visibility: hidden;position: absolute;top: 0px;left: 0px;margin-left:0px;z-index: 9;background: rgba(0,0,0,.5); } .up-section:hover{border: 2px solid #f15134; } .up-section:hover .close-upimg{display: block; } .up-section:hover .up-span{visibility: visible; } .z_photo .up-img{display: block;width: 150px;height: 112.6px; } .loading{border: 1px solid #D1D1D1;background:url(${ctxStatic}/images/loading.gif) no-repeat center; } .up-opcity{opacity: 0; } .img-base64-textarea{display: none; } .upimg-div .up-section {width: 150px;height: 112.6px; } .img-box .upimg-div .z_file {width: 150px;height: 112.6px;display:inline-block; vertical-align:top; } .z_file .add-img {display: block;width: 150px;height: 112.6px; } /*遮罩层样式*/ .mask{z-index: 1000;display: none;position: fixed;top: 0px;left: 0px;width: 100%;height: 100%;background: rgba(0,0,0,.4); } .mask .mask-content{width: 500px;position: absolute;top: 50%;left: 50%;margin-left: -250px;margin-top: -80px;background: white;height: 160px;text-align: center; } .mask .mask-content .del-p{color: #555;height: 94px;line-height: 94px;font-size: 18px;border-bottom: 1px solid #D1D1D1; } .mask-content .check-p{height: 66px;line-height: 66px;position: absolute;bottom: 0px;left: 0px;width: 100%; } .mask-content .check-p span{width: 49%;display:inline-block;text-align: center;color:#d4361d ;font-size: 18px; } .check-p .del-com{border-right: 1px solid #D1D1D1; } .up-section .type-upimg{display: none; } ::-ms-clear,::-ms-reveal{display:none;}/*** Copyright © 2012-2014 Its111 All rights reserved.*/ package com.its.modules.goods.web;import java.awt.Image; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.List;import javax.imageio.ImageIO; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; 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.servlet.mvc.support.RedirectAttributes; import org.springframework.web.servlet.support.RequestContextUtils;import com.its.common.config.Global; import com.its.common.persistence.Page; import com.its.common.web.BaseController; import com.its.common.utils.DateUtils; import com.its.common.utils.StringUtils; import com.its.modules.goods.entity.GoodsInfo; import com.its.modules.goods.entity.GoodsInfoPic; import com.its.modules.goods.entity.GoodsSkuPrice; import com.its.modules.goods.entity.SkuKey; import com.its.modules.goods.entity.SortInfo; import com.its.modules.goods.service.GoodsInfoService; import com.its.modules.goods.service.SkuKeyService; import com.its.modules.goods.service.SortInfoService; import com.its.modules.setup.entity.BusinessInfo; import com.its.modules.setup.entity.BusinessUnit; import com.its.modules.setup.service.BusinessInfoService; import com.its.modules.setup.service.BusinessUnitService; import com.its.modules.sys.entity.User; import com.its.modules.sys.utils.UserUtils; import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGImageEncoder;import sun.misc.BASE64Decoder;/*** 商品信息Controller* * @author test* @version 2017-07-04*/ @Controller @RequestMapping(value = "${adminPath}/goods/goodsInfo") public class GoodsInfoController extends BaseController {/*** 商品分类信息Service*/@Autowiredprivate SortInfoService sortInfoService;/*** 商品信息Service*/@Autowiredprivate GoodsInfoService goodsInfoService;/** 商品规格名称Service */@Autowiredprivate SkuKeyService skuKeyService;/** 商家单位信息Service */@Autowiredprivate BusinessUnitService businessUnitService;/** 商家信息管理Service */@Autowiredprivate BusinessInfoService businessInfoService;/*** 商品信息保存处理* * @param goodsInfo* 商品信息Entity* @param model* @param redirectAttributes* @return*/@RequiresPermissions("goods:goodsInfo:edit")@RequestMapping(value = "save")public String save(GoodsInfo goodsInfo, HttpServletRequest request, Model model,RedirectAttributes redirectAttributes) {// 从SESSION中取得商家信息User user = UserUtils.getUser();// 商家ID设定goodsInfo.setBusinessInfoId(user.getBusinessinfoId());// 如果本身没有图片,且画面上没有添加if (StringUtils.isBlank(goodsInfo.getImgs())&& (goodsInfo.getPicList() == null || goodsInfo.getPicList().size() == 0)) {addMessage(model, "未选择任何图片");return form(goodsInfo, request, model);}// 删除后的图片名称String imgUrlsForUpdate = goodsInfo.getImgs();if (StringUtils.isNotBlank(goodsInfo.getDelImageName())){String[] delImgName = goodsInfo.getDelImageName().split(",");for (String imgName : delImgName) {imgUrlsForUpdate = imgUrlsForUpdate.replace(imgName + ",", "");// 避免该文件在最后一个imgUrlsForUpdate = imgUrlsForUpdate.replace(imgName, "");}}// 本身有图片,但全部删除场合if (StringUtils.isBlank(imgUrlsForUpdate)&& (goodsInfo.getPicList() == null || goodsInfo.getPicList().size() == 0)) {addMessage(model, "未选择任何图片");return form(goodsInfo, request, model);}if (!beanValidator(model, goodsInfo)) {return form(goodsInfo, request, model);}// BASE64解码器BASE64Decoder decoder = new BASE64Decoder();// 图片保存路径:发布路径/upload/商家ID/商品ID/StringBuffer ctxPath = new StringBuffer();ctxPath.append(RequestContextUtils.getWebApplicationContext(request).getServletContext().getRealPath("/"));ctxPath.append("upload");ctxPath.append("\\");// 如果没有upload的话就创建该目录File dir = new File(ctxPath.toString());if (!dir.exists()) {dir.mkdir();}ctxPath.append(user.getBusinessinfoId());ctxPath.append("\\");// 如果没有该商家目录的话就创建该目录dir = new File(ctxPath.toString());if (!dir.exists()) {dir.mkdir();}ctxPath.append(goodsInfo.getId());ctxPath.append("\\");// 如果没有该商品目录的话就创建该目录dir = new File(ctxPath.toString());if (!dir.exists()) {dir.mkdir();}// 原图片保存路径dir = new File(ctxPath.toString() + "temp\\");if (!dir.exists()) {dir.mkdir();}// 220 * 165压缩版本保存路径dir = new File(ctxPath.toString() + "compress1\\");if (!dir.exists()) {dir.mkdir();}// 134 * 100压缩版本保存路径dir = new File(ctxPath.toString() + "compress2\\");if (!dir.exists()) {dir.mkdir();}ListimgNameUrl = new ArrayList();if (goodsInfo.getPicList() != null) {for (GoodsInfoPic goodsInfoPic : goodsInfo.getPicList()) {try {if (StringUtils.isEmpty(goodsInfoPic.getImgBase64())) {continue;}// 将BASE64编码开头去掉String img = goodsInfoPic.getImgBase64().replaceAll("data:" + goodsInfoPic.getType() + ";base64,","");byte[] b = decoder.decodeBuffer(img);// 文件名以当前时间+2位随机数构成int i = (int) (Math.random() * 900) + 100;String fileName = DateUtils.getDate("yyyyMMddHHmmss") + String.valueOf(i) + ".jpg";// 生成jpg图片String imgFilePath = ctxPath + "temp\\" + fileName;// 新生成的图片OutputStream out = new FileOutputStream(imgFilePath);out.write(b);out.flush();out.close();imgNameUrl.add(fileName);// 图片750 * 563压缩resize(750, 563, ctxPath + fileName, imgFilePath);boolean firstImg = true;if (firstImg) {// 图片220 * 165压缩resize(220, 165, ctxPath + "compress1\\" + fileName, imgFilePath);// 图片134 * 100压缩resize(134, 100, ctxPath + "compress2\\" + fileName, imgFilePath);firstImg = false;}} catch (FileNotFoundException e) {addMessage(redirectAttributes, "图片保存失败");return "redirect:" + Global.getAdminPath() + "/goods/goodsInfo/?repage";} catch (IOException e) {addMessage(redirectAttributes, "图片保存失败");return "redirect:" + Global.getAdminPath() + "/goods/goodsInfo/?repage";}}}// 文件删除if (StringUtils.isNotBlank(goodsInfo.getDelImageName())) {String[] delImgName = goodsInfo.getDelImageName().split(",");for (String imgName : delImgName) {// 源文件删除File file = new File(ctxPath + "temp\\" + imgName);// 源文件删除file.delete();// 750X563压缩版file = new File(ctxPath + imgName);// 50X563压缩版文件删除file.delete();// 220 * 165压缩版file = new File(ctxPath + "compress1\\" + imgName);// 220 * 165压缩版文件删除file.delete();// 134 * 100压缩版file = new File(ctxPath + "compress2\\" + imgName);// 134 * 100压缩版文件删除file.delete();}}// 将上传成功的图片地址更新到DB中goodsInfoService.imgNameUpdate(goodsInfo, imgNameUrl);addMessage(redirectAttributes, "保存商品成功");return "redirect:" + Global.getAdminPath() + "/goods/goodsInfo/?repage";}/*** 强制压缩图片到固定的大小* * @param w* int 新宽度* @param h* int 新高度* @param path* 压缩后图片路径+文件名* @param imgFilePath* 原图片路径*/private void resize(int w, int h, String path, String imgFilePath) throws IOException {File file = new File(imgFilePath);// 读入文件Image img = ImageIO.read(file); // 构造Image对象// SCALE_SMOOTH 的缩略算法 生成缩略图片的平滑度的 优先级比速度高 生成的图片质量比较好 但速度慢BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);image.getGraphics().drawImage(img, 0, 0, w, h, null); // 绘制缩小后的图File destFile = new File(path);FileOutputStream out = new FileOutputStream(destFile); // 输出到文件流// 可以正常实现bmp、png、gif转jpgJPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);// JPEG编码encoder.encode(image);out.close();} }


注意点:

      1.

                 var reader = new FileReader();
                 reader.readAsDataURL(fileList[i]);
                 console.log();
                 reader.onload = function(e){
                         if (document.getElementsByName("picList[0].imgBase64")[0].innerHTML == "") {
                             document.getElementsByName("picList[0].imgBase64")[0].innerHTML = this.result;
                             document.getElementsByName("imgName0")[0].src = this.result;
                         } else if (document.getElementsByName("picList[1].imgBase64")[0].innerHTML == "") {
                             document.getElementsByName("picList[1].imgBase64")[0].innerHTML = this.result;
                             document.getElementsByName("imgName1")[0].src = this.result;
                         } else if (document.getElementsByName("picList[2].imgBase64")[0].innerHTML == "") {
                             document.getElementsByName("picList[2].imgBase64")[0].innerHTML = this.result;
                             document.getElementsByName("imgName2")[0].src = this.result;
                         } else if (document.getElementsByName("picList[3].imgBase64")[0].innerHTML == "") {
                             document.getElementsByName("picList[3].imgBase64")[0].innerHTML = this.result;
                             document.getElementsByName("imgName3")[0].src = this.result;
                         } else if (document.getElementsByName("picList[4].imgBase64")[0].innerHTML == "") {
                             document.getElementsByName("picList[4].imgBase64")[0].innerHTML = this.result;
                             document.getElementsByName("imgName4")[0].src = this.result;
                         }
                 }

                为什么要写成这个样子,因为reader.onload这个是一个独立的线程,所以无法以FOR循环的index来判断。这一点困扰了我好久。。。。

      2.后台代码接收到BASE64编码格式之后一定要把头部信息去掉,注意头部信息中文件类型是跟着上传文件来变的


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部