悟空CRM采用全新的前後端分離模式,本倉庫代碼中已內建前端vue打包後檔案,可免去打包操作
如需調整前端代碼,請單獨下載下傳前端代碼,前端代碼在根目錄的ux檔案夾中
主要技術棧
核心架構:jfinal3.8
緩存:redis caffeine
資料庫連接配接池:Druid
工具類:hutool,fastjson,poi-ooxml
定時任務:jfinal-cron
項目建構工具:maven
Web容器:tomcat,undertow(預設)
前端MVVM架構:Vue.JS 2.5.x
路由:Vue-Router 3.x
資料互動:Axios
UI架構:Element-UI 2.6.3
悟空CRM是一個基于jfinal的開源crm系統,采用前後端分離的開發模式,提供了Aop,查詢緩存,資料庫連接配接池,定時器,excel導入導出等功能。
項目中主要有CRM,OA,項目管理,BI等子產品,通過角色,部門,菜單實作了按鈕級的功能權限控制和資料權限控制,通過将使用者登入資訊儲存至redis來實作支援項目的熱重新開機和分布式部署。
項目還擁有如下特性:
項目通過jfinal強大的AOP将權限判斷從代碼中抽離出來,使用者無需手動判斷登陸角色是否擁有權限,以下為通過權限注解在攔截器判斷使用者是否擁有通路權限
@Override
public void intercept(Invocation invocation) {
//TODO 權限功能背景攔截
Permissions permissions=invocation.getMethod().getAnnotation(Permissions.class);
if(permissions!=null&&permissions.value().length>0){
JSONObject jsonObject= Aop.get(AdminRoleService.class).auth(BaseUtil.getUserId());
//組裝應有權限清單
List<String> arr=queryAuth(jsonObject, "");
boolean isRelease=false;
for (String key : permissions.value()) {
if(!isRelease){
if(arr.contains(key)){
isRelease=true;
}
}
}
if(!isRelease){
invocation.getController().renderJson(R.error("無權通路"));
return;
}
}
invocation.invoke();
}
通過AOP和注解對資料進行非空校驗,無需一個個判斷參數是否為空,資料為空直接傳回
自定義分頁資料接收,自動處理分頁參數和資料對象,給controller方法加上參數
BasePageRequest,T為對象類型,然後參數就會自動組裝成分頁參數和定義的對象類,以下為實作代碼:
public class PageParaGetter extends ParaGetter<BasePageRequest> {
public PageParaGetter(String parameterName, String defaultValue) {
super(parameterName, defaultValue);
}
@Override
protected BasePageRequest to(String s) {
return null;
}
@Override
@SuppressWarnings("unchecked")
public BasePageRequest get(Action action, Controller controller) {
Parameter[] parameters=action.getMethod().getParameters();
Class clazz=null;
for (Parameter parameter:parameters){
if(BasePageRequest.class.isAssignableFrom(parameter.getType())){
Type parameterizedType=parameter.getParameterizedType();
if (parameterizedType instanceof ParameterizedType) {
Type[] params = ((ParameterizedType) parameterizedType).getActualTypeArguments();
clazz= TypeUtils.getClass(params[0]);
}
break;
}
}
boolean isJson=controller.getHeader("Content-Type")!=null&&controller.getHeader("Content-Type").toLowerCase().contains("application/json");
return isJson?new BasePageRequest(controller.getRawData(),clazz):new BasePageRequest(controller.getKv(),clazz);
}
}
自定義json工廠,實作對資料的個性化解析傳回,如實作将資料傳回時将資料轉成駝峰規則,自定義某種類型的對象的傳回格式等。
可以自定義錯誤處理模闆,在出現錯誤或者其他異常的情況下,可以給予使用者一個清晰的提示,避免使用者看到一些無用的錯誤資訊等功能
檔案可以上傳到項目目錄之外,避免了重新打包項目後檔案的丢失
@Override
public void configConstant(Constants me) {
me.setDevMode(prop.getBoolean("jfinal.devMode", true));
me.setInjectDependency(true);
//設定上傳檔案到哪個目錄
me.setBaseUploadPath(BaseConstant.UPLOAD_PATH);
me.setBaseDownloadPath(BaseConstant.UPLOAD_PATH);
//自定義json工廠
me.setJsonFactory(new ErpJsonFactory());
//限制上傳100M
me.setMaxPostSize(104857600);
}
采用項目分層化的設計,職責分工明确,降低代碼的耦合性Hander->對指定規則的url進行捕獲或者放心Interceptor->環繞式AOP攔截,對通路權限,資料權限,參數等進行校驗,可以配置在全局,單個路由,單個controller,單個方法等上面,可進行自定義實作,對資料進行處理
Router->對不同規則的資料進行分發,不同url進入不同路由和controller
Controller->對參數進行組裝,将資料傳入到service處理後進行render傳回
Service->對業務代碼進行處理,并将資料轉入Db處理或緩存
Db->對資料庫進行操作
Render->将service傳回的資料在controller進行傳回,以及出錯後通過
SQL模闆功能,将sql寫入到xx.sql檔案中,如果sql檔案有變動,無需重新編譯打包,直接改動sql檔案中的sql即可,以下為自動掃描指定路徑下sql檔案的代碼:
private void getSqlTemplate(String path, ActiveRecordPlugin arp) {
File file = new File(path);
if (file.exists()) {
File[] files = file.listFiles();
if (files != null && files.length > 0) {
for (File childFile : files) {
if (childFile.isDirectory()) {
getSqlTemplate(childFile.getAbsolutePath(), arp);
} else {
if (childFile.getName().toLowerCase().endsWith(".sql")) {
arp.addSqlTemplate(childFile.getAbsolutePath().replace(PathKit.getRootClassPath(), "").replace("\\", "/"));
}
}
}
}
}
}
以下是系統的部分截圖:
以下為悟空CRM9.0 JAVA版部分功能系統截圖
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnL4UTNzgTM0ETNwkTMwIzX2QTMxATMvwFMvwVZyFGaz9CXn1WavwFZh9GbwV3Lc12bj5Cbh5Wamp2Lc9CX6MHc0RHaiojIsJye.png)