`

annotation实现数据映射

    博客分类:
  • java
阅读更多

 

前言:在写《来!认识一下强大的Annotation》的时候我说大家喜欢我就再写一篇详细介绍和一篇实例文章。

现在我兑现了我的承诺,并且写了2篇实例文章,感谢大家的支持和关注~

阅读此文前建议先看《来!认识一下强大的Annotation》《Annotation详细介绍》两篇文章。

 另一篇实例文章《model自动生成对应crud sql》

 

1.本例能干什么?

  • 一个通用的将任何类型的object和数据库进行交互
  • 注意是任何类型的object哦,所以是通用型。
  • 保证通用的前提是您的model必须使用DbInfo、Id、columns 三个annotation进行标记

2.实现步骤:

  1. 创建三个annotation(DbInfo、Id、columns)。
  2. 创建User类,并用上面三个annotation对相应元素进行标记。
  3. 实现DbApDbAp相关方法。
  4. 编写AnnotationDbTest类来测试上面的方法
  5. 通用性测试,编写一个新的类来测试其通用性

3.说明:

  1. 程序存在不完善的地方,有兴趣的朋友可以自己进行完善。
    1.每次都要重新读取object的信息,这样及其不好,应该对于同类的只读一次。
    2.只实现了 创建数据表、插入方法和查询方法,其余方法类似 请自己实现。
    3.采用的是hashmap 所以遍历出来的字段顺序并不是想像中的顺序。
  2. 本例抛砖引玉,沿着这个思路其实有很多拓展方向,自己动动脑考虑一下吧。
  3. 为什么我总爱说 抛砖引玉?
    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.文章反映个人愚见,如有异议欢迎讨论指正

 

  • 大小: 38.6 KB
5
0
分享到:
评论
7 楼 city_moon 2014-04-17  
city_moon 写道
东西写的真心不错,清晰,明了。一看就懂,学习了!
但是,我把上面的代码贴到eclipse中,jdk1.7的,部是报错无法编译通过,请问是什么原因?
具体报错信息和位置是以下几行:
1、报错信息:DbInfo cannot be resolved to a type;

if (clz.isAnnotationPresent(DbInfo.class)) {
DbInfo d = (DbInfo) clz.getAnnotation(DbInfo.class);

2、Bound mismatch: The generic method getAnnotation(Class<T>) of type AnnotatedElement is not applicable for the arguments (Class<Id>). The inferred type Id is not a valid substitute for the bounded parameter <T extends Annotation>

Id cannot be resolved to a type

if (f.isAnnotationPresent(Id.class)) {
Id id = f.getAnnotation(Id.class);

if (f.isAnnotationPresent(columns.class)) {
columns c = f.getAnnotation(columns.class);




问题解决了,是因为我放在了不同的包下面,移到一个包下面就没有问题了!
6 楼 city_moon 2014-04-17  
东西写的真心不错,清晰,明了。一看就懂,学习了!
但是,我把上面的代码贴到eclipse中,jdk1.7的,部是报错无法编译通过,请问是什么原因?
具体报错信息和位置是以下几行:
1、报错信息:DbInfo cannot be resolved to a type;

if (clz.isAnnotationPresent(DbInfo.class)) {
DbInfo d = (DbInfo) clz.getAnnotation(DbInfo.class);

2、Bound mismatch: The generic method getAnnotation(Class<T>) of type AnnotatedElement is not applicable for the arguments (Class<Id>). The inferred type Id is not a valid substitute for the bounded parameter <T extends Annotation>

Id cannot be resolved to a type

if (f.isAnnotationPresent(Id.class)) {
Id id = f.getAnnotation(Id.class);

if (f.isAnnotationPresent(columns.class)) {
columns c = f.getAnnotation(columns.class);

5 楼 snkcxy 2013-04-28  
LinApex 写道
测试了性能没有。

没有 这仅仅是一个应用的展示  并不是什么直接可用的框架或者成型的组建啥的
就是 举个给annotation举个例子
4 楼 LinApex 2013-04-27  
测试了性能没有。
3 楼 snkcxy 2013-03-13  
lishl 写道
支持原创,支持分享。谢谢。

感谢支持~
2 楼 lishl 2013-03-13  
支持原创,支持分享。谢谢。
1 楼 Androclus 2013-03-07  
java 7 了啊~~我还6呢。。

相关推荐

    hibernate annotation 中文文档

    用cascading实现传播性持久化(Transitive persistence) 2.2.5.5. 关联关系获取 2.2.6. 映射复合主键与外键 2.2.7. 映射二级表(secondary tables) 2.3. 映射查询 2.3.1. 映射EJBQL/HQL查询 2.3.2. 映射本地化查询 ...

    damapping:DA 映射框架

    数据映射框架DAMapping 框架是一个组件。 DAMapping 框架帮助开发人员将 bean 映射代码构建为专用于实现 bean 映射的类,并使她或他免于编写所有接口 + 类的良好实践,以实现可测试性和轻松保持关注点分离。 为此,...

    Struts2.1Spring2.5IBatisJQuery框架

    3) 利用Spring的@Service、@Repository两个Annotation来实现Service类、DAO类在Spring容器中的自动注册,利用@Autowired来实现Service与其他对象的引用。 通过框架提供的以上组件,除了基本的配置,如数据源、事务等...

    CRM-master.zip

    于 JavaEE 相关技术实现的"客户关系管理系统"。CRM(Customer Relationship Management) 即...Hibernate 4.x:数据持久化技术实现(实体关系映射采用 Annotation 方式实现) MySQL:数据库系统 Tomcat:JavaEE应用服务器

    openjpa实体标识的生成策略

    JPA 充分利用了注释(Annotation)和对象/关系映射,为数据持久化提供了更简单、易用的编程方式。OpenJPA 是 Apache 组织提供的 JPA 标准实现。本文是 使用 Apache OpenJPA 开发 EJB 3.0 应用系列 的第五部分,介绍...

    低清版 大型门户网站是这样炼成的.pdf

    4.3.1 hibernate的基本映射数据类型 212 4.3.2 hibernate的主键映射 218 4.3.3 hibernate的实体映射 228 4.3.4 映射一对一关联关系 228 4.3.5 映射多对一单向关联关系 235 4.3.6 映射一对多双向关联关系 239 ...

    JAVA_API1.6文档(中文)

    javax.sql.rowset.serial 提供实用工具类,允许 SQL 类型与 Java 编程语言数据类型之间的可序列化映射关系。 javax.sql.rowset.spi 第三方供应商在其同步提供者的实现中必须使用的标准类和接口。 javax.swing 提供...

    hibernate 框架详解

    XML映射元数据 19.3. 操作XML数据 20. 提升性能 20.1. 抓取策略(Fetching strategies) 20.1.1. 操作延迟加载的关联 20.1.2. 调整抓取策略(Tuning fetch strategies) 20.1.3. 单端关联代理(Single-ended ...

    Hibernate_3.2.0_符合Java习惯的关系数据库持久化

    18.2. XML映射元数据 18.3. 操作XML数据 19. 提升性能 19.1. 抓取策略(Fetching strategies) 19.1.1. 操作延迟加载的关联 19.1.2. 调整抓取策略(Tuning fetch strategies) 19.1.3. 单端关联代理(Single-...

    Hibernate+中文文档

    18.2. XML映射元数据 18.3. 操作XML数据 19. 提升性能 19.1. 抓取策略(Fetching strategies) 19.1.1. 操作延迟加载的关联 19.1.2. 调整抓取策略(Tuning fetch strategies) 19.1.3. 单端关联代理(Single-...

    Hibernate参考文档

    18.2. XML映射元数据 18.3. 操作XML数据 19. 提升性能 19.1. 抓取策略(Fetching strategies) 19.1.1. 操作延迟加载的关联 19.1.2. 调整抓取策略(Tuning fetch strategies) 19.1.3. 单端关联代理(Single-ended ...

    hibernate 体系结构与配置 参考文档(html)

    使用 JDK 5.0 的注解(Annotation) 5.6. 数据库生成属性(Generated Properties) 5.7. 辅助数据库对象(Auxiliary Database Objects) 6. 集合类(Collections)映射 6.1. 持久化集合类(Persistent collections) ...

    JAVA上百实例源码以及开源项目源代码

     Java实现的FTP连接与数据浏览程序,实现实例化可操作的窗口。  部分源代码摘录:  ftpClient = new FtpClient(); //实例化FtpClient对象  String serverAddr=jtfServer.getText(); //得到服务器地址  ...

    Hibernate中文详细学习文档

    18.2. XML映射元数据 18.3. 操作XML数据 19. 提升性能 19.1. 抓取策略(Fetching strategies) 19.1.1. 操作延迟加载的关联 19.1.2. 调整抓取策略(Tuning fetch strategies) 19.1.3. 单端关联代理(Single-...

    HibernateAPI中文版.chm

    18.2. XML映射元数据 18.3. 操作XML数据 19. 提升性能 19.1. 抓取策略(Fetching strategies) 19.1.1. 操作延迟加载的关联 19.1.2. 调整抓取策略(Tuning fetch strategies) 19.1.3. 单端关联代理(Single-...

    hibernate3.2中文文档(chm格式)

    18.2. XML映射元数据 18.3. 操作XML数据 19. 提升性能 19.1. 抓取策略(Fetching strategies) 19.1.1. 操作延迟加载的关联 19.1.2. 调整抓取策略(Tuning fetch strategies) 19.1.3. 单端关联代理(Single-...

    Hibernate 中文 html 帮助文档

    18.2. XML映射元数据 18.3. 操作XML数据 19. 提升性能 19.1. 抓取策略(Fetching strategies) 19.1.1. 操作延迟加载的关联 19.1.2. 调整抓取策略(Tuning fetch strategies) 19.1.3. 单端关联代理(Single-ended ...

    hibernate3.04中文文档.chm

    19.2. XML映射元数据 19.3. 操作XML数据 20. 提升性能 20.1. 抓取策略(Fetching strategies) 20.1.1. 操作延迟加载的关联 20.1.2. 调整抓取策略(Tuning fetch strategies) 20.1.3. 单端关联代理(Single-...

    Hibernate教程

    19.2. XML映射元数据 19.3. 操作XML数据 20. 提升性能 20.1. 抓取策略(Fetching strategies) 20.1.1. 操作延迟加载的关联 20.1.2. 调整抓取策略(Tuning fetch strategies) 20.1.3. 单端关联代理(Single-...

    最全Hibernate 参考文档

    18.2. XML映射元数据 18.3. 操作XML数据 19. 提升性能 19.1. 抓取策略(Fetching strategies) 19.1.1. 调整抓取策略(Tuning fetch strategies) 19.1.2. 单端关联代理(Single-ended association proxies) ...

Global site tag (gtag.js) - Google Analytics