Hey ScannerUtils 扫包工具类
In doing we learn.– 实践长才干.
最近做项目时,有个特殊的需求,就是进行扫注解,但是呢,此注解并不是基于springboot的而是自定义的,那怎么才能做到类上或者方法上的注解呢?鉴于此,我就写了一个进行扫包,扫类,扫注解的工具类,方便大家使用,详细类见如下:
//扫包工具类
public class ScannerUtils {
// 得到所有的 目标类 (Controller类)
private static Set<Class> classets = new LinkedHashSet<>();
// 存放所有关于 此注解 的类
private static Set<PermissonBean> classPermissonBeanSet = new LinkedHashSet<>();
// 存放 含有此注解的 方法
private static Set<PermissonBean> methodPermissonBeanSet = new LinkedHashSet<>();
/**
* 根据指定的包扫描下面所有的类 得到所有的类
*
* @param packagename com.masterjen.project
* @return
*/
private static void getClassSet(String packagename) throws Exception {
// 把所有的类的 绝对路径进行转换成 com/master/projec的文件的形式
URL resource = PermsAnnoUtils.class.getClassLoader().getResource(packagename.replace(".", "/"));
// 得到 目标文件夹 进行判断
if (resource != null && "file".equalsIgnoreCase(resource.getProtocol())) {
//当前项目运行环境所在的绝对路径
String packagepath = URLDecoder.decode(resource.getFile(), "UTF-8");
// 进行扫包 packagename : com.master.project... packagepath:com/master/project
addClass(packagename, packagepath);
}
}
/**
* 进行扫包
* @param packagename com.masterjen.project
* @param packagepath com/masterjen/project
* @throws Exception
*/
private static void addClass(String packagename, String packagepath) throws Exception {
//创建一个文件数组, 数组里面的内容都是class文件 添加一个过滤器 进行过滤得到 以class结尾的文件
File[] files = new File(packagepath).listFiles(new FileFilter() {
@Override
public boolean accept(File pathfile) {
//返回值代表是否被添加
return (pathfile.isFile() && pathfile.getName().endsWith("class")) || pathfile.isDirectory();
}
});
//遍历files
for (File file : files) {
//com/masterjen/project/..../controller/UserController
String fileName = file.getName();
if (file.isFile()) {
//代表 是一个文件也就是class结尾的文件
//如果它不是controller 就跳过
//如何区分是不是controller,那我们定义了所有的controller都在controller包中
if (!fileName.contains("Controller")) {
//不是controller
continue;
}
// 如果是 Controller文件 那么得到 UserController 类 方便反射进行读取
String classname = fileName.substring(0, fileName.lastIndexOf("."));
//class.forname(com.masterjer.project) 得到全限定名称
classname = packagename + "." + classname;
// 进行反射该类 com.masterjen.project..controller.UserController
doAddClass(classname);
} else {
// 说明是文件夹 在此进行扫包 但是需要加上此文件夹的名称
String subPackagepath = fileName;
if (!StringUtils.IsEmpty(packagepath)) {
subPackagepath = packagepath + "/" + subPackagepath;
}
// 包的名称也要加上名字
String subPackagename = fileName;
if (!StringUtils.IsEmpty(packagename)) {
subPackagename = packagename + "." + subPackagename;
}
// 再次进行扫包 操作
addClass(subPackagename, subPackagepath);
}
}
}
/**
* 根据全限定名称进行 反射操作.
* @param classname 权限定名称
* @throws Exception
*/
private static void doAddClass(String classname) throws Exception {
Class<?> aClass = Class.forName(classname);//加载类
classets.add(aClass);//添加到集合中
}
/**
* 进行扫描类上的注解操作
* @param packgename
* @throws Exception
*/
public static void inject(String packgename) throws Exception {
// 首先把上面所有的内容清空,保持唯一性
classets.clear();
classPermissonBeanSet.clear();
methodPermissonBeanSet.clear();
//当这个方法执行完成后,set中就有所有的类了
getClassSet(packgename);
for (Class clazz : classets) {
//获取我们遍历到的每一个controller class
//Annotation a 得到类上面的注解
PermsAnno classAnnotation = (PermsAnno) clazz.getAnnotation(PermsAnno.class);
// 注解的内容
String classComment = null;
String classParent = null;
boolean classIsMenu = false;
String classValue = null;
// 如果存在注解 那么进行对类操作
if (classAnnotation != null) {
//描述
classComment = classAnnotation.comment();
//父是谁,和父中的comment一个值
classParent = classAnnotation.parentConment();
//是不是菜单
classIsMenu = classAnnotation.isMenu();
//权限的值
classValue = classAnnotation.permsValue();
// 根据自定义注解 实现的实体类
PermissonBean permissonBean = new PermissonBean();
permissonBean.setIsMenu(classIsMenu ? 1 : 0);
permissonBean.setParentComment(classParent);
permissonBean.setPermsValue(classValue);
permissonBean.setComment(classComment);
// 把类 放到set集合中 保持唯一性
classPermissonBeanSet.add(permissonBean);
}
// 对类上的方法 进行扫描注解
Method[] methods = clazz.getMethods();
for (Method method : methods) {
PermsAnno methodAnnotation = method.getAnnotation(PermsAnno.class);
if (methodAnnotation != null) {
//描述
String comment = methodAnnotation.comment();
//父是谁,和父中的comment一个值
String parent = methodAnnotation.parentConment();
//是不是菜单
boolean menu = methodAnnotation.isMenu();
//权限的值
String value = methodAnnotation.permsValue();
// /user/getuserlistbypage 此路径应该是 类上的加上方法上的 路径
String permission = classValue + value;
PermissonBean permissonBean = new PermissonBean();
permissonBean.setIsMenu(menu ? 1 : 0);
permissonBean.setParentComment(parent);
permissonBean.setPermsValue(permission);
permissonBean.setComment(comment);
// 放到 set集合中
methodPermissonBeanSet.add(permissonBean);
}
}
}
}
public static void main(String[] args) throws Exception {
// 测试 完成后 工具类里面 就得到了 两个目标set 集合 就可以进行操作了
inject("com.masterjen.project");
System.out.println(classPermissonBeanSet);
System.out.println(methodPermissonBeanSet);
}
public static Set<PermissonBean> getClassPermissonBeanSet() {
return classPermissonBeanSet;
}
public static Set<PermissonBean> getMethodPermissonBeanSet() {
return methodPermissonBeanSet;
}
}
需要扫描的 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD,ElementType.TYPE})
public @interface PermsAnno {
// 权限的值
String permsValue();
// 权限的描述
String comment();
// 权限的 父类描述
String parentConment();
// 是否是菜单
boolean isMenu() default false;
}
带有此注解的实体类以及方法
@RestController
@RequestMapping("/user")
@PermsAnno(comment = "用户管理", parentConment = "", permsValue = "/user")
public class UserController {
@PermsAnno(permsValue = "/getalluser", comment = "得到所有的用户列表", parentConment = "用户管理", isMenu = true)
@RequestMapping(value = "/getalluser", method = {RequestMethod.GET, RequestMethod.POST})
public ResultBean getAllUser(Integer pageNum,Integer pageSize) {
pageNum = pageNum==null?1:pageNum;
pageSize = pageSize==null?3:pageSize;
List<User> list = userService.findAllUser(pageNum,pageSize);
return ResultBean.setOk(0, "OK", list);
}
}
如此便可以通过工具类的getSet()方法得到带有此注解的类和方法了,里面存放的是类和方法的路径名 ,接下类就可以根据自己的需求进行操作了.