一,生產環境中的復雜參數上傳的場景
1,保存排序值 :
例如:某一件商品的多張展示圖片排序,提交的排序值要和圖片的id相對應
2,上傳多張圖片,圖片要和指定的變量相對應
例如:在添加商品sku時,
需要為指定有圖片的屬性上傳圖片,
讓用戶看上去更直觀
這里演示了這兩種常見的參數上傳,
電商系統中的sku的添加是很關鍵的一個功能模塊,
必須讓后台的操作人員能直觀的看到自己的操作結果,
這里有一些js代碼可以供大家參考
說明:劉宏締的架構森林是一個專注架構的博客,地址:https://www.cnblogs.com/architectforest
對應的源碼可以訪問這里獲取: https://github.com/liuhongdi/
說明:作者:劉宏締 郵箱: 371125307@qq.com
二,演示項目的相關信息
1,項目地址:
https://github.com/liuhongdi/arrayparam
2,功能說明:
演示了提交多個數組和提交多個數組變量及多個文件
3,項目結構:如圖:
三,配置文件說明
1,pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--thymeleaf begin--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <!--validation begin--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <!--commons-fileupload--> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.4</version> </dependency> <!--commons-io--> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.8.0</version> </dependency> <!--fastjson begin--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.73</version> </dependency>
2,application.properties
#thymeleaf spring.thymeleaf.cache=false spring.thymeleaf.encoding=UTF-8 spring.thymeleaf.mode=HTML spring.thymeleaf.prefix=classpath:/templates/ spring.thymeleaf.suffix=.html #error server.error.include-stacktrace=always #errorlog logging.level.org.springframework.web=trace
四,java代碼說明
1,GoodsController.java
@Controller @RequestMapping("/goods") public class GoodsController { //顯示商品圖片 @GetMapping("/image") public String goodsimage(Model model,@Min(value = 1,message = "商品id需要>0")@RequestParam("goodsId") Long goodsId) { model.addAttribute("goodsId", goodsId); return "goods/image"; } //保存各圖片的排序值 @PostMapping("/contentsaveorder") @ResponseBody public String goodsContentSaveOrder(HttpServletRequest request, @Min(value = 1,message = "商品id需要>0")@RequestParam("goodsId") Long goodsId, @RequestParam(value = "imgids[]") Long[] imgids, @RequestParam(value = "orders[]") int[] orders ) { String res = "當前商品id:"+goodsId+"\n"; for (int i = 0; i < imgids.length; i++) { Long imageId = imgids[i]; int orderNum = orders[i]; res += "當前圖片id:"+imageId+";排序值:"+orderNum+"\n"; } return res; } //顯示商品sku @GetMapping("/sku") public String sku(Model model,@Min(value = 1,message = "商品id需要>0")@RequestParam("goodsId") Long goodsId) { model.addAttribute("goodsId", goodsId); return "goods/sku"; } //保存商品的sku @PostMapping("/skuadded") @ResponseBody public String skuadded(@RequestParam("json") String json,HttpServletRequest request) { SkuForm skuform = JSONObject.parseObject(json, SkuForm.class); String res = "goodsId:"+skuform.getGoodsId()+"\n"; for (Sku skuOne : skuform.getSkuList()) { res+="key:"+skuOne.getKey()+";price:"+skuOne.getPrice()+";stock:"+skuOne.getStock()+"\n"; } for (AttrType typeone :skuform.getTypeList()) { res+="typename:"+typeone.getTypeName()+";isimage:"+typeone.getIsImage()+";attrlist:"+typeone.getAttrList()+"\n"; } for (FormFile fileOne : skuform.getFileList()) { res+="filelist:fileName:"+fileOne.getFileName()+"\n"; } CommonsMultipartResolver multipartResolver=new CommonsMultipartResolver(request.getSession().getServletContext()); // 判斷是否是多數據段提交格式 if (multipartResolver.isMultipart(request)) { System.out.println("isMultipart"); MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest)request; Iterator<String> iter = multiRequest.getFileNames(); Integer fileCount = 0; while (iter.hasNext()) { MultipartFile multipartFile = multiRequest.getFile(iter.next()); String varName = multipartFile.getName(); String fileName = multipartFile.getOriginalFilename(); if(fileName == null || fileName.trim().equals("")){ continue; } else { res+="file:fileName:"+fileName+";varName:"+varName+"\n"; } } } else { System.out.println("not isMultipart"); } return res; } }
2,SkuForm.java
public class SkuForm { //goodsid private Long goodsId; public Long getGoodsId() { return this.goodsId; } public void setGoodsId(Long goodsId) { this.goodsId = goodsId; } //type list private List<AttrType> typeList; public List<AttrType> getTypeList() { return this.typeList; } public void setTypeList(List<AttrType> typeList) { this.typeList = typeList; } //sku list private List<Sku> skuList; public List<Sku> getSkuList() { return this.skuList; } public void setSkuList(List<Sku> skuList) { this.skuList = skuList; } //file list private List<FormFile> fileList; public List<FormFile> getFileList() { return this.fileList; } public void setFileList(List<FormFile> fileList) { this.fileList = fileList; } }
3,AttrType.java
public class AttrType { //typename private String typeName; public String getTypeName() { return this.typeName; } public void setTypeName(String typeName) { this.typeName = typeName; } //isImage private int isImage; public int getIsImage() { return this.isImage; } public void setIsImage(int isImage) { this.isImage = isImage; } //attr list private List<String> attrList; public List<String> getAttrList() { return this.attrList; } public void setAttrList(List<String> attrList) { this.attrList = attrList; } }
4,Sku.java
public class Sku { //key private String key; public String getKey() { return this.key; } public void setKey(String key) { this.key = key; } //price private String price; public String getPrice() { return this.price; } public void setPrice(String price) { this.price = price; } //stock private int stock; public int getStock() { return this.stock; } public void setStock(int stock) { this.stock = stock; } }
5,FormFile.java
public class FormFile { //fileName private String fileName; public String getFileName() { return this.fileName; } public void setFileName(String fileName) { this.fileName = fileName; } }
五,html/js代碼說明:
1,image.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script type="text/javascript" language="JavaScript" src="/js/jquery-1.6.2.min.js"></script> </head> <body> <form id='content_order'> <div style='width:320px;background-color: #000000;font-size: 14px;height: 20px;color: #ffffff;text-align: center;line-height: 20px;'>商品詳情</div> <div id="main" style="display: flex;flex-direction: column;"> <div style='width: 320px;'> <div style='width:150px;float:left;line-height: 0px;'><img src='/img/3.jpg' style='width: 150px;' /></div> <div style='width:150px;float:left;'> 圖片id:3 <br/> 排序值:<br/><input type='text' style='width:30px;' name='orderNum_3' value='' /> </div> </div> <div style='width: 320px;'> <div style='width:150px;float:left;line-height: 0px;'><img src='/img/4.jpg' style='width: 150px;' /></div> <div style='width:150px;float:left;'> 圖片id:4 <br/> 排序值:<br/><input type='text' style='width:30px;' name='orderNum_4' value='' /> </div> </div> <div style='width: 320px;'> <div style='width:150px;float:left;line-height: 0px;'><img src='/img/5.jpg' style='width: 150px;' /></div> <div style='width:100px;float:left;'> 圖片id:5 <br/> 排序值:<br/><input type='text' style='width:30px;' name='orderNum_5' value='' /> </div> </div> </div> <!--main end--> </form> <input type="button" value="保存排序值" th:onclick="saveOrder([[${goodsId}]])" /> <script> //保存排序值 function saveOrder(goodsId){ var form = document.getElementById("content_order"); var tagElements = form.getElementsByTagName('input'); var postdata = {}; var imgids = []; var orders = []; for (var j = 0; j < tagElements.length; j++){ var curid = tagElements[j].name.replace("orderNum_", ""); imgids.push(curid); orders.push(tagElements[j].value); } postdata['imgids'] = imgids; postdata['orders'] = orders; postdata['goodsId'] = goodsId; $.ajax({ type:"POST", url:"/goods/contentsaveorder", data:postdata, //返回數據的格式 datatype: "text",//"xml", "html", "script", "json", "jsonp", "text". //成功返回之后調用的函數 success:function(data){ alert(data); }, //調用執行后調用的函數 complete: function(XMLHttpRequest, textStatus){ //alert(XMLHttpRequest.responseText); //alert(textStatus); }, //調用出錯執行的函數 error: function(){ //請求出錯處理 alert('error'); } }); } </script> </body> </html>
2,sku.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script type="text/javascript" language="JavaScript" src="/js/jquery-1.6.2.min.js"></script> </head> <body> <form id='content_order'> <div id="main" style="display: flex;flex-direction: column;"> <div> <input type="text" id="attrtype" name="attrtype" value="" /> <input type="button" value="添加sku分類" onclick="addattrtype()"> </div> <div id="attrlist" style="width:500px;background: #ffffff;overflow: hidden;"> </div> <div id="skulist" style="width:500px;background: #ffffff;display: flex;flex-direction: column;overflow: hidden;"> </div> </div> <!--main end--> </form> <input type="button" value="保存sku" th:onclick="savesku([[${goodsId}]])" /> <script> //------------------------------------------------------------global var //分類列表 var global_type = []; //分類1的屬性列表 var attr_list_0 = []; //分類2的屬性列表 var attr_list_1 = []; //-------------------------------------------------------------method //添加分類 function addattrtype() { if (global_type.length >=2 ){ alert("屬性種類數量不能超過2類"); return false; } var typename = document.getElementById('attrtype').value; if (global_type.indexOf(typename)>=0) { alert(typename+"已存在"); return false; } if (typename == "") { alert("類別名稱不可為空"); return false; } global_type.push(typename); //addonetype(typename); var html = "<div id='type"+typename+"' style='background: #ffffff;width:500px;min-height:130px;'>" + "<div style='background: #eeeeee;text-align: left;height:30px;border-radius:5px;'>"+ "<div style='float:left;margin-left:10px;'>"+typename+"<input id='checkimage"+typename+"' type='checkbox' onclick='checkimage(\""+typename+"\")'/>圖片</div>" + "<div style='height:30px;float:right;'>" + "<input type='text' id='"+typename+"attrnew' value='' />" + "<input type='button' value='添加屬性' onclick='addattr(\""+typename+"\")'/>" + "<input type='button' value='刪除分類' onclick='delete_type(\""+typename+"\")'/>" + "</div></div>"+ "<div id='"+typename+"attrlist' style='background: #ffffff;width:500px;min-height:100px;overflow:hidden;'>" + "</div>"+ "</div>"; //document.getElementById('attrlist').innerHTML += html; $("#attrlist").append(html); } //設置是否上傳圖片 function checkimage(typename) { var ischecked = document.getElementById("checkimage"+typename).checked; alert(typename+":"+ischecked); if (ischecked == true) { for(i = 0; i < global_type.length; i++) { //var curdispid = "dispup"+cur_attr_list[i]; //document.getElementById(curdispid).style.display="block"; if (global_type[i] == typename) { continue; } else { var isotherchecked = document.getElementById("checkimage"+global_type[i]).checked; if (isotherchecked == true) { alert(global_type[i]+"已被選中使用圖片,如果要設置"+typename+"使用圖片請先把其他使用圖片的分類取消"); document.getElementById("checkimage"+typename).checked = false; return false; } } } } if (ischecked == true) { settypeimagetrue(typename) } else { settypeimagefalse(typename) } } //使一個分類下的attr支持上傳圖片 function settypeimagetrue(typename) { var typeidx = global_type.indexOf(typename); var cur_attr_list; if (typeidx == 0) { cur_attr_list = attr_list_0; } else { cur_attr_list = attr_list_1; } for(i = 0; i < cur_attr_list.length; i++) { var curdispid = "dispup"+cur_attr_list[i]; document.getElementById(curdispid).style.display="block"; } } //使一個分類下的attr不支持上傳圖片 function settypeimagefalse(typename) { var typeidx = global_type.indexOf(typename); var cur_attr_list; if (typeidx == 0) { cur_attr_list = attr_list_0; } else { cur_attr_list = attr_list_1; } for(i = 0; i < cur_attr_list.length; i++) { var curdispid = "dispup"+cur_attr_list[i]; document.getElementById(curdispid).style.display="none"; //清除圖片 document.getElementById("img"+cur_attr_list[i]).src=""; document.getElementById("img"+cur_attr_list[i]).style.display="none"; //清除file的選中文件 document.getElementById("file"+cur_attr_list[i]).value=''; } } //預覽圖片 function preview(attrname) { var fileObj = document.getElementById("file"+attrname); var file=fileObj.files[0]; var r = new FileReader(); r.readAsDataURL(file); r.onload=function(e){ document.getElementById("img"+attrname).src = e.target.result; document.getElementById("img"+attrname).style.display="block"; } } //添加屬性 function addattr(typename) { var typeidx = global_type.indexOf(typename); var cur_attr_list; if (typeidx == 0) { cur_attr_list = attr_list_0; } else { cur_attr_list = attr_list_1; } var attrname = document.getElementById(typename+'attrnew').value; if (attr_list_0.indexOf(attrname)>=0) { alert(attrname+"已存在"); return false; } if (attr_list_1.indexOf(attrname)>=0) { alert(attrname+"已存在"); return false; } if (attrname == "") { alert("屬性名稱不可為空"); return false; } cur_attr_list.push(attrname); var ischecked = document.getElementById("checkimage"+typename).checked; var imagetextdisp = ""; if (ischecked == true) { imagetextdisp = "block"; } else { imagetextdisp = "none"; } var html = "<div id='attr"+attrname+"' style='margin-left:8px;margin-top:8px;width:80px;height:80px;line-height:80px;text-align:center;background: #eeeeee;float:left;border-radius:10px;position:relative;overflow:hidden;'>"+ "<img id='img"+attrname+"' src='' style='position:absolute;width:80px;height:80px;display: none;' />"+ "<div style='width:20px;height:20px;line-height:20px;background: #eeeeee;right:0px;position:absolute;text-align: center;' onclick='delete_attr(\""+typename+"\",\""+attrname+"\")'>x</div>"+ "<div id='dispup"+attrname+"' style='width:80px;height:20px;opacity:0.9;line-height:20px;background: rgb(138, 138, 238);bottom:0px;position:absolute;text-align: center;display: "+imagetextdisp+";'>"+ "<div style='position:relative;'>" + "<input type='file' name='file"+attrname+"' id='file"+attrname+"' onchange='preview(\""+attrname+"\")' style='position:absolute;z-index:100;width:80px;height:20px;left:0px;background: #ff0000;opacity:0;'/>"+ "<div style='position: absolute;width:80px;height:20px;line-height:20px;opacity:0.9;font-size:12px;text-align:center;'>上傳圖片</div>"+ "</div></div>"+ attrname+ "</div>"; document.getElementById(typename+'attrlist').innerHTML += html; refresh_sku_list(); } //刪除分類 function delete_type(typename) { if (confirm("確認刪除分類:"+typename+"嗎?") == false) { return false; } //清空數組 var typeidx = global_type.indexOf(typename); if (typeidx == 0) { attr_list_0.length = 0; //如果刪除的是第一個分類? attr_list_0 = attr_list_1.concat(); attr_list_1.length = 0; } else { attr_list_1.length = 0; } //從type數組中刪除 var typeidx = global_type.indexOf(typename); global_type.splice(typeidx,1); //從div中刪除 $("#type"+typename).remove(); //刷新sku refresh_sku_list(); } //刪除屬性 function delete_attr(typename,attrname) { if (confirm("確認刪除屬性:"+attrname+"嗎?") == false) { return false; } var typeidx = global_type.indexOf(typename); //alert(typename+";idx:"+typeidx); var cur_attr_list; if (typeidx == 0) { cur_attr_list = attr_list_0; } else { cur_attr_list = attr_list_1; } //從數組中刪除 var attridx = cur_attr_list.indexOf(attrname); cur_attr_list.splice(attridx,1); //從div中刪除 $("#attr"+attrname).remove(); //刷新sku refresh_sku_list(); } //刷新sku列表 function refresh_sku_list() { //只有一個為空 if (attr_list_0.length == 0 && attr_list_1.length == 0) { document.getElementById('skulist').innerHTML = ""; } if (attr_list_0.length > 0 && attr_list_1.length == 0) { var html = "<div style='border-radius:8px;margin-left:5px;width:490px;background:#eeeeee;'>"+ "<div style='padding-left:10px;width:200px;float:left;'>屬性</div>"+ "<div style='width:100px;float:left;'>價格</div>"+ "<div style='width:100px;float:left;'>庫存</div>"+ "</div>"; document.getElementById('skulist').innerHTML = html; // //if (attr_list_0.length) var htmlattr= "<div style='border-radius:8px;margin-left:5px;margin-top:10px;width:490px;background:#eeeeee;display: flex;flex-direction: column;'>"; for(i = 0; i < attr_list_0.length; i++) { htmlattr += "<div>"+ "<div style='padding-left:10px;width:200px;float:left;'>"+attr_list_0[i]+"</div>"+ "<div style='width:100px;float:left;'><input type='text' name='price_'"+attr_list_0[i]+" value='0.00'></div>"+ "<div style='width:100px;float:left;'><input type='text' name='stock_'"+attr_list_0[i]+" value='0'></div>"+ "</div>"; } htmlattr +="</div>"; document.getElementById('skulist').innerHTML += htmlattr; } if (attr_list_0.length > 0 && attr_list_1.length > 0) { var html = "<div style='border-radius:8px;margin-left:5px;width:490px;background:#eeeeee;'>"+ "<div style='padding-left:10px;width:210px;float:left;'>屬性</div>"+ "<div style='width:100px;float:left;'>價格</div>"+ "<div style='width:120px;float:left;'>庫存</div>"+ "</div>"; document.getElementById('skulist').innerHTML = html; //得到每大行高度 var blockheight = attr_list_1.length*30; for(i = 0; i < attr_list_0.length; i++) { var html = "<div style='background: #eeeeee;border-radius: 5px;margin-left:5px;margin-top:5px;width:490px;'>"+ "<div style='padding-left:10px;width:90px;float:left;height:"+blockheight+"px;line-height:"+blockheight+"px;'>"+attr_list_0[i]+"</div>"+ "<div style='width:380px;float:left;display: flex;flex-direction: column;'>"; for(j = 0; j < attr_list_1.length; j++) { html += "<div style='width:400px;'><div style='width:100px;float:left;height:30px;line-height:30px;'>"+attr_list_1[j]+"</div>"+ "<div style='float:left;width:100px;'><input type='text' id='price_"+attr_list_0[i]+"_"+attr_list_1[j]+"' value='0.00'></div>"+ "<div style='float:left;width:100px;'><input type='text' id='stock_"+attr_list_0[i]+"_"+attr_list_1[j]+"' value='0'></div></div>"; } html += "</div>"+ "</div>"; document.getElementById('skulist').innerHTML += html; } } } //提交sku的數據 function savesku(goodsId) { //alert(goodsId); var postdata = {}; postdata['goodsId'] = goodsId; var typelist = []; //得到兩個分類 for(i = 0; i < global_type.length; i++) { var typeobj = {"typeName":global_type[i]}; var isotherchecked = document.getElementById("checkimage"+global_type[i]).checked; if (isotherchecked == true) { typeobj["isImage"] = 1; } else { typeobj["isImage"] = 0; } //得到下面的屬性: var cur_attr_list; if (i == 0) { cur_attr_list = attr_list_0; } else { cur_attr_list = attr_list_1; } var attrlist=[]; for(j = 0; j < cur_attr_list.length; j++) { attrlist.push(cur_attr_list[j]); } typeobj['attrList'] = attrlist; //typeobj typelist.push(typeobj); } postdata["typeList"] = typelist; //遍歷sku: var skulist = []; for(i = 0; i < attr_list_0.length; i++) { for(j = 0; j < attr_list_1.length; j++) { var key = attr_list_0[i]+"_"+attr_list_1[j]; var price = document.getElementById('price_'+key).value; var stock = document.getElementById('stock_'+key).value; var skuone = {"key":key,"price":price,"stock":stock}; skulist.push(skuone); } } postdata["skuList"] = skulist; var filelist = []; var cur_attr_list; if (i == 0) { cur_attr_list = attr_list_0; } else { cur_attr_list = attr_list_1; } for(i = 0; i < global_type.length; i++) { var typeobj = {"typename": global_type[i]}; var isotherchecked = document.getElementById("checkimage" + global_type[i]).checked; if (isotherchecked == true) { if (i == 0) { cur_attr_list = attr_list_0; } else if (i == 1) { cur_attr_list = attr_list_1; } } } //var postdatafile = {}; var postdatafile=new FormData(); // for(i = 0; i < cur_attr_list.length; i++) { var fileid = "file"+cur_attr_list[i]; if ("undefined" == typeof($("#"+fileid)[0].files[0])) { continue; } else { // var fileobj = {"fileName":cur_attr_list[i],"file":$("#"+fileid)[0].files[0]}; postdatafile.append(["file_"+cur_attr_list[i]],$("#"+fileid)[0].files[0]); filelist.push(fileobj); } } postdata["fileList"] = filelist; console.log(postdata); var postdatajson = {}; //postdatafile['json'] = JSON.stringify(postdata); postdatafile.append("json",JSON.stringify(postdata)); console.log(postdatafile); alert("begin ajax"); $.ajax({ type:"POST", url:"/goods/skuadded", data:postdatafile, //返回數據的格式 datatype: "text",//"xml", "html", "script", "json", "jsonp", "text". processData:false, // 將數據轉換成對象,不對數據做處理,故 processData: false contentType:false, // 不設置數據類型 //成功返回之后調用的函數 success:function(data){ alert(data); }, //調用執行后調用的函數 complete: function(XMLHttpRequest, textStatus){ //alert(XMLHttpRequest.responseText); //alert(textStatus); }, //調用出錯執行的函數 error: function(){ //請求出錯處理 alert('error'); } }); } </script> </body> </html>
六,測試效果
1,測試提交排序值:
訪問:
http://127.0.0.1:8080/goods/image?goodsId=2
如圖:
服務端能正確接收到圖片id和提交的圖片的排序值
2,測試提交創建商品sku:
訪問:
http://127.0.0.1:8080/goods/sku?goodsId=2
如圖:
可以看到服務端可以接收到屬性對應的圖片文件和屬性的對應關系,以及sku的價格庫存信息
七,查看spring boot版本
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.4.RELEASE)