基于Nutz.Dao的数据权限管理的实现2
上篇文章说到简单的实现了数据权限的管理,但是从代码清晰度、条理性上来看,还是十分粗糙的,只能凑合着使用。要么说干这行纯粹就是跟自己作对呢,要么说程序员大都是完美主义者呢,所以我用我仅有的Java编程经验,绞尽脑汁的又改了一版出来,我觉的对于我来说没准就算到头了。
这次改进主要关注以下几个点:
1. 当前登录的人员不再由调用方传入,所以减少了一个参数。我觉的就应该是这样的,调用方不需要传输无用的参数,不管调用方怎么调用,该做数据过滤的时候是一定要做的,这个其实应该由底层去强制控制,越底层越好。
2. 不要普通的工程师在开发Dao内的函数时显式调用工具类生成SQL,应该直接指定SQL,然后由底层去格式化。这样的话,一般的工程师不需要管数据权限是怎么实现的,只需要按照规则去写代码即可,便于项目组中的成员高低搭配。但是我做不到或者不想做成在JDBC层直接拦截的,因为我觉的分析原生SQL是一件很麻烦的事情,没有时间去开发、调试、改进。所以我还是定下了SQL书写的规则,通过模板引擎来间接实现控制,这样折中的办法对于我来说性价比较高。
以下就是实现的过程(贴代码):
1. 自定义Nutz.Dao的FileSqlManager
- import com.xnck.common.util.BeanUtil;
- import org.nutz.dao.SqlNotFoundException;
- import org.nutz.dao.Sqls;
- import org.nutz.dao.impl.NutDao;
- import org.nutz.dao.sql.Sql;
- /**
- * 重写nutz.dao的FileSqlManager类
- * 使用SQL文件创建Sql对象时,如果包含指定的关键字,则使用权限控制
- */
- public class FileSqlManager extends org.nutz.dao.impl.FileSqlManager {
- private String ruleKeyword = "ByRule";
- private volatile static NutDao dao;
- public FileSqlManager(String... paths){
- super(paths);
- }
- public String getRuleKeyword() {
- return ruleKeyword;
- }
- public void setRuleKeyword(String ruleKeyword) {
- this.ruleKeyword = ruleKeyword;
- }
- public Sql create(String key) throws SqlNotFoundException {
- String sql = get(key);
- if (key.toLowerCase().contains(ruleKeyword.toLowerCase())){
- NutDao dao = getDao();
- sql = SqlRuleTool.injectSearchSql(dao, key, sql);
- }
- return Sqls.create(sql);
- }
- private static NutDao getDao() {
- if (null == dao) {
- synchronized (FileSqlManager.class){
- if (null == dao){
- dao = BeanUtil.getBean("dao", NutDao.class);
- }
- }
- }
- return dao;
- }
- }
2. 修改Spring配置文件
- <bean id="daoRunner" class="com.xnck.sysbase.dao.helper.SpringDaoRunner" />
- <bean id="sqlManager" class="com.xnck.sysbase.dao.helper.FileSqlManager">
- <constructor-arg name="paths" value="all.sqls" />
- </bean>
- <bean id="dao" class="org.nutz.dao.impl.NutDao">
- <property name="dataSource" ref="dataSource"/>
- <property name="runner" ref="daoRunner"/>
- <property name="sqlManager" ref="sqlManager"/>
- </bean>
然后就没了,上文中的SqlRuleTool可以参见上一篇文章,调用的时候会更加简洁,比如:
- public List<UserInfo> getUsersByRule(String byUserId, Condition cnd){
- //Sql sql = SqlTool.injectSearchSql(this.dao, "userDao.getUsersByRule", byUserId);
- Sql sql = this.dao.sqls().create("userDao.getUsersByRule");
- sql.setParam("byuserid", byUserId);
- sql.setCondition(cnd);
- return this.search(sql);
- }
如果确定不需要传入byUserId的话,可以将原始SQL语句的@byUserId作为保留字,在自定义的FileSqlManager 内判断处理后的SQL是否包含这个保留字,如果包含的话直接用sql.setParam给参数赋值,就能够让代码更加简洁一些。
这里要注意的是SqlRuleTool或得当前登录人是通过一个封装类来完成的。我前几年一直在微软平台下工作,当时.NET有一个全局的封装类可以获得当前的登录人,在使用Java时我还苦恼为什么没有这么一个类,直到前些日子我才偶然发现这个类其实是需要自己封装的,所以才能让我豁然开朗了一小下。
至此,我觉的我已经尽了全力进行封装,除非哪天再豁然开朗一下了。同时推荐读一下《聊聊数据权限那些事》,是通过JDBC层来进行数据权限管理,更加底层更加灵活更加完善,当然要熟悉和使用或者自行仿制一个也更耗费时间,不过借鉴一下,将某些东西植入到自己的东西里面,也是一件不错的事情。