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='后台权限';
以上仅完成了项目启动时,自动构建权限。
阅读全文
0 0
- JFinal后台权限项目启动时自动生成
- Jenkins启动项目后台进程自动杀掉
- Jfinal后台
- Web应用启动时,后台自动启动一个线程
- Web应用启动时,后台自动启动一个线程
- JFinal Web开发学习(四)数据库连接与自动生成model
- Tomcat自动启动后台任务
- Laravel--自动生成后台面板
- JFinal框架启动时遇到的问题
- 关于使用JFinal构建maven项目时,使用jetty启动项目,无法渲染jsp页面的问题
- 后台自动生成Excel,指定生成路径
- AndroidStudio启动时不自动打开项目
- 系统自动启动项目
- Yii自动生成项目
- Yii自动生成项目
- “应用自动启动”和“关联启动”权限
- JavaWeb 项目启动时,后台开启一个线程的方法
- Ionic 自动生成启动图标
- 设计一个针对全球的、访问量极大的id生成系统。 必须保证用户每次从该系统得到的id是唯一的,而且在概率上毫无碰撞可能。
- c语言的内存管理
- 应用经验 项目 基于51的数据采集系统感想(科技)
- L
- 53. Maximum Subarray
- JFinal后台权限项目启动时自动生成
- css的背景及背景图片的属性
- C++学习之路(2)---两招让你成为牛X的T型人才
- 第一节总结
- 七牛云-上传策略常用示例
- 219. Contains Duplicate II
- 最小公倍数
- 关闭CPU C State 解决卡屏死机问题
- 单例与线程安全