在使用jFinal的时候因为不想每个Model都一个个去写映射关系,因此使用了 的AutoTableBindPlugin来自动绑定Model与表之间的映射,但是在jFinal升级到1.6后AutoTableBindPlugin不支持多数据源,因此对AutoTableBindPlugin做了小小的一点改造使它支持多数据源。
因为在使用AutoTableBindPlugin的时候它会检索到所有继承Model类的子类来进行绑定映射关系。因此在配置多个AutoTableBindPlugin的时候前面配置的AutoTableBindPlugin会加载后面配置的AutoTableBindPlugin中其他数据源的Model这个时候就报错了,提示找不到表了!
我的解决办法是添加一个包扫描的方法以及在AutoTableBindPlugin的构造方法中添加一个configName的参数
public class AutoTableBindPlugin extends ActiveRecordPlugin { protected final Logger log = Logger.getLogger(getClass()); @SuppressWarnings({"unchecked" }) private List> excludeClasses = Lists.newArrayList(); private List packageList = Lists.newArrayList(); private List includeJars = Lists.newArrayList(); private boolean autoScan = true; private boolean includeAllJarsInLib; private INameStyle nameStyle; public AutoTableBindPlugin(DataSource dataSource) { this(dataSource, SimpleNameStyles.DEFAULT); } public AutoTableBindPlugin(DataSource dataSource, INameStyle nameStyle) { super(dataSource); this.nameStyle = nameStyle; } public AutoTableBindPlugin(String confitName,DataSource dataSource, INameStyle nameStyle) { super(confitName,dataSource); this.nameStyle = nameStyle; } public AutoTableBindPlugin(IDataSourceProvider dataSourceProvider,String... packages) { this(dataSourceProvider, SimpleNameStyles.DEFAULT); } public AutoTableBindPlugin(IDataSourceProvider dataSourceProvider, INameStyle nameStyle) { super(dataSourceProvider); this.nameStyle = nameStyle; } public AutoTableBindPlugin(String configName,IDataSourceProvider dataSourceProvider, INameStyle nameStyle) { super(configName,dataSourceProvider); this.nameStyle = nameStyle; } @SuppressWarnings({"unchecked"}) public AutoTableBindPlugin addExcludeClasses(Class ... clazzes) { for (Class clazz : clazzes) { excludeClasses.add(clazz); } return this; } @SuppressWarnings({"unchecked" }) public AutoTableBindPlugin addExcludeClasses(List > clazzes) { if (clazzes != null) { excludeClasses.addAll(clazzes); } return this; } public AutoTableBindPlugin addJars(List jars) { if (jars != null) { includeJars.addAll(jars); } return this; } public AutoTableBindPlugin addJars(String... jars) { if (jars != null) { for (String jar : jars) { includeJars.add(jar); } } return this; } public AutoTableBindPlugin scanPackages(String...packages){ if(packages != null){ for (String pack : packages) { packageList.add(pack); } } return this; } @Override @SuppressWarnings({"unchecked"}) public boolean start() { List > modelClasses = ClassSearcher.of(Model.class).injars(includeJars).includeAllJarsInLib(includeAllJarsInLib).search(); TableBind tb = null; for (Class modelClass : modelClasses) { //指定了扫描包的情况下根据包名来进行加载映射关系,否则就全部加载 if(!packageList.isEmpty()){ for (String pack : packageList) { if(modelClass.getName().startsWith(pack)){ scanModel(tb,modelClass); } } }else{ scanModel(tb,modelClass); } } return super.start(); } @Override public boolean stop() { return super.stop(); } @SuppressWarnings({ "unchecked"}) private void scanModel(TableBind tb,Class clazz){ if (!excludeClasses.contains(clazz)) { tb = (TableBind) clazz.getAnnotation(TableBind.class); String tableName; if (tb == null) { if (autoScan) { tableName = nameStyle.name(clazz.getSimpleName()); this.addMapping(tableName, clazz); log.debug("addMapping(" + tableName + ", " + clazz.getName() + ")"); } } else { tableName = tb.tableName(); if (StringKit.notBlank(tb.pkName())) { this.addMapping(tableName, tb.pkName(), clazz); log.debug("addMapping(" + tableName + ", " + tb.pkName() + "," + clazz.getName() + ")"); } else { this.addMapping(tableName, clazz); log.debug("addMapping(" + tableName + ", " + clazz.getName() + ")"); } } } } public AutoTableBindPlugin autoScan(boolean autoScan) { this.autoScan = autoScan; return this; } public AutoTableBindPlugin includeAllJarsInLib(boolean includeAllJarsInLib) { this.includeAllJarsInLib = includeAllJarsInLib; return this; }
这样改造之后如果你没有使用多数据源的话就和原来一样不需要任何变化,如果有多数据源的话你就只需要配置一个你处在不同package下的多数据源的Model以及一个configName就行了:
例如:数据源datasource1的model处在com.test.model.ds1下
//自动绑定数据库表() AutoTableBindPlugin atbp1= new AutoTableBindPlugin(c3p0Plugin1,SimpleNameStyles.LOWER); //扫描com.test.model.ds1下的model atbp1.scanPackages("com.test.model.ds1"); atbp1.setShowSql(true); //不扫描没有注解的Model类 atbp1.autoScan(false); me.add(atbp1);
此处没有配置configName表示的是主数据源,也可以配置一个
如果数据源datasource2的model处在com.test.model.ds2下就在上面代码中只需要改变这两个地方就行。如下:
//指定configName以及相应的数据源配置AutoTableBindPlugin atbp2= new AutoTableBindPlugin("configName",c3p0Plugin2,SimpleNameStyles.LOWER);//指定需要扫描的包名atbp2.scanPackages("com.test.model.ds2");
这样的好处就是如果你项目之前没有使用多数据源原来的代码不需要任何改变,后面才加入的多数据源的话你只需要配置下这个数据源下Model所在的包名就行了,就算你某个数据源的Model分散在几个包下atbp1.scanPackages("xxx.xxx1","xxx.xxx2")也是可以配置多个的。如果你多个数据源的Model都放在某个包下,那.... 只能说你包结构有些混乱了至少要区分下吧,这样的话你还是一个Model一个Model的映射吧,或许有更好的解决办法。目前我觉得这样还是挺方便的。