陳學(xué)明
摘要:Spring作為企業(yè)級(jí)應(yīng)用開發(fā)框架,配置煩瑣;Spring Boot簡(jiǎn)化了Spring的配置,實(shí)現(xiàn)了開箱即用。Ext JS是一站式前端開發(fā)框架,可以搭配Spring Boot買現(xiàn)前后端分離的Java Web應(yīng)用框架。該文基于Spring Boot和Ext JS,提出以實(shí)體類為驅(qū)動(dòng)的前后端協(xié)同開發(fā)和準(zhǔn)前后端分離的通用平臺(tái),在基本規(guī)格確認(rèn)的基礎(chǔ)上獨(dú)立開發(fā),使用單個(gè)和數(shù)個(gè)JSP頁(yè)面實(shí)現(xiàn)SPA(單頁(yè)面應(yīng)用程序)的開發(fā)方式,通過(guò)JSP的Session管理用戶認(rèn)證信息。該平臺(tái)在統(tǒng)一規(guī)格的基礎(chǔ)上,實(shí)現(xiàn)開發(fā)分離,提高開發(fā)和測(cè)試效率;合并部署,簡(jiǎn)化部署過(guò)程和部署架構(gòu),適用于中小型及快速開發(fā)的企業(yè)級(jí)應(yīng)用。
關(guān)鍵詞:Spring Boot;Ext JS;MVC;MVVM;準(zhǔn)前后端分離;類驅(qū)動(dòng);約定優(yōu)于配置
中圖分類號(hào):TP311 文獻(xiàn)標(biāo)識(shí)碼:A
文章編號(hào):1009-3044(2019)35-0063-04
1 背景
IoC與AOP是Spring框架最重要的兩個(gè)編程思想,基于Spring框架開發(fā)Web應(yīng)用,需要整合MVC框架(比如SpringMVC、Structs2等)、數(shù)據(jù)持久化框架(比如Hibemate、MyBatis等)以及JSP模板引擎等。雖然兼容性是Spring框架的優(yōu)點(diǎn),但不同的框架搭配對(duì)應(yīng)的配置不盡相同,這些配置煩瑣卻又樣板化。對(duì)于大多數(shù)企業(yè)級(jí)應(yīng)用而言,個(gè)性化配置基本沒(méi)有要求。提供一種默認(rèn)的框架組合,在不配置或少量配置的狀況下使用框架開發(fā),就可以省去項(xiàng)目搭建的工作,Spring Boot即在此背景下產(chǎn)生的。
Spring Boot使用默認(rèn)或簡(jiǎn)化配置實(shí)現(xiàn)了框架的開箱即用,而且其內(nèi)置了Web服務(wù)器,保持了Web應(yīng)用程序與一般應(yīng)用相同的開發(fā)方式。在應(yīng)用前端展現(xiàn)上,基于Spring Boot框架的Web應(yīng)用,既可以使用后端模板引擎開發(fā)前端頁(yè)面,比如Free-Marker或Thymeleaf;也可以作為后端服務(wù)框架搭配前端Web框架進(jìn)行開發(fā)。
在Spring Boot以及與前端框架結(jié)合的研究上,劉玉號(hào)、李沛在基于Spring Boot的后臺(tái)服務(wù)器開發(fā)中使用Spring Boot代替SSH或SSM,提出了脫離復(fù)雜的環(huán)境配置,快速搭建Spring應(yīng)用程序Ⅲ;張峰總結(jié)了Spring Boot在應(yīng)用系統(tǒng)開發(fā)的架構(gòu)設(shè)計(jì)、開發(fā)、測(cè)試、部署和監(jiān)控上帶來(lái)了變更和便捷嘲;張雷,王悅對(duì)Spring Boot作為MVC的微服務(wù)架構(gòu)進(jìn)行了研究[3];楊妍探討了Spring Boot與Vue結(jié)合的系統(tǒng)管理模塊開發(fā)[4];莫秋晶,黃志遠(yuǎn)等基于Spring Boot設(shè)計(jì)和實(shí)現(xiàn)了Spring+Vue以及Vue+Elemen-tUI的前后端分離的框架[5];周玉,聞金華,徐建良則研究了ExtJS框架MVC模式的面向?qū)ο蟮膹?fù)用技術(shù)[6]。
基于Spring Boot和JSP或模板引擎的Web開發(fā),無(wú)法發(fā)揮前端的優(yōu)勢(shì),前后端代碼混雜,維護(hù)性差;開發(fā)人員兼顧前后,無(wú)法發(fā)揮專業(yè)化優(yōu)勢(shì),效率不高;完全的前后端分離開發(fā),除了物理架構(gòu)和部署工作量稍大之外,主要是需要單獨(dú)處理用戶認(rèn)證及Session問(wèn)題。大部分企業(yè)級(jí)應(yīng)用的特點(diǎn)是對(duì)前端UI和交互的要求較高,需要美觀的頁(yè)面樣式的流暢的動(dòng)態(tài)引導(dǎo),但用戶數(shù)量有限,并發(fā)訪問(wèn)量不高,對(duì)分布式也沒(méi)有要求。實(shí)現(xiàn)系統(tǒng)豐富、動(dòng)態(tài)UI同時(shí),簡(jiǎn)化系統(tǒng)架構(gòu)和提高開發(fā)效率是本文研究的方向。本文提出了基于Spring Boot+Ext JS的準(zhǔn)前后端分離的通用框架,從規(guī)格出發(fā),以模型類為驅(qū)動(dòng),分離前后端開發(fā)、合并部署,實(shí)現(xiàn)系統(tǒng)功能性能的同時(shí)、簡(jiǎn)化開發(fā)的復(fù)雜度和提升開發(fā)效率。
2 Spring Boot與Ext JS介紹
Spring Boot不是全新框架,其是Spring、Spring MVC以及Hibernate等一系列框架的默認(rèn)配置。中小型的企業(yè)級(jí)應(yīng)用系統(tǒng),配置Spring和Spring MVC的配置文件顯得煩瑣,耗費(fèi)時(shí)間且無(wú)必要性,基于Spring Boot可以實(shí)現(xiàn)零配置。Ext JS包含豐富的前端組件,支持基于MVC和MVVM的開發(fā)模式,是一站式Web框架。
2.1Spring Boot
Spring Boot首版于2014年發(fā)布,本文基于Spring 2.1.9版本。Spring Boot遵循約定優(yōu)于配置,自動(dòng)檢測(cè)JDBC、Hiber-nate、JPA等框架并自動(dòng)配置,可以開發(fā)桌面應(yīng)用,也可以開發(fā)Web應(yīng)用,因?yàn)槠鋬?nèi)置Web服務(wù)器,默認(rèn)端口8080,基于IDE開發(fā)可像開發(fā)桌面應(yīng)用一樣的開發(fā)Web應(yīng)用,不需要部署到服務(wù)器。
通過(guò)Spring Initializr,可以很容易初始化Spring Boot項(xiàng)目,在使用Maven管理項(xiàng)目的狀況下,不需要在pom.xml配置依賴的版本,因?yàn)轫?xiàng)目默認(rèn)繼承自spring-boot-starter-parent父項(xiàng)目,該父項(xiàng)目中實(shí)現(xiàn)了默認(rèn)的配置且自動(dòng)管理依賴的版本?;赟pring Boot的Web應(yīng)用至少需要導(dǎo)入以下依賴項(xiàng):
1)spring-boot-starter Spring Boot核心啟動(dòng)器。包括配置、日志等。
2)spring-boot-starter-web:自動(dòng)引入Web模塊。
基于Spring Boot的應(yīng)用中,@SpringBootApplication是項(xiàng)目的核心注解,其是@Configuration、@EnableAutoConfiguration、@ComponentScan的組合注解。默認(rèn)配置可以通過(guò)application。propenies或application.yml文件進(jìn)行配置修改。前后端分離架構(gòu)下,控制器使用@RestController注解,返回JSON格式數(shù)據(jù);使用@Service注解服務(wù)類;使用@PersistenceContext注解實(shí)體管理器進(jìn)行數(shù)據(jù)庫(kù)持久化操作。
2.2Ext JS
Ext JS提供輸入框、工具欄、下拉單輸入框、表單、表格、樹、圖表等前端組件,支持經(jīng)典(Classic)和現(xiàn)代(Modern)兩種樣式。Classic是傳統(tǒng)樣式,適用在桌面端;Modem是新一代的樣式,考慮了移動(dòng)端的顯示。開發(fā)上,Ext JS基于面向?qū)ο蟮睦砟?,支持前端類的層?jí)結(jié)構(gòu),通過(guò)繼承擴(kuò)展前端類,類定義格式如下:
Ext.define('全路徑類名',{
extend:'父全路徑類型',
其他配置
})
在Ext JS框架下,可以像創(chuàng)建Java對(duì)象一樣創(chuàng)建組件對(duì)象。對(duì)象創(chuàng)建的語(yǔ)法如下:
Ext。create('類名',{配置項(xiàng)});
早期Ext JS的開發(fā)通過(guò)導(dǎo)入。js的文件到JSP或html進(jìn)行開發(fā),Sencha CMD工具之后,就可以以一個(gè)前端應(yīng)用為單位進(jìn)行開發(fā)了。創(chuàng)建前端應(yīng)用之后,通過(guò)配置方式進(jìn)行視圖組件注冊(cè)和組裝,數(shù)據(jù)綁定上,可以選擇MVC和MVVM方式。前端的MVC模式,Model模型類似于后端的實(shí)體類,用于定義數(shù)據(jù)的屬性。View是視圖顯示Controller使用Ajax方式調(diào)用后端服務(wù)或是前端的動(dòng)態(tài)效果。VM是ViewModel,直接綁定數(shù)據(jù)和視圖。
類似Spring Boot,Sencha CMD同樣內(nèi)置服務(wù)器,默認(rèn)端口是1841,運(yùn)行sencha app watch既可以在瀏覽器中查看開發(fā)的實(shí)時(shí)效果,避免瀏覽器緩存的問(wèn)題且在Chrome等瀏覽器可以進(jìn)行源調(diào)試。正式環(huán)境部署使用CMD對(duì)源碼編譯、壓縮,使用index。html或index。jsp作為你模板,壓縮后JS源碼在一份文件,前端需要的文件數(shù)量和大小都減少了,加快了網(wǎng)絡(luò)傳輸和頁(yè)面響應(yīng)的速度。
3 平臺(tái)整體設(shè)計(jì)
數(shù)據(jù)對(duì)象及關(guān)系管理是企業(yè)應(yīng)用系統(tǒng)管理的核心,圍繞此衍生文檔、權(quán)限等其他功能模塊。平臺(tái)采用準(zhǔn)前后端分離方式,即:開發(fā)階段,前后端分離開發(fā);集成測(cè)試與部署階段,前端編譯產(chǎn)生JSP文件,通過(guò)JSP Session管理用戶登錄和認(rèn)證信息。
3.1平臺(tái)功能模塊與設(shè)計(jì)
企業(yè)應(yīng)用系統(tǒng)管理企業(yè)運(yùn)營(yíng)中的數(shù)據(jù),按照面向?qū)ο蟮木幊趟枷?,這些數(shù)據(jù)可以歸類為不同的對(duì)象類型,對(duì)這些對(duì)象類型的數(shù)據(jù)進(jìn)行對(duì)象信息、狀態(tài)信息以及關(guān)聯(lián)的管理。以辦公自動(dòng)化系統(tǒng)為例,有請(qǐng)假單、加班單、資源申請(qǐng)單等;以制造企業(yè)的PLM系統(tǒng)為例,有零件、部件、產(chǎn)品等;以ERP為例,有銷售單、入庫(kù)單、出庫(kù)單、薪資單等。不同對(duì)象之間除了其本身的管理之外,還存在與其他對(duì)象的關(guān)聯(lián),比如在PLM系統(tǒng)中,各種零件組裝成部件,最后組裝成產(chǎn)品,零部件關(guān)系構(gòu)成物料清單(BOM)。除數(shù)據(jù)本身及關(guān)聯(lián)的管理外,一個(gè)完備的框架還包括權(quán)限、日志等管理。該平臺(tái)的基礎(chǔ)功能模塊包括:
1)業(yè)務(wù)對(duì)象管理:使用數(shù)據(jù)庫(kù)表和字段存儲(chǔ)業(yè)務(wù)對(duì)象的屬性和內(nèi)容。
2)對(duì)象關(guān)系管理:主要包括關(guān)聯(lián)關(guān)系和組合關(guān)系,通過(guò)屬性或是關(guān)聯(lián)表實(shí)現(xiàn)。
3)文檔管理:文檔包括文件,除文件本身之外,還包括該文件的描述,比如上傳時(shí)間、上傳人、更新時(shí)間以及版本信息等。
4)權(quán)限管理:包括認(rèn)證和授權(quán),認(rèn)證是對(duì)當(dāng)前用戶身份有效性的確認(rèn),授權(quán)則是對(duì)數(shù)據(jù)或動(dòng)作操作權(quán)限的控制。常用的認(rèn)證包括:用戶名/密碼,LDAP認(rèn)證和SSO自動(dòng)登錄等,授權(quán)則可以分為多個(gè)層級(jí)實(shí)現(xiàn)。
3.2平臺(tái)架構(gòu)設(shè)計(jì)
平臺(tái)基于Spring Boot后端框架、使用Ext JS作為前端框架,采用SPA(single page application,單頁(yè)面應(yīng)用程序)的方式。生產(chǎn)環(huán)境中,前后端集成于index.jsp頁(yè)面,使用JSP的Session對(duì)象管理用戶登錄信息。平臺(tái)整體框架如圖1所示。
后端遵循MVC的設(shè)計(jì)典范,對(duì)外提供RESTful的服務(wù)接口,響應(yīng)JSON格式數(shù)據(jù)。前端利用Ext JS規(guī)范的MVC+MVVM的開發(fā)方式,調(diào)用后端服務(wù)呈現(xiàn)頁(yè)面和交互。前后端按照功能模塊拆分目錄,各功能模塊內(nèi)部再按照類的MVC規(guī)劃源碼文件。
3.2.1后端設(shè)計(jì)
后端以業(yè)務(wù)實(shí)體類型為驅(qū)動(dòng)進(jìn)行設(shè)計(jì),源碼對(duì)應(yīng)模型層Model、視圖層View和控制層Controlller,各層保持命名的相關(guān)性,以實(shí)體類Demo為例,定義的源碼類如表1所示。
使用JPA的EntityManager操作數(shù)據(jù),省去DAO層,在控制器中,ModeIAndView類型返回僅用在主頁(yè)登錄或少量特殊需要頁(yè)面跳轉(zhuǎn)場(chǎng)景,控制器類基本使用@RestController注解返回JSON格式數(shù)據(jù)。默認(rèn)對(duì)實(shí)體類型提供增、刪、該、查的服務(wù)(其中查包括根據(jù)主鍵查詢單個(gè)或根據(jù)條件查詢列表),單個(gè)實(shí)體類默認(rèn)包括五個(gè)服務(wù)。服務(wù)地址遵循RESTful風(fēng)格,結(jié)合不同的HTTP請(qǐng)求方法,以實(shí)體類名全小寫后面加s,以Demo類為例,對(duì)應(yīng)服務(wù)地址及HTTP請(qǐng)求方法如表2所示。
3.2.2前端設(shè)計(jì)
前端同樣以實(shí)體類為驅(qū)動(dòng),結(jié)合MVC和MVVM架構(gòu)。前端模型類的屬性盡量保持與后端實(shí)體類一致,可以適量增減。定義實(shí)例類似:
Ext.define('Splm.model.demo.Demo',{
extend:'Ext.data.Model',
fields:[
'obid','name','descrip'
]});
視圖是前端框架中最重要的部分,從Ext JS框架繼承前端組件類,單個(gè)實(shí)體類對(duì)應(yīng)的基本視圖包括:查詢視圖、編輯視圖、查看視圖。
1)查詢視圖:布局分為兩部分,上半部分是過(guò)濾條件篩選,下半部分是查詢的結(jié)果列表。
2)編輯視圖:通用于創(chuàng)建和更新,對(duì)基本信息欄位進(jìn)行編輯。布局上輸入框可以一列,也可以多列,還可以是根據(jù)瀏覽器窗口大小自動(dòng)變化的響應(yīng)式布局。在更新視圖中,使用ViewModel綁定視圖和數(shù)據(jù)。
3)查看視圖,以多標(biāo)簽頁(yè)方式顯示,分為基本信息、關(guān)聯(lián)信息、其他信息(比如更新日志等),使用ViewModel綁定基本信息和部分關(guān)聯(lián)信息。
View Model用于自動(dòng)綁定數(shù)據(jù)和視圖,可以單向或雙向的自動(dòng)綁定,綁定效果數(shù)據(jù)發(fā)生變化自動(dòng)顯示在頁(yè)面中對(duì)應(yīng)的組件或頁(yè)面組件輸入值變化自動(dòng)更新到數(shù)據(jù)。本平臺(tái)將ViewModel使用在基本信息的綁定,適用在更新頁(yè)面和對(duì)象查看頁(yè)面。除此的其他非數(shù)據(jù)綁定的場(chǎng)景,通過(guò)在控制器中使用Ajax調(diào)用服務(wù),獲取返回后實(shí)現(xiàn),比如創(chuàng)建、刪除等功能。
前端類的命名與源碼文件命名保持統(tǒng)一,同樣相關(guān)于實(shí)體類的命名,以Demo為例,類命名對(duì)應(yīng)DemoQuery、DemoEdit和DemoInfo。
3.2.3前后端數(shù)據(jù)格式與整合
JSP頁(yè)面部署在Servlet容器中,根據(jù)客戶端請(qǐng)求,動(dòng)態(tài)生成HTML等響應(yīng)返回。JSP內(nèi)置了REQUEST、SESSION等九種內(nèi)置對(duì)象,瀏覽器端訪問(wèn)JSP頁(yè)面時(shí),會(huì)創(chuàng)建SESSION對(duì)象,并使用唯一ID保存在Servlet容器中,這個(gè)Session的ID會(huì)響應(yīng)到瀏覽器端并且記錄在名字是JSESSIONID的Cookie中。瀏覽器在下次訪問(wèn)該站點(diǎn)服務(wù)時(shí)會(huì)將JSESSIONID附加上,在后端從Re-quest對(duì)象中獲取Session對(duì)象。如果Session對(duì)象超時(shí),會(huì)被清空。但HTML頁(yè)面并不具備Session對(duì)象,在完全的前后端分離框架中,就需要借助Token實(shí)現(xiàn)登錄身份認(rèn)證,或者持久化Ses-sion信息到文件或是數(shù)據(jù)庫(kù),或者使用JWT讓前端處理驗(yàn)證。但不管哪種,都要額外處理。完全的前后端獨(dú)立框架可以實(shí)現(xiàn)分布式架構(gòu),但一般的企業(yè)級(jí)應(yīng)用對(duì)分布式架構(gòu)和橫向擴(kuò)展基本沒(méi)要求,導(dǎo)入獨(dú)立用戶驗(yàn)證處理會(huì)使開發(fā)和架構(gòu)變復(fù)雜。該平臺(tái)保留JSP的Session對(duì)象,使用Ext JS的CMD編譯產(chǎn)生in-dex。jsp,實(shí)現(xiàn)兩者的融合,在每個(gè)控制器觸發(fā)的服務(wù)方法上從Session獲取是否存在登錄用戶信息,驗(yàn)證錯(cuò)誤則返回對(duì)應(yīng)的JSON數(shù)據(jù)交由前端處理。
3.3平臺(tái)復(fù)用設(shè)計(jì)
前后端都可以通過(guò)父類繼承提取共用功能,后端結(jié)合Spring AOP,降低耦和性、增加平臺(tái)的動(dòng)態(tài)擴(kuò)展性,進(jìn)一步提高復(fù)用性。
3.3.1后端復(fù)用設(shè)計(jì)
模型類和服務(wù)類抽象共用屬性和共用方法的父類。業(yè)務(wù)實(shí)體類具備主鍵、創(chuàng)建人、創(chuàng)建時(shí)間、更新人、更新時(shí)間等基本屬性,考慮顯示的通用性定義一個(gè)displayName的動(dòng)態(tài)屬性,該屬性值由該類型的其他屬性組合而來(lái)。公用基本屬性具體如表3所示。
遵循屬性共用原則,模型類結(jié)合屬性及功能所屬,從頂層開始包括:Root(平臺(tái)實(shí)體類根類)、BusItem(業(yè)務(wù)類型的父類)和DataItem(文檔類型的父類)。
3.3.2前端復(fù)用設(shè)計(jì)
前端模型、視圖和控制層都可以定義父類。前端模型父類包含后端基本屬性,考慮查詢頁(yè)面、編輯頁(yè)面和查看頁(yè)面的基本布局的相似性,在父類上設(shè)計(jì)基本的頁(yè)面布局和設(shè)置,類名設(shè)計(jì)為:ItemEdit、ItemInfo、ItemQuery。定義BaseController及其子類ItemController的控制器,BaseController定義基本的方法,比如異常處理、獲取服務(wù)連接,通用Ajax服務(wù)呼叫。ItemCon-troller中定義查詢和創(chuàng)建等功能。而對(duì)于Info頁(yè)面,因?yàn)楦鲗?shí)體類的功能不同,不定義父類。
3.3.3AOP設(shè)計(jì)
系統(tǒng)屬性值的設(shè)置、日志、權(quán)限驗(yàn)證等功能通過(guò)SpringAOP框架動(dòng)態(tài)增加。使用@Aspect定義切面類,在切面類中使用@Pointcut和@Around等注解定義切點(diǎn)和增強(qiáng)。
4 框架實(shí)現(xiàn)與整合部署
使用Maven管理項(xiàng)目,前后端作為項(xiàng)目模塊構(gòu)建父子項(xiàng)目,基于Eclipse等IDE開發(fā)。開發(fā)階段完全前后端分離,集成測(cè)試和部署則合并前后端。
4.1平臺(tái)功能模塊與設(shè)計(jì)
后端項(xiàng)目不繼承spring-boot-starter-parent,需要配置spring-boot-dependencies的依賴管理。父項(xiàng)目創(chuàng)建一個(gè)簡(jiǎn)單項(xiàng)目,打包的類型選擇pom。在此項(xiàng)目下建立前后端的模塊。以項(xiàng)目名是crab為例,其包含crab_front和crab_back兩個(gè)模塊。
4.2前后端分離開發(fā)與數(shù)據(jù)交互
后端以模型類為驅(qū)動(dòng),提供標(biāo)準(zhǔn)RESTful開發(fā),對(duì)服務(wù)層和控制層接口的測(cè)試使用Spring及MVC測(cè)試框架,前端開發(fā)可以在瀏覽器端執(zhí)行或是通過(guò)PostMan等工具進(jìn)行驗(yàn)證。前端與后端開發(fā)同步進(jìn)行,不需要依賴后端服務(wù),定義交互格式文件,該文件既可以作為前后交互的規(guī)范,也可以直接用來(lái)作為前端的開發(fā)臨時(shí)接口服務(wù)。以JSON文件作為數(shù)據(jù)文件格式,提供單個(gè)對(duì)象和對(duì)象類表的數(shù)據(jù)文件,以Demo類為例,查詢和顯示的JSON的文件分別是DemoInfo.json和DemoList.json,內(nèi)容格式如下:
{
"obid":"97d66b3e-338d-40c5-908c-fe33ea0db143",
"sysCreatedDate":"2019/08/18",
"displayName":"Demo 1"
}
{
"total":8,
"datas":[
{
"obid":"97d66b3e-338d-40c5-908c-fe33ea0db143",
"sysCreatedDate":"2019/08/18",
"displayName":"Demo 1"
}
}