Java修道之路:JFinal实现自动扫描Controller并设置注解的controllerkey

由于最近在研究JFinal,所以就用JFinal的框框来写例子吧。

JFinal设置Controller的访问路径是在Config的configRoute方法中设置,使用me.add(String path, Class controller),如果有多个Controller,那么需要添加多行代码!

如果Controller非常多,那么后期的更改操作将比较麻烦,所以需要自动扫描Controller,将指定的注解的属性配置到me.add方法中(这里设计为Controller添加自定义注解@PVAnnotation(path = “/visit”),path就是访问路径)。

思路:

1,根据设置的包路径获取到文件路径,使用递归得到所有的.class文件(java字节码文件),将所有的.class的Class放入一个List

2,遍历1中得到的List,通过反射判断Class有没有指定的注解,如果有就获得注解并获得对应的注解属性,如果没有就continue

代码:

1,先创建SearchUtil.java,包含递归扫描所有的.class文件,和返回扫描到的Class

public class ClassSearchUtil {

	private static List<Class<?>> clazzes;

	public synchronized static List<Class<?>> searchClass(String packagePath)
			throws URISyntaxException, ClassNotFoundException {

		// 考虑到不只是访问路径需要自动配置,JSP的文件位置也可能需要配置
		// 如果都要扫描,那么可能出现多次扫描,浪费资源
		// 所以,这里类似单例模式,如果已经扫描过了,那么就直接返回扫描结果
		// 该方法使用同步也是为了保证只扫描一次
		if (clazzes != null) {
			return clazzes;
		}

		List<Class<?>> clazzes = new ArrayList<Class<?>>();

		// 通过包路径获取到文件的路径
		URI uri = ClassSearchUtil.class.getClassLoader().getResource(packagePath).toURI();
		File classFile = new File(uri);

		// 递归查到所有controller
		ClassSearchUtil csu = new ClassSearchUtil();
		csu.getAllFile(classFile, clazzes, packagePath);

		ClassSearchUtil.clazzes = clazzes;
		return clazzes;
	}

	/**
	 * 递归查找所有class文件,并放入clazzes
	 */
	private void getAllFile(File dire, List<Class<?>> clazzes, String packagePath)
			throws ClassNotFoundException {

		if (dire.isFile()) {
			if (dire.getName().endsWith(".class")) {

				// 获取.class的路径,截去前面的“.../classes/”
				String clazzPath = dire.getPath();
				String packPath = clazzPath.substring((PathKit.getRootClassPath() + File.separator).length());
				packPath = packPath.substring(0, packPath.lastIndexOf(".class"))
						.replace(File.separatorChar, '.');
				// 将Class字符串转换为Class,并加入到List
				clazzes.add(Class.forName(packPath));
			}
			return;
		}

		File[] sonFiles = dire.listFiles();
		for (File sonFile : sonFiles) {
			getAllFile(sonFile, clazzes, packagePath);
		}
	}
}

2,创建自定义注解

// @Target是指定该注解的定义范围,TYPE是指类,还有FIELD,METHOD等
@Target(ElementType.TYPE)
// @Retention是该注解的作用时机,RUNTIME是运行是作用,还有RESOURCE,CLASS
@Retention(RetentionPolicy.RUNTIME)
public @interface PVAnnotation {

	// 用于设置访问路径
	String path();

	// 用于设置JSP的路径,default是默认值,设置后注解的时候可以不用设置
	// 本例中只是示范,并没有使用
	String view() default "";
}

3,使用自定义注解

	@Override
	public void configRoute(Routes me) {

		//me.add("/file", FileOperController.class);

		// 通过注解获取访问路径配置
		List<Class<?>> clazzes = ClassSearchUtil.searchClass("");
		// 遍历所有的Class
		for (Class<?> clazz : clazzes) {
			// 如果Class不是继承自Controller,那么跳过
			// 用法:父类.isAssignableFrom(子类)
			if (!Controller.class.isAssignableFrom(clazz)) continue;
			// 转换成Controller类
			Class<? extends Controller> controller = (Class<? extends Controller>) clazz;
			// 在判断是否有指定的注解
			// 用法:类.isAnnotationPresent(注解类)
			if (controller.isAnnotationPresent(PVAnnotation.class)) {
				// 如果有指定注解,那么将指定的属性添加到me中
				me.add(controller.getAnnotation(PVAnnotation.class).path(), controller);
			}
		}
	}

这样,就完成自动扫描Controller,然后配置访问路径的功能了。

本文《Java修道之路:JFinal实现自动扫描Controller并设置注解的controllerkey》来自 www.juwends.com ,欢迎转载或CV操作,但请注明出处,谢谢!