【IT168 技术文档】小弟关注Groovy已有数月(您可以到Groovy官方网站 http://groovy.codehaus.org 下载),发现其极具魅力,故在我参加的学校'创新试验项目'中,就用它来实现最简易的ORM,做的非常简单,主要原因是没有时间,因为小弟学业繁重,所以抽出一个下午的时间来实现一个简易版的ORM,数据库用的是MySQL。现在简单说明一下所示代码,将User类的一个实例通过save方法保存到数据库中,然后再根据给定条件通过findBy方法从数据库中取出实例,最后删除一个特定实例。由于深知通过XML文件进行配置的痛苦,所以在设计时没有用到任何XML文件。此程序让程序员只需关注自己要处理的对象,而不用关心数据库方面的东西,简化开发过程。最后我想说明的是,由于时间问题,所以编码方面只注重算法的体现,没有考虑其他方面。下面给出的代码仅供演示及参考(源码已经上传,点击下载):
1 package edu.ecust.orm 2 3 import groovy.sql.Sql 4 import groovy.text.Template 5 import groovy.text.SimpleTemplateEngine 6 7 public class User { 8 private int id 9 private String name 10 private int age 11 12 public User() {} 13 14 public User( int id) { 15 this .id = id 16 } 17 18 public User( int id, String name, int age) { 19 this.id = id 20 this.name = name 21 this.age = age 22 } 23 24 public int getId() { 25 return id 26 } 27 28 public void setId( int id) { 29 this.id = id 30 } 31 32 public String getName() { 33 return name 34 } 35 36 public void setName(String name) { 37 this.name = name 38 } 39 40 public int getAge() { 41 return age 42 } 43 44 public void setAge( int age) { 45 this.age = age 46 } 47 48 49 50 public String toString() { 51 return name + "(#" + id + ", " + age + ")" 52 } 53 } 54 55 typemap = [ "int" : "INTEGER" , "java.lang.Integer" : "INTEGER" , "long" : "BIGINT", "java.lang.Long" : "BIGINT" , "short" : "SMALLINT" , "java.lang.Short" : "SMALLINT" ,"byte" : "TINYINT" , "java.lang.Byte" : "TINYINT" , "float" : "FLOAT" , "java.lang.Float": "FLOAT" , "double" : "DOUBLE" , "java.lang.Double" : "DOUBLE" , "java.math.BigDecimal": "NUMERIC" , "char" : "CHAR(1)" , "java.lang.Character" : "CHAR(1)" , "java.lang.String": "VARCHAR(50)" , "boolean" : "BIT" , "java.lang.Boolean" : "BIT" ] 56 57 def capitalize(str) { 58 def c = str.charAt( 0 ) 59 int asci = ( int )c 60 if (asci > 96 && asci < 123 ) { 61 return (( char )(asci - 32 )).toString() + str.substring( 1 ) 62 } 63 } 64 65 def user = new User( 1 , "Daniel" , 21 ) 66 67 def connect() { 68 return Sql.newInstance( 69 "jdbc:mysql://localhost:3306/orm" , "root" , 70 "1106" , "com.mysql.jdbc.Driver" ) 71 } 72 73 def pointToLine(str) { 74 return str.replaceAll( "\\p{Punct}" , "_" ) 75 } 76 77 def getFields(u) { 78 def clazz = u.getClass() 79 def fields = clazz.getDeclaredFields() 80 def fieldunit = [:] 81 for (f in fields) { 82 def fstr = f.toString() 83 if (fstr.startsWith( "private" )) { 84 def fieldname = fstr.substring(fstr.lastIndexOf( "." ) + 1 ) 85 def methodname = "get" + capitalize(fieldname) 86 fieldunit.put(fieldname, clazz.getMethod(methodname).invoke(u)) 87 } 88 } 89 90 return fieldunit 91 } 92 93 tablename = ""; 94 def save(u) { 95 def clazz = u.getClass() 96 def classname = clazz.getName() 97 def classunit = [:] 98 fieldunit = getFields(u) 99 classunit.put(classname, fieldunit) 100 def keySet = classunit.keySet() 101 def it = keySet.iterator() 102 def fields 103 while (it.hasNext()) { 104 tablename = it.next() 105 fields = classunit.get(tablename) 106 } 107 tablename = pointToLine(tablename) 108 def fkeySet = fields.keySet() 109 def fit = fkeySet.iterator() 110 def creationstmt = "" 111 112 def order = [:] 113 def num = 0 114 while (fit.hasNext()) { 115 def fieldname = fit.next() 116 def fieldvalue = fields.get(fieldname) 117 if ( "id" == fieldname) { 118 creationstmt += "id INTEGER PRIMARY KEY not null," 119 } else { 120 creationstmt += fieldname + " " + typemap.get(fieldvalue.getClass().getName()) + "," 121 } 122 order.put(num++ , fieldname) 123 } 124 creationstmt = creationstmt.substring( 0 , creationstmt.length() - 1 ) 125 def valuestr = "(" 126 def vkeySet = order.keySet() 127 def vit = vkeySet.iterator() 128 params = "(" 129 while (vit.hasNext()) { 130 def elem = vit.next() 131 def v = order.get(elem) 132 valuestr += "'\${" + v + "}'," 133 params += "`" + v + "`," 134 } 135 valuestr = valuestr.substring( 0 , valuestr.length() - 1 ) 136 params = params.substring( 0 , params.length() - 1 ) 137 valuestr += ")" 138 params += ")" 139 def insertstmt = "INSERT INTO `" + tablename + "`" + params + " VALUES" 140 insertstmt += valuestr 141 def engine = new SimpleTemplateEngine() 142 def template = engine.createTemplate(insertstmt).make(fields) 143 insertstmt = template.toString() 144 def createstmt = """ 145 CREATE TABLE IF NOT EXISTS `""" + tablename + """` 146 ( 147 """ + creationstmt + """ 148 ); 149 """ 150 try { 151 def sql = connect() 152 sql.execute(createstmt) 153 sql.execute(insertstmt) 154 155 } catch (Exception e) { 156 int id = u.getId() 157 id++ 158 u.setId(id) 159 save(u) 160 //println e.getMessage() 161 } 162 163 return u.getId() 164 } 165 166 def delete(u) { 167 try { 168 def id = u.getId() 169 def sql = connect() 170 def result = sql.execute("DELETE FROM `" + tablename + "` WHERE id=" + id); 171 println "delete operation completed!" 172 } catch (Exception e) { 173 println e.getMessage() 174 } 175 } 176 177 def findBy(classname, condition) { 178 def sql = connect() 179 objs = [] 180 sql.eachRow( "select * from " + pointToLine(classname) + " where " + condition) { 181 obj = Class.forName(classname).newInstance() 182 183 def clazz = obj.getClass() 184 def fields = clazz.getDeclaredFields() 185 def methods = clazz.getDeclaredMethods() 186 for (f in fields) { 187 def fstr = f.toString() 188 if (fstr.startsWith( "private" )) { 189 def fieldname = fstr.substring(fstr.lastIndexOf( "." ) + 1 ) 190 def setmethodname = "set" + capitalize(fieldname) 191 def setmethod 192 for (m in methods) { 193 def methodname = m.toString() 194 if (methodname.contains(setmethodname)) { 195 setmethod = m 196 } 197 } 198 def fieldvalue = it.getProperty(fieldname) 199 setmethod.invoke(obj, fieldvalue) 200 } 201 } 202 203 objs.add(obj) 204 } 205 206 return objs 207 } 208 209 println "Id of the saved object is " + save(user) 210 println "Found " + findBy( "edu.ecust.orm.User" , "id = '11'" ) 211 userToDelete = new User(12, "Daniel", 21) 212 delete(userToDelete) 213