工欲善其事,必先利其器。
一年前,我接到为团队落地一个快速开发脚手架
的任务。javascript
在月底这节骨眼上,时间紧,任务急,有想本身撸一个脚手架的人都赶忙把这想法收起来吧!这劳民又伤身的事咱确定是不能干的!前端
因而,我将目光放在了 Gitee Star
比较靠前的开源项目上,这是当时调研的数据 Java Web 开发脚手架调研。vue
其中MCMS、lenosp、bootdo等项目,咱们甚至已经有过项目落地经验,但最终咱们仍是选择了jeecg-boot,选择它的理由咱们有这几点:java
[x] 先后分离架构webpack
[x] 热门技术栈git
Spring Boot + Mybatis Plus
,能更专一理解需求与业务逻辑Vue + Ant Design Vue
,既能快速开发业务,还有时间对页面性能优化作研究Ant Design
组件库设计资源,统一了设计风格[x] 基于角色的访问控制体系github
[x] 完善的开发文档web
[x] 活跃的社区生态redis
1300+
20000+
正是基于这些点,咱们选择相信 jeecg-boot!<img src="https://img-blog.csdnimg.cn/20200827115123583.png" width="100px"/>spring
通过一年多,咱们见证了 jeecg-boot 在 github 从 star 2000+
到如今的 star 14.7k
,
而咱们团队也已经有 5 个服务是基于 jeecg-boot 2.0.0 进行开发,并有 4 个服务已投入生产使用。
相比咱们使用的 2.0.0 版本,jeecg-boot 2.2.1
在功能上已经很是完善,且已经造成了稳定的代码风格,在代码分层的工做上也细化了不少。
可是,在分层领域模型
方面,始终是使用Entity
贯穿各层,若是能将分层领域模型
落地,jeecg-boot 必定会更加优秀。
咱们在分层领域模型规约的一些实践: 遵循 JAVA开发手册
# 对象模型 Model (接口入参 表单验证 swagger注解) VO (返回页面对象) View Object BO (业务层对象) DO (数据库返回结果集) DTO (远程调用传输对象) 实体类 (与数据表一一对应) # 接口入参接收对象:XXXModel 【推荐】不包含`id、updateBy、updateTime、createBy、createTime`等属性,经过sql拦截注入这一系列字段 【推荐】必传字段校验 【推荐】字段长度校验 【推荐】格式校验 【推荐】时间格式转换 `@DateTimeFormat` (入参格式化,将字符串时间格式化为Date对象) # 接口返回值:XXXVO 【强制】不包含敏感字段(手机号、密码、邮箱、身份证号) 【强制】包含敏感字段时对数据加密 【推荐】使用`@JsonView`注解控制返回值的字段可见性 【推荐】字典字段转换 如,`@Dict(dicCode = "sex")` 【推荐】时间格式转换 `@JsonFormat` (出参格式化,将Date对象时间格式化为字符串)
这里之因此有这个建议,是由于咱们安所有门的同窗找了开发同窗好几回麻烦,最后咱们将 token 的存储作了一些改造。
方案一:
username_token
的形式,使用 username_UUID
。ShiroRealm#doGetAuthenticationInfo
逻辑,先使用 token 从 redis 获取 jwt token 。JwtUtil.getUsername(token)
以前须要先从 redis 获取 jwt token 。方案二:
固然,还能够将 jwt token 进行加密,向前端返回加密后的 token,然后端只需增长一个对被加密的token
进行解密
的过滤器。
既可知足不将 jwt token 返回给前端,又不会对原有逻辑进行调整,知足开闭原则
。
这也是安所有门同窗找开发同窗谈过话的案例!<img src="https://img-blog.csdnimg.cn/20200827114603322.png" width="50px"/>
咱们的实践方案:
使用 redis 对单位时间内(咱们是 5 分钟)的用户登陆失败次数进行计数。
失败次数达到 5 次后,将对该帐户进行冻结(5 分钟),5 分钟后 redis key 过时,该用户便可正常登陆。
JeecgPorperties.java
对前缀为jeecg
的配置进行管理,避免使用@Value
获取属性值的行为。spring-boot-configuration-processor
依赖,为已声明的配置项增长提示。.env.*
配置文件,将配置与环境隔离目前 jeecg-boot 的前端,一直使用的是 window._CONFIG
来挂载相关全局变量,它有一个缺点就是没有将配置与环境隔离
。
好比:
在开发环境下window._CONFIG['domianURL'] = 'http://127.0.0.1:8080/jeecg-boot'
在测试环境下window._CONFIG['domianURL'] = 'http://test.product.com:8080/jeecg-boot'
在生产环境下window._CONFIG['domianURL'] = 'http://prod.product.com:8080/jeecg-boot'
打包不一样的环境,都须要人为的去改动这些配置,对CI/CD
极不友好。
咱们的实践方案:
分环境提供配置,并在package.json
增长相应打包脚本,提升部署效率。
相似于后端项目中的:
application.yml application-dev.yml application-prod.yml application-test.yml
咱们能够看到initDictConfig
是一个空方法,它就是一个勾子函数,子组件若是重写了该方法,则会在执行created生命周期函数
时,执行子组件中重写的逻辑。
因此,咱们能够向JeecgListMixin
的赋能更多勾子函数,知足更多场景,提升灵活性,提升开发效率。
咱们的实践方案:
// created生命周期函数中执行 应用场景:加载异步词典项等 initDictConfig() {} // 搜索以前执行 应用场景:对 queryParam 对象内的数据,作一些数据转换工做等 beforeSearch() {} // 重置以前执行 应用场景:重置一些没有绑定在 queryParam 对象内的数据等 beforeReset() {} // loadData加载数据成功以后执行 应用场景:须要在该时机下作一些数据的转换工做等 afterLoadDataSuccess() {} // 在 loadData 内执行 应用场景:自定义数据加载逻辑 // 执行 loadData 时,会先判断是否重写了 customLoadData 方法 customLoadData() {}
刷新时会触发两次路由守卫的beforeEach函数
当前 jeecg-boot 2.2.1 是一次性加载全部资源,不管是开发仍是生产阶段都是不利的!
对于开发阶段,开发同窗每次刷新页面须要等待 3 ~ 4 秒,
对于生产阶段,就会涉及到首屏加载
这个指标的考验。
对资源作按需加载/缩减资源体积
能极大的优化加载性能,也是一件颇有意义的事。
咱们能够对 jeecg-boot 前端作的一些优化:
component:() => import(/* webpackChunkName: "component" */ component.vue)
splitChunks
对依赖的第三方资源拆包固然,还有更多 jeecg-boot 用户能够作的优化
在业务开发过程当中,一个页面可能有不少Modal / Drwaer
,就须要咱们加一些响应式变量和方法去控制这些Modal / Drawer
的 显示/关闭,而这些工做每每都是重复的。
那么,咱们能不能抽象一下这些重复的工做,将更多的精力放在组件的逻辑上去呢?
咱们的实践方案:
Modal / Drawer 的父组件引入@/mixins/ModalParentMixin
,并在mounted
生命周期函数中使用register
方法对 ref 的值进行注册
<template> <div> <a-button type="primary" @click="showModal('addModal')">新增</a-button> <a-button type="primary" @click="showModal('editModal')">编辑</a-button> <a-button type="primary" @click="showModal('detailModal')">详情</a-button> <!--新增--> <modal-add ref="addModal" @ok="searchReset"/> <!--编辑--> <modal-edit ref="editModal" @ok="searchReset"/> <!--详情--> <!--条件渲染,将v-if="isShow('detailModal')" @close="closeModal"一块儿使用便可--> <modal-detail ref="detailModal" @ok="searchReset" v-if="isShow('detailModal')" @close="closeModal"/> </div> </template> <script> import ModalParentMixin from '@/mixins/ModalParentMixin' export default { mixins: [ ModalParentMixin], mounted() { // 注册当前页面有哪些modal this.register(['addModal', 'editModal', 'detailModal']) }, } </script>
@/mixins/ModalMixin
如今咱们控制页面上全部的 Modal / Drawer 是否是要轻松不少了呢?
不再用声明各类不一样的 xxxVisible
来控制这些子组件的显示/关闭
。
这个本应该去 Ant Design Vue 提 issue 的,可是跟了好几个版本以后,他们并无作修复,获得的答案彷佛是:设计如此
!
既然这样,咱们就本身来作一些处理,去规避掉这个 BUG。
{ total: 11, current: 2, pageSize: 10 }
。{ total: 10, current: 2, pageSize: 10 }
,显示暂无数据
。JeecgListMixin.js
的handleDelete
、batchDel
等方法,在操做成功后,对current
进行从新计算。{ total: 11, current: 2, pageSize: 10 }
。{ total: 10, current: 1, pageSize: 10 }
,正常显示第一页的数据。更新计划
菜单能方便你们了解到 JEECG团队 对新版本的迭代方向,增长用户粘度。
关于这个建议已经有 issue,相信在近期内就会看到这个菜单!
不少社区的朋友都有反应这个问题。确实,当咱们的业务代码与 jeecg-boot 的源码融合在一块儿的时候,作版本升级是比较头疼的。
特别是大版本的升级,除了源码的变更,可能还有数据库表的变动,升级会不会对咱们的业务产生影响,谁也说不清楚!
咱们的实践方案:
依赖 jeecg-spring-boot-starter,解决业务代码与 jeecg-boot 源码融合的在一块儿的窘境。
适用人群
有兴趣的同窗,能够去 github 了解它 https://github.com/tanpenggood/jeecg-spring-boot-starter。
最后,但愿 jeecg-boot 的代码质量更加优秀,但愿 jeecg-boot 成为2020最最最最受欢迎的开源项目!