天天看點

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

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

  • 官方網站: http://www.jeecg.com
  • 源碼下載下傳: https://github.com/zhangdaiscott/jeecg-boot
  • 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);