我對jeecg-boot項目的理解、使用心得和改進建議


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配置表單、編碼表單。同時實現了流程與表單的分離設計(松耦合)、並支持任務節點靈活配置,既保證了公司流程的保密性,又減少了開發人員的工作量。

技術架構:

后端技術: 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);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM