商品修改與審核
課程目標
目標1:完成商家后台商品列表的功能
目標2:完成商家后台商品修改的功能
目標3:完成運營商后台商品審核的功能
目標4:完成運營商后台商品刪除的功能
目標5:掌握注解式事務的配置
1.商家后台-商品管理【商品列表】
1.1需求分析
在商家后台,顯示該商家的商品列表信息,如下圖:
1.2查詢商家商品列表
1.2.1后端代碼
修改pinyougou-shop-web工程的GoodsController.java的search方法
@RequestMapping("/search") public PageResult search(@RequestBody TbGoods goods, int page, int rows ){ //獲取商家ID String sellerId = SecurityContextHolder.getContext().getAuthentication().getName(); //添加查詢條件 goods.setSellerId(sellerId); return goodsService.findPage(goods, page, rows); } |
修改pinyougou-sellergoods-service 工程com.pinyougou.sellergoods.service.impl 的findPage方法,修改條件構建部分代碼,將原來的模糊匹配修改為精確匹配
if(goods.getSellerId()!=null && goods.getSellerId().length()>0){ //criteria.andSellerIdLike("%"+goods.getSellerId()+"%"); criteria.andSellerIdEqualTo(goods.getSellerId()); } |
1.2.2前端代碼
修改goods.html. 引入js
<script type="text/javascript" src="../plugins/angularjs/angular.min.js"></script> <!-- 分頁組件開始 --> <script src="../plugins/angularjs/pagination.js"></script> <link rel="stylesheet" href="../plugins/angularjs/pagination.css"> <!-- 分頁組件結束 --> <script type="text/javascript" src="../js/base_pagination.js"></script> <script type="text/javascript" src="../js/service/goodsService.js"></script> <script type="text/javascript" src="../js/service/itemCatService.js"></script> <script type="text/javascript" src="../js/service/uploadService.js"></script> <script type="text/javascript" src="../js/service/typeTemplateService.js"></script> <script type="text/javascript" src="../js/controller/baseController.js"></script> <script type="text/javascript" src="../js/controller/goodsController.js"></script> |
添加指令
<body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="goodsController"> |
在頁面上放置分頁控件
<tm-pagination conf="paginationConf"></tm-pagination> |
循環列表
<tr ng-repeat="entity in list"> <td><input type="checkbox"></td> <td>{{entity.id}}</td> <td>{{entity.goodsName}}</td> <td>{{entity.price}}</td> <td>{{entity.category1Id}}</td> <td>{{entity.category2Id}}</td> <td>{{entity.category3Id}}</td> <td> {{entity.auditStatus}} </td> <td class="text-center"> <button type="button" class="btn bg-olive btn-xs">修改</button> </td> </tr> |
顯示效果如下:
1.3顯示狀態
修改goodsController.js,添加state數組
$scope.status=['未審核','已審核','審核未通過','關閉'];//商品狀態 |
修改列表顯示
{{status[entity.auditStatus]}} |
顯示效果如下:
1.4顯示分類
我們現在的列表中的分類仍然顯示ID
如何才能顯示分類的名稱呢?
方案一:在后端代碼寫關聯查詢語句,返回的數據中直接有分類名稱。
方案二:在前端代碼用ID去查詢后端,異步返回商品分類名稱。
我們目前采用方案二:
(1)修改goodsController
$scope.itemCatList=[];//商品分類列表 //加載商品分類列表 $scope.findItemCatList=function(){ itemCatService.findAll().success( function(response){ for(var i=0;i<response.length;i++){ $scope.itemCatList[response[i].id]=response[i].name; } } ); } |
代碼解釋:因為我們需要根據分類ID得到分類名稱,所以我們將返回的分頁結果以數組形式再次封裝。
(2)修改goods.html ,增加初始化調用
<body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="goodsController" ng-init="findItemCatList()"> |
(3)修改goods.html , 修改列表
<td>{{itemCatList[entity.category1Id]}}</td> <td>{{itemCatList[entity.category2Id]}}</td> <td>{{itemCatList[entity.category3Id]}}</td> |
1.5條件查詢
根據狀態和商品名稱進行查詢
修改goods.html
<div class="has-feedback"> 狀態:<select ng-model="searchEntity.auditStatus"> <option value="">全部</option> <option value="0">未審核</option> <option value="1">已審核</option> <option value="2">審核未通過</option> <option value="3">關閉</option> </select> 商品名稱:<input ng-model="searchEntity.goodsName"> <button class="btn btn-default" ng-click="reloadList()">查詢</button> </div> |
2.商家后台-商品管理【商品修改】
2.1需求分析
在商品列表頁面點擊修改,進入商品編輯頁面,並傳遞參數商品ID,商品編輯頁面接受該參數后從數據庫中讀取商品信息,用戶修改后保存信息。
2.2基本信息讀取
我們首選讀取商品分類、商品名稱、品牌,副標題,價格等信息
2.2.1后端代碼
(1)修改pinyougou-sellergoods-interface的GoodsService.java
/** * 根據ID獲取實體 * @param id * @return */ public Goods findOne(Long id); |
(2)修改pinyougou-sellergoods-service的GoodsServiceImpl.java
@Override public Goods findOne(Long id) { Goods goods=new Goods(); TbGoods tbGoods = goodsMapper.selectByPrimaryKey(id); goods.setGoods(tbGoods); TbGoodsDesc tbGoodsDesc = goodsDescMapper.selectByPrimaryKey(id); goods.setGoodsDesc(tbGoodsDesc); return goods; } |
(3)修改pinyougou-shop-web(和pinyougou-manager-web)的GoodsController.java
/** * 獲取實體 * @param id * @return */ @RequestMapping("/findOne") public Goods findOne(Long id){ return goodsService.findOne(id); } |
2.2.2前端代碼
(1)在goodsController中引入$location服務
//商品控制層(商家后台) app.controller('goodsController',function($scope,$controller,$location,goodsService,uploadService,item_catService,type_templateService){ ...... |
(2)修改goodsController 添加代碼:
//查詢實體 $scope.findOne=function(){ var id= $location.search()['id'];//獲取參數值 if(id==null){ return ; } goodsService.findOne(id).success( function(response){ $scope.entity= response; } ); } |
在goods_edit.html頁面上添加指令
<body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="goodsController" ng-init="selectItemCat1List();findOne()"> |
測試:
地址欄輸入
http://localhost:9102/admin/goods_edit.html#?id=149187842867969
注意: ?前要加# ,則是angularJS的地址路由的書寫形式
2.3讀取商品介紹(富文本編輯器)
修改前端代碼 goodsController
//查詢實體 $scope.findOne=function(){ ................. goodsService.findOne(id).success( function(response){ $scope.entity= response; //向富文本編輯器添加商品介紹 editor.html($scope.entity.goodsDesc.introduction); } ); } |
2.4顯示商品圖片列表
修改goodsController.js ,在dataLogic方法添加代碼,將圖片列表由字符串轉換為json集合對象
//查詢實體 $scope.findOne=function(){ .............. //如果有ID,則查詢實體 goodsService.findOne(id).success( function(response){ $scope.entity= response; //向富文本編輯器添加商品介紹 editor.html($scope.entity.goodsDesc.introduction); //顯示圖片列表 $scope.entity.goodsDesc.itemImages= JSON.parse($scope.entity.goodsDesc.itemImages); } ); } |
2.5讀取商品擴展屬性
修改goodsController.js
//查詢實體 $scope.findOne=function(){ ......... goodsService.findOne(id).success( function(response){ ....................... //顯示擴展屬性 $scope.entity.goodsDesc.customAttributeItems= JSON.parse($scope.entity.goodsDesc.customAttributeItems); } ); } |
經過測試,我們發現擴展屬性值並沒有讀取出來,這是因為與下列代碼發生沖突
$scope.$watch('entity.goods.typeTemplateId',function(newValue,oldValue){ ...... $scope.entity.goodsDesc.customAttributeItems = JSON.parse($scope.typeTemplate.customAttributeItems);//擴展屬性 } |
我們讀取出來的值被覆蓋了,我們需要改寫代碼, 添加判斷,當用戶沒有傳遞id參數時再執行此邏輯
//監控模板ID ,讀取品牌列表 $scope.$watch('entity.goods.typeTemplateId',function(newValue,oldValue){ //讀取品牌列表和擴展屬性 typeTemplateService.findOne(newValue).success( function(response){ ....... //如果沒有ID,則加載模板中的擴展數據 if($location.search()['id']==null){ $scope.entity.goodsDesc.customAttributeItems = JSON.parse($scope.typeTemplate.customAttributeItems);//擴展屬性 } } ); ....... }); |
2.6讀取商品規格屬性
修改goodsController
//查詢實體 $scope.findOne=function(){ ...... goodsService.findOne(id).success( function(response){ $scope.entity= response; editor.html($scope.entity.goodsDesc.introduction);//商品介紹 $scope.entity.goodsDesc.itemImages= JSON.parse($scope.entity.goodsDesc.itemImages);//圖片列表 //擴展屬性列表 $scope.entity.goodsDesc.customAttributeItems =JSON.parse($scope.entity.goodsDesc.customAttributeItems); //規格 $scope.entity.goodsDesc.specificationItems=JSON.parse($scope.entity.goodsDesc.specificationItems); } ); } |
//根據規格名稱和選項名稱返回是否被勾選 $scope.checkAttributeValue=function(specName,optionName){ var items= $scope.entity.goodsDesc.specificationItems; var object= $scope.searchObjectByKey(items,'attributeName',specName); if(object==null){ return false; }else{ if(object.attributeValue.indexOf(optionName)>=0){ return true; }else{ return false; } } } |
修改頁面上規格面板的復選框,運用 ng-checked指令控制復選框的勾選狀態
<input type="checkbox" ng-click="updateSpecAttribute($event,pojo.text,p.optionName);createSKUTable()" ng-checked="checkAttributeValue(pojo.text,p.optionName)">{{p.optionName}} |
2.7讀取SKU數據
顯示SKU商品列表,並自動讀取價格、庫存等數據加載到列表中
2.7.1后端代碼
在GoodsServiceImpl的findOne方法中加載SKU商品數據
//查詢SKU商品列表 TbItemExample example=new TbItemExample(); com.pinyougou.pojo.TbItemExample.Criteria criteria = example.createCriteria(); criteria.andGoodsIdEqualTo(id);//查詢條件:商品ID List<TbItem> itemList = itemMapper.selectByExample(example); goods.setItemList(itemList); |
2.7.2前端代碼
在goodsController.js修改findOne方法的代碼
//查詢實體 $scope.findOne=function(){ ........ goodsService.findOne(id).success( function(response){ $scope.entity= response; ......... //SKU列表規格列轉換 for( var i=0;i<$scope.entity.itemList.length;i++ ){ $scope.entity.itemList[i].spec = JSON.parse( $scope.entity.itemList[i].spec); } } ); } |
2.8保存數據
2.8.1后端代碼
修改 pinyougou-sellergoods-interface 的 GoodsService.java
public void update(Goods goods); |
修改pinyougou-sellergoods-service的GoodsServiceImpl ,將SKU列表插入的代碼提取出來,封裝到私有方法中
/** * 插入SKU列表數據 * @param goods */ private void saveItemList(Goods goods){ if("1".equals(goods.getGoods().getIsEnableSpec())){ for(TbItem item :goods.getItemList()){ .........中間代碼略 } }else{ TbItem item=new TbItem(); .........中間代碼略 itemMapper.insert(item); } } |
在add方法中調用 此方法,修改如下:
public void add(Goods goods) { goods.getGoods().setAuditStatus("0"); goodsMapper.insert(goods.getGoods()); //插入商品表 goods.getGoodsDesc().setGoodsId(goods.getGoods().getId()); goodsDescMapper.insert(goods.getGoodsDesc());//插入商品擴展數據 saveItemList(goods);//插入商品SKU列表數據 } |
怎么樣,是不是比原來更加清爽了呢?
接下來,我們修改update方法,實現修改
public void update(Goods goods){ goods.getGoods().setAuditStatus("0");//設置未申請狀態:如果是經過修改的商品,需要重新設置狀態 goodsMapper.updateByPrimaryKey(goods.getGoods());//保存商品表 goodsDescMapper.updateByPrimaryKey(goods.getGoodsDesc());//保存商品擴展表 //刪除原有的sku列表數據 TbItemExample example=new TbItemExample(); com.pinyougou.pojo.TbItemExample.Criteria criteria = example.createCriteria(); criteria.andGoodsIdEqualTo(goods.getGoods().getId()); itemMapper.deleteByExample(example); //添加新的sku列表數據 saveItemList(goods);//插入商品SKU列表數據 } |
修改pinyougou-manager-web工程的GoodsController.java
@RequestMapping("/update") public Result update(@RequestBody Goods goods){ ...... } |
修改pinyougou-shop-web工程的GoodsController.java
/** * 修改 * @param goods * @return */ @RequestMapping("/update") public Result update(@RequestBody Goods goods){ //校驗是否是當前商家的id Goods goods2 = goodsService.findOne(goods.getGoods().getId()); //獲取當前登錄的商家ID String sellerId = SecurityContextHolder.getContext().getAuthentication().getName(); //如果傳遞過來的商家ID並不是當前登錄的用戶的ID,則屬於非法操作 if(!goods2.getGoods().getSellerId().equals(sellerId) || !goods.getGoods().getSellerId().equals(sellerId) ){ return new Result(false, "操作非法"); } try { goodsService.update(goods); return new Result(true, "修改成功"); } catch (Exception e) { e.printStackTrace(); return new Result(false, "修改失敗"); } } |
代碼解釋:出於安全考慮,在商戶后台執行的商品修改,必須要校驗提交的商品屬於該商戶
2.8.2前端代碼
(1)修改goodsController.js ,新增保存的方法
//保存 $scope.save=function(){ //提取文本編輯器的值 $scope.entity.goodsDesc.introduction=editor.html(); var serviceObject;//服務層對象 if($scope.entity.goods.id!=null){//如果有ID serviceObject=goodsService.update( $scope.entity ); //修改 }else{ serviceObject=goodsService.add( $scope.entity );//增加 } serviceObject.success( function(response){ if(response.success){ alert('保存成功'); $scope.entity={}; editor.html(""); }else{ alert(response.message); } } ); } |
(2)修改goods_edit.html 調用
<button class="btn btn-primary" ng-click="save()"><i class="fa fa-save"></i>保存</button> |
2.9頁面跳轉
(1)由商品列表頁跳轉到商品編輯頁
修改goods.html表格行的修改按鈕
<a href="goods_edit.html#?id={{entity.id}}" class="btn bg-olive btn-xs">修改</a> |
(2)由商品編輯頁跳轉到商品列表
修改goods_edit.html 的返回列表按鈕
<a href="goods.html" class="btn btn-default">返回列表</a> |
(3)保存成功后返回列表頁面
//保存 $scope.save=function(){ ..... serviceObject.success( function(response){ if(response.success){ location.href="goods.html";//跳轉到商品列表頁 }else{ alert(response.message); } } ); } |
3.運營商后台-商品管理【商品審核】
3.1待審核商品列表
需求:參照商家后台商品列表。代碼:
(1)修改pinyougou-manager-web的goodsController.js,注入itemCatService,添加代碼
$scope.status=['未審核','已審核','審核未通過','關閉'];//商品狀態 $scope.itemCatList=[];//商品分類列表 //查詢商品分類 $scope.findItemCatList=function(){ itemCatService.findAll().success( function(response){ for(var i=0;i<response.length;i++){ $scope.itemCatList[response[i].id ]=response[i].name; } } ); } |
(2)修改goods.html ,引入js
<script type="text/javascript" src="../plugins/angularjs/angular.min.js"></script> <!-- 分頁組件開始 --> <script src="../plugins/angularjs/pagination.js"></script> <link rel="stylesheet" href="../plugins/angularjs/pagination.css"> <!-- 分頁組件結束 --> <script type="text/javascript" src="../js/base_pagination.js"></script> <script type="text/javascript" src="../js/service/goodsService.js"></script> <script type="text/javascript" src="../js/service/itemCatService.js"></script> <script type="text/javascript" src="../js/controller/baseController.js"></script> <script type="text/javascript" src="../js/controller/goodsController.js"></script> |
(3)指令,完成初始調用
<body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="goodsController" ng-init="searchEntity={auditStatus:'0'};findItemCatList()"> |
(4)循環列表
<tr ng-repeat="entity in list"> <td><input type="checkbox"></td> <td>{{entity.id}}</td> <td>{{entity.goodsName}}</td> <td>{{entity.price}}</td> <td>{{itemCatList[entity.category1Id]}}</td> <td>{{itemCatList[entity.category2Id]}}</td> <td>{{itemCatList[entity.category3Id]}}</td> <td>{{status[entity.auditStatus]}}</td> <td class="text-center"> </td> </tr> |
(5)分頁控件
<tm-pagination conf="paginationConf"></tm-pagination> |
3.2商品詳情展示(學員實現)
需求:點擊列表右側的“詳情”按鈕,彈出窗口顯示商品信息。代碼略。
3.3商品審核與駁回
需求:商品審核的狀態值為1,駁回的狀態值為2 。用戶在列表中選中ID后,點擊審核或駁回,修改商品狀態,並刷新列表。
3.3.1后端代碼
(1)在pinyougou-sellergoods-interface的GoodsService.java新增方法定義
/** * 批量修改狀態 * @param ids * @param status */ public void updateStatus(Long []ids,String status); |
(2)在pinyougou-sellergoods-service的GoodsServiceImpl.java實現該方法
public void updateStatus(Long[] ids, String status) { for(Long id:ids){ TbGoods goods = goodsMapper.selectByPrimaryKey(id); goods.setAuditStatus(status); goodsMapper.updateByPrimaryKey(goods); } } |
(3)在pinyougou-shop-web的GoodsController.java新增方法
/** * 更新狀態 * @param ids * @param status */ @RequestMapping("/updateStatus") public Result updateStatus(Long[] ids, String status){ try { goodsService.updateStatus(ids, status); return new Result(true, "成功"); } catch (Exception e) { e.printStackTrace(); return new Result(false, "失敗"); } } |
3.3.2前端代碼
(1)修改pinyougou-manager-web的goodsService.js ,增加方法
//更改狀態 this.updateStatus=function(ids,status){ return $http.get('../goods/updateStatus.do?ids='+ids+"&status="+status); } |
(2)修改pinyougou-manager-web的goodsController.js ,增加方法
//更改狀態 $scope.updateStatus=function(status){ goodsService.updateStatus($scope.selectIds,status).success( function(response){ if(response.success){//成功 $scope.reloadList();//刷新列表 $scope.selectIds=[];//清空ID集合 }else{ alert(response.message); } } ); } |
(3)修改pinyougou-manager-web的goods.html 頁面,為復選框綁定事件指令
<input type="checkbox" ng-click="updateSelection($event,entity.id)" > |
(4)修改頁面上的審核通過和駁回按鈕
<button type="button" class="btn btn-default" title="審核通過" ng-click="updateStatus('1')"><i class="fa fa-check"></i> 審核通過</button> <button type="button" class="btn btn-default" title="駁回" ng-click="updateStatus('2')" ><i class="fa fa-ban"></i> 駁回</button> |
4.運營商后台-商品管理【商品刪除】
4.1需求分析
我們為商品管理提供商品刪除功能,用戶選中部分商品,點擊刪除按鈕即可實現商品刪除。注意,這里的刪除並非是物理刪除,而是修改tb_goods表的is_delete字段為1 ,我們可以稱之為“邏輯刪除”
4.2邏輯刪除的實現
4.2.1后端代碼
修改pinyougou-sellergoods-service工程的GoodsServiceImpl.java的delete方法
/** * 批量刪除 */ @Override public void delete(Long[] ids) { for(Long id:ids){ TbGoods goods = goodsMapper.selectByPrimaryKey(id); goods.setIsDelete("1"); goodsMapper.updateByPrimaryKey(goods); } } |
4.2.2前端代碼
修改pinyougou-manager-web的goods.html上的刪除按鈕
<button type="button" class="btn btn-default" title="刪除" ng-click="dele()"><i class="fa fa-trash-o"></i> 刪除</button> |
4.3排除已刪除記錄
修改pinyougou-sellergoods-service工程GoodsServiceImpl.java的findPage方法,添加以下代碼:
criteria.andIsDeleteIsNull();//非刪除狀態 |
5.商家后台-【商品上下架】(學員實現)
5.1需求分析
什么是商品上下架?其實上下架也是商品的一個狀態,但是不同於審核狀態。審核狀態的控制權在運營商手中,而上下架的控制權在商戶手中。商戶可以隨時將一個已審核狀態的商品上架或下架。上架表示正常銷售,而下架則表示暫停銷售。
5.2實現思路提示
其實商品的上下架就是對上下架狀態的修改。字段為tb_goods表的is_marketable字段。1表示上架、0表示下架。
6.注解式事務配置
6.1事務異常測試
我們修改pinyougou-sellergoods-service工程GoodsServiceImpl.java的add方法
/** * 增加 */ @Override public void add(Goods goods) { goods.getGoods().setAuditStatus("0"); goodsMapper.insert(goods.getGoods()); //插入商品表 int x=1/0; goods.getGoodsDesc().setGoodsId(goods.getGoods().getId()); goodsDescMapper.insert(goods.getGoodsDesc());//插入商品擴展數據 saveItemList(goods);//插入商品SKU列表數據 } |
在插入商品表后,人為制造一個異常。我們運行程序,新增商品數據,觀察運行結果。
通過觀察,我們發現,程序發生異常 ,商品表仍然會存儲記錄,這是不符合我們要求的。這是因為我們目前的系統還沒有配置事務。
6.2注解式事務解決方案
6.2.1配置文件
在pinyougou-sellergoods-service工程的spring目錄下創建applicationContext-tx.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 事務管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 開啟事務控制的注解支持 --> <tx:annotation-driven transaction-manager="transactionManager"/> </beans> |
6.2.2在方法上添加注解
/** * 服務實現層 * @author Administrator * */ @Service @Transactional public class GoodsServiceImpl implements GoodsService{ ........ } |
經過測試,我們發現,系統發生異常,商品表不會新增記錄,事務配置成功。
刪除掉測試代碼int x=1/0
我們需要將所有涉及多表操作的服務類添加事務注解,例如SpecificationServiceImpl類