有很多讀者都希望我出一些詳細介紹 Java 實戰(zhàn)類項目的文章,畢竟項目實戰(zhàn)經(jīng)驗還是挺重要的,不論是對于找工作還是提高個人工程能力。我自己也發(fā)現(xiàn)很多讀者不怎么會學習開源項目,不知道如何把開源項目的一些精華為自己所用。
我們這里分析的是?eladmin[1]?這個基于 Spring Boot + Spring Security +JPA +Vue 的前后端分離的后臺管理系統(tǒng)。
薦過這個項目。

后臺首頁
開源工具庫
這部分簡單分析一下項目使用到的一些比較有用的開源工具庫:MapStruct(Java 對象映射框架)、OSHI(基于 JNA 的操作系統(tǒng)和硬件信息庫)、Hutool(Java 工具類庫)。
MapStruct
MapStruct[2]?不僅能夠在 bean 之間復制屬性,還能夠在不同類型之間自動轉(zhuǎn)換。

相比于其他常見的映射框架, Dozer、Orika、ModelMapper、JMapper,MapStruct 的性能更好。
OSHI
OSHI[5]?是一款為 Java 語言提供的基于 JNA 的(本機)操作系統(tǒng)和硬件信息庫。
通過 OSHI ,我們不需要安裝任何其他本機庫,就能查看內(nèi)存和 CPU 使用率、磁盤和分區(qū)使用情況、設備、傳感器等信息。
OSHI 旨在提供一種跨平臺的實現(xiàn)來檢索系統(tǒng)信息,支持 Windows、Linux、MacOS、Unix 等主流操作系統(tǒng)。
使用 oshi 你可以輕松制作出項目常用的系統(tǒng)監(jiān)控功能,如下圖所示:

Hutool
Hutool[6]?一個非常實用的 Java 工具類庫,對文件、流、加密解密、轉(zhuǎn)碼、正則、線程、XML 等 JDK 方法進行了封裝。

小技巧
這部分內(nèi)容會簡單分析一下從這個開源項目中看到的一些亮點以及小技巧。
優(yōu)化表命名
根據(jù)項目不同的 Module 作為表名的前綴,這樣看起來更加直觀。

巧用 AOP 簡化代碼
AOP(Aspect-Oriented Programming:面向切面編程)?能夠?qū)⒛切┡c業(yè)務無關,卻為業(yè)務模塊所共同調(diào)用的邏輯或責任(例如事務處理、日志管理、權限控制等)封裝起來,便于減少系統(tǒng)的重復代碼,降低模塊間的耦合度,提高系統(tǒng)可拓展性和可維護性。
這個項目中就大量使用了?AOP?思想。簡單舉兩個例子吧!
日志記錄
利用 AOP 方式記錄日志,只需要在?controller?的方法上使用?@Log("")?注解,就可以將用戶操作記錄到數(shù)據(jù)庫,源碼可查看?eladmin-logging這個 Module。。
@Log("新增用戶")@PostMapping(value?="/users")public?ResponseEntity?create(@Validated@RequestBodyUser?resources){checkLevel(resources);returnnewResponseEntity(userService.create(resources),HttpStatus.CREATED);}
Redis 限流
利用 AOP 方式對接口進行限流,只需要在?controller?的方法上使用@Limit("")?注解即可,源碼可查看?eladmin-common這個 Module。
/**
?*?測試限流注解,下面配置說明該接口?60秒內(nèi)最多只能訪問?10次,保存到redis的鍵名為?limit_test,
?*/@AnonymousGetMapping@ApiOperation("測試")@Limit(key?="test",?period?=60,?count?=10,?name?="testLimit",?prefix?="limit")public?int?test()?{returnATOMIC_INTEGER.incrementAndGet();}
基于 RBAC 的權限模塊設計
系統(tǒng)權限控制采用?RBAC 基于角色的權限訪問控制(Role-Based Access Control)?思想(一種最常見的權限管理思想,在一些對于全權限控制要求比較嚴格的系統(tǒng)會使用到)。
什么是 RBAC 呢?
簡單地說:一個用戶可以擁有若干角色,每一個角色有可以被分配若干權限這樣,就構造成“用戶-角色-權限” 的授權模型。在這種模型中,用戶與角色、角色與權限之間構成了多對多的關系,如下圖

RBAC
在 RBAC 中,權限與角色相關聯(lián),用戶通過成為適當角色的成員而得到這些角色的權限。這就極大地簡化了權限的管理。
本系統(tǒng)的權限設計相關的表如下(一共 5 張表,2 張用戶建立表之間的聯(lián)系):

通過這個權限模型,我們可以創(chuàng)建不同的角色并為不同的角色分配不同的權限范圍(菜單)。

自定義權限驗證方式
Spring Security?提供了Spring EL表達式,允許我們在定義接口的方法上面添加注解來實現(xiàn)權限控制。比如下面的接口表示用戶擁有?admin、menu:edit?權限中的任意一個就能能訪問update接口。

但是,由于每個接口都需要給超級管理員放行,所以單純使用這種注解的方式每次都需要重復的添加 admin 權限、
因此我們可以加入自定義權限驗證方式,在驗證的時候默認給擁有 admin 權限的用戶放行。
源碼:
//?eladmin-common?->?me.zhengjie.config.ElPermissionConfig@Service(value?="el")publicclassElPermissionConfig{publicBooleancheck(String?...permissions){//?獲取當前用戶的所有權限List?elPermissions?=?SecurityUtils.getCurrentUser().getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());//?判斷當前用戶的所有權限是否包含接口上定義的權限r(nóng)eturnelPermissions.contains("admin")?||?Arrays.stream(permissions).anyMatch(elPermissions::contains);????}}
使用方式:
@ApiOperation("查詢?nèi)蝿請?zhí)行日志")@GetMapping(value?="/logs")@PreAuthorize("@el.check('timing:list')")publicResponseEntity?queryJobLog(JobQueryCriteria?criteria,?Pageable?pageable){returnnew?ResponseEntity<>(quartzJobService.queryAllLog(criteria,pageable),?HttpStatus.OK);}
對應的數(shù)據(jù)庫內(nèi)容如下:


審計功能
在這個項目中,繼承了?BaseEntity?的類會自動寫入創(chuàng)建時間、修改時間、創(chuàng)建人、更新人這些數(shù)據(jù)。

簡單介紹一下上面涉及到的一些注解:
@CreationTimestamp?: 創(chuàng)建對象的時候自動生成時間戳。
@UpdateTimestamp:創(chuàng)建對象的時候自動生成時間戳。
@CreatedBy?:表示該字段為創(chuàng)建人,在這個實體被 insert 的時候會設置值,@LastModifiedBy同理。
審計功能對應的配置類:

可優(yōu)化點
可以考慮使用阿里開源的 easyexcel 來做 Excel 的導入導出,避免 OOM。
可以參考?《實際項目中我們是這樣做異常處理的》[7]?對項目全局異常處理部分進行優(yōu)化。
一些重復代碼可以抽取出來,比如eladmin-common?模塊中的?BaseDTO.java和?BaseEntity.java的toString()方法。
項目的 json 解析庫用到了 fastjson。實際上,我更推薦使用 Spring 默認的 JSON 解析庫 Jackson。這兩者中, Fastjson 的代碼質(zhì)量以及設計更差,并且,經(jīng)常被爆出有安全漏洞(設計問題)。雖然 Fastjson 在速度方面稍稍取勝,但是,速度方面的優(yōu)勢不太明顯,影響不大。
可以使用?Caffeine?來做本地緩存。
后記
我發(fā)現(xiàn)很多人對于開源項目的態(tài)度就是:克隆下來就簡單玩玩功能就算了。
我覺得這樣不太好。你把項目克隆下來之后,首先肯定是自己體驗一下系統(tǒng)的核心功能。體驗了核心功能之后,你可以分析分析項目代碼,檢查一下有沒有 bug,看看有沒有可以優(yōu)化的代碼/模塊,思考一下有沒有需要完善的功能模塊......。我在自己分析、調(diào)試這個開源項目的時候,就發(fā)現(xiàn)了一個小 bug 并提交了相應的 issue (目前已經(jīng)被采納)。