143 Star 228 Fork 125

xautlx / s2jh4net

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
310.基础数据.md 5.69 KB
一键复制 编辑 原始数据 按行查看 历史

概要说明

在一个项目的开发和测试过程中,有套快速有效的基础数据和开发测试数据重建生成机制非常有必要。一般传统的做法是额外维护一套数据SQL脚本,但是这个做法有个比较大的问题就在于,程序代码不断迭代更新数据库结构随时变更,需要同步管理维护SQL脚本的结构定义和数据变更工作非常繁琐。

既然框架选择了Hibernate作为ORM处理,并且提倡以Code First风格直接定义Entity对象直接以hbm2ddl生成数据库结构,索性再进一步把基础数据和开发测试数据的维护也以Java代码的方式来实现。这样的方式对于开发人员来说也更容易上手,一边开发一边维护数据,随时保持代码和数据的同步一致性。另外还有个好处是,相关数据初始化代码直接引用Service接口进行数据处理,编写模拟数据初始化的过程也就是在梳理业务接口逻辑的过程,因此很大程度上可作为一个比较有效的覆盖率比较高的集成测试用途。在开发测试过程,如果出现数据初始化逻辑运行异常,也就意味着相关接口出现问题,可以及时有效的接口问题修正,提高代码质量。

数据重建功能的目标

对于数据的处理,我们希望能达到如下目标:

  • 只要有个可用数据库,能随时随地自动完成重建开发或测试环境需要的数据
  • 应用反复更新部署,既能自动追加新的数据,又尽量不影响已有的数据,避免影响开发或测试的连续性

数据初始化设计

各模块继承实现了DatabaseDataInitializeProcessor的数据初始化处理类将被自动回调执行initializeInternal方法,按照Spring常规的方式Autowire注入相关Service接口对象,按照业务流程编写数据初始化代码。

由于整个初始化逻辑在一个线程进行,而系统实际运行肯定是不同用户在不同时间点不同事务步骤完成的,针对这些场景,可通过在适当的位置调用基类的flush()方法来触发立即提交当前数据并继续进行下一个分步骤数据的处理。

框架层面提供一个MockEntityUtils封装一系列帮助类方法,例如基于实体类构造随机填充的实例:SiteUser siteUser = MockEntityUtils.buildMockObject(SiteUser.class);以及其他一些常用的构造随机数,随机日期,随机集合元素选取等功能。

另外一个点就是 关于随机时间的处理,例如希望模拟创建一大批订单数据,而且最好是这些订单相关的日期时间属性能随机分布,以便更真实的测试不同时间段下单产生的数据。一般常见的业务逻辑代码写法是类似:order.setSubmitTime(new Date())直接取系统时间,为了能更好的支持随机模拟数据的生成,框架层面按照如下方式实现:

  • 所有业务代码中,凡是涉及到取当前系统时间的地方,统一改用从帮助方法DateUtils.currentDateTime()获取,例如:下单接口中下单时间 order.setSubmitTime(DateUtils.currentDateTime()),另外个付款接口中付款时间 order.setPayTime(DateUtils.currentDateTime());

  • 在模拟数据构造过程中,在不同业务操作时间点位置调用DateUtils.setCurrentDateTime(dateTime)合理的设置当前系统时间,然后在业务接口中就能正确的取到当前模拟设置的系统时间作为当前业务数据的操作时间值。

权限基础数据处理

对于Web应用最典型的权限控制粒度就是在Web Action或Controller层方法的访问控制,基于框架集成的Apache Shiro,相比Spring Security权限组件,Shiro一个比较实用的特性就是其控制粒度比角色Role还细一层可以基于权限Permission进行控制。为了实现细粒度的权限控制,因此采用实用Shiro的@RequiresPermissions注解在Controller方法上,例如:

    @MenuData("配置管理:权限管理:用户账号")
    @RequiresPermissions("配置管理:权限管理:用户账号")
    @RequestMapping(value = "", method = RequestMethod.GET)
    public String index(@ModelEntity User entity, Model model) {
        return "admin/auth/user-index";
    }

其中,为了便于直观生成权限配置数据,就不再额外定义权限代码,而是直接在@RequiresPermissions注解中实用中文字符,并且以冒号作为层次划分标识。

在ControllerMetaDataPostProcessor中提取所有Controller类中的RequiresPermissions注解值,自动实现权限数据的增量更新以及过期数据的清理,每次更新版本自动保持了全面代码控制逻辑和基础数据的同步一致性。

菜单基础数据处理

菜单数据本身和权限数据一般是相连的,即用户菜单列表的动态显示是基于用户的角色权限关联计算的,如上节示意代码中的@MenuData("配置管理:权限管理:用户账号")注解,定义了当前Controller对应URL的访问菜单路径,以冒号划分菜单显示的父子层级关系。

在ControllerMetaDataPostProcessor中提取所有Controller类中的MenuData、RequestMapping等注解值,构造菜单数据的路径,URL链接,Method方法信息等,自动实现菜单数据的增量更新以及过期数据的清理,每次更新版本自动刷新最新菜单数据项。

在MenuService的processUserMenu接口方法,根据当前用户的角色权限集合,结合菜单项对应的Method方法相关RequiresPermissions注解值进行比对计算用户的可见菜单列表数据。

其他基础数据

其他诸如基础的系统参数,数据字典,基础用户,关联配置等数据,请参考框架中的 BasicDatabaseDataInitializeProcessor 和 DemoDatabaseDataInitializeProcessor 相关代码逻辑。

Java
1
https://gitee.com/xautlx/s2jh4net.git
git@gitee.com:xautlx/s2jh4net.git
xautlx
s2jh4net
s2jh4net
master

搜索帮助