fhs-framwork是一個集成了國內外諸多優秀開源項目的快速開發平臺,除了在常規快速開發平臺提供 用戶,角色,權限,菜單,字典,操作日志,代碼生成器 等功能的基礎上,還在以下方面為您的快速開發做出了努力。
1. 項目基礎框架搭建期
導入一份sql,copy一個pom稍作修改,copy3個配置文件稍作修改,copy一個springboot啟動類稍作修改即可完成框架搭建。
2. DB接入方面
- 減少手寫sql
fhs 使用了Mybatis Jpa+Mybatis Plus 框架來幫大家自動生成常見sql,Mybatis Jpa是fhs-opensource下的一款基于Mybatis的JPA的實現,為了補足復雜sql的生成,Mybatis Jpa 又對Mybatis Plus做了兼容,可以使用Mybatis Plus的注解來實現sql自動生成,有了Mybatis Jpa+Mybatis Plus 實現80%的單表查詢無需寫一行sql的效果
- 數據源路由
通過簡單的配置即可實現分庫,分表,讀寫分離操作。
- 聲明式事物
add,update,del,save 開頭的service方法,會默認開啟事物,自定義部分請使用注解。
- 數據權限控制
通過簡單的配置即可實現組合或者單一數據權限控制
3. 日常業務方面
- 大量的base類使用
通過繼承即可完成大部分CRUD操作。
- 提供常見的工具類
日期,日志,反射,網絡,校驗,文件等等。
- 其他
統一驗證框架處理器,統一異常處理器,控制器返回數據json字段過濾器,xss,csrf攔截器等等
4. 前端封裝
- 給Easyui,Jquery Validform,My97做了整容手術
Easyui是一款顏值稍低但是功能強大上手容易開發效率極高的UI框架,為了讓其能不被大家拋棄,繼續讓他發光發熱,我們為其定制了一套BootStrap皮膚,效果堪比Layui。
- 使用Beetl標簽技術對常見的表單控件做了封裝
后臺程序員有句俗話叫做后端10分鐘,前端2小時。前端是很多人不愿意碰觸的,于是有了很多公司一個項目要招聘2波人,后端專門寫后端,前端專門寫前段,但是明明一個人就能搞定的事情,非得要2個人?使用fhs的標簽,所有的控件做到了統一化,不需要自己寫js去初始化,去做校驗,去賦值,只要使用了標簽,標簽中初始化,布局html,賦值,獲取值,校驗的js就都包含了,很大程度上降低了前端的學習和使用成本。
- 一款幫你寫代碼的引擎-PAGEX
使用市面上的代碼生成器,你做一個CRUD的需要多久呢?如果加上Excel導出,校驗,列點擊排序這些功能呢?如果要加數據權限,分庫,支持多租戶呢?要寫多少后臺代碼,寫多少sql,寫多少js和html?使用pagex,你只需要定義一個JS,你需要的java類框架在運行期(非生成到硬盤上噢)直接給你編譯為class扔到classLoader了,Html JS SQL 后臺接口 按照指定的路徑請求引擎也幫你自動生成,而你無需擔心JS被暴露,因為JS僅僅被PAGEX引擎加載當做配置文件用的,既然是配置文件為何選擇JS呢?第一:JAVA有JS引擎,可以執行JS代碼;第二:JS中有JSON格式,做配置比XML和YML方便,比Properties強大;第三:很多CRUD我們需要自己寫一些JS方法,來控制一些插件的隱藏顯示以及一些前端業務,把他們寫到JS文件中總比寫到XML中強很多倍吧。
PAGEX可以通過簡單的配置自動生成CRUD代碼,可實現導入,字段排序,數據權限,租戶權限,字典翻譯,表關聯,各類表單插件一行json配置等功能,更讓人驚喜的是,pagex的js可以通過Idea 的EasyCode插件自動生成,然后稍作改動就可以使用了。
下面是使用PAGEX引擎的一個我們項目中月租戶類型管理的demo
var modelConfig={title:'月租戶類型',pkey:'id',type:'uuid',orderBy:'update_time Desc', namespace:"parking_lease_type",table:'t_park_lease_type',trans:true,db:"park"}; var listPage={ listFieldSett:function(){ return [ {name:'lease_name',title:'類型名稱',width:'20%',align:'center'}, {name:'park_id',title:'停車場名稱',width:'20%',isJoin:true,namespace:'parking',showField:'transMap.parkName',align:'center'},//自動表關聯 {name:'is_disable',title:'是否禁用',width:'10%',formart:'formatRowColor',align:'center',trans:'book',key:'is_disable',showField:'transMap.is_disableName'},//字典翻譯 {name:'create_user',title:'創建人',width:'8%',align:'center',trans:'user',showField:'transMap.create_userUserName'},//用戶翻譯 {name:'create_time',title:'創建時間',width:'10%',align:'center'}, {name:'update_user',title:'更新人',width:'8%',align:'center',trans:'user',showField:'transMap.create_userUserName'}, {name:'update_time',title:'更新時間',width:'10%',align:'center'}, {name:'is_sync',title:'是否已下發',width:'5%',align:'center',trans:'book',key:'yesOrNo',showField:'transMap.is_syncName'},//字典翻譯 ]}, isColumnButton:function(){ return false; }, filters:function(){ return [ {name:'park_id',type:'select',url:'${path.basePath}/ms/x/parking/findListData', valuefield:'id',textfield:'parkName',title:'停車場'},//下拉插件 {name:'lease_name',type:'input',title:'出入口名稱',filterType:'like'}, ]; }, buttons:function(){ return [ //自定義按鈕數組 ]; }, disableButtons:function(){ return [];//禁用掉默認提供的按鈕 默認提供了增刪改查 + 導出 }, otherFunctions:function(){ return {}//其他的自定義方法 } }; var add={ formFields:function(){//表單內容 return [ {name:'park_id',type:'select',url:'${path.basePath}/ms/x/parking/findListData', valuefield:'id',textfield:'parkName',title:'停車場',required:true,},//一個下拉 {name:'lease_name',title:'名稱',required:true,type:'input'},//一個input {name:'is_disable',title:'是否禁用',type:'switch',dft:false},//一個開關滑塊 {name:'is_sync',title:'是否下發',type:'hide'},//一個隱藏域 ]; }, otherFunctions:function(){ return { ready:function(){ }, loadSuccess:function(info){//加載后臺數據成功的事件 }, onSave:function(){//保存前執行方法 $('#isSync').val(0); }, saveSucess:function(){//保存成功執行方法 }, saveError:function(){//保存失敗執行的方法 }, } } }
5. 翻譯服務
翻譯服務用于根據表中存放的id來翻譯出對應的文字給做客戶做顯示使用,系統默認實現對省市區,后臺用戶,部門,字典的翻譯支持,您通過簡單的幾行js配置即可把自己的表維護的翻譯服務中,翻譯服務使用進程緩存,當數據有更新的時候會自動重新加載(支持分布式),有著很高的效率,可減少表關聯sql的書寫。
自定義表加入到翻譯服務demo(使用pagex方法):
var modelConfig={title:'停車場',pkey:'id',type:'uuid',orderBy:'update_time Desc', namespace:"parking",table:'t_park_parking',trans:true,extendsParam:'parent_park_id=${param.parent_park_id}', joinColumns:JSON.stringify({park_name:'parkName'}),db:"park",dp:JSON.stringify({id:'parkIds'}),isMultiTenant:true};
使用:
{name:'park_id',title:'停車場名稱',width:'20%',trans:'pagex',key:'parking',showField:'transMap.parkName',align:'center'},//自動表關聯
或者在java代碼中使用
@Trans(type="pagex",key="parking") private String parkId;
6. c端支持
支持微信,支付寶 用戶自動登陸接入。
7.支持分布式和單機部署模式
項目集成了分布式模式和單機模式2種模式,分布式模式依賴比較多,需要安裝apollo(分布式配置中心),CAS,redis,啟動文件服務jar包,靜態文件jar包,eureka jar包。 單機模式,可以把文件服務的依賴,靜態文件的依賴,都添加到自己項目的依賴中,可以不依賴apollo,使用本地配置文件啟動。。
技術棧
導入導出實在多例子,很多成熟的組建都分裝了導入和導出,這一節演示利用LinqToExcel組件對Excel的導入,這個是一個極其簡單的例子。
我并不是說導入的簡單。而是LinqToExcel讓我們對Excel操作更加簡單!
最后我們將利用ClosedXML輸出Excel。這個比現流行NPOI與EPPlus更加優秀的組件,以Open XML SDK為基礎,所以只支持xlsx,不支持xls格式(現階段誰沒有個office2007以上版本)
他導出的Excel根據官方描述,兼容性遠超同行對手
如果你不是使用本架構只看2,3,4點,使用BLL層的代碼,這同樣適用你的MVC程序
LinqToExcel組件讀取Excel文件
ClosedXML組件輸出Excel
一張演示的數據庫表
安裝LinqToExcel NuGet包
文件上傳樣例
CloseXML導出Excel
1.數據表
如何使用這個框架?
按照之前的做法,更新到EF。并利用T4生成DAL,BLL,MODEL。再用代碼生成器生成界面復制進解決方案,一步到位
配置好訪問地址和權限,直接運行
再手動在工具欄添加導入和導出的按鈕(別忘記添加權限)
因為我們讀取Excel放在BLL層,所有在BLL層安裝LinqToExcel包
(這一點簡單帶過,可以到網上下載上傳代碼植入到自己系統中)
或者下載第32節的源碼 或者下載本節的示例代碼都可以
我這里使用普通的form上傳功能
添加導入前端代碼
導入按鈕事件只要彈出上傳框就好
保證上傳是成功的。
直接查看源碼的C#上傳代碼
-------------------------------------------------------------------------------------------------------上面只是前期的準備工作--------------------------------------------------------------
在業務層添加以下代碼
代碼包含兩個方法
public bool CheckImportData( string fileName, List<Spl_PersonModel> personList,ValidationErrors errors )
fileName為我們上傳的文件。
personList為承接數據List
ValidationErrors 錯誤集合
public void SaveImportData(IEnumerable<Spl_PersonModel> personList)
保存數據
別忘記添加接口
簡單明白,直接看代碼,不再解析。OK這樣控制器就可以直接調用了
最后前端還需要把路徑給回來。
OK測試一下!建立一個新的excel格式
一般情況下我們是提供模版給用戶下載供用戶輸入數據,來確保格式的正確性
--------------------------------------------------------------------------------------導出功能------------------------------------------------------------------------------
在控制器添加以下代碼:
注意:ExportExcelResult
此類是使用ClosedXML.Excel,已經封裝好了。大家直接拿來用就可以。把關注點都放在業務中
本節知識點,全部聚集在CheckImportData方法上。
對應列頭是模版xlsx的列頭
1.如果模版需要是是中文的,如Name=名字,那么方法應該這么寫
excelFile.AddMapping<Spl_PersonModel>(x=> x.Name, "名字");
2.導入第幾個sheet工作薄可以這么寫
我這里寫0是指第一個sheet工作薄。可以直接指定工作薄
var excelContent=excelFile.Worksheet<Spl_PersonModel>("Sheet1");
3.檢查正確性可以確保數據的來源。可以給出用戶正確的修改提示。
4.借助ClosedXML,導出實際只需要幾行代碼。哈哈..這是如此的簡單。
作者:YmNets
出處:http://ymnets.cnblogs.com/