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(); }); // 文件大小长宽CHECK function 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 */ @Autowired private SortInfoService sortInfoService; /** * 商品信息Service */ @Autowired private GoodsInfoService goodsInfoService; /** 商品规格名称Service */ @Autowired private SkuKeyService skuKeyService; /** 商家单位信息Service */ @Autowired private BusinessUnitService businessUnitService; /** 商家信息管理Service */ @Autowired private 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(); } List imgNameUrl = 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转jpg JPEGImageEncoder 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编码格式之后一定要把头部信息去掉,注意头部信息中文件类型是跟着上传文件来变的

你可能感兴趣的:(JAVA,base64,图片)