ORMLite反向重置数据库表

如果是Hibernate,反向生成数据库大家肯定会想到hbm2ddl,但是ORMLite呢?ORMLite虽然提供了按照对象来反向生成表的方法,但还不够。因为我希望.新增一个表,不要额外单独写创建表、删除表的操作。

因此想到了Spring的packagesToScan,不过暂未深究Spring,只好找了个现成的类。实现非子目录的扫描:

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

public class ReflectionUtil {

	private ReflectionUtil() {}
	
	public static List<Class<? extends Annotation>> getClassesWithAnnotation(String packageName, Class<? extends Annotation> annotationType) throws ClassNotFoundException, IOException{
		List<Class<? extends Annotation>> annotatedClassList = new ArrayList<Class<? extends Annotation>>();
		for(Class type: getClasses(packageName)){
			if(type.getAnnotation(annotationType) != null){
				annotatedClassList.add(type);
			}
		}
		return annotatedClassList;
	}
	
	
	/**
	 * Scans all classes accessible from the context class loader which belong
	 * to the given package and subpackages.
	 * 
	 * @param packageName
	 *            The base package
	 * @return The classes
	 * @throws ClassNotFoundException
	 * @throws IOException
	 */
	public static List<Class<?>> getClasses(String packageName) throws ClassNotFoundException, IOException
	{
	    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
	    String path = packageName.replace('.', '/');
	    Enumeration<URL> resources = classLoader.getResources(path);
	    List<File> dirs = new ArrayList<File>();
	    while (resources.hasMoreElements())
	    {
	        URL resource = resources.nextElement();
	        dirs.add(new File(resource.getFile()));
	    }
	    List<Class<?>> classes = new ArrayList<Class<?>>();
	    for (File directory : dirs)
	    {
	        classes.addAll(findClasses(directory, packageName));
	    }
	
	    return classes;
	}
	
	/**
	 * Recursive method used to find all classes in a given directory and
	 * subdirs.
	 * 
	 * @param directory
	 *            The base directory
	 * @param packageName
	 *            The package name for classes found inside the base directory
	 * @return The classes
	 * @throws ClassNotFoundException
	 */
	private static List<Class<?>> findClasses(File directory, String packageName) throws ClassNotFoundException
	{
	    List<Class<?>> classes = new ArrayList<Class<?>>();
	    if (!directory.exists())
	    {
	        return classes;
	    }
	    File[] files = directory.listFiles();
	    for (File file : files)
	    {
	        if (file.isDirectory())
	        {
	            classes.addAll(findClasses(file, packageName + "." + file.getName()));
	        }
	        else if (file.getName().endsWith(".class"))
	        {
	            classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6)));
	        }
	    }
	    return classes;
	}
}

完成后就可以在Spring的InitializingBean去干初始化系统的活了,调用ORMLite的数据库操作功能,先drop,后create:

            	for(Class<? extends Annotation> type: ReflectionUtil.getClassesWithAnnotation("org.我的包.com", DatabaseTable.class)){
                	TableUtils.dropTable(connectionSource, type, true);
                	TableUtils.createTable(connectionSource, type);
            	}

这里提醒下,大家Spring一般用的是DataSource,而ORMLite用的是ConnectionSource,在ConnectionSource构造方法里有包装DataSource的方法,在spring里配置下即可:

	<bean id="connectionSource" class="com.j256.ormlite.jdbc.DataSourceConnectionSource" init-method="initialize">
		<property name="dataSource" ref="dataSource" />
		<property name="databaseUrl" value="${dataSource.driverUrl}" />
	</bean>



不知道如何采用spring package-scan机制完成,看看spring源码理论上应该是可行的。暂未深究,在此就算抛砖引玉了。

/* -------------------- 2016年的分割线 -------------------------- */

之前看过包扫描的代码,自己居然给忘了,这记性……

用包扫描来代替ReflectionUtil,写起来其实非常简单:

for(Class<? extends Annotation> type: ReflectionUtil.getClassesWithAnnotation("org.我的包.com", DatabaseTable.class)){

可以直接换成:

for(Class<? extends Annotation> type: scanOrmLiteClasses("classpath:org/我的包/com/*/xxxx/*.class")){

还支持部分路径匹配,方便极了。scanOrmLiteClasses的代码如下:

    @SuppressWarnings({ "unchecked", "rawtypes" })
	private List<Class<? extends Annotation>> scanOrmLiteClasses(String pattern) throws URISyntaxException, IOException, ClassNotFoundException{
    	List<Class<? extends Annotation>> annotatedClassList = new ArrayList<Class<? extends Annotation>>();
    	int pathLen = Thread.currentThread().getContextClassLoader().getResource(".").toURI().toString().length();
    	ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
    	for(Resource resources: resolver.getResources(pattern)){
    		String uriStr = resources.getURI().toString();
    		Class scanClass = Class.forName(uriStr.substring(pathLen, uriStr.length() - 6).replaceAll("/", "."));
			if(scanClass.getAnnotation(DatabaseTable.class) != null){
				annotatedClassList.add(scanClass);
			}
    	}
    	return annotatedClassList;
    }


你可能感兴趣的:(ormlite)