簡單實現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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章