前言:在写《来!认识一下强大的Annotation》的时候我说大家喜欢我就再写一篇详细介绍和一篇实例文章。
现在我兑现了我的承诺,并且写了2篇实例文章,感谢大家的支持和关注~
阅读此文前建议先看《来!认识一下强大的Annotation》、《Annotation详细介绍》两篇文章。
另一篇实例文章《model自动生成对应crud sql》
1.本例能干什么?
- 一个通用的将任何类型的object和数据库进行交互
- 注意是任何类型的object哦,所以是通用型。
- 保证通用的前提是您的model必须使用DbInfo、Id、columns 三个annotation进行标记
2.实现步骤:
- 创建三个annotation(DbInfo、Id、columns)。
- 创建User类,并用上面三个annotation对相应元素进行标记。
- 实现DbApDbAp相关方法。
- 编写AnnotationDbTest类来测试上面的方法
- 通用性测试,编写一个新的类来测试其通用性
3.说明:
- 程序存在不完善的地方,有兴趣的朋友可以自己进行完善。
1.每次都要重新读取object的信息,这样及其不好,应该对于同类的只读一次。
2.只实现了 创建数据表、插入方法和查询方法,其余方法类似 请自己实现。
3.采用的是hashmap 所以遍历出来的字段顺序并不是想像中的顺序。 - 本例抛砖引玉,沿着这个思路其实有很多拓展方向,自己动动脑考虑一下吧。
- 为什么我总爱说 抛砖引玉?
1.写一个完善的成型的程序 是需要花费大量时间的,这也是例子存在很多不完善的原因。
2.一个完善的程序势必会包含很多独特的业务逻辑和验证,会使得代码庞大且复杂 不利于学习。
3.所以我的文章总爱说 抛砖引玉,技术和思路分享给你,怎么用就是各位的事了~
定义3个annotation
package com.cxy.annotation.db;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author cxy
* 将annotation都定义在这个文件方便看
*/
public class AnnotationPool{}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface DbInfo
{
String url(); //数据库地址
String un(); //数据库连接用户名
String pw(); //数据库连接密码
String tableName(); //model对应数据表
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Id
{
String column(); //数据库对应字段
String describe(); //字段描述
String generator() default "uuid"; //id生成方式,默认是uuid
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface columns
{
String type(); //数据库类型
String column(); //数据库对应字段
int length() default 200; //数据库字段长度
String describe(); //字段描述
}
编写annotation处理器
package com.cxy.annotation.db;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.sql.rowset.CachedRowSet;
import javax.sql.rowset.RowSetFactory;
import javax.sql.rowset.RowSetProvider;
/** 通用处理器
* @author cxy
*/
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedAnnotationTypes({"DbInfo","Id","columns"})
public class DbAp
{
static CachedRowSet crs;
public static void saveToDb(Object obj) throws Exception
{
Map<String,String> dbInfo=new HashMap<>(); //用来存储数据库相关信息
Map<String,String> pkInfo=new HashMap<>(); //主键信息
Map<String,Map<String,Object>> columnInfo=new HashMap<>(); //字段信息
Class clz=obj.getClass();
//获取对象的信息
getClassInfo(clz, dbInfo, pkInfo, columnInfo);
//插入操作
String uuid=UUID.randomUUID().toString().replaceAll("-", "");
String insertSql="";
String colStr="("+pkInfo.get("c")+",";
String val="('"+uuid+"',";
//拼装insert语句
insertSql="insert into "+dbInfo.get("table")+" ";
for(String one : columnInfo.keySet())
{
colStr+=one+",";
String methodName="get"+String.valueOf(one.charAt(0)).toUpperCase()+one.substring(1);
Method m=clz.getMethod(methodName, null);
Object valObj=m.invoke(obj, null);
if(valObj instanceof String)
{
val+="'"+valObj+"',";
}
if(valObj instanceof Integer)
{
val+=valObj+",";
}
}
colStr=colStr.substring(0, colStr.length()-1);
val=val.substring(0, val.length()-1);
insertSql=insertSql+colStr+") values "+val+");";
//System.out.println(insertSql);
crs.setCommand(insertSql);
crs.execute();
crs.close();
System.out.println(obj.toString()+"插入成功");
}
public static void deleteToDb(Object obj) throws Exception{}
public static void updateToDb(Object obj) throws Exception{}
public static void queryFromDb(Class clz) throws Exception
{
Map<String,String> dbInfo=new HashMap<>(); //用来存储数据库相关信息
Map<String,String> pkInfo=new HashMap<>(); //主键信息
Map<String,Map<String,Object>> columnInfo=new HashMap<>(); //字段信息
//获取对象的信息
getClassInfo(clz, dbInfo, pkInfo, columnInfo);
//查询语句
StringBuilder sql= new StringBuilder("");
sql.append("select ");
for(String one : columnInfo.keySet())
{
sql.append(one+" as "+columnInfo.get(one).get("d")+",");
}
sql.delete(sql.length()-1, sql.length());
sql.append(" from "+dbInfo.get("table"));
crs.setCommand(sql.toString());
crs.execute();
//通用型遍历
ResultSetMetaData rsm=crs.getMetaData();
int colNum=rsm.getColumnCount();
String[] colName=new String[colNum]; //字段名
String[] colLabel=new String[colNum]; //别名
for(int i=1;i<=colNum;i++)
{
colName[i-1]=rsm.getColumnName(i);
colLabel[i-1]=rsm.getColumnLabel(i);
}
//把结果集封装成List<Map<String,String>>
List<Map<String,String>> dbData=new ArrayList<>();
while(crs.next())
{
Map<String,String> one = new HashMap<String, String>();
for(int i=1;i<=colNum;i++)
{
one.put(colLabel[i-1], crs.getString(i));
}
dbData.add(one);
}
//System.out.println(dbData);
for(String one:colLabel)
{
System.out.print(one+"\t\t");
}
System.out.println();
for(Map<String,String> one : dbData)
{
for(String one1:colLabel)
{
System.out.print(one.get(one1)+"\t\t");
}
System.out.println();
}
}
/**生成数据库操作
* @param clz
* @throws Exception
*/
public static void createTable(Class clz,Map<String,String> dbInfo, Map<String,String>pkInfo,Map<String,Map<String,Object>> columnInfo) throws Exception
{
//数据库信息
if(clz.isAnnotationPresent(DbInfo.class))
{
DbInfo d=(DbInfo) clz.getAnnotation(DbInfo.class);
dbInfo.put("url",d.url());
dbInfo.put("un",d.un());
dbInfo.put("pw",d.pw());
dbInfo.put("table",d.tableName());
}
RowSetFactory rsf=RowSetProvider.newFactory();
crs=rsf.createCachedRowSet();
crs.setUrl(dbInfo.get("url"));
crs.setUsername(dbInfo.get("un"));
crs.setPassword(dbInfo.get("pw"));
StringBuilder sql= new StringBuilder("CREATE TABLE IF NOT EXISTS ");
sql.append(dbInfo.get("table"));
sql.append(" ( ");
sql.append(pkInfo.get("c")+" "+pkInfo.get("t")+" NOT NULL UNIQUE PRIMARY KEY,");
for(String one : columnInfo.keySet())
{
sql.append(one +" "+columnInfo.get(one).get("t")+"("+columnInfo.get(one).get("l")+"),");
}
sql.delete(sql.length()-1, sql.length());
sql.append(" );");
crs.setCommand(sql.toString());
crs.execute();
}
/** 获取对类信息
*/
private static void getClassInfo(Class clz, Map<String, String> dbInfo,
Map<String, String> pkInfo,
Map<String, Map<String, Object>> columnInfo) throws Exception
{
//遍历所有字段包括私有的
for(Field f:clz.getDeclaredFields())
{
//System.out.println(f.getName());
//关键字信息
if(f.isAnnotationPresent(Id.class))
{
Id id=f.getAnnotation(Id.class);
pkInfo.put("t",jtd(f.getClass().getSimpleName().toString())+"(32)");
pkInfo.put("c",id.column());
pkInfo.put("d",id.describe());
pkInfo.put("u",id.generator());
}
//获取字段信息
Map<String,Object> tempOne=null;
if(f.isAnnotationPresent(columns.class))
{
columns c=f.getAnnotation(columns.class);
tempOne =new HashMap<>();
tempOne.put("t", jtd(c.type()));
tempOne.put("c", c.column());
tempOne.put("d", c.describe());
tempOne.put("l", c.length());
columnInfo.put(f.getName().toString(), tempOne);
}
}
createTable(clz,dbInfo,pkInfo,columnInfo); //如果表不存在那么就创建数据表
// System.out.println("annotation信息获取结束。");
// System.out.println(dbInfo);
// System.out.println(pkInfo);
// System.out.println(columnInfo);
}
/** javaTypeToDbType、java类型和数据库类型的转换
* @param type String
* @return VARCHAR
*/
public static String jtd(String type)
{
if("String".equals(type)) return "varchar";
if("int".equals(type)) return "int";
//其他的自己扩展吧
return "varchar";
}
}
编写一个User类,用定义好的三个annotation标记(修饰)
package com.cxy.annotation.db;
/**
* @author cxy
*/
@DbInfo(url="jdbc:mysql://localhost/dbtest",un="root",pw="root",tableName="t_test_user")
public class User
{
@Id(column="id_",describe="唯一标识")
private String id;
@columns(column="user_name_",describe="用户名",type="string")
private String userName;
@columns(column="friend_num_",describe="好友数量",type="int",length=10)
private int friendNum;
public User(String id, String userName, int friendNum)
{
super();
this.id = id;
this.userName = userName;
this.friendNum = friendNum;
}
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public String getUserName()
{
return userName;
}
public void setUserName(String userName)
{
this.userName = userName;
}
public int getFriendNum()
{
return friendNum;
}
public void setFriendNum(int friendNum)
{
this.friendNum = friendNum;
}
}
写一个测试类
package com.cxy.annotation.db;
/**
* @author cxy
*/
public class AnnotationDbTest
{
public static void main(String[] args) throws Exception
{
//创建对象 然后使用DbApDbAp.saveToDb(object); 将其保存到数据库
//id不用给值,后面会自动生成
User u1=new User("", "cxy", 1000);
User u2=new User("", "lyh", 100);
DbAp.saveToDb(u1);
DbAp.saveToDb(u2);
DbAp.queryFromDb(User.class);
System.out.println("========================");
Article a1=new Article("", "标题", "内容", 100);
Article a2=new Article("", "标题1", "内容1", 200);
DbAp.saveToDb(a1);
DbAp.saveToDb(a2);
DbAp.queryFromDb(Article.class);
}
}
写一个新的测试对象类,来测试其通用性
package com.cxy.annotation.db;
/** 文章类 用于测试apt的通用性
* @author cxy
*/
@DbInfo(url="jdbc:mysql://localhost/dbtest",un="root",pw="root",tableName="t_test_article")
public class Article
{
@Id(column="sid",describe="文章唯一标识")
private String sid=""; //文章id
@columns(column="title_",describe="标题",type="string")
private String title="";
@columns(column="content_",describe="内容",type="string",length=2000)
private String content="";
@columns(column="click_num_",describe="点击量",type="int")
private int clickNum =0;
public Article(String sid, String title, String content, int clickNum)
{
super();
this.sid = sid;
this.title = title;
this.content = content;
this.clickNum = clickNum;
}
public String getSid()
{
return sid;
}
public void setSid(String sid)
{
this.sid = sid;
}
public String getTitle()
{
return title;
}
public void setTitle(String title)
{
this.title = title;
}
public String getContent()
{
return content;
}
public void setContent(String content)
{
this.content = content;
}
public int getClickNum()
{
return clickNum;
}
public void setClickNum(int clickNum)
{
this.clickNum = clickNum;
}
}
结果图:
声明:
1.原创文章,转载请标明并加本文连接。
2.文章反映个人愚见,如有异议欢迎讨论指正