文章目录
-
-
- 1. Controller层的实现
- 2. View层的实现
-
- 2.1 productoperation.html
- 2.2 productoperation.js
- 2.3 productmanagement.css
- 2.4 ShopAdminController添加路由
- 3. 前后端联合调试
-
1. Controller层的实现
import com.fasterxml.jackson.databind.ObjectMapper;
import com.imooc.o2o.dto.ImageHolder;
import com.imooc.o2o.dto.ProductExecution;
import com.imooc.o2o.entity.Product;
import com.imooc.o2o.entity.Shop;
import com.imooc.o2o.enums.ProductStateEnum;
import com.imooc.o2o.exceptions.ProductOperationException;
import com.imooc.o2o.service.ProductService;
import com.imooc.o2o.util.CodeUtil;
import com.imooc.o2o.util.HttpServletRequestUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Controller
@RequestMapping("/shopadmin")
public class ProductManagementController {
@Autowired
private ProductService productService;
//支持上传商品详情图的最大数量
private static final int IMAGEMAXCOUNT = 6;
@RequestMapping(value = "/addproduct",method = RequestMethod.POST)
@ResponseBody
private Map<String,Object> addProduct(HttpServletRequest request) throws IOException {
Map<String,Object> modelMap = new HashMap<>();
//验证码校验
if(!CodeUtil.verifyCode(request)){
modelMap.put("success",false);
modelMap.put("errMsg","输入了错误的验证码");
return modelMap;
}
//接收前端参数的变量的初始化,包括商品,缩略图,详情图列表实体类
//1.图片
MultipartHttpServletRequest multipartRequest = null;
ImageHolder thumbnail = null;
List<ImageHolder> productImgList = new ArrayList<>();
//从Session中获取文件流
CommonsMultipartResolver multipartResolver
= new CommonsMultipartResolver(request.getSession().getServletContext());
try {
//如果请求中有文件流,那么取出相关的文件(包括缩略图和详情图)
if(multipartResolver.isMultipart(request)){
multipartRequest = (MultipartHttpServletRequest)request;
//取出缩略图并构建ImageHolder对象
CommonsMultipartFile thumbnailFile
= (CommonsMultipartFile)multipartRequest.getFile("thumbnail");
thumbnail
= new ImageHolder(thumbnailFile.getOriginalFilename(),thumbnailFile.getInputStream());
//取出详情图列表并构建List<ImageHolder>列表对象,最多支持6张图片上传
for(int i=0;i<IMAGEMAXCOUNT;i++){
CommonsMultipartFile productImgFile
= (CommonsMultipartFile)multipartRequest.getFile("productImg"+i);
if(productImgFile!=null){
//如果取出的第i个详情图片不为空,那么将其加入详情图列表
ImageHolder productImg =
new ImageHolder(productImgFile.getOriginalFilename(),productImgFile.getInputStream());
productImgList.add(productImg);
}else{
//如果取出的第i个详情图片文件为空,则终止循环
break;
}
}
}else{
modelMap.put("success",false);
modelMap.put("errMsg","上传图片不能为空");
return modelMap;
}
} catch (Exception e) {
modelMap.put("success",false);
modelMap.put("errMsg",e.toString());
return modelMap;
}
//2.商品实体类
ObjectMapper mapper = new ObjectMapper();
Product product = null;
String productStr = HttpServletRequestUtil.getString(request,"productStr");
try {
//尝试获取前台穿来的表单将其装换为Product实体类
product = mapper.readValue(productStr,Product.class);
} catch (Exception e) {
modelMap.put("success",false);
modelMap.put("errMsg",e.toString());
return modelMap;
}
//进行商品添加工作
if(product!=null && thumbnail!=null && productImgList.size()>0){
try {
//从当前店铺中获取店铺的id并赋值给product,减少对前端数据的依赖
Shop currentShop = (Shop)request.getSession().getAttribute("currentShop");
Shop shop = new Shop();
shop.setShopId(currentShop.getShopId());
product.setShop(shop);
ProductExecution productExecution
= productService.addProduct(product, thumbnail, productImgList);
if(productExecution.getState() == ProductStateEnum.SUCCESS.getState()){
modelMap.put("success",true);
}else{
modelMap.put("success",false);
modelMap.put("errMsg",productExecution.getStateInfo());
}
} catch (ProductOperationException e) {
modelMap.put("success",false);
modelMap.put("errMsg",e.toString());
return modelMap;
}
}else{
modelMap.put("success",false);
modelMap.put("errMsg","请输入商品信息");
}
return modelMap;
}
}
2. View层的实现
2.1 productoperation.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>商品操作</title>
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
<link rel="shortcut icon" href="/favicon.ico">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link rel="stylesheet"
href="//g.alicdn.com/msui/sm/0.6.2/css/sm.min.css">
<link rel="stylesheet"
href="//g.alicdn.com/msui/sm/0.6.2/css/sm-extend.min.css">
<link rel="stylesheet" href="../resources/css/shop/productmanagement.css">
</head>
<body>
<header class="bar bar-nav">
<h1 class="title">商品操作</h1>
</header>
<div class="content">
<div class="list-block">
<ul>
<li>
<div class="item-content">
<div class="item-media">
<i class="icon icon-form-name"></i>
</div>
<div class="item-inner">
<div class="item-title label">商品名称</div>
<div class="item-input">
<input type="text" id="product-name" placeholder="商品名称">
</div>
</div>
</div>
</li>
<li>
<div class="item-content">
<div class="item-media">
<i class="icon icon-form-email"></i>
</div>
<div class="item-inner">
<div class="item-title label">目录</div>
<div class="item-input">
<select id="product-category">
</select>
</div>
</div>
</div>
</li>
<li>
<div class="item-content">
<div class="item-media">
<i class="icon icon-form-email"></i>
</div>
<div class="item-inner">
<div class="item-title label">优先级</div>
<div class="item-input">
<input type="number" id="priority" placeholder="数字越大越排前面">
</div>
</div>
</div>
</li>
<li>
<div class="item-content">
<div class="item-media">
<i class="icon icon-form-email"></i>
</div>
<div class="item-inner">
<div class="item-title label">原价</div>
<div class="item-input">
<input type="number" id="normal-price" placeholder="可选">
</div>
</div>
</div>
</li>
<li>
<div class="item-content">
<div class="item-media">
<i class="icon icon-form-email"></i>
</div>
<div class="item-inner">
<div class="item-title label">现价</div>
<div class="item-input">
<input type="number" id="promotion-price" placeholder="可选">
</div>
</div>
</div>
</li>
<li>
<div class="item-content">
<div class="item-media">
<i class="icon icon-form-email"></i>
</div>
<div class="item-inner">
<div class="item-title label">缩略图</div>
<div class="item-input">
<input type="file" id="small-img">
</div>
</div>
</div>
</li>
<li>
<div class="item-content">
<div class="item-media">
<i class="icon icon-form-email"></i>
</div>
<div class="item-inner detail-img-div">
<div class="item-title label">详情图片</div>
<div class="item-input" id="detail-img">
<input type="file" class="detail-img">
<!-- <input type="file" class="detail-img" id="detail-img-1">
<input type="file" class="detail-img" id="detail-img-2"> -->
</div>
</div>
</div>
</li>
<li>
<div class="item-content">
<div class="item-media">
<i class="icon icon-form-email"></i>
</div>
<div class="item-inner">
<div class="item-title label">商品描述</div>
<div class="item-input">
<textarea id="product-desc" placeholder="商品描述"></textarea>
</div>
</div>
</div>
</li>
<li>
<div class="item-content">
<div class="item-media">
<i class="icon icon-form-email"></i>
</div>
<div class="item-inner">
<label for="j_captcha" class="item-title label">验证码</label> <input
id="j_captcha" name="j_captcha" type="text"
class="form-control in" placeholder="验证码" />
<div class="item-input">
<img id="captcha_img" alt="点击更换" title="点击更换"
onclick="changeVerifyCode(this)" src="../Kaptcha" />
</div>
</div>
</div>
</li>
</ul>
</div>
<div class="content-block">
<!-- 预留两个按钮 TODO -->
<div class="row">
<div class="col-50">
<a href="#"
class="button button-big button-fill button-danger" id="back">返回商品管理</a>
</div>
<div class="col-50">
<a href="#" class="button button-big button-fill" id="submit">提交</a>
</div>
</div>
</div>
</div>
<script type='text/javascript' src='//g.alicdn.com/sj/lib/zepto/zepto.min.js' charset='utf-8'></script>
<script type='text/javascript' src='//g.alicdn.com/msui/sm/0.6.2/js/sm.min.js' charset='utf-8'></script>
<script type='text/javascript' src='//g.alicdn.com/msui/sm/0.6.2/js/sm-extend.min.js' charset='utf-8'></script>
<!-- 引入自定义的JS -->
<script type='text/javascript' src='../resources/js/common/common.js' charset='utf-8'></script>
<script type='text/javascript' src='../resources/js/shop/productoperation.js' charset='utf-8'></script>
</body>
</html>
2.2 productoperation.js
/**
* 因为商品的添加和编辑复用同一个页面,所以需要根据url中的商品Id来判断
*/
$(function(){
//通过url是否含有productId来判断是添加商品还是编辑
var productId = getQueryString('productId');
// 标示符 productId非空则为true即编辑,否则为添加商品
var isEdit = productId ? true : false ;
// 商品添加URL
var addProductURL = '/o2o/shopadmin/addproduct';
// 获取商品初始化信息的URL 根据页面原型只需要获取productCategory即可,后台调用之前写好的路由方法即可
var initProductURL = '/o2o/shopadmin/getproductcategorylist';
// 通过标示符,确定调用的方法
if(isEdit){
// 为true,则根据productId调用获取product信息的方法 TODO
getProductInfoById(productId);
}else{
// 为false,则初始化新增product页面
getProductInitInfo();
}
/**
* 始化新增product页面
*
* 根据页面原型和数据模型,需要加载该shop对应的productCategory信息(shop信息从服务端session中获取)
*/
function getProductInitInfo(){
$.getJSON(initProductURL,
function(data){
if(data.success){
// 设置product_category
var productCategoryList = data.data;
var productCategoryTempHtml = '';
productCategoryList.map(function(item, index) {
productCategoryTempHtml
+= '<option data-value="'
+ item.productCategoryId
+ '">'
+ item.productCategoryName
+ '</option>';
});
$('#product-category').html(productCategoryTempHtml);
}else{
$.toast(data.errMsg)
}
});
};
/**
* 点击控件的最后一个且图片数量小于6个的时候,生成一个选择框
*/
$('.detail-img-div').on('change', '.detail-img:last-child', function() {
if ($('.detail-img').length < 6) {
$('#detail-img').append('<input type="file" class="detail-img">');
}
});
/**
* 提交按钮的响应时间,分别对商品添加和商品编辑做不同的相应
*/
$('#submit').click(
function(){
// 创建商品Json对象,并从表单对象中获取对应的属性值
var product = {};
// 如果是编辑操作,需要传入productId
if(isEdit){
product.productId = productId;
}
product.productName = $('#product-name').val();
product.productDesc = $('#product-desc').val();
// 获取商品的特定目录值
product.productCategory = {
productCategoryId : $('#product-category').find('option').not(
function() {
return !this.selected;
}).data('value')
};
product.priority = $('#priority').val();
product.normalPrice = $('#normal-price').val();
product.promotionPrice = $('#promotion-price').val();
// 生成表单对象用于接收参数并传递给后台
var formData = new FormData();
// 缩略图 (只有一张),获取缩略图的文件流
var thumbnail = $('#small-img')[0].files[0];
formData.append('thumbnail',thumbnail);
// 图片详情
$('.detail-img').map(
function(index, item) {
// 判断该控件是否已经选择了文件
if ($('.detail-img')[index].files.length > 0) {
// 将第i个文件流赋值给key为productImgi的表单键值对里
formData.append('productImg' + index,
$('.detail-img')[index].files[0]);
}
});
// 将product 转换为json ,添加到forData
formData.append('productStr', JSON.stringify(product));
// 获取表单中的验证码
var verifyCodeActual = $('#j_captcha').val();
if (!verifyCodeActual) {
$.toast('请输入验证码!');
return;
}
formData.append("verifyCodeActual", verifyCodeActual);
// 使用ajax异步提交
$.ajax({
url: isEdit?editProductURL:addProductURL,
type: 'POST' ,
data : formData,
contentType : false,
processData : false,
cache : false,
success: function(data){
if (data.success) {
$.toast('提交成功!');
$('#captcha_img').click();
} else {
$.toast('提交失败!');
$('#captcha_img').click();
}
}
});
});
});
2.3 productmanagement.css
.row-product {
border: 1px solid #999;
padding: .5rem;
border-bottom: none;
}
.row-product:last-child {
border-bottom: 1px solid #999;
}
.product-name {
white-space: nowrap;
overflow-x: scroll;
}
.product-wrap a {
margin-right: 1rem;
}
2.4 ShopAdminController添加路由
@RequestMapping(value="/productoperation")
public String productOperation(){
return "shop/productoperation";
}
3. 前后端联合调试
先按f10一步步调试: