jeecg-boot是什么?
官方介紹
JeecgBoot 是一款基於代碼生成器的低代碼開發平台,零代碼開發!采用前后端分離架構:SpringBoot2.x,Ant Design&Vue,Mybatis-plus,Shiro,JWT。強大的代碼生成器讓前后端代碼一鍵生成,無需寫任何代碼! JeecgBoot引領新的開發模式(Online Coding模式-> 代碼生成器模式-> 手工MERGE智能開發), 幫助解決Java項目70%的重復工作,讓開發更多關注業務邏輯。既能快速提高開發效率,幫助公司節省成本,同時又不失靈活性!JeecgBoot還獨創在線開發模式(No代碼概念):在線表單配置(表單設計器)、移動配置能力、工作流配置(在線設計流程)、報表配置能力、在線圖表配置、插件能力(可插拔)等等!
JeecgBoot在提高UI能力的同時,降低了前后分離的開發成本,JeecgBoot還獨創在線開發模式(No代碼概念),一系列在線智能開發:在線配置表單、在線配置報表、在線圖表設計、在線設計流程等等。
JEECG宗旨是:簡單功能由Online Coding配置實現(在線配置表單、在線配置報表、在線圖表設計、在線設計流程、在線設計表單),復雜功能由代碼生成器生成進行手工Merge,既保證了智能又兼顧了靈活;
業務流程采用工作流來實現、擴展出任務接口,供開發編寫業務邏輯,表單提供多種解決方案: 表單設計器、online配置表單、編碼表單。同時實現了流程與表單的分離設計(松耦合)、並支持任務節點靈活配置,既保證了公司流程的保密性,又減少了開發人員的工作量。
- QQ交流群:②769925425、①284271917、③816531124
- 在線演示: http://boot.jeecg.com
- 版本日志: http://www.jeecg.com/doc/log
- 新手指南: 快速入門 | 常見問題| 視頻教程 | 反饋問題
技術架構:
后端技術: SpringBoot_2.1.3.RELEASE + Mybatis-plus_3.1.2 + Shiro_1.4.0 + Jwt_3.7.0 + Swagger-ui + Redis 前端技術: Ant-design-vue + Vue + Webpack 其他技術: Druid(數據庫連接池)、Logback(日志工具) 、poi(Excel工具)、 Quartz(定時任務)、lombok(簡化代碼) 項目構建: Maven、Jdk8
前端開發必讀文檔:
前端UI組件: Ant Design of Vue
https://www.antdv.com/docs/vue/introduce
報表UI組件:viser-vue
https://viserjs.gitee.io/demo.html#/viser/bar/basic-bar
VUE基礎知識:
https://cn.vuejs.org/v2/guide
Ant Design Vue Pro:
https://pro.loacg.com/docs/getting-started
為什么要用jeecg-boot?
作為一個后端開發人員,每次在為一家新的公司開發系統的時候,都在想盡快給公司開發出來一套簡單,美觀,好用的后台管理系統,讓后進的開發者注重專注業務,降低技術難度,從而節省人力成本,縮短項目周期,提高軟件安全質量。
既然是想盡快搞出來一套完美的系統,如果靠重新開發,耗費的精力是非常多的。
因此重新開發這條路是行不通的。
所以去開源項目尋找一套現成的系統是一種不錯的捷徑。人生有時候是需要靠捷徑的,站在前人的肩膀之上來成就自己。我們可以少走更多彎路。路走直了,通往勝利的燈塔還遠嗎?
在開源社區里面,這樣的系統是非常多的。怎么樣才茫茫項目之中,挑選出來一套適合自己的項目呢?
其實每個公司選擇項目的標准基本都是統一的
1:開源
2:最新技術棧(前后端分離+微服務)
3:ui美觀
4:功能完善
5:簡單上手
6:易於二次開發
看了很多優秀的開源項目,最終選擇了jeectboot這套低代碼快速開發平台。
選擇它的理由,當然最基本的是必須滿足以上6點。
除此之外還有
7:簡化第三方登錄和單點登錄
8:簡化導出導出功能
9:簡化文件上傳功能
10:后端代碼生成
11:前端表單生成
改進建議
項目
1:將單體版和微服務版分離開。不要放在同一項目中,不要通過修改代碼的方式實現單體和微服務切換
開發文檔
2:開發文檔分離。將單體版和微服務版開發文檔單獨分開
配置
3:去掉本地host配置
命名規范
4:類名【JeecgFeignService】應以Impl結尾。
對於Service和DAO類,基於SOA的理念,暴露出來的服務一定是接口,內部的實現類用Impl的后綴與接口區別
5:DySmsHelper類中的常量【product】【domain】命名應該全部大寫並以下划線分隔
常量命名應該全部大寫,單詞間用下划線隔開,力求語義表達完整清楚,不要嫌名字長
6:FreemarkerParseFactory類中的常量【_tplConfig】【_sqlConfig】【p】命名應該全部大寫並以下划線分隔
7:JacksonUtil類中的常量【objectMapper】命名應該全部大寫並以下划線分隔
8:MD5Util類中的常量【hexDigits】命名應該全部大寫並以下划線分隔
9:MybatisPlusConfig類中的常量【tenant_field】【tenantTable】命名應該全部大寫並以下划線分隔
10:PasswordUtil類中的常量【Salt】命名應該全部大寫並以下划線分隔
11:RandImageUtil類中的常量【key】【width】【height】【count】【lineWidth】命名應該全部大寫並以下划線分隔
12:SqlInjectionUtil類中的常量【xssStr】命名應該全部大寫並以下划線分隔
13:YouBianCodeUtil類中的常量【zhanweiLength】命名應該全部大寫並以下划線分隔
14:枚舉【BrowserType】【DySmsEnum】【ExecutorRouteStrategyEnum】【QueryRuleEnum】
【QueryRuleEnum】【TriggerTypeEnum】【UrlMatchEnum】的字段缺少注釋信息
15:類DateUtils中的【_date】命名不能以_開頭
所有編程相關的命名均不能以_或者$開始
16:抽象類【ExecutorRouter】命名應以Abstract或者Base開頭
17:類AutoPoiDictConfig中的變量名【commonAPI】不符合lowerCamelCase命名風格
方法名,參數名,成員變量,局部變量都統一使用lowerCamelCase,必須遵從駝峰形式
18:類BaseAspect方法名【getValueBySpEL】不符合lowerCamelCase命名風格
19:類BaseCommonService變量名【LogContent】不符合lowerCamelCase命名風格
20:類CommonController變量名【sysBaseAPI】【httpURL】和方法名【transitRESTful】不符合lowerCamelCase命名風格
21:類CookieUtil變量名【arr_cookie】不符合lowerCamelCase命名風格
22:類CronExpression變量名【dayOfWSpec】不符合lowerCamelCase命名風格
23:類DataSourceCachePool變量名【commonAPI】不符合lowerCamelCase命名風格
24:類DepartIdModel方法名【getSerialVersionUID】不符合lowerCamelCase命名風格
25:類DistributedLockHandler變量名【valueBySpEL】不符合lowerCamelCase命名風格
26:類DlMockController變量名【tug_status】【dataDB】不符合lowerCamelCase命名風格
27:類EmailSendMsgHandle方法名【SendMsg】變量名【es_receiver】【es_title】【es_content】不符合lowerCamelCase命名風格
28:類ExecutorRouteBusyover變量名【idleBeatResultSB】不符合lowerCamelCase命名風格
29:類ExecutorRouteFailover變量名【beatResultSB】不符合lowerCamelCase命名風格
30:接口ISendMsgHandle方法名【SendMsg】和變量名【es_receiver】【es_title】【es_content】不符合lowerCamelCase命名風格
31:接口ISysBaseAPI方法名【queryAllDSysCategory】不符合lowerCamelCase命名風格
32:類JeecgDataAutorUtils方法名【loadDataSearchConditonSQLString】不符合lowerCamelCase命名風格
33:類JimuReportTokenService變量名【sysBaseAPI】不符合lowerCamelCase命名風格
34:類JobGroupController變量名【list_count】【jobGroupList_all】不符合lowerCamelCase命名風格
35:類JobLogController變量名【jobGroupList_all】【list_count】不符合lowerCamelCase命名風格
36:類JobTriggerPoolHelper變量名【triggerPool_】【minTim_now】不符合lowerCamelCase命名風格
37:類JwtFilter變量名【tenant_id】不符合lowerCamelCase命名風格
38:類LoginController變量名【sysBaseAPI】不符合lowerCamelCase命名風格
39:類MD5Util方法名【MD5Encode】不符合lowerCamelCase命名風格
40:類MinioUtil變量名【file_url】方法名【getObjectURL】不符合lowerCamelCase命名風格
41:類MockController方法名【permission_no_page】不符合lowerCamelCase命名風格
42:類MybatisInterceptor變量名【local_createBy】【local_createDate】【local_sysOrgCode】不符合lowerCamelCase命名風格
43:類MybatisPlusConfig變量名【tenant_id】【sql_lowercase】不符合lowerCamelCase命名風格
44:類PasswordUtil方法名【getPBEKey】不符合lowerCamelCase命名風格
45:類PermissionDataAspect變量名commonAPI不符合lowerCamelCase命名風格
46:類Result方法名【OK】不符合lowerCamelCase命名風格
47:類ShiroRealm變量名【commonAPI】不符合lowerCamelCase命名風格
48:類SmsSendMsgHandle方法名【SendMsg】變量名【es_receiver】【es_title】【es_content】不符合lowerCamelCase命名風格
49:類SysAnnouncementController變量名【sysBaseAPI】【tokenOK】不符合lowerCamelCase命名風格
50:類SysDepartPermissionController變量名【SysDepartRolePermission】不符合lowerCamelCase命名風格
51:類SysDepartTreeModel方法名【getSerialVersionUID】不符合lowerCamelCase命名風格
52:類SysLogServiceImpl變量名【sysBaseAPI】不符合lowerCamelCase命名風格
53:類SysMessageTemplateController變量名【is_sendSuccess】不符合lowerCamelCase命名風格
54:類SystemAPIController變量名【sysBaseAPI】和方法名【queryAllDSysCategory】不符合lowerCamelCase命名風格
55:類SysUploadController變量名【file_url】不符合lowerCamelCase命名風格
56:類SysUserDepartServiceImpl變量名【queryUDep】不符合lowerCamelCase命名風格
57:類ThirdAppController變量名【msg_task_id】不符合lowerCamelCase命名風格
58:類ThirdAppTypeConfig變量名【WECHAT_ENTERPRISE】【DINGTALK】不符合lowerCamelCase命名風格
59:枚舉UrlMatchEnum變量名【match_url】不符合lowerCamelCase命名風格
60:類UserController變量名【list_count】不符合lowerCamelCase命名風格
61:類UUIDGenerator方法名【getJVM】和【getIP】不符合lowerCamelCase命名風格
62:類VxeMockController變量名【tug_status】和【dataDB】不符合lowerCamelCase命名風格
63:類WxSendMsgHandle方法名【SendMsg】和變量名【es_receiver】【es_title】【es_content】不符合lowerCamelCase命名風格
64:類XxlJobExecutor變量名【ip_port_address】不符合lowerCamelCase命名風格
65:類XxlJobTrigger變量名【runResultSB】不符合lowerCamelCase命名風格
線程池
66:JobFailMonitorHelper,JobLosedMonitorHelper,JobRegistryMonitorHelper不要顯示創建顯示創建線程,請使用線程池。
線程資源必須通過線程池提供,不允許在應用中自行顯示創建線程。
魔法值
67:不允許任何魔法值(即未經定義的常量)直接出現在代碼中
比如AdminBizImpl中的魔法值【15000】
AutoLogAspect中的魔法值【"list"】魔法值【"add"】【"edit"】【"delete"】【"import"】【"export"】【"POST"】【"PUT"】【"PATCH"】【"500"】等
事務
68:事務場景中,拋出異常被catch后,如果需要回滾,一定要手動回滾事務。
1:JeecgDemoServiceImpl方法【testTran】需要在Transactional注解指定rollbackFor或者在方法中顯示的rollback
2:JeecgOrderMainServiceImpl方法【saveMain】【updateMain】【updateCopyMain】【delMain】【delbatchMain】需要在Transactional注解指定rollbackFor或者在方法中顯示的rollback
3:SysAnnouncementServiceImpl方法【saveAnnouncement】【upDateAnnouncement】需要在Transactional注解指定rollbackFor或者在方法中顯示的rollback
4:SysPermissionDataRuleImpl方法【savePermissionDataRule】【deletePermissionDataRule】需要在Transactional注解指定rollbackFor或者在方法中顯示的rollback
5:SysPermissionServiceImpl方法【deletePermission】需要在Transactional注解指定rollbackFor或者在方法中顯示的rollback
6:SysUserServiceImpl方法【addUserWithRole】【editUserWithRole】【addUserWithDepart】需要在Transactional注解指定rollbackFor或者在方法中顯示的rollback
單個方法總行數
單個方法的總行數不超過80行。
1:類JobLogReportHelper中的方法【start】的總行數不要超過80行
2:類JobScheduleHelper中的方法【start】的總行數不要超過80行
3:類MybatisInterceptor中的方法【intercept】的總行數不要超過80行
4:類VxeMockController中的方法【getMockDdjhData】的總行數不要超過80行
垃圾代碼
及時清理不再使用的代碼片段或配置信息,對於垃圾代碼或者過時的配置,堅決清理干凈,避免程序過度臃腫,代碼冗余。
比如:DynamicRouteLoader類中的這些被注釋掉的代碼
// private void loadRoutesByDataBase() { // List<GatewayRouteVo> routeList = jdbcTemplate.query(SELECT_ROUTES, new RowMapper<GatewayRouteVo>() { // @Override // public GatewayRouteVo mapRow(ResultSet rs, int i) throws SQLException { // GatewayRouteVo result = new GatewayRouteVo(); // result.setId(rs.getString("id")); // result.setName(rs.getString("name")); // result.setUri(rs.getString("uri")); // result.setStatus(rs.getInt("status")); // result.setRetryable(rs.getInt("retryable")); // result.setPredicates(rs.getString("predicates")); // result.setStripPrefix(rs.getInt("strip_prefix")); // result.setPersist(rs.getInt("persist")); // return result; // } // }); // if (ObjectUtil.isNotEmpty(routeList)) { // // 加載路由 // routeList.forEach(route -> { // RouteDefinition definition = new RouteDefinition(); // List<PredicateDefinition> predicatesList = Lists.newArrayList(); // List<FilterDefinition> filtersList = Lists.newArrayList(); // definition.setId(route.getId()); // String predicates = route.getPredicates(); // String filters = route.getFilters(); // if (StringUtils.isNotEmpty(predicates)) { // predicatesList = JSON.parseArray(predicates, PredicateDefinition.class); // definition.setPredicates(predicatesList); // } // if (StringUtils.isNotEmpty(filters)) { // filtersList = JSON.parseArray(filters, FilterDefinition.class); // definition.setFilters(filtersList); // } // URI uri = UriComponentsBuilder.fromUriString(route.getUri()).build().toUri(); // definition.setUri(uri); // this.repository.save(Mono.just(definition)).subscribe(); // }); // log.info("加載路由:{}==============", routeList.size()); // Mono.empty(); // } // }
被//注釋的代碼項目中有很多處,此處不再一一列出。
注釋規范
1:所有的抽象方法(包括接口中的方法)必須使用javadoc注釋,除了返回值,參數,異常說明外,還必須指出該方法做什么事情,實現什么功能。
2:所有的類都必須添加創作者信息
3:方法內部單行注釋,在被注釋語句上方另起一行,使用//注釋。方法內部多行注釋使用/**/注釋。注意與代碼對齊
代碼可讀性
除常用方法(如getXxx/isXxx)等外,不要再條件判斷中執行復雜的語句,將復雜邏輯判斷的結果賦值給一個有意義的布爾變量,以提高可讀性
比如:NgAlainServiceImpl中的以下代碼
if(permission.getUrl()!=null&&(permission.getUrl().startsWith("http://")||permission.getUrl().startsWith("https://"))) { String url= new String(Base64.getUrlEncoder().encode(permission.getUrl().getBytes())); json.put("path", "/sys/link/" +url.replaceAll("=","")); }else { json.put("path", permission.getUrl()); }
和
if(permission.getUrl()!=null&&(permission.getUrl().startsWith("http://")||permission.getUrl().startsWith("https://"))) { meta.put("url", permission.getUrl()); }
SysCategoryServiceImpl中的如下代碼片段
if((dataList == null || dataList.size()==0) && !Arrays.asList(idArr).contains(metaPid) && !sb.toString().contains(metaPid)){ //如果當前節點原本有子節點 現在木有了,更新狀態 sb.append(metaPid).append(","); }
SysPermissionController中的如下代碼片段
if (url != null && (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("{{"))) { return true; }
SysPermissionDataRuleImpl中的如下代碼片段
if(permission!=null && (permission.getRuleFlag()==null || permission.getRuleFlag().equals(CommonConstant.RULE_FLAG_0))) { permission.setRuleFlag(CommonConstant.RULE_FLAG_1); sysPermissionMapper.updateById(permission); }
SysPermissionServiceImpl中的如下代碼片段
if((oConvertUtils.isNotEmpty(pid) && !pid.equals(p.getParentId())) || oConvertUtils.isEmpty(pid)&&oConvertUtils.isNotEmpty(p.getParentId())) { }
XxlJobServiceImpl類中的如下代碼片段
if (GlueTypeEnum.BEAN==GlueTypeEnum.match(jobInfo.getGlueType()) && (jobInfo.getExecutorHandler()==null || jobInfo.getExecutorHandler().trim().length()==0) ) { return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+"JobHandler") ); }
集合初始化大小
集合初始化時,指定集合初始化值大小
HashMap使用如下構造方法進行初始化,如果暫時無法確定集合大小,那么指定默認值(16)即可
比如項目中多處用到
Map<String,Object> map = new HashMap<>();
建議更改為
Map<String,Object> map = new HashMap<>(16);