您的位置:首页 > 编程语言 > Java开发

深入理解Java的Annotation系列-第五部分 使用注解编写ORM框架

2017-08-24 10:36 726 查看
一、什么是ORM?

    对象关系映射(英语:(Object Relational Mapping,简称ORM,或O/RM,或O/Rmapping),是一种程序技术,随着面向对象的软件开发方法发展而产生的。用来把对象模型表示的对象映射到基于S
Q L 的关系模型数据库结构中去,或者把表中的一条记录自动封装成对象。

         



采用ORM优势在于,程序员采用面向对象的方法来访问数据库,简化了编码,提高了开发速度,ORM自动完成类和表,属性名和字段名的映射。

    使用本ORM框架,在处理查询业务逻辑时,只要编写形如"from 类名"的SQL语句,就可以得到封装好的所查询所有结果的List集合,处理添加业务时,只要调用Add(obj)方法即可实现添加功能。其他的功能读者可自行添加。

二、整体思路

  1、自定义ORM注解,包含@Table和@Column。

   2、写一个类,解析注解信息,并存入Map对象

   3、实现查询和添加功能

   4、使用自定义的ORM框架,实现业务逻辑

   5、测试

三、具体实现

  1、整体架构

     


   2、建表并插入数据的SQL

       showdatabases;

       create database czf;

       use czf;

       create table stu(id int primary key,namevarchar(40),age int);

       insert into stuvalues(1,'czf',34),(2,'afeng',25);

       select * from stu;

       createtable teacher(tid int primary key,tname varchar(40),tage int);

       insertinto teacher values(1,'czf',34),(2,'afeng',25);

       insert into teacher(tid,tname,tage)values(3,'czf3',33);

        select * from teacher;

3、具体代码

                 第一部分  ORM部分代码的编写

   3.1 Table.java

     packagecn.com.bochy.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 自定义注解,用于注解类名所对应的表名
 * @authorchenzhengfeng
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public
@interface
Table {
      String value();//表名
}

3.2 Column.java

   package cn.com.bochy.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 自定义注解,用于注解对象的属性名所对应的表的列名
 * @authorchenzhengfeng
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public
@interface
Column {
   String value();//列名
}

3.3 OrmImpl.java

   package cn.com.bochy.orm;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import cn.com.bochy.annotation.Column;
import cn.com.bochy.annotation.Table;
/**
 * 解析注解信息,并存入Map中
 * @authorchenzhengfeng
 */
public
class
OrmImpl {
    //用于存储类名对应的表名,其中key是类名,value是表名
    private Map<String,String>mapTable=newHashMap<String,String>();
    //用于属性名对应的表的字段名,其中key是属性名,value是字段名
    private Map<String,String>mapColumns=newHashMap<String,String>();
    public Map<String, String> getMapTable() {
       returnmapTable;
    }
    public
void
setMapTable(Map<String, String>
mapTable) {
       this.mapTable =mapTable;
    }
    private  StringtableName="";
    public String getTableName() {
       returntableName;
    }
    public
void
setTableName(String tableName) {
       this.tableName =tableName;
    }
    public Map<String, String> getMapColumns() {
       returnmapColumns;
    }
    public
void
setMapColumns(Map<String, String>
mapColumns) {
       this.mapColumns =mapColumns;
    }
    /**
     * 解析实体类的注解信息,其中c1是实体类的类对象
     * @param c1
     */
public
void
parseAnnotation(Class<?> c1) {
    Table
table=c1.getAnnotation(Table.class);
    tableName=table.value();//获取注解的表名
    mapTable.put(c1.getName(),tableName);//存入
    Field[] fields=c1.getDeclaredFields();//获取所有的属性名
    for(Fieldf:fields) {//遍历属性名
       if(!f.getName().equals("serialVersionUID")) {
           Column
c=f.getAnnotation(Column.class);
           mapColumns.put(f.getName(),c.value());//获取该属性名所对应的字段,并存入
       }
    }
}
}

3.4  OrmQuery.java

package cn.com.bochy.orm;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import cn.com.bochy.dbutil.DBHepler;
/**
 * 实现查询功能
 * @authorchenzhengfeng
 *
 */
public
class
OrmQuery {
    DBHepler helper=new DBHepler();
    private
static
OrmImpl orm=null;
    private
static
String tableName="";
    private
static
Map<String,String> mapColumns=null;//存储属性和字段对应关系的MAP
    private
static
Map<String,String> mapTables=null;//存储类名和表名对应关系的MAP
    private Class<?>classc1;//查询对象的类对象
    /**
     * 通过构造方法实现初始化工作
     * @param c1
     */
    public OrmQuery(Class<?>c1) {
       this.classc1=c1;
        orm=new OrmImpl();
           orm.parseAnnotation(classc1);//解析要查询对象的注解信息
           tableName=orm.getTableName();
           mapColumns=orm.getMapColumns();
           mapTables=orm.getMapTable();
    }
    /**
     * 查询sql形如"from类名"格式的语句,并封装成List,其他的形式请读者自行添加
     * @param hql
     * @return
     */
    @SuppressWarnings("rawtypes")
    public List query(Stringhql){ 

        int
index=hql.indexOf("from");
        /**
         * 以下语句是从hql语句中截取类名
         */
        StringclassName="";//类名
        StringfullclassName="";//包含包名的类名
        Stringsql="";
        Stringhqlsub=hql.substring(index+5);//form的长度为4,再加上空格,所以为5
        className=hqlsub;
           //遍历mapTables,查找类名对应的表名
        for(Stringkey:mapTables.keySet()) {
           if(key.contains(className)) {
               tableName=mapTables.get(key);
               fullclassName=key;
              
           }
        }
        sql="select * from "+tableName;
     ResultSet rs=
helper.query(sql, null);
    List<Object>lists=new ArrayList<Object>();
        try {
           while(rs.next()) {         
              Class<?>c1=  Class.forName(fullclassName);  //查询对象的类对象    
              Objects=   
c1.newInstance();//创建一个查询对象
           Field[]fs=  
c1.getDeclaredFields();//获取该对象的所有属性
             for(Fieldf:fs) {//遍历属性
               String fname=
f.getName();//获取某个属性名
              StringsetMethod="set"+FirstBig(fname);//某个属性名对应的setter方法名
                   Method[] methods=c1.getDeclaredMethods();//获取该对象的所有方法
                   for(Methodm:methods) {//遍历方法
                       if(m.getName().equals(setMethod)) {//如果找到对应的方法
                          String columnName=mapColumns.get(fname);//属性名对应的字段名
      
                             m.invoke(s,rs.getObject(columnName));//执行该setter方法,给对象m赋值
                          break;
                       }
                   }
             }
              lists.add(s);//把对象存入列表
           }
       } catch (SQLException |ClassNotFoundException | InstantiationException | IllegalAccessExceptione) {
           // TODO Auto-generated catch block
           e.printStackTrace();
       } catch(IllegalArgumentExceptione) {
           // TODO Auto-generatedcatch block
           e.printStackTrace();
       } catch (InvocationTargetExceptione) {
           // TODO Auto-generatedcatch block
           e.printStackTrace();
       }
      return
lists;  
    }
    //把第一个字符变为大写
    public String FirstBig(Stringstr) {
        returnstr.substring(0,1).toUpperCase()+str.substring(1);
    }
}
3.5  OrmAdd.java

package cn.com.bochy.orm;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import cn.com.bochy.dbutil.DBHepler;
/**
 * 实现ORM中的添加功能
 * @authorchenzhengfeng
*/
public
class
OrmAdd {
    DBHepler helper=new DBHepler();
    private
static
OrmImpl orm=null;
    private
static
Map<String,String> mapColumns=null;
    private Class<?>classc1;//指定要添加的对象的类类型
    //通过构造方法初始化
    public OrmAdd(Class<?>c1) {
       this.classc1=c1;
        orm=new OrmImpl();
           orm.parseAnnotation(classc1);//解析注解信息
           mapColumns=orm.getMapColumns();//获取属性名和字段名的对应信息 
    }
    /**
     * 通过Java的反射机制结合注解信息实现添加功能
     * @param obj
     * @return
     */
   public
boolean
add(Object obj) {
       //获取表名
     for(String key:mapTables.keySet()) {
     if(key.equals(obj.getClass().getName())) {
     tableName=mapTables.get(key);
     }
     }
       Method[] methods=
obj.getClass().getDeclaredMethods();//获取添加对象中所有的方法
       Field[] fileds=obj.getClass().getDeclaredFields();//获取添加对象中所有的属性
       String sqlColumn="";//用于拼接要添加表中所有的字段
       String sqlvalue="";//用于拼接要添加的所有值,用?代替
      List<Object> parmas=newArrayList<Object>();//存储要添加的所有值
       for(Fieldf:fileds)//遍历属性
       for(Methodm:methods) {//遍历方法
               //获取该属性对应的getter方法
           if(m.getName().equals("get"+FirstBig(f.getName()))) {      
               Object values1;
              try {
                  values1 =
m.invoke(obj);//调用该对象的getter方法
                  parmas.add(values1);//把添加的值存入列表       
                  sqlColumn+=mapColumns.get(f.getName())+",";
                  sqlvalue+="?,";
              } catch (IllegalAccessExceptione) {
                  // TODO Auto-generatedcatch block
                  e.printStackTrace();
              } catch (IllegalArgumentExceptione) {
                  // TODO Auto-generatedcatch block
                  e.printStackTrace();
              } catch (InvocationTargetExceptione) {
                  // TODO Auto-generatedcatch block
                  e.printStackTrace();
              }          
           }
       }
       sqlColumn=CutoutLastChar(sqlColumn);//把最后一个","去掉
       sqlvalue=CutoutLastChar(sqlvalue);//把最后一个","去掉
       String sql="insert into "+tableName+"("+sqlColumn+")"+"
values("+sqlvalue+")";
      Object[] param=parmas.toArray();//把集合列表转化为数组
    return
helper.noQuery(sql,
param); //调用helper对象中noQuery实现添加功能
   }
   /**
    * 去掉字符串最后一个字符
    * @param str
    * @return
    */
   public String CutoutLastChar(Stringstr) {
       returnstr.substring(0,str.length()-1);
   }
   /**
    * 把字符串的首字符变为大写
    * @param str
    * @return
    */
    public String FirstBig(Stringstr) {
        returnstr.substring(0,1).toUpperCase()+str.substring(1);
    }
}
3.6 DBHepler.java
package cn.com.bochy.dbutil;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
 * 简单的JDBC的封装
 * @authorchenzhengfeng
 *
 */
public
class
DBHepler {
    private  Stringurl="jdbc:mysql://localhost:3306/czf";
    private  Stringuser="root";
    private  Stringpassword="root";
    public  Connectionconn=null;
    public  PreparedStatementpstmt=null;
    public  ResultSetrs=null;
   //1、得到连接对象
   public  ConnectiongetConnection(){
       try {
       Class.forName("com.mysql.jdbc.Driver");
       conn=DriverManager.getConnection(url,user,
password);
    } catch (ClassNotFoundExceptione) {
       // TODO Auto-generatedcatch block
       e.printStackTrace();
    } catch (SQLExceptione) {
       // TODO Auto-generatedcatch block
       e.printStackTrace();
    }
    return
conn; 
   }
   //2、关闭资源
   public 
void
closeAll(){
       try {
       if(rs!=null){
              rs.close();
          }
          if(pstmt!=null){
              pstmt.close();
          }
          if(conn!=null){
              conn.close();
          }
    } catch (SQLExceptione) {
       // TODO Auto-generatedcatch block
       e.printStackTrace();
      
      
    }
   }
    //3、通用查询方法
   public  ResultSetquery(Stringsql,Object[]
param){
       try {
          getConnection();
       pstmt=conn.prepareStatement(sql);
       if(param!=null)
       for(inti=0;i<param.length;i++){
           pstmt.setObject(i+1,param[i]);
       }
       rs=pstmt.executeQuery();
    } catch (SQLExceptione) {
       // TODO Auto-generatedcatch block
       e.printStackTrace();
    }
      
       returnrs;
   }
   //4、通用非查询方法
   public 
boolean
noQuery(String sql,Object[]param){
       getConnection();
       int
a=0;
       try {
       pstmt=conn.prepareStatement(sql);
       if(param!=null)
           for(inti=0;i<param.length;i++){
              pstmt.setObject(i+1,param[i]);
           }
       a=pstmt.executeUpdate();
    } catch (SQLExceptione) {
       // TODO Auto-generatedcatch block
       e.printStackTrace();
    }
       closeAll();
       if(a>0)
       return
true
;
       else
          return
false
;
   }
}
             第二部分  ORM应用

3.7  实体类Stu.java

package cn.com.bochy.entity;
import java.io.Serializable;
import cn.com.bochy.annotation.Column;
import cn.com.bochy.annotation.Table;
/**
 * 实体类
 * @author Administrator
 *
 */
@Table("stu")//通过注解,类Stu对应表stu
public
class
Stu implements Serializable {
    private
static final
long serialVersionUID
= 1L;
    @Column("id")//通过注解,属性名id对应字段名(列名)id
    private
int
id;
   
public
int
getId() {
       returnid;
    }
    public
void
setId(intid) {
       this.id =id;
    }
public String getName() {
       returnname;
    }
    public
void
setName(String name) {
       this.name =name;
    }
    public
int
getAge() {
       returnage;
    }
    public
void
setAge(intage) {
       this.age =age;
    }
    @Column("name")//通过注解,属性名name对应字段名(列名)name
private String name;
    @Column("age")//通过注解,属性名age对应字段名(列名)age
  private
int
age;
  public Stu() {
    // TODO Auto-generatedconstructor stub
}
}
3.8 实体类Teacher.java

package cn.com.bochy.entity;
import java.io.Serializable;
import cn.com.bochy.annotation.Column;
import cn.com.bochy.annotation.Table;
@Table("teacher")//通过注解,类Teacher对应表teacher
public
class
Teacher implements Serializable {
    private
static final
long serialVersionUID
= 1L;
    @Column(value="tid")//通过注解,属性名id对应字段名(列名)tid
    private
int
id;
   
public
int
getId() {
       returnid;
    }
    public
void
setId(intid) {
       this.id =id;
    }
public String getName() {
       returnname;
    }
    public
void
setName(String name) {
       this.name =name;
    }
    public
int
getAge() {
       returnage;
    }
    public
void
setAge(intage) {
       this.age =age;
    }
    @Column("tname")//通过注解,属性名name对应字段名(列名)tname
private String name;
    @Column("tage")//通过注解,属性名age对应字段名(列名)tage
  private
int
age;
  public Teacher() {
    // TODO Auto-generatedconstructor stub
}
}
3.9  具体业务逻辑类StuBiz.java

package cn.com.bochy.biz;
import java.util.ArrayList;
import java.util.List;
import cn.com.bochy.entity.Stu;
import cn.com.bochy.orm.OrmAdd;
import cn.com.bochy.orm.OrmQuery;
/**
 * 使用自定义ORM框架实现具体的业务逻辑
 * @authorchenzhengfeng
 */
public
class
StuBiz {
       OrmQuery query=new OrmQuery(Stu.class);
       OrmAdd Add=new OrmAdd(Stu.class);
     @SuppressWarnings("rawtypes")
    List lists=new ArrayList();
  @SuppressWarnings({
"rawtypes" })
  /**
   * 查选业务逻辑
   * @return
   */
public List getAllStus(){
      String hql="from Stu";
      lists=query.query(hql);
      return
lists;
   }
  /**
   * 添加业务逻辑
   * @params
   * @return
   */
  public
boolean
add(Stu s){
      return
Add.add(s);
   }
}
3.10 具体业务逻辑类TeacherBiz.java
package cn.com.bochy.biz;
import java.util.ArrayList;
import java.util.List;
import cn.com.bochy.entity.Stu;
import cn.com.bochy.entity.Teacher;
import cn.com.bochy.orm.OrmAdd;
import cn.com.bochy.orm.OrmQuery;
/**
 * 使用自定义ORM框架实现具体的业务逻辑
 * @authorchenzhengfeng
 *
 */
public
class
TeacherBiz {
     OrmQuery query=newOrmQuery(Teacher.class);
     OrmAdd Add=new OrmAdd(Teacher.class);
     List<Stu>  lists=new ArrayList<Stu>();
  @SuppressWarnings({
"unchecked", "rawtypes" })
  /**
   * 查选的业务逻辑
   * @return
   */
public List getAllTeachers(){
      String hql="from Teacher";
      lists=query.query(hql);
      return
lists;
   }
  /**
   * 添加的业务逻辑
   * @param s
   * @return
   */
  public
boolean
addTeacher(Teacher t1) {
      return
Add.add(t1);
  }
}
3.11 测试类TestDemo.java

package cn.com.bochy.test;
importcn.com.bochy.biz.StuBiz;
importcn.com.bochy.biz.TeacherBiz;
importcn.com.bochy.entity.Stu;
importcn.com.bochy.entity.Teacher;
public
class TestDemo {
  public
static void main(String[]
args) {
     StuBiz biz=new StuBiz();
     Stu s1=new Stu();
      s1.setId(5);
      s1.setAge(25);
      s1.setName("dsew25");
      biz.add(s1); 
      System.out.println(biz.getAllStus().size());
      for(Object
s:biz.getAllStus()) {
         if(sinstanceof Stu) {
             Stu stu=(Stu)s;
             System.out.println(stu.getId()+" "+stu.getName()+" 
"+stu.getAge());
         }
      }
     
     TeacherBiz tbiz=new TeacherBiz();
      Teacher t1=new Teacher();
    t1.setId(5);
    t1.setName("sds5");
    t1.setAge(25);
   
    tbiz.addTeacher(t1);
      System.out.println(tbiz.getAllTeachers().size());
      for(Object
s:tbiz.getAllTeachers()){
         if(sinstanceof Teacher) {
             Teacher t=(Teacher)s;
             System.out.println(t.getId()+" "+t.getName()+"  "+t.getAge());
         }
      }
}
}

四、推荐内容

http://blog.csdn.net/zhoudaxia/article/details/33731583 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Annotation orm 框架