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

本文介绍了一个改进的JFinal后台权限管理系统,在项目启动时自动扫描Controller类并根据注解生成权限,避免了需要操作者首次触发权限检查时的不便。通过扫描指定路径获取Controller类,对比数据库已有权限,动态创建缺失的父权限和子权限。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【前言】
原来的后台(前辈搭好的)权限管理已经能自动生成了,不过必须要有操作者响应某个操作(方法级别的),拦截器检查该操作是否有权限注解,有的话查询该注解的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='后台权限';

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值