整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          基于SpringBoot2的開源管理后臺系統(tǒng)springboot-plus

          一個基于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ā)平臺適合自己

          • 要明白單體系統(tǒng),系統(tǒng)拆分,微服務(wù)三個不同構(gòu)建開發(fā)平臺方式,plus支持單體和系統(tǒng)拆分,一般而言,后臺管理系統(tǒng)適合單體和系統(tǒng)拆分。微服務(wù)并不適合系統(tǒng)管理,以我知道的互聯(lián)網(wǎng)大廠,央企后臺管理系統(tǒng),還是以前倆個為多
          • 你需要的是技術(shù)框架還是開發(fā)平臺,技術(shù)框架就是技術(shù)堆砌,開發(fā)平臺必須具備一定復(fù)雜基礎(chǔ)業(yè)務(wù)功能
          • 看權(quán)限模型,支持功能權(quán)限和數(shù)據(jù)權(quán)限。plus具備強(qiáng)大的功能權(quán)限和數(shù)據(jù)權(quán)限,且可以擴(kuò)展n種數(shù)據(jù)權(quán)限
          • 看用戶是否能屬于多個部門,用戶兼職情況很常見
          • 看數(shù)據(jù)字典是否支持級聯(lián),數(shù)據(jù)字典級聯(lián)太常見了,平臺需要提供數(shù)據(jù)和前端的支持。puls系統(tǒng)支持
          • 看代碼生成是否支持預(yù)覽,為什么要預(yù)覽,因?yàn)樯蓵采w,預(yù)覽可以修改已經(jīng)生成的代碼

          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.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工程,包含倆個子工程

          • admin-core ,核心包,包含了緩存,數(shù)據(jù)權(quán)限,公用的JS和HTML頁面。
          • admin-console, 系統(tǒng)管理功能,包含了用戶,組織機(jī)構(gòu),角色,權(quán)限,數(shù)據(jù)權(quán)限,代碼生成等管理功能

          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)級菜單,出現(xiàn)在頁面頂部,表示一個子系統(tǒng)
          • 導(dǎo)航菜單,出現(xiàn)在頁面左邊,點(diǎn)擊導(dǎo)航將打開其下所有菜單
          • 菜單,點(diǎn)開菜單將定位到頁面,菜單必須關(guān)聯(lián)到一個功能點(diǎ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āng)此實(shí)體顯示在任何地方的時(shí)候,能代表此實(shí)體的名稱,比如用戶名,組織機(jī)構(gòu)名
          • 變量名:可以自己設(shè)定一個較短的名字,此變量名會用于前后端的變量
          • urlBase:你規(guī)劃的子系統(tǒng),最后訪問路徑是urlBase+變量名字
          • system: 存放sql目錄的的名稱

          其他修改的地方有

          是否包含導(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.

          • index.js: 系統(tǒng)入口JS,包含了查詢和表格
          • add.js : 新增操作的所有JS
          • edit.js: 編輯操作的所有JS
          • del.js: 刪除操作的所有JS

          基礎(chǔ)JS

          • Common.js: 封裝了通常JS功能,如jquery的post方法,layui的窗口方法
          • Lib.js 封裝了業(yè)務(wù)相關(guān)方法,如submitForm,loadOrgPanel等方法

          1.3.2 HTML代碼

          頁面采用layui,文檔參考 http://www.layui.com/demo/

          模板語言了使用Beetl,文檔參考ibeetl.com

          • index.html: 功能首頁
          • add.html: 新增首頁
          • edit.html: 編輯操作首頁

          采用layui的好處是自帶了頁面和組件還有JS的管理,能完成大多數(shù)業(yè)務(wù)需求

          基礎(chǔ)UI組件:

          • orgInput.tag.html 組織機(jī)構(gòu)輸入框
          • simpleDictSelect.tag.html 字典下拉列表
          • simpleDataSelect.tag 包含key-value的下拉列表
          • searchForm.tag.html 通用搜索表單
          • submitButtons.tag.html 提交按鈕
          • accessButton.tag.html 普通按鈕(含權(quán)限)
          • attachment.tag.html 附件管理組件
          • ....

          2 單體系統(tǒng),系統(tǒng)拆分和微服務(wù)

          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包,部署。這樣有如下明顯好處

          • 單體系統(tǒng)開發(fā)方式簡單,我們從剛開始學(xué)習(xí)編程,就是完成的單體系統(tǒng),開發(fā)人員只要集中精力開發(fā)當(dāng)前工程
          • 容易修改,如果需要修改任何功能,都非常方便,只需要修改一個工程范圍的代碼
          • 測試簡單,單體系統(tǒng)測試不需要考慮別的系統(tǒng),避免本書下冊要提到的各種REST,MQ調(diào)用
          • 部署也很容易:不需要考慮跟別的系統(tǒng)關(guān)系,直接打war包部署到Web服務(wù)器即可
          • 性能容易擴(kuò)展,可以通過Nginx,把一個應(yīng)用部署到多個服務(wù)器上。

          隨著業(yè)務(wù)發(fā)展,重構(gòu),單體系統(tǒng)越來越多,在開發(fā)一個龐大的單體系統(tǒng)的時(shí)候,就會有如下弊病

          • 單體系統(tǒng)龐大,越來越難理解單體系統(tǒng),微小的改動牽涉面廣泛導(dǎo)致開發(fā)小組小心謹(jǐn)慎,開發(fā)速度會越來越慢。另外,啟動一個龐大的單體系統(tǒng),可能需要3分鐘,或者更多時(shí)間
          • 多個功能在同一個單體系統(tǒng)上開發(fā),導(dǎo)致測試越來越慢,比如,測試必須排期,串行測試
          • 單體系統(tǒng)如果想對技術(shù)進(jìn)行更新?lián)Q代,那代價(jià)非常大,如果是個小系統(tǒng)構(gòu)成,則可以選取一個小系統(tǒng)先做嘗試。單體大系統(tǒng)是幾乎不可能做技術(shù)升級的
          • 單體系統(tǒng)的所有功能運(yùn)行在同一個JVM里,功能會互相影響,比如一個統(tǒng)計(jì)上傳word文檔的頁碼的功能由于非常消耗CPU,因此,會因?yàn)檎{(diào)用統(tǒng)計(jì)功能,導(dǎo)致整個系統(tǒng)短暫都不可用,出現(xiàn)假死的現(xiàn)象

          因此,越來越多的架構(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>

          • 傳統(tǒng)IT系統(tǒng)本質(zhì)上還是會用一個數(shù)據(jù)庫,而微服務(wù)提倡的是一個服務(wù)一個數(shù)據(jù)庫
          • 傳統(tǒng)IT系統(tǒng)很少需要調(diào)用其他模塊服務(wù)。傳統(tǒng)IT系統(tǒng)通過工作流來串聯(lián)其他子系統(tǒng)。而電商類的微服務(wù)則是通過RPC等方式進(jìn)行交互,是一個輕量級協(xié)議。傳統(tǒng)IT系統(tǒng)也可以通過SOA,JMS跟其他系統(tǒng)(非子系統(tǒng))交互,采用重量級協(xié)議
          • 微服務(wù)對系統(tǒng)的基礎(chǔ)設(shè)施要求很高,比如微服務(wù)治理,彈性庫等等,只要電商系統(tǒng)才有人力物力去做這種事情,而傳統(tǒng)IT系統(tǒng),及時(shí)財(cái)大氣粗,也暫時(shí)不具備微服務(wù)那樣的IT基礎(chǔ)設(shè)置

          因此,對于大多數(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)用格式:

          模板文件的寫法支持下面幾種:


          1. 基本使用

          下面是一個最典型的用法,不帶任何參數(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ù)覽:


          2. 修改模板引擎的view_depr(模板文件名分隔符)設(shè)置

          ①修改模板引擎的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ù)覽:


          3. 如果沒有按照模板定義規(guī)則來定義模板文件(或者需要調(diào)用其他控制器下面的某個模板)

          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ù)覽:


          4. 跨模塊渲染模板

          【例】在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ù)覽:

          5. 從視圖根目錄開始讀取模板

          支持從視圖根目錄開始讀取模板,即從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模板。


          6. 自定義模板文件位置

          如果你的模板文件位置比較特殊或者需要自定義模板文件的位置,可以采用下面的方式處理。

          ①在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)用的入口文件,而不是模板目錄。

          ThinkPHP5連載為卓象程序員原創(chuàng),轉(zhuǎn)載請聯(lián)系卓象程序員

          關(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.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.商品錄入【品牌選擇】

          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.商品錄入【擴(kuò)展屬性】

          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.商品錄入【規(guī)格選擇】

          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.商品錄入【SKU商品信息】

          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.商品錄入【是否啟用規(guī)格】

          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方法


          主站蜘蛛池模板: 欧洲亚洲综合一区二区三区| 一区二区三区AV高清免费波多| 亚洲色无码专区一区| 国产一区三区三区| 国产经典一区二区三区蜜芽| 日本高清成本人视频一区| 一区二区三区午夜| 波多野结衣一区二区三区高清av| 亚洲色偷偷偷网站色偷一区| 成人免费av一区二区三区| 一区二区三区免费高清视频| 日韩福利视频一区| 国产在线观看精品一区二区三区91| 中文字幕日韩一区二区不卡| 亚洲高清美女一区二区三区| 精品无码人妻一区二区免费蜜桃 | 在线观看国产区亚洲一区成人| 女人18毛片a级毛片一区二区| 亚洲一区二区三区国产精品无码| 国产另类TS人妖一区二区| 国产精品美女一区二区视频 | 国产伦精品一区二区免费| 日韩有码一区二区| 亚洲国产成人久久一区WWW| 国产高清在线精品一区二区三区| 无遮挡免费一区二区三区| 一区二区高清在线| 国产午夜精品一区二区三区嫩草| 三上悠亚精品一区二区久久| 国产成人无码精品一区二区三区| 日韩高清国产一区在线| 亚洲欧美日韩中文字幕在线一区 | 久久一区二区三区99| 国产一区二区三区精品视频| 亚洲爆乳精品无码一区二区三区| 精品成人乱色一区二区| 在线观看精品一区| 国产精久久一区二区三区| 亚洲国产精品一区第二页| 精品无码成人片一区二区98| 精品无码国产AV一区二区三区 |