annotation实现数据映射
程序员文章站
2022-04-05 17:52:39
...
前言:在写《来!认识一下强大的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.文章反映个人愚见,如有异议欢迎讨论指正
推荐阅读
-
Kafka利用Java实现数据的生产和消费实例教程
-
如何利用FluentMigrator实现数据库迁移
-
php将mysql数据库整库导出生成sql文件的具体实现
-
Ajax+ASP和Flash+ASP数据读取取方法有些相似的实现方法
-
数据库中两张表之间的数据同步增加、删除与更新实现思路
-
微信小程序使用map组件实现获取定位城市天气或者指定城市天气数据功能
-
Python中使用scapy模拟数据包实现arp攻击、dns放大攻击例子
-
python中plot实现即时数据动态显示方法
-
Android开发使用json实现服务器与客户端数据的交互功能示例
-
VUE-Table上绑定Input通过render实现双向绑定数据的示例