1. 注解在Nutz中的应用
在nutz中,和数据库对应的pojo,我们可以使用注解的方式来配置field和table的column之间的对应,也可以用注解来配置两个pojo之间的关系,例如我有一个POJO,名字叫"Box",里面包含两个字段:
(1)
@Column("boxid")
@Id
private int id;
对于字段id,@Column("boxid")说明在数据库中对应column "boxid", @Id说明,这个是主键。
(2)
@Many(target = BoxInfo.class, field = "boxId")
private BoxInfo[] infos;
这个注解声明了Box和BoxInfo这两个POJO之间存在一对多的关系:Box----->多个 BoxInfo,也就是说给定一个boxid,您可以在BoxInfo对应的table里面找到多条记录,通过"boxId"与"Box"关联。如果我没有说清楚这个例子,您可以去参考nutz项目的wiki,你会发现更多实用的注解和介绍。
2.注解的简单介绍
我相信,在此之前,您一定使用过注解,我猜测您用过junit4,hibernate3,等等框架或工具,最起码你用过@Override(我不信你没用过这个)。
Annotation是jdk1.5引进的,它的引入给我们了一种新的手段来增加程序的信息,在src,class或runtime级别。程序员可以自己定义一些Annotation,然后把它用到自己的程序中,当然您还得编写自己的Annotation处理器。
3.简单的例子
(3.1) 假如我想定义两个Annotation(@TableName ,@Column)给POJO使用,@TableName用在POJO的类上,声明对应于数据库的哪个table,@Column用在POJO的field上,用于指明对应的column,那么我可以这么做:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableName{
String value();
}
@Target(ElementType.TYPE)说明了这是一个"类、接口(包括注释类型)或枚举声明",打开你的JDKAPI,去找“java.lang.annotation.ElementType”,您会发现更多的可选Target。
@Retention(RetentionPolicy.RUNTIME)指明"编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取"。
再来定义一个
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String value() default "";
}
(3.2) 把这两个注解应用到我的code中
@TableName("tbl_user")
public class User {
@Column
private int id;
@Column
private String name;
@Column("age")
private int userAge;
public int getId() {return id;}
public void setId(int id) {this.id = id;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public int getUserAge() {return userAge;}
public void setUserAge(int userAge) {this.userAge = userAge;}
}
(3.3) 假如我想写一个处理器,为使用这两个注解的POJO生成Insert语句,那么我可以这么做。(为了不使示例复杂,这里只考虑最天真幼稚的情况,并且把所有代码放在一块,您明白什么意思就行)。
public class SqlGetter {
public static void main(String[] args) throws Exception {
User user = new User();
user.setId(1);
user.setName("Tom");
user.setUserAge(12);
System.out.println(new SqlGetter().getInsertSql(user));
}
public String getInsertSql(Object obj) throws Exception {
//获取table名称
String tableName=obj.getClass().getAnnotation(TableName.class).value();
// 存放column---value
HashMap<String, Object> kvs = new HashMap<String, Object>();
Field[] fs = obj.getClass().getDeclaredFields();
for (Field f : fs) {
String cn = this.getFieldColumn(f);
if (cn != null) {
kvs.put(f.getName(), this.getFieldValue(obj,f));
}
}
//硬拼SQl
StringBuilder prefix = new StringBuilder();
StringBuilder suffix = new StringBuilder();
for(Iterator<String> it=kvs.keySet().iterator();it.hasNext();){
String key=it.next();
prefix.append(key);
suffix.append(kvs.get(key));
if (it.hasNext()) {
prefix.append(",");
suffix.append(",");
}
}
return String.format("INSERT INTO %s (%s) VALUES (%s)", tableName,prefix,suffix);
}
private String getFieldColumn(Field field) {
Column column = field.getAnnotation(Column.class);
if (column != null) {
if ("".equals(column.value()))
return field.getName();
else {
return column.value();
}
}
return null;
}
private Object getFieldValue(Object obj,Field field) throws Exception {
String name = field.getName();
String c = name.substring(0, 1);
name = name.replaceFirst(c, c.toUpperCase());
Method m = obj.getClass().getMethod("get" + name, new Class<?>[] {});
return m.invoke(obj, new Object[] {});
}
}
不出意外,输出应该是"INSERT INTO tbl_user (id,name,userAge) VALUES (1,Tom,12)"。
通过这个例子您会发现许多问题:
(1)代码结构差 (2)异常处理差 (3)结果都不对,因为sql语句没有给string类型加上引号。(4).....
但是,如果您之前对Annotation不是特别了解,但愿本文能起到一个抛砖引玉的作用。
最后,您可以去使用一下Nutz的dao功能,去体验一下Annotation给我们带来的便利。http://code.google.com/p/nutz/