最近想实现用户自定义数据库中的字段,我想大部分人第一想到的就是EAV(Entity-Attribute-Value),这种方式对于写一个小的毕业设计应该还可以使用,当然也有很多CMS系统采用这种方式,毕竟其中Value表中的数据会猛增,同样,会涉及到查询优化问题,暂不考虑。
其次,在J2EE中,如果使用spring+hbiernate+springMVC(struts2),Entity类有两种方式和数据库进行映射,一种是注解方式,一种是*.hbm.xml配置文件方式。
①注解方式,对于注解方式,因为最终目的是根据自定义的字段可以实时的在数据库表中对其字段进行生成,然后可以使用,最初想到的解决方法是重写相应实体类的.class文件,然后根据最新的.class文件生成相应的*.hbm.xml文件,利用configuration重新读取*.hbm.xml文件来建立buildSessionFactory(下面会给出详细代码),最后发现即使实现了增加字段,也无法通过这种方式删除字段,不过还是看看往.class文件中写入field以及其getter/setter方法的java语句吧。
1 /*2 * 添加字段
3*/
4 public class AddFieldAdapter extendsClassAdapter {5
6 private intaccessModifier;7 privateString name;8 privateString desc;9 private booleanisFieldPresent;10
11 public AddFieldAdapter(ClassVisitor cv, intaccessModifier, String name,12String desc) {13 super(cv);14 this.accessModifier =accessModifier;15 this.name =name;16 this.desc =desc;17}18
19 public FieldVisitor visitField(intaccess, String name, String desc,20String signature, Object value) {21 if (name.equals(this.name)) {22 isFieldPresent = true;23}24 returncv.visitField(access, name, desc, signature, value);25}26
27 public voidvisitEnd() {28 if (!isFieldPresent) {29 FieldVisitor fv = cv.visitField(accessModifier, name, desc, null,30 null);31
32 if (null !=fv) {33fv.visitEnd();34}35}36cv.visitEnd();37}39 }
1 //创建get,public,无参数,有返回值
2 MethodVisitor mv = cWriter.visitMethod(Opcodes.ACC_PUBLIC, "get"
3 + StringUtils.capitalize(filedName), "()" + type, null,//type为返回的类型
4 null);5mv.visitCode();6 mv.visitVarInsn(Opcodes.ALOAD, 0);//将this压栈
7mv.visitFieldInsn(Opcodes.GETFIELD,8 this.entityClass.getSimpleName(), filedName, type);9mv.visitInsn(Opcodes.ARETURN);10 mv.visitMaxs(1, 1);11mv.visitEnd();12
13 //创建set方法,public,传递一个参数
14 mv = cWriter.visitMethod(Opcodes.ACC_PUBLIC,//方法名为public
15 "set" + StringUtils.capitalize(filedName), "(" + type //传递一个参数
16 + ")V", null, null);//V表示返回的是void
17 mv.visitCode();//开始执行
18 mv.visitVarInsn(Opcodes.ALOAD, 0);//将this压栈
19 mv.visitVarInsn(Opcodes.ALOAD, 1);//将局部变量压栈
20mv.visitFieldInsn(Opcodes.PUTFIELD,21 this.entityClass.getSimpleName(), filedName, type);22mv.visitInsn(Opcodes.ARETURN);23 mv.visitMaxs(2, 2);24 mv.visitEnd();//执行结束
关于如何将.class文件生成*.hbm.xml可以从网上找相关模板,借助模板将class文件转换生成xml配置文件方式,因为重点不采用这种方式,所以简单介绍下如何重写class文件即可,关于如何从*.hbm.xml文件重构sessionfactory映射到数据库中在稍后贴出代码。
②配置文件方式,配置文件的方式对于项目中使用本身就不是特别方便的(相对于注解来说),所有这种方式也是一开始只是为了尝试在重写了*.hbm.xml后是否可以通过代码的方式,在不重启服务器的情况下,将修改的内容实时的反映到我们的数据库中,所以在一开始的时候定义model或者entity时候,就应该写个与之对应的*.hbm.xml,例如下面这样。
1 /**
2 *实体类3 */
4 public class Contact extendsCustomizableEntity {5
6 /**
7 * ID8 */
9 private intid;10
11 /**
12 * 名称13 */
14 privateString name;15
16 public intgetId() {17 returnid;18 }19
20