JFinal后台权限项目启动时自动生成

来源:互联网 发布:52单片机引脚图 编辑:程序博客网 时间:2024/05/17 01:01

【前言】
原来的后台(前辈搭好的)权限管理已经能自动生成了,不过必须要有操作者响应某个操作(方法级别的),拦截器检查该操作是否有权限注解,有的话查询该注解的value(权限名称)是否已经存在,如果不存在则新建该权限,权限生成好了才能授予用户相应权限。这个过程其实用用也没啥问题,就是别扭,权限不能提前授予用户,而是让第一个操作者先“踩坑”然后再填坑。
基于前面的问题,本文在原先的注解基础上设计了项目启动时自动生成的权限
注:用户-角色-权限关系,权限的拦截检测等不在本文讨论范围。
【原理】
1. 扫描指定路径(放置Controller类的包的全路径)
2. 获取该路径下(递归子孙包)所有的Controller类的Class对象
3. 获取数据库已有的权限(父权限+对应的子权限)
4. 遍历2中的所有Class对象,判断是否有权限注解,再与3中的父权限比较是否存在
4.1不存在。创建父权限,创建Class对象里的含权限注解的所有Method级别的子权限
4.2存在。不创建父权限,遍历Class对象里的含权限注解的所有Method级别的子权限,判断是否已经存在该子权限,不存在则新建权限
5.项目启动后即执行以上过程。

【正文】
创建权限注解类

@Retention(RetentionPolicy.RUNTIME)public @interface PermissionOwn {    String name();//权限名称    }

Controller和其方法Method加注解。例如:

@PermissionOwn(name = "权限管理")public class PermissionController extends BaseController {    @PermissionOwn(name = "权限列表")    public void perms() {        ......    }    ......

核心工具类,有点长,还可以优化的

public class PermissionAutoBuild {    private static final Logger LOG = LoggerFactory.getLogger(PermissionAutoBuild.class);    public void build(String packageUrl) {        try {            // 是否循环遍历            boolean recursive = false;            // 获取包的名字和文件路径            String packageName = packageUrl;            String packagePath = packageName.replace('.', '/');            // 存放获取的class文件            Map<String, Class<?>> classes = new HashMap<>();            // 获取指定路径下所有class文件            findAndAddClassesInPackageByFile(packageName, packagePath, recursive, classes);            if (classes.isEmpty()) {                LOG.error("PermissionAutoBuild [Set<Class<?>> classes = NULL]");                return;            }            // 查询数据库中已有的权限            //获取父权限            List<Record> parentRrcord = Db.find("SELECT * FROM auth_permission WHERE parent_id=0");            Map<String, List<Record>> permissionMap = new HashMap<String, List<Record>>();            //获取父权限对应的子权限            for (Record r : parentRrcord) {                List<Record> kidRecord = Db                        .find("SELECT * FROM auth_permission WHERE parent_id=" + r.get("id"));                permissionMap.put(r.getStr("name"), kidRecord);            }            // 获取每个class里的注解和方法注解            Set<Entry<String, Class<?>>> entrySet = classes.entrySet();            Iterator<Entry<String, Class<?>>> iterator = entrySet.iterator();            while (iterator.hasNext()) {                Entry<String, Class<?>> next = iterator.next();                String controllerAlias = next.getKey();                Class<?> clazz = next.getValue();                PermissionOwn permissionOwn = clazz.getAnnotation(PermissionOwn.class);                if (permissionOwn != null) {                    String name = permissionOwn.name();                    List<Record> list = permissionMap.get(name);                    //判断父权限是否存在                    if (!permissionMap.containsKey(name)) {                        // 创建父权限                        Db.save("auth_permission", new Record().set("name", name).set("alias", controllerAlias)                                .set("parent_id", 0).set("permission", "").set("add_time", new Date()));                        LOG.info(String.format("自动创建权限[controllerAlias=%s,controllerName=%s]", controllerAlias, name));                    }                    Record controllerPermission = getControllerPermission(controllerAlias);                    if (controllerPermission == null) {                        throw new RuntimeException("controller权限不存在,无法建立权限!");                    }                    //遍历类中的方法,判断是否有权限注解,再判断权限是否已经存在                    Method[] methods = clazz.getMethods();                    for (Method m : methods) {                        boolean flag = false;                        PermissionOwn methodPermission = m.getAnnotation(PermissionOwn.class);                        if (methodPermission != null) {                            String mAlias = m.getName();                            String mName = methodPermission.name();                            if(CollectionUtils.isEmpty(list)){                                //首次创建                                flag=true;                            }else{                                for (Record r : list) {                                    if (mName.equals(r.getStr("name"))) {                                        flag=false;                                        break;                                    }                                    flag=true;                                }                            }                            if(flag){                                // 创建子权限                                Db.save("auth_permission",                                        new Record().set("name", mName).set("alias", mAlias)                                        .set("parent_id", controllerPermission.get("id"))                                        .set("permission", controllerAlias + "-" + mAlias)                                        .set("add_time", new Date()));                                LOG.info(String.format(                                        "自动创建权限[controllerAlias=%s,methodAlias=%s,methodName=%s,permission=%s]",                                        controllerAlias, mAlias, mName, controllerAlias + "-" + mAlias));                            }                        }                    }                }            }        } catch (Exception e) {            e.printStackTrace();            LOG.error("创建权限失败:e==" + e);            return;        }        LOG.info("创建权限成功");    }    /**     * 以文件的形式来获取包下的所有Class     * 注:该方法源自网友,做了部分修改,增加了获取Class目录     * @param packageName     * @param packagePath     * @param recursive     * @param classes     */    private void findAndAddClassesInPackageByFile(String packageName, String packagePath, final boolean recursive,            Map<String, Class<?>> classes) {        //获取Class目录        String path = PermissionAutoBuild.class.getResource("/").getPath();        // 获取此包的目录 建立一个File        File dir = new File(path+packagePath);        // 如果不存在或者 也不是目录就直接返回        if (!dir.exists() || !dir.isDirectory()) {             LOG.warn("用户定义包名 " + packageName + " 下没有任何文件");            return;        }        // 如果存在 就获取包下的所有文件 包括目录        File[] dirfiles = dir.listFiles(new FileFilter() {            // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)            public boolean accept(File file) {                return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));            }        });        // 循环所有文件        for (File file : dirfiles) {            // 如果是目录 则继续扫描            if (file.isDirectory()) {                findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive,                        classes);            } else {                // 如果是java类文件 去掉后面的.class 只留下类名                String className = file.getName().substring(0, file.getName().length() - 6);                try {                    classes.put(className,                            Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));                } catch (ClassNotFoundException e) {                    LOG.error("添加用户自定义视图类错误 找不到此类的.class文件");                    e.printStackTrace();                }            }        }    }    private Record getControllerPermission(String controllerAlias) {        Record controllerRecord = Db.findFirst(                "select * from auth_permission where alias = ? and permission = ? and parent_id = 0",                controllerAlias, "");        return controllerRecord;    }}

在JFinal的config类里的afterJFinalStart()中添加

        //构建权限        LOG.info("构建权限启动");        PermissionAutoBuild builder = new PermissionAutoBuild();        builder.build("top.rushpeak.edu06.admin");//此处填写你的Controller文件所在包的全名

权限表

CREATE TABLE `auth_permission` (  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',  `name` varchar(50) NOT NULL COMMENT '权限名字',  `alias` varchar(50) NOT NULL COMMENT '权限别名',  `parent_id` int(10) unsigned NOT NULL COMMENT '父级权限',  `permission` varchar(100) NOT NULL COMMENT '权限值',  `add_time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '添加的时间',  PRIMARY KEY (`id`),  UNIQUE KEY `auth_permission_alias_parent_id` (`alias`,`parent_id`),) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='后台权限';

以上仅完成了项目启动时,自动构建权限。
这里写图片描述

原创粉丝点击