代碼倉庫地址https://gitee.com/wukongcrm/7...前端
悟空CRM採用全新的先後端分離模式,本倉庫代碼中已集成前端vue打包後文件,可免去打包操做vue
如需調整前端代碼,請單獨下載前端代碼,前端代碼在根目錄的ux文件夾中java
主要技術棧ios
核心框架:jfinal3.8git
緩存:redis caffeineredis
數據庫鏈接池:Druidsql
工具類:hutool,fastjson,poi-ooxml數據庫
定時任務:jfinal-cronjson
項目構建工具: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>,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版部分功能系統截圖