一個基于SpringBoot 2 的管理后臺系統(tǒng),有數(shù)十個基于此的商業(yè)應(yīng)用,包含了用戶管理,組織機(jī)構(gòu)管理,角色管理,功能點(diǎn)管理,菜單管理,權(quán)限分配,數(shù)據(jù)權(quán)限分配,代碼生成等功能 相比其他開源的后臺開發(fā)平臺腳手架,SpringBoot-Plus 使用簡單,可以輕易完成中型,大型系統(tǒng)開發(fā)。同時(shí)技術(shù)棧較為簡單
如何判斷一個開源開發(fā)平臺適合自己
Plus系統(tǒng)是一個使用簡單,功能較為復(fù)雜的開源系統(tǒng),已經(jīng)數(shù)十家商業(yè)公司采用
系統(tǒng)基于Spring Boot2.1技術(shù),前端采用了Layui2.4。數(shù)據(jù)庫以MySQL/Oracle/Postgres/SQLServer為實(shí)例,理論上是跨數(shù)據(jù)庫平臺.
1.1 安裝說明
建議在徹底熟悉plus系統(tǒng)之前,先暫時(shí)不要修改其他配置選項(xiàng),免得系統(tǒng)無法訪問
本系統(tǒng)基于Spring Boot 2 ,因此請務(wù)必使用JDK8,且打開編譯選項(xiàng)parameters(點(diǎn)擊了解parameters), 并重新編譯工程,如果你沒有使用Java8的 parameters 特性,系統(tǒng)不能正常使用
從Git上獲取代碼后,通過IDE導(dǎo)入此Maven工程,包含倆個子工程
com.ibeetl.admin.CosonleApplication 是系統(tǒng)啟動類,在admin-console包下,在運(yùn)行這個之前,還需要初始化數(shù)據(jù)庫,位于doc/starter-mysql.sql,目前只提供mysql, oracle, postgresql腳本。理論上支持所有數(shù)據(jù)庫
還需要修改SpringBoot配置文件application.properties,修改你的數(shù)據(jù)庫地址和訪問用戶
spring.datasource.baseDataSource.url=jdbc:mysql://127.0.0.1:3306/starter?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false&useInformationSchema=true
spring.datasource.baseDataSource.username=root
spring.datasource.baseDataSource.password=123456
spring.datasource.baseDataSource.driver-class-name=com.mysql.cj.jdbc.Driver
運(yùn)行CosonleApplication,然后訪問http://127.0.0.1:8080/ 輸入admin/123456 則可以直接登錄進(jìn)入管理系統(tǒng)
1.2 創(chuàng)建子系統(tǒng)
SpringBoot-plus 是一個適合大系統(tǒng)拆分成小系統(tǒng)的架構(gòu),或者是一個微服務(wù)系統(tǒng),因此,如果你需要創(chuàng)建自己的業(yè)務(wù)系統(tǒng),比如,一個CMS子系統(tǒng),建議你不要在SpringBoot-Plus 添加代碼,應(yīng)該是新建立一個maven工程,依賴admin-core,或者依賴admin-console(如果你有后臺管理需求,通常都有,但不是必須的)
創(chuàng)建子系統(tǒng),可以進(jìn)入代碼生成>子系統(tǒng)生成, 輸入maven項(xiàng)目路徑,還有包名,就可以直接生成一個可運(yùn)行的基于SpringBoot-Plus 的子系統(tǒng),所有代碼可以在個項(xiàng)目里些完成,直接運(yùn)行MainApplication,
@SpringBootApplication @EnableCaching @ComponentScan(basePackages= {"com.corp.xxx","com.ibeetl.admin"}) public class MainApplication extends SpringBootServletInitializer implements WebApplicationInitializer { public static void main(String[] args) { SpringApplication.run(MainApplication.class, args); } }
子系統(tǒng)包含了admin-core和admin-console, 因此你可以直接在子系統(tǒng)里使用core和console提供的所有功能,通過子系統(tǒng)的console功能的代碼生成來完成進(jìn)一步開發(fā)
子系統(tǒng)可以單獨(dú)運(yùn)行和維護(hù),也可以集成到nginx后構(gòu)成一個龐大的企業(yè)應(yīng)用系統(tǒng)
1.2.1 配置子系統(tǒng)
子系統(tǒng)不需要做任何配置即可在IDE里直接運(yùn)行,如果你想打包jar方式運(yùn)行,則需要添加
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
如果你想打包成war放到tomcat下運(yùn)行,需要修改maven打包為war
<packaging>war</packaging>
1.2.2 菜單系統(tǒng)
系統(tǒng)默認(rèn)提供三種類型菜單
建議新建立一個子系統(tǒng)來放置新功能
SpringPlus-Boot 并非以菜單或者按鈕來組織整個系統(tǒng),而是以功能點(diǎn)來組織整個系統(tǒng)提供的功能。如果要使得菜單生效,你必須要先常見一個功能點(diǎn)并且功能點(diǎn)有一個訪問地址,然后將此菜單關(guān)聯(lián)到這個功能點(diǎn)
SpringBoot-Plus 先建立功能點(diǎn)是個好習(xí)慣,功能點(diǎn)被組織成一顆樹,代表了系統(tǒng)應(yīng)該提供功能的功能,我們看代碼就會看到,功能點(diǎn)跟菜單,跟權(quán)限,和數(shù)據(jù)權(quán)限都有密切關(guān)系
1.2.2 添加代碼
可以參考1.3業(yè)務(wù)代碼生成生成初始化的代碼,業(yè)務(wù)代碼生成了14個文件,包含前后端所有代碼,可以通過生成來了解代碼習(xí)作規(guī)范
1.3 業(yè)務(wù)代碼生成
在介紹如何利用Plus開發(fā)系統(tǒng)之前,先介紹代碼生成功能,此功能可以生成前后端代碼總計(jì)14個文件,你可以通過預(yù)覽功能了解如何開發(fā)這個系統(tǒng)
代碼生成針對表進(jìn)行代碼生成,包括JS,JAVA,SQL和HTML,可以通過預(yù)覽功能直接預(yù)覽。在生成代碼到本地前,有些參數(shù)需要修改,否則,代碼生成后顯示的都是英文
其他修改的地方有
是否包含導(dǎo)入導(dǎo)出,如果選擇,則會生成導(dǎo)入導(dǎo)出的代碼,導(dǎo)入導(dǎo)出模板則需要參考已有功能(比如數(shù)據(jù)字典)來完成
是否包含附件管理,如果選擇,則業(yè)務(wù)對象可以關(guān)聯(lián)一組附件,比如客戶關(guān)聯(lián)一組附件,或者申請信息關(guān)聯(lián)一組附件。
字段信息的顯示名字,這個用于前端列表,表單的顯示,應(yīng)當(dāng)輸入中文名字
作為搜索,可以勾選幾個搜索條件,系統(tǒng)自動生成一個搜索配置類
如果字段關(guān)聯(lián)數(shù)據(jù)字典,那么設(shè)置一個數(shù)據(jù)字典,這樣,生成的界面將會變成一個下拉列表
1.3.1 前端代碼
前端代碼采用了layui的JS框架,使用了按需加載的方式,文檔參考 http://www.layui.com/doc/base/infrastructure.html.
基礎(chǔ)JS
1.3.2 HTML代碼
頁面采用layui,文檔參考 http://www.layui.com/demo/
模板語言了使用Beetl,文檔參考ibeetl.com
采用layui的好處是自帶了頁面和組件還有JS的管理,能完成大多數(shù)業(yè)務(wù)需求
基礎(chǔ)UI組件:
plus是一個適合單體系統(tǒng),系統(tǒng)拆分的java快速開發(fā)平臺,也可以經(jīng)過改造成微服務(wù)平臺(以前做一個版本,但覺得plus應(yīng)該聚焦系統(tǒng)核心,而不是簡單堆砌功能,所以放棄了)
以下是單體系統(tǒng),小系統(tǒng),和微服務(wù)的區(qū)別
單體系統(tǒng)是一種常見系統(tǒng)設(shè)計(jì)方式,也是這十幾年年來最主要的設(shè)計(jì)方式。單體系統(tǒng)的所有功能都在一個工程里,打成一個war包,部署。這樣有如下明顯好處
隨著業(yè)務(wù)發(fā)展,重構(gòu),單體系統(tǒng)越來越多,在開發(fā)一個龐大的單體系統(tǒng)的時(shí)候,就會有如下弊病
因此,越來越多的架構(gòu)師在設(shè)計(jì)系統(tǒng)的時(shí)候,會考慮系統(tǒng)拆分成多個單體小系統(tǒng)甚至是微服務(wù)。對于傳統(tǒng)企業(yè)應(yīng)用,拆成小系統(tǒng)更合適,對互聯(lián)網(wǎng)系統(tǒng),使用微服務(wù)個更合適,這是因?yàn)?/p>
因此,對于大多數(shù)傳統(tǒng)IT應(yīng)用來說,單體拆分小系統(tǒng)在技術(shù)上沒有風(fēng)險(xiǎn),是一個可以立即實(shí)施的架構(gòu)。如下是一個單體系統(tǒng)拆分后的物理架構(gòu)
對于用戶來說,訪問不同的菜單功能,講定位到不同得子系統(tǒng),提供服務(wù)。
一篇文章講解“重定向”,本篇文章講解“視圖-模板渲染”。
因?yàn)樾掳娴目刂破骺梢詿o需繼承任何的基礎(chǔ)類,因此在控制器中如何使用視圖取決于你怎么定義控制器。
渲染模板最常用的是控制器類在繼承系統(tǒng)控制器基類(\think\Controller)后調(diào)用fetch方法,調(diào)用格式:
模板文件的寫法支持下面幾種:
下面是一個最典型的用法,不帶任何參數(shù):
①新建Index控制器,并在控制器中新建index方法
注意:
1. 不帶任何參數(shù),表示系統(tǒng)會按照默認(rèn)規(guī)則自動定位模板文件,其規(guī)則是:
當(dāng)前模塊/view/當(dāng)前控制器名(小寫)/當(dāng)前操作(小寫).html
②在index/view/index/下新建index.html模板文件
預(yù)覽:
①修改模板引擎的view_depr為“_”
位置:配置項(xiàng)文件config.php的template參數(shù)下。
注意:
1. 如果有更改模板引擎的view_depr設(shè)置(假設(shè)'view_depr'=>'_')的話,則上面的自動定位規(guī)則變成:
當(dāng)前模塊/view/當(dāng)前控制器(小寫)_當(dāng)前操作(小寫).html
②在index/view下新建index_index.html模板文件
訪問Index控制器下的index方法,預(yù)覽:
1)沒有按照模板定義規(guī)則來定義模板文件
【例】在Index控制器的add方法中要調(diào)用同控制器下的edit.html模板
①Index控制器的add方法
注意:
1. $this->fetch(‘edit’);表示調(diào)用當(dāng)前控制器的edit模板。
②在index/view/index/下新建edit.html模板(view_depr設(shè)置為默認(rèn))。
訪問add方法,預(yù)覽:
2)調(diào)用其他控制器下的某個模板
【例】在Index控制器的edit方法下,調(diào)用News控制器下的add模板。
①Index控制器下的edit方法:
②在index/view/news下新建add.html模板。
訪問Index控制器的edit方法,預(yù)覽:
【例】在index模塊的Index控制器的del方法中,調(diào)用admin模塊User控制器下的index.html模板。
①index模塊的Index控制器的del方法
②admin模塊的User控制器下的index.html模板
訪問index模塊的Index的del方法,預(yù)覽:
注意:
1. 渲染輸出不需要寫模板文件的路徑和后綴。
2. 這里面的控制器和操作并不一定需要有實(shí)際對應(yīng)的控制器和操作,只是一個目錄名稱和文件名稱而已。
【例2】你的項(xiàng)目里面可能根本沒有Public控制器,更沒有Public控制器的menu操作,但是一樣可以使用。
①在Index控制器中新建pub方法,調(diào)用Public控制器的menu模板
②在index/view/public下新建menu.html模板
訪問Index控制器的pub方法,預(yù)覽:
支持從視圖根目錄開始讀取模板,即從view文件夾下讀取。
①在Index控制器中新建viewFloder方法,調(diào)用視圖根目錄下的模板。
②在index/view下新建folder.html模板
訪問Index控制器的viewFloder方法,預(yù)覽:
注意:
1. 如果需要調(diào)用視圖類(think\View)的其它方法,可以直接使用$this->view對象。
【例】調(diào)用視圖類的config方法(配置模板引擎),設(shè)置模板后綴。
視圖類(think\View)的config方法:
默認(rèn)的模板后綴:
在Index方法中,新建viewTest方法
訪問viewTest方法,預(yù)覽:
注意:
1. 在視圖根目錄下有folder.html模板,當(dāng)設(shè)置模板后綴為.htm時(shí),那么將不會訪問folder.html模板,將會訪問folder.htm模板。
如果你的模板文件位置比較特殊或者需要自定義模板文件的位置,可以采用下面的方式處理。
①在Index控制器中新建Custom方法,調(diào)用自定義的模板文件位置
../template/index/是相當(dāng)于當(dāng)前項(xiàng)目入口文件的位置。
②在項(xiàng)目下創(chuàng)建template/index文件夾,并新建custom.html模板
預(yù)覽:
注意:
1. 這種方式需要帶模板路徑和后綴指定一個完整的模板文件位置,這里的../template/index目錄是相對于當(dāng)前項(xiàng)目入口文件位置。
2. 如果是其他的后綴文件,也支持直接輸出,例如:
return $this->fetch('../template/public/menu.tpl');
只要../template/index/menu.tpl是一個實(shí)際存在的模板文件。
3. 要注意模板文件位置是相對于應(yīng)用的入口文件,而不是模板目錄。
關(guān)注卓象程序員,定期發(fā)布技術(shù)文章
下一篇講解“視圖-助手函數(shù)+渲染內(nèi)容”
程目標(biāo)
目標(biāo)1:完成選擇商品分類功能
目標(biāo)2:完成品牌選擇功能
目標(biāo)3:完成擴(kuò)展屬性功能
目標(biāo)4:完成規(guī)格選擇功能
目標(biāo)5:完成SKU商品信息功能
目標(biāo)6:完成是否啟用規(guī)格功能
1.1需求分析
在商品錄入界面實(shí)現(xiàn)商品分類的選擇(三級分類)效果如下:
當(dāng)用戶選擇一級分類后,二級分類列表要相應(yīng)更新,當(dāng)用戶選擇二級分類后,三級列表要相應(yīng)更新。
1.2準(zhǔn)備工作
(1)在pinyougou-shop-web工程中創(chuàng)建ItemCatController.(可拷貝運(yùn)營商后臺的代碼)
(2)創(chuàng)建item_catService.js (可拷貝運(yùn)營商后臺的代碼)
(3)修改goodsController.js,引入itemCatService
(4)修改goods_edit.html,添加引用
<script type="text/javascript" src="../js/base.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>
1.3代碼實(shí)現(xiàn)
1.3.1一級分類下拉選擇框
在goodsController增加代碼
//讀取一級分類 $scope.selectItemCat1List=function(){ itemCatService.findByParentId(0).success( function(response){ $scope.itemCat1List=response; } ); }
頁面加載調(diào)用該方法
<body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="goodsController" ng-init="selectItemCat1List()">
修改goods_edit.html一級分類下拉選擇框
<select class="form-control" ng-model="entity.goods.category1Id" ng-options="item.id as item.name for item in itemCat1List"></select>
ng-options屬性可以在表達(dá)式中使用數(shù)組或?qū)ο髞碜詣由梢粋€select中的option列表。ng-options與ng-repeat很相似,很多時(shí)候可以用ng-repeat來代替ng-options。但是ng-options提供了一些好處,例如減少內(nèi)存提高速度,以及提供選擇框的選項(xiàng)來讓用戶選擇。
運(yùn)行效果如下:
1.3.2二級分類下拉選擇框
在goodsController增加代碼:
//讀取二級分類 $scope.$watch('entity.goods.category1Id', function(newValue, oldValue) { //根據(jù)選擇的值,查詢二級分類 itemCatService.findByParentId(newValue).success( function(response){ $scope.itemCat2List=response; } ); });
$watch方法用于監(jiān)控某個變量的值,當(dāng)被監(jiān)控的值發(fā)生變化,就自動執(zhí)行相應(yīng)的函數(shù)。
修改goods_edit.html中二級分類下拉框
<select class="form-control select-sm" ng-model="entity.goods.category2Id" ng-options="item.id as item.name for item in itemCat2List"></select>
1.3.3三級分類下拉選擇框
在goodsController增加代碼:
//讀取三級分類 $scope.$watch('entity.goods.category2Id', function(newValue, oldValue) { //根據(jù)選擇的值,查詢二級分類 itemCatService.findByParentId(newValue).success( function(response){ $scope.itemCat3List=response; } ); });
修改goods_edit.html中三級分類下拉框
<select class="form-control select-sm" ng-model="entity.goods.category3Id" ng-options="item.id as item.name for item in itemCat3List"></select>
1.3.4讀取模板ID
在goodsController增加代碼:
//三級分類選擇后 讀取模板ID $scope.$watch('entity.goods.category3Id', function(newValue, oldValue) { itemCatService.findOne(newValue).success( function(response){ $scope.entity.goods.typeTemplateId=response.typeId; //更新模板ID } ); });
在goods_edit.html顯示模板ID
模板ID:{{entity.goods.typeTemplateId}}
2.1需求分析
在用戶選擇商品分類后,品牌列表要根據(jù)用戶所選擇的分類進(jìn)行更新。具體的邏輯是根據(jù)用戶選擇的三級分類找到對應(yīng)的商品類型模板,商品類型模板中存儲了品牌的列表json數(shù)據(jù)。
2.2代碼實(shí)現(xiàn)
(1)在pinyougou-shop-web工程創(chuàng)建TypeTemplateController (可從運(yùn)營商后臺拷貝)
(2)在pinyougou-shop-web工程創(chuàng)建typeTemplateService.js (可從運(yùn)營商后臺拷貝)
(3)在goodsController引入typeTemplateService 并新增代碼
//模板ID選擇后 更新品牌列表 $scope.$watch('entity.goods.typeTemplateId', function(newValue, oldValue) { typeTemplateService.findOne(newValue).success( function(response){ $scope.typeTemplate=response;//獲取類型模板 $scope.typeTemplate.brandIds= JSON.parse( $scope.typeTemplate.brandIds);//品牌列表 } ); });
在頁面goods_edit.html 引入js
<script type="text/javascript" src="../js/service/typeTemplateService.js"> </script>
添加品牌選擇框
<select class="form-control" ng-model="entity.goods.brandId" ng-options="item.id as item.text for item in typeTemplate.brandIds"></select>
3.1需求分析
在商品錄入實(shí)現(xiàn)擴(kuò)展屬性的錄入。
3.2代碼實(shí)現(xiàn)
修改goodsController.js ,在用戶更新模板ID時(shí),讀取模板中的擴(kuò)展屬性賦給商品的擴(kuò)展屬性。
//模板ID選擇后 更新模板對象 $scope.$watch('entity.goods.typeTemplateId', function(newValue, oldValue) { typeTemplateService.findOne(newValue).success( function(response){ $scope.typeTemplate=response;//獲取類型模板 $scope.typeTemplate.brandIds= JSON.parse( $scope.typeTemplate.brandIds);//品牌列表 $scope.entity.goodsDesc.customAttributeItems=JSON.parse( $scope.typeTemplate.customAttributeItems);//擴(kuò)展屬性 } ); });
修改goods_edit.html
<!--擴(kuò)展屬性--> <div class="tab-pane" id="customAttribute"> <div class="row data-type"> <div ng-repeat="pojo in entity.goodsDesc.customAttributeItems"> <div class="col-md-2 title">{{pojo.text}}</div> <div class="col-md-10 data"> <input class="form-control" ng-model="pojo.value" placeholder="{{pojo.text}}"> </div> </div> </div> </div>
4.1需求分析
顯示規(guī)格及選項(xiàng)列表(復(fù)選框)如下圖,并保存用戶選擇的結(jié)果
4.2代碼實(shí)現(xiàn)
4.2.1 顯示規(guī)格選項(xiàng)列表
由于我們的模板中只記錄了規(guī)格名稱,而我們除了顯示規(guī)格名稱還是顯示規(guī)格下的規(guī)格選項(xiàng),所以我們需要在后端擴(kuò)充方法。
(1)在pinyougou-sellergoods-interface的TypeTemplateService.java新增方法定義
/** * 返回規(guī)格列表 * @return */ public List<Map> findSpecList(Long id);
(2)在pinyougou-sellergoods-service的TypeTemplateServiceImpl.java新增方法
@Autowired private TbSpecificationOptionMapper specificationOptionMapper; @Override public List<Map> findSpecList(Long id) { //查詢模板 TbTypeTemplate typeTemplate = typeTemplateMapper.selectByPrimaryKey(id); List<Map> list = JSON.parseArray(typeTemplate.getSpecIds(), Map.class) ; for(Map map:list){ //查詢規(guī)格選項(xiàng)列表 TbSpecificationOptionExample example=new TbSpecificationOptionExample(); com.pinyougou.pojo.TbSpecificationOptionExample.Criteria criteria = example.createCriteria(); criteria.andSpecIdEqualTo( new Long( (Integer)map.get("id") ) ); List<TbSpecificationOption> options = specificationOptionMapper.selectByExample(example); map.put("options", options); } return list; }
(3)在pinyougou-shop-web的TypeTemplateController.java新增方法
@RequestMapping("/findSpecList") public List<Map> findSpecList(Long id){ return typeTemplateService.findSpecList(id); }
測試后端代碼:
(4)前端代碼:修改pinyougou-shop-web的typeTemplateService.js
//查詢規(guī)格列表 this.findSpecList=function(id){ return $http.get('../typeTemplate/findSpecList.do?id='+id); }
(5)修改pinyougou-shop-web的goodsController.js
//模板ID選擇后 更新模板對象 $scope.$watch('entity.goods.typeTemplateId', function(newValue, oldValue) { typeTemplateService.findOne(newValue).success( function(response){ $scope.typeTemplate=response;//獲取類型模板 $scope.typeTemplate.brandIds= JSON.parse( $scope.typeTemplate.brandIds);//品牌列表 $scope.entity.goodsDesc.customAttributeItems=JSON.parse( $scope.typeTemplate.customAttributeItems);//擴(kuò)展屬性 } ); //查詢規(guī)格列表 typeTemplateService.findSpecList(newValue).success( function(response){ $scope.specList=response; } ); });
(6)修改goods_edit.html頁面
<div ng-repeat="pojo in specList"> <div class="col-md-2 title">{{pojo.text}}</div> <div class="col-md-10 data"> <span ng-repeat="option in pojo.options"> <input type="checkbox" >{{option.optionName}} </span> </div> </div>
4.2.2 保存選中規(guī)格選項(xiàng)
我們需要將用戶選中的選項(xiàng)保存在tb_goods_desc表的specification_items字段中,定義json格式如下:
[{“attributeName”:”規(guī)格名稱”,”attributeValue”:[“規(guī)格選項(xiàng)1”,“規(guī)格選項(xiàng)2”.... ] } , .... ]
(1)在baseController.js增加代碼
//從集合中按照key查詢對象 $scope.searchObjectByKey=function(list,key,keyValue){ for(var i=0;i<list.length;i++){ if(list[i][key]==keyValue){ return list[i]; } } return null; }
(2)在goodsController.js增加代碼
$scope.entity={ goodsDesc:{itemImages:[],specificationItems:[]} }; $scope.updateSpecAttribute=function($event,name,value){ var object= $scope.searchObjectByKey( $scope.entity.goodsDesc.specificationItems ,'attributeName', name); if(object!=null){ if($event.target.checked ){ object.attributeValue.push(value); }else{//取消勾選 object.attributeValue.splice( object.attributeValue.indexOf(value ) ,1);//移除選項(xiàng) //如果選項(xiàng)都取消了,將此條記錄移除 if(object.attributeValue.length==0){ $scope.entity.goodsDesc.specificationItems.splice( $scope.entity.goodsDesc.specificationItems.indexOf(object),1); } } }else{ $scope.entity.goodsDesc.specificationItems.push( {"attributeName":name,"attributeValue":[value]}); } }
(3)在goods_edit.html調(diào)用方法
<div ng-repeat="pojo in specList"> <div class="col-md-2 title">{{pojo.text}}</div> <div class="col-md-10 data"> <span ng-repeat="option in pojo.options"> <input type="checkbox" ng-click="updateSpecAttribute($event,pojo.text,option.optionName)">{{option.optionName}} </span> </div> </div>
為了方便測試,我們可以在頁面上某個區(qū)域臨時(shí)添加表達(dá)式,以便觀測測試結(jié)果
{{entity.goodsDesc.specificationItems}}
5.1需求分析
基于上一步我們完成的規(guī)格選擇,根據(jù)選擇的規(guī)格錄入商品的SKU信息,當(dāng)用戶選擇相應(yīng)的規(guī)格,下面的SKU列表就會自動生成,如下圖:
實(shí)現(xiàn)思路:實(shí)現(xiàn)思路:
(1)我們先定義一個初始的不帶規(guī)格名稱的集合,只有一條記錄。
(2)循環(huán)用戶選擇的規(guī)格,根據(jù)規(guī)格名稱和已選擇的規(guī)格選項(xiàng)對原集合進(jìn)行擴(kuò)充,添加規(guī)格名稱和值,新增的記錄數(shù)與選擇的規(guī)格選項(xiàng)個數(shù)相同
生成的順序如下圖:
5.2前端代碼
5.2.1 生成SKU列表(深克隆)
(1)在goodsController.js實(shí)現(xiàn)創(chuàng)建sku列表的方法
//創(chuàng)建SKU列表 $scope.createItemList=function(){ $scope.entity.itemList=[{spec:{},price:0,num:99999,status:'0',isDefault:'0' } ];//初始 var items= $scope.entity.goodsDesc.specificationItems; for(var i=0;i< items.length;i++){ $scope.entity.itemList = addColumn( $scope.entity.itemList,items[i].attributeName,items[i].attributeValue ); } } //添加列值 addColumn=function(list,columnName,conlumnValues){ var newList=[];//新的集合 for(var i=0;i<list.length;i++){ var oldRow= list[i]; for(var j=0;j<conlumnValues.length;j++){ var newRow= JSON.parse( JSON.stringify( oldRow ) );//深克隆 newRow.spec[columnName]=conlumnValues[j]; newList.push(newRow); } } return newList; }
(2)在更新規(guī)格屬性后調(diào)用生成SKU列表的方法
<input type="checkbox" ng-click="updateSpecAttribute($event,pojo.text,option.optionName);createItemList()">{{option.optionName}}
(3)在頁面上添加表達(dá)式,進(jìn)行測試
{{entity.itemList}}
顯示效果如下:
5.2.2 顯示SKU列表
goods_edit.html頁面上綁定SKU列表
<table class="table table-bordered table-striped table-hover dataTable"> <thead> <tr> <th class="sorting" ng-repeat="item in entity.goodsDesc.specificationItems">{{item.attributeName}}</th> <th class="sorting">價(jià)格</th> <th class="sorting">庫存</th> <th class="sorting">是否啟用</th> <th class="sorting">是否默認(rèn)</th> </tr> </thead> <tbody> <tr ng-repeat="pojo in entity.itemList"> <td ng-repeat="item in entity.goodsDesc.specificationItems"> {{pojo.spec[item.attributeName]}} </td> <td> <input class="form-control" ng-model="pojo.price" placeholder="價(jià)格"> </td> <td> <input class="form-control" ng-model="pojo.num" placeholder="庫存數(shù)量"> </td> <td> <input type="checkbox" ng-model="pojo.status" ng-true-value="1" ng-false-value="0" > </td> <td> <input type="checkbox" ng-model="pojo.isDefault" ng-true-value="1" ng-false-value="0"> </td> </tr> </tbody> </table>
刪除掉原來的測試用的表達(dá)式
5.3后端代碼
(1)在GoodsServiceImpl添加屬性
@Autowired private TbItemMapper itemMapper; @Autowired private TbBrandMapper brandMapper; @Autowired private TbItemCatMapper itemCatMapper; @Autowired private TbSellerMapper sellerMapper;
(2)修改GoodsServiceImpl的add方法,增加代碼,實(shí)現(xiàn)對SKU商品信息的保存
/** * 增加 */ @Override public void add(Goods goods) { goods.getGoods().setAuditStatus("0"); goodsMapper.insert(goods.getGoods()); //插入商品表 goods.getGoodsDesc().setGoodsId(goods.getGoods().getId()); goodsDescMapper.insert(goods.getGoodsDesc());//插入商品擴(kuò)展數(shù)據(jù) for(TbItem item :goods.getItemList()){ //標(biāo)題 String title= goods.getGoods().getGoodsName(); Map<String,Object> specMap = JSON.parseObject(item.getSpec()); for(String key:specMap.keySet()){ title+=" "+ specMap.get(key); } item.setTitle(title); item.setGoodsId(goods.getGoods().getId());//商品SPU編號 item.setSellerId(goods.getGoods().getSellerId());//商家編號 item.setCategoryid(goods.getGoods().getCategory3Id());//商品分類編號(3級) item.setCreateTime(new Date());//創(chuàng)建日期 item.setUpdateTime(new Date());//修改日期 //品牌名稱 TbBrand brand = brandMapper.selectByPrimaryKey(goods.getGoods().getBrandId()); item.setBrand(brand.getName()); //分類名稱 TbItemCat itemCat = itemCatMapper.selectByPrimaryKey(goods.getGoods().getCategory3Id()); item.setCategory(itemCat.getName()); //商家名稱 TbSeller seller = sellerMapper.selectByPrimaryKey(goods.getGoods().getSellerId()); item.setSeller(seller.getNickName()); //圖片地址(取spu的第一個圖片) List<Map> imageList = JSON.parseArray(goods.getGoodsDesc().getItemImages(), Map.class) ; if(imageList.size()>0){ item.setImage ( (String)imageList.get(0).get("url")); } itemMapper.insert(item); } }
6.1需求分析
在規(guī)格面板添加是否啟用規(guī)格,當(dāng)用戶沒有選擇該項(xiàng),將原來的規(guī)格面板和SKU列表隱藏,用戶保存商品后只生成一個SKU.
6.2前端代碼
goods_add.html添加復(fù)選框
<div class="row data-type"> <div class="col-md-2 title">是否啟用規(guī)格</div> <div class="col-md-10 data"> <input type="checkbox" ng-model="entity.goods.isEnableSpec" ng-true-value="1" ng-false-value="0"> </div> </div>
用if指令控制規(guī)格面板與SKU列表的顯示與隱藏
<div ng-if="entity.goods.isEnableSpec==1"> ......SKU表格部分 </div>
6.3后端代碼
修改GoodsServiceImpl的add方法
*請認(rèn)真填寫需求信息,我們會在24小時(shí)內(nèi)與您取得聯(lián)系。