`

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)

    **标题:“Hibernate继承映射(Annotation)详解”** 在Java持久化框架Hibernate中,继承映射是一种关键特性,它允许开发者将对象模型的继承结构映射到数据库的表结构。在传统的面向对象编程中,继承是实现代码复用和...

    java后台数据隔离实现方式

    从`操作流程.jpeg`来看,实现数据隔离的步骤可能包括: a) 设计数据权限模型,如定义`DataScope`枚举。 b) 在`SysUserServiceImpl`中,根据用户角色加载对应的数据范围。 c) 使用AOP切面`DataScopeAspect`拦截...

    compass annotation关联关系

    在 Compass 中,Annotation 是一种元数据注解方式,它允许开发者在对象模型上直接定义搜索映射,使得对象与索引之间的关系更加清晰,简化了搜索引擎的集成工作。 一、Compass Annotation 概述 Compass Annotation ...

    Extjs+s2sh基于annotation实现的酒店管理系统

    【标题】:“Extjs+s2sh基于annotation实现的酒店管理系统”是一个综合性的IT项目,它融合了前端的Extjs框架和后端的Spring、Struts2以及Hibernate这三大经典技术(合称为S2SH),并利用注解(Annotation)进行简化...

    Hibernate组件映射(annotation/xml)

    在传统的Hibernate配置中,组件映射通常通过XML配置文件实现。例如: ```xml &lt;id name="id" column="ID"&gt;&lt;/id&gt; &lt;!-- 如果组件类需要独立表 --&gt; ... ``` XML方式的组件映射更为直观,但代码...

    hibernate annotation 中文文档

    ### Hibernate Annotation 中文文档知识点概览 #### 一、创建注解项目 ##### 1.1 系统需求 在创建一个使用 Hibernate 注解的项目之前,需要满足一定的系统环境需求,例如支持 Java 的开发环境、JDK 版本、支持 ...

    hibernate-Annotation.jar

    在Hibernate 3.x版本中,引入了Annotation注解,这是一种元数据的方式,可以替代XML配置文件来描述对象与数据库表之间的映射关系。 **Hibernate Annotation注解** 在Hibernate 3.x之前,对象到数据库的映射通常...

    annotation

    在编程领域,注解(Annotation)是Java等编程语言中的一种元数据,它提供了在编译时或运行时处理程序信息的方式。元数据是关于数据的数据,它为编译器、构建工具、框架或者JVM提供了有关代码的额外信息。在Java中,...

    map-annotation

    在Java编程领域,注解(Annotation)是一种元数据机制,它允许程序员在代码中嵌入额外的信息,这些信息可以被编译器或者运行时环境读取,以实现各种功能。"map-annotation"是一个特定的注解开发包,主要用于entity类...

    JDK5.0 Java Annotation 介绍(ppt)

    Java Annotation 是 JDK5.0 引入的一种元数据机制,它允许程序员在代码中嵌入额外的信息,这些信息可以被编译器、构建工具或运行时系统用来执行特定的任务。Annotation 提供了一种安全、灵活的方式来描述代码的属性...

    Hibernate关联关系的CRUD和集合映射(annotation)

    综上所述,Hibernate通过注解方式实现了对象关系映射的简洁性,使得关联关系、CRUD操作和集合映射变得更加直观。开发者可以根据业务需求灵活选择关联类型和加载策略,从而提高代码的可维护性和性能。在实际项目中,...

    Hibernate distribution and annotation

    **正文** 标题“Hibernate ...在实际项目中,这些工具可以帮助实现高效、便捷的数据库操作,降低了与数据库交互的复杂性。了解和熟练掌握Hibernate的使用,对于任何Java后端开发人员来说都是至关重要的技能。

    hibernate annotation api chm文件

    **正文** 《Hibernate Annotation API...通过合理运用注解,开发者能够高效地管理数据层,实现面向对象编程和关系型数据库之间的无缝对接。在实际开发中,理解并熟练掌握这些注解,能够提升开发效率,降低维护成本。

    Hibernate Annotation库

    总之,Hibernate Annotation库是Java开发中不可或缺的工具,它通过注解的方式简化了ORM的过程,使得开发者能更专注于业务逻辑,而不是底层的数据操作细节。通过理解并熟练使用这些注解,可以有效地提升开发效率和...

    java之Annotation及其应用

    Java注解(Annotation)是Java语言的一个重要特性,它为元数据提供了强大的支持。元数据是一种描述数据的数据,可以提供有关代码的附加信息,而这些信息并不直接影响代码的执行。在Java中,注解用于向编译器、JVM或...

    Java Annotation注解.doc

    Java Annotation,也称为注解,是Java编程语言中的一种元数据机制,用于向编译器、JVM或工具提供有关代码的附加信息。这些信息不直接影响代码的执行,但可以被编译器或运行时环境用来执行特定的操作,如代码分析、...

    struts1.3+spring2.5+hibernate3.3 组合开发 annotation实现

    在本项目中,这些框架的集成使用了注解(Annotation)来简化配置,使得代码更加简洁和易于维护。 Struts1.3 是一个基于 Model-View-Controller (MVC) 模式的开源框架,用于构建动态 Web 应用。它提供了一种结构化的...

Global site tag (gtag.js) - Google Analytics