简单实现JFinal注解配置Controller,Model

本人小菜一枚,表达能力也不是很好,哪里写了不好的地方请大神评论下。


首先写Controller对映的注解,这里我将其命名为C

这个注解现在比较简单些

package net.zz.annotation;
import java.lang.annotation.*;

/**
 * Created by ZaoSheng on 2015/5/24.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
public @interface C {
    String value();
}
首先写Model对映的注解,这里我将其命名为M这个注解现在也是比较简单些,呵呵!
package net.zz.annotation;

import java.lang.annotation.*;

/**
 * Created by ZaoSheng on 2015/5/28.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
public @interface M
{
    String value() default "";//这里默认为Model的名字小写
    String id() default "id";
}
注解写好了,接下来得写一个对类的扫描器.这里我写了也比较简单,主要只是为了实现这个Demo
package net.zz.plugin;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class Scan {
    private HttpServletRequest request;
    public Scan() {
    }

    public Scan(HttpServletRequest request) {
        this.request = request;
    }

    public  Set<Class<?>> getClasses(String pack) {
        
           // 第一个class类的集合  
           Set<Class<?>> classes = new LinkedHashSet<Class<?>>();  
           // 是否循环迭代  
           boolean recursive = true;  
           // 获取包的名字 并进行替换  
           String packageName = pack;  
           String packageDirName = packageName.replace('.', '/'); 
           
           // 定义一个枚举的集合 并进行循环来处理这个目录下的things  
           Enumeration<URL> dirs;  
           try {  
               dirs = Thread.currentThread().getContextClassLoader().getResources(  
                       packageDirName);  
               // 循环迭代下去  
               while (dirs.hasMoreElements()) {  
                   // 获取下一个元素  
                   URL url = dirs.nextElement();  
                   // 得到协议的名称  
                   String protocol = url.getProtocol();  
                   // 如果是以文件的形式保存在服务器上  
                   if ("file".equals(protocol)) {  

                       // 获取包的物理路径  
                       String filePath = URLDecoder.decode(url.getFile(), "UTF-8");  
                       // 以文件的方式扫描整个包下的文件 并添加到集合中  
                       findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);  
                   } else if ("jar".equals(protocol)) {  
                       // 如果是jar包文件  
                       // 定义一个JarFile  

                       JarFile jar;  
                       try {  
                           // 获取jar  
                           jar = ((JarURLConnection) url.openConnection())  
                                   .getJarFile();  
                           // 从此jar包 得到一个枚举类  
                           Enumeration<JarEntry> entries = jar.entries();  
                           // 同样的进行循环迭代  
                           while (entries.hasMoreElements()) {  
                               // 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件  
                               JarEntry entry = entries.nextElement();  
                               String name = entry.getName();  
                               // 如果是以/开头的  
                               if (name.charAt(0) == '/') {  
                                   // 获取后面的字符串  
                                   name = name.substring(1);  
                               }  
                               // 如果前半部分和定义的包名相同  
                               if (name.startsWith(packageDirName)) {  
                                   int idx = name.lastIndexOf('/');  
                                   // 如果以"/"结尾 是一个包  
                                   if (idx != -1) {  
                                       // 获取包名 把"/"替换成"."  
                                       packageName = name.substring(0, idx)  
                                               .replace('/', '.');  
                                   }  
                                   // 如果可以迭代下去 并且是一个包  
                                   if ((idx != -1) || recursive) {  
                                       // 如果是一个.class文件 而且不是目录  
                                       if (name.endsWith(".class")  
                                               && !entry.isDirectory()) {  
                                           // 去掉后面的".class" 获取真正的类名  
                                           String className = name.substring(  
                                                   packageName.length() + 1, name  
                                                           .length() - 6);  
                                           try {  
                                               // 添加到classes  
                                               classes.add(Class  
                                                       .forName(packageName + '.'  
                                                               + className));  
                                           } catch (ClassNotFoundException e) {  
                                               // log  
                                               // .error("添加用户自定义视图类错误 找不到此类的.class文件");  
                                               e.printStackTrace();  
                                           }  
                                       }  
                                   }  
                               }  
                           }  
                       } catch (IOException e) {  
                           // log.error("在扫描用户定义视图时从jar包获取文件出错");  
                           e.printStackTrace();  
                       }  
                   }  
               }  
           } catch (IOException e) {  
               e.printStackTrace();  
           }  
     
           return classes;  
       }  
    
    
    
      public  void findAndAddClassesInPackageByFile(String packageName,  
               String packagePath, final boolean recursive, Set<Class<?>> classes) {  
           // 获取此包的目录 建立一个File  
           File dir = new File(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.add(Class.forName(packageName + '.' + className));  
                                            //经过回复同学的提醒,这里用forName有一些不好,会触发static方法,没有使用classLoader的load干净  
                      Class<?> cls=Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className);
                            
                                           classes.add(cls);    
                                   } catch (ClassNotFoundException e) {  
                       // log.error("添加用户自定义视图类错误 找不到此类的.class文件");  
                       e.printStackTrace();  
                   }  
               }  
           }  
       }  
      
      
        
   public static void getName(String path) {  
          File file = new File(path);  
              if (file.isDirectory()) {  
                  File[] dirFile = file.listFiles();  
                  for (File f : dirFile) {  
                      if (f.isDirectory())  
                          getName(f.getAbsolutePath());  
                      else {  
                          if (f.getName().endsWith(".class"))  
                              System.out.println(f.getAbsolutePath());  
                      }  
                  }  
              }  
          }  

}
这个简单的扫描起就这样写完了,接下来就是最重要的JFinal配置的部分,实现注解处理适配的部分
编写一个抽象类JFinalConfig,这个配置类跟之前写的差不多,我们继承com.jfinal.config.JFinalConfig这个类,并实现下面这几个方法
public void configRoute(Routes me) 
public void configPlugin(Plugins me) 

编写三个抽象方法
/**
 * Scan control
 * @param controlPackage 存储需要扫描的control包
 */
protected abstract void controlSscan(List<String> controlPackage);

/**
 * Scan basePackage
 * @param basePackage 存储需要扫描的model包
 */
protected abstract void componentSscan(List<String> basePackage);

/**
 *  设置数据源
 * @param showSql 是否显示SQL, true为现实,默认为false
 * @return IDataSourceProvider
 */
protected abstract IDataSourceProvider setDataSource ();

controlSscan方法主要用于设置controller的扫描,componentSscan也是一样的意思。
setDataSource 这个方法配置数据源。
接下来一个是用于开发者进行需要时覆盖的方法,用于活动记录的插件添加
/**
 * 这里进行附加的活动记录的添加,
 * @param arp 活动记录插件
 */
public void addActiveRecord(ActiveRecordPlugin arp){}


下面是对应的具体代码。
package net.zz.config;
import com.jfinal.config.*;
import com.jfinal.core.Controller;
import com.jfinal.plugin.IPlugin;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.activerecord.IDataSourceProvider;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.c3p0.C3p0Plugin;
import net.zz.annotation.C;
import net.zz.annotation.M;
import net.zz.plugin.Scan;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
 * Created by ZaoSheng on 2015/5/24.
 */
public abstract class JFinalConfig  extends com.jfinal.config.JFinalConfig{
    private static final List<String> controlPackage = new ArrayList<String>();
    private static final List<String> basePackage = new ArrayList<String>();
    /**
     * Scan control
     * @param controlPackage 存储需要扫描的control包
     */
    protected abstract void controlSscan(List<String> controlPackage);
    /**
     * Scan basePackage
     * @param basePackage 存储需要扫描的model包
     */
    protected abstract void componentSscan(List<String> basePackage);
    /**
     *  设置数据源
     * @param showSql 是否显示SQL, true为现实,默认为false
     * @return IDataSourceProvider
     */
    protected abstract IDataSourceProvider setDataSource (boolean showSql);
    /**
     *  controller
     * @param me
     */
    @Override
    public void configRoute(Routes me) {
        controlSscan(controlPackage);//获取需要扫描的包
        //扫描器
        Scan driven = new Scan();
        for (String pake : controlPackage){
            Set<Class<?>> clazzs = driven.getClasses(pake);
            for (Class<?> clazz : clazzs) {
                System.out.println(clazz.getName());
               if (clazz.isAssignableFrom(com.jfinal.core.Controller.class)) {
                   C con = clazz.getAnnotation(C.class);
                   if (null != con) {
                       me.add(con.value(), (Class<? extends Controller>) clazz);
                   }
               }
            }
        }
    }
    /**
     * model
     * @param me
     */
    @Override
    public void configPlugin(Plugins me) {
         componentSscan(basePackage);
       
        IDataSourceProvider iDataSourceProvider = setDataSource();
        try {
            me.add((IPlugin) iDataSourceProvider);
        }catch (Exception e){
            throw new RuntimeException("is not IPlugin type");
        }
        ActiveRecordPlugin arp = new ActiveRecordPlugin(iDataSourceProvider);
        
        addActiveRecord(arp); // 加入附加的活动记录
        Scan driven = new Scan();
        for (String pake : controlPackage){
            Set<Class<?>> clazzs = driven.getClasses(pake);
            for (Class<?> clazz : clazzs) {
                System.out.println(clazz.getName());
                if (clazz.isAssignableFrom(com.jfinal.plugin.activerecord.Model.class)) {
                   M model = clazz.getAnnotation(M.class);
                    if (null != model) {
                        arp.addMapping(model.value(), model.id(), (Class<? extends Model<?>>) clazz);
                    }
                }
            }
        }
        me.add(arp);
    }
    /**
     * 这里进行附加的活动记录的添加,
     * @param arp 活动记录插件
     */
    protected void addActiveRecord(ActiveRecordPlugin arp){
           // arp.setShowSql(true);//设置是sql显示开关
 }
}


接下来是简单实现Config配置的例子
package net.zz.config;
import com.jfinal.plugin.activerecord.IDataSourceProvider;
import net.mzzo.inter.JsonCrossDomain;
import net.mzzo.inter.Login;
import com.jfinal.config.Constants;
import com.jfinal.config.Handlers;
import com.jfinal.config.Interceptors;
import com.jfinal.plugin.c3p0.C3p0Plugin;
import net.zz.config.JFinalConfig;
import java.util.List;
public class ZZConfig extends JFinalConfig {
   public void configConstant(Constants me) {
      loadPropertyFile("config.properties");
      me.setDevMode(getPropertyToBoolean("devMode", false));
   }
   public void configHandler(Handlers me) {
      
   }
    @Override
    public void controlSscan(List<String> list) {
        list.add("net.zz.controler");
        list.add("net.zz.util");
    }
    @Override
    public void componentSscan(List<String> list) {
        list.add("net.mzzo.model");
    }
    @Override
    public IDataSourceProvider setDataSource() {
        showSql = true;
        C3p0Plugin c3p0Plugin = new C3p0Plugin(getProperty("jdbcUrl"), getProperty("user"), getProperty("password"), getProperty("driverClass"), getPropertyToInt("maxPoolSize"), getPropertyToInt("minPoolSize"), getPropertyToInt("initialPoolSize"), getPropertyToInt("maxIdleTime"), getPropertyToInt("acquireIncrement"));
        return c3p0Plugin;
    }
    public void configInterceptor(Interceptors me) {
      me.add(new JsonCrossDomain());
      me.add(new Login());
   }
}
//接下来就是Controller的例子

@C("/users")
public class UsersControl extends Controller {

}
下面就是Model的例子

@M("users")
public class Users extends Model<Users> {

}


再次说下表达不是很好。
接下来的想法是将JFinal的Model部分稍微包装一下,github地址:https://github.com/cnzzs/zjf

你可能感兴趣的:(注解,配置,jFinal)