Actframework是一款让人耳目一新的java mvc框架,简洁的api,强大的路由深深的吸引着我。
迁移项目到act的过程中,实在是接受不了ebean的sql操作,好在国产的beetlsql正中下怀,于是将其集成到act中,方便使用。本文涉及到的内容尚未经过严格测试,如有不到之处还请指出。
1package org.piaohao.act.beetlsql; 2 3import com.alibaba.druid.pool.DruidDataSource; 4import org.beetl.sql.core.*; 5import org.beetl.sql.core.db.DBStyle; 6import org.beetl.sql.core.db.MySqlStyle; 7import org.beetl.sql.ext.DebugInterceptor; 8 9/** 10 * <p>Created by piaohao on 2017/3/16 0016. 11 * 12 * @author piaohao 13 */ 14//@AutoConfig("db") 15public class ActBeetlsql { 16 17 /** 18 * 以下属性使用autoconfig注入存在问题,所以写死 19 */ 20 private static String driver = "com.mysql.jdbc.Driver"; 21 private static String url = "jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8"; 22 private static String userName = "root"; 23 private static String password = "root"; 24 25 private static SQLManager sqlManager; 26 27 public static void init() { 28 DruidDataSource ds = new DruidDataSource(); 29 ds.setUrl(url); 30 ds.setDriverClassName(driver); 31 ds.setUsername(userName); 32 ds.setPassword(password); 33 ConnectionSource source = ConnectionSourceHelper.getSingle(ds); 34 DBStyle mysql = new MySqlStyle(); 35 // sql语句放在classpagth的/sql 目录下 36 SQLLoader loader = new ClasspathLoader("/sql"); 37 // 数据库命名跟java命名一样,所以采用DefaultNameConversion,还有一个是UnderlinedNameConversion,下划线风格的, 38 //UnderlinedNameConversion nc = new UnderlinedNameConversion(); 39 DefaultNameConversion nc = new DefaultNameConversion(); 40 // 最后,创建一个SQLManager,DebugInterceptor 不是必须的,但可以通过它查看sql执行情况 41 sqlManager = new SQLManager(mysql, loader, source, nc, new Interceptor[]{new DebugInterceptor()}); 42 } 43 44 public static SQLManager dao() { 45 if (sqlManager != null) 46 return sqlManager; 47 else { 48 init(); 49 if (sqlManager != null) { 50 return sqlManager; 51 } 52 throw new RuntimeException("未初始化,需要调用init方法"); 53 } 54 } 55 56} 57 58 59package org.piaohao.act.beetlsql; 60 61import org.beetl.sql.core.SQLManager; 62import org.beetl.sql.core.mapper.DefaultMapperBuilder; 63import org.beetl.sql.core.mapper.MapperJavaProxy; 64import org.osgl.inject.Module; 65 66import java.lang.reflect.Proxy; 67import java.util.List; 68 69public class BeetlSqlModule extends Module { 70 71 @Override 72 protected void configure() { 73 final SQLManager sqlManager = ActBeetlsql.dao(); 74 /* 75 这个为dao接口所在包,实际可将路径配置到properties文件 76 */ 77 String packageName = "com.ridersunion.h5.dao"; 78 List<Class> classList = ClassUtil.getAllClass(packageName); 79 classList.forEach(clazz -> { 80 registerGenericTypedBeanLoader(clazz, spec -> { 81 Object dao = Proxy.newProxyInstance(App.class.getClassLoader(), 82 new Class<?>[]{clazz}, 83 new MapperJavaProxy(new DefaultMapperBuilder(sqlManager), sqlManager, clazz)); 84 return dao; 85 }); 86 }); 87 } 88} 89 90package org.piaohao.act.beetlsql; 91 92import java.io.File; 93import java.io.FileFilter; 94import java.io.IOException; 95import java.net.JarURLConnection; 96import java.net.URL; 97import java.net.URLDecoder; 98import java.util.ArrayList; 99import java.util.Enumeration; 100import java.util.List; 101import java.util.jar.JarEntry; 102import java.util.jar.JarFile; 103 104/** 105 * 类相关的工具类 106 */ 107public class ClassUtil { 108 109 public static void main(String[] args) throws Exception { 110 List<Class> classes = ClassUtil.getAllClass("com.ridersunion.h5.dao"); 111 for (Class clas : classes) { 112 System.out.println(clas.getName()); 113 } 114 } 115 116 /** 117 * 取得某个接口下所有实现这个接口的类 118 */ 119 public static List<Class> getAllClassByInterface(Class c) { 120 List<Class> returnClassList = null; 121 122 if (c.isInterface()) { 123 // 获取当前的包名 124 String packageName = c.getPackage().getName(); 125 // 获取当前包下以及子包下所以的类 126 List<Class<?>> allClass = getClasses(packageName); 127 if (allClass != null) { 128 returnClassList = new ArrayList<Class>(); 129 for (Class classes : allClass) { 130 // 判断是否是同一个接口 131 if (c.isAssignableFrom(classes)) { 132 // 本身不加入进去 133 if (!c.equals(classes)) { 134 returnClassList.add(classes); 135 } 136 } 137 } 138 } 139 } 140 141 return returnClassList; 142 } 143 144 /** 145 * 取得某个接口下所有实现这个接口的类 146 */ 147 public static List<Class> getAllClass(String packageName) { 148 List<Class> returnClassList = null; 149 // 获取当前包下以及子包下所以的类 150 List<Class<?>> allClass = getClasses(packageName); 151 if (allClass != null) { 152 returnClassList = new ArrayList<Class>(); 153 for (Class classes : allClass) { 154 returnClassList.add(classes); 155 } 156 } 157 return returnClassList; 158 } 159 160 161 /* 162 * 取得某一类所在包的所有类名 不含迭代 163 */ 164 public static String[] getPackageAllClassName(String classLocation, String packageName) { 165 //将packageName分解 166 String[] packagePathSplit = packageName.split("[.]"); 167 String realClassLocation = classLocation; 168 int packageLength = packagePathSplit.length; 169 for (int i = 0; i < packageLength; i++) { 170 realClassLocation = realClassLocation + File.separator + packagePathSplit[i]; 171 } 172 File packeageDir = new File(realClassLocation); 173 if (packeageDir.isDirectory()) { 174 String[] allClassName = packeageDir.list(); 175 return allClassName; 176 } 177 return null; 178 } 179 180 /** 181 * 从包package中获取所有的Class 182 * 183 * @return 184 */ 185 public static List<Class<?>> getClasses(String packageName) { 186 187 //第一个class类的集合 188 List<Class<?>> classes = new ArrayList<Class<?>>(); 189 //是否循环迭代 190 boolean recursive = true; 191 //获取包的名字 并进行替换 192 String packageDirName = packageName.replace('.', '/'); 193 //定义一个枚举的集合 并进行循环来处理这个目录下的things 194 Enumeration<URL> dirs; 195 try { 196 dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName); 197 //循环迭代下去 198 while (dirs.hasMoreElements()) { 199 //获取下一个元素 200 URL url = dirs.nextElement(); 201 //得到协议的名称 202 String protocol = url.getProtocol(); 203 //如果是以文件的形式保存在服务器上 204 if ("file".equals(protocol)) { 205 //获取包的物理路径 206 String filePath = URLDecoder.decode(url.getFile(), "UTF-8"); 207 //以文件的方式扫描整个包下的文件 并添加到集合中 208 findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes); 209 } else if ("jar".equals(protocol)) { 210 //如果是jar包文件 211 //定义一个JarFile 212 JarFile jar; 213 try { 214 //获取jar 215 jar = ((JarURLConnection) url.openConnection()).getJarFile(); 216 //从此jar包 得到一个枚举类 217 Enumeration<JarEntry> entries = jar.entries(); 218 //同样的进行循环迭代 219 while (entries.hasMoreElements()) { 220 //获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件 221 JarEntry entry = entries.nextElement(); 222 String name = entry.getName(); 223 //如果是以/开头的 224 if (name.charAt(0) == '/') { 225 //获取后面的字符串 226 name = name.substring(1); 227 } 228 //如果前半部分和定义的包名相同 229 if (name.startsWith(packageDirName)) { 230 int idx = name.lastIndexOf('/'); 231 //如果以"/"结尾 是一个包 232 if (idx != -1) { 233 //获取包名 把"/"替换成"." 234 packageName = name.substring(0, idx).replace('/', '.'); 235 } 236 //如果可以迭代下去 并且是一个包 237 if ((idx != -1) || recursive) { 238 //如果是一个.class文件 而且不是目录 239 if (name.endsWith(".class") && !entry.isDirectory()) { 240 //去掉后面的".class" 获取真正的类名 241 String className = name.substring(packageName.length() + 1, name.length() - 6); 242 try { 243 //添加到classes 244 classes.add(Class.forName(packageName + '.' + className)); 245 } catch (ClassNotFoundException e) { 246 e.printStackTrace(); 247 } 248 } 249 } 250 } 251 } 252 } catch (IOException e) { 253 e.printStackTrace(); 254 } 255 } 256 } 257 } catch (IOException e) { 258 e.printStackTrace(); 259 } 260 261 return classes; 262 } 263 264 /** 265 * 以文件的形式来获取包下的所有Class 266 * 267 * @param packageName 268 * @param packagePath 269 * @param recursive 270 * @param classes 271 */ 272 public static void findAndAddClassesInPackageByFile(String packageName, String packagePath, final boolean recursive, List<Class<?>> classes) { 273 //获取此包的目录 建立一个File 274 File dir = new File(packagePath); 275 //如果不存在或者 也不是目录就直接返回 276 if (!dir.exists() || !dir.isDirectory()) { 277 return; 278 } 279 //如果存在 就获取包下的所有文件 包括目录 280 File[] dirfiles = dir.listFiles(new FileFilter() { 281 //自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件) 282 public boolean accept(File file) { 283 return (recursive && file.isDirectory()) || (file.getName().endsWith(".class")); 284 } 285 }); 286 //循环所有文件 287 for (File file : dirfiles) { 288 //如果是目录 则继续扫描 289 if (file.isDirectory()) { 290 findAndAddClassesInPackageByFile(packageName + "." + file.getName(), 291 file.getAbsolutePath(), 292 recursive, 293 classes); 294 } else { 295 //如果是java类文件 去掉后面的.class 只留下类名 296 String className = file.getName().substring(0, file.getName().length() - 6); 297 try { 298 //添加到集合中去 299 classes.add(Class.forName(packageName + '.' + className)); 300 } catch (ClassNotFoundException e) { 301 e.printStackTrace(); 302 } 303 } 304 } 305 } 306} 307 308package org.piaohao.act.beetlsql; 309 310import act.Act; 311import act.job.OnAppStart; 312import org.osgl.mvc.annotation.GetAction; 313 314/** 315 * Hello world! 316 */ 317public class App { 318 319 @GetAction("/") 320 public String index() { 321 return "Hello Act!"; 322 } 323 324 @OnAppStart 325 public static void onAppStart() { 326 ActBeetlsql.init(); 327 } 328 329 public static void main(String[] args) throws Exception { 330 Act.start("Riders Union"); 331 } 332} 333 334 335package org.piaohao.act.beetlsql; 336 337import act.controller.Controller; 338import com.ridersunion.h5.dao.PlanDao; 339import com.ridersunion.h5.dao.UserDao; 340import org.osgl.mvc.annotation.GetAction; 341import org.osgl.util.C; 342 343import javax.inject.Inject; 344 345/** 346 * 欢迎<br> 347 * Created by Administrator on 2016/4/26 0026. 348 */ 349@Controller 350public class IndexController extends BaseController { 351 352 @Inject 353 private PlanDao planDao; 354 @Inject 355 private UserDao userDao; 356 357 @GetAction("/dao") 358 public void dao() { 359 json(C.map("plan", planDao.single(1), "user", userDao.all())); 360 } 361 362}