文章目录

  • 一、定义注解
  • 二、注解处理器
  • 三、工具类
  • 四、测试类

完善《java高级程序设计》中第四章注解的4.5实例

通过扫描指定路径下的所有类,找到含有指定注解的实体,解析这些实体,并生成对应的SQL命令,在数据库中创建相应的表

一、定义注解

用于指明那些类需要映射成数据库的字段

/*** @Auther: Parsifal* @Date: 2021/03/30/20:12* @Description:  用于指明那些类需要映射成数据库的字段*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {//字段的名字public String value() default "";//约束条件://是否可以为空public boolean nullable() default true;//字段长度public int length() default -1;}

用于指明那些需要映射成数据库的表

/*** @Auther: Parsifal* @Date: 2021/03/30/20:10* @Description:*  用于指明那些需要映射成数据库的表*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Entity {//数据库映射后表的名字public String value() default "";
}

作用与属性,表示属性作为映射表的主键

/*** @Auther: Parsifal* @Date: 2021/03/30/20:14* @Description:  作用与属性,表示属性作为映射表的主键*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ID {public String value() default "";
}

二、注解处理器

注解处理器接口

/*** @Auther: Parsifal* @Date: 2021/03/31/15:39* @Description: 注解处理器*/
public interface IProcessor {public String process(String url)throws Exception;
}

处理器实现类

  • 通过扫描器获得类的信息,同过TableInfo 的toStirng方法获得该类的sql语句
/*** @Auther: Parsifal* @Date: 2021/03/31/15:40* @Description:*/
public class TableProcessor implements IProcessor {@Overridepublic String process(String url) throws Exception {//扫描 url下的实体Scanner scanner = new Scanner(url);//获得实体的Class<?>List<Class<?>> entities = scanner.getEntity();//获得创建表和属性的sqlStringBuilder sql  = new StringBuilder();entities.forEach(entity->{TableInfo tableInfo = new TableInfo();TableInfo parse = tableInfo.parse(entity);if (parse!=null){sql.append(tableInfo.toString());}});return sql.toString();}
}

三、工具类

定义的常量

/*** @Auther: Parsifal* @Date: 2021/03/30/21:15* @Description:*/
public class Symbol {public static final String BLANK=" ";public static final String TAB="\t";public static final String LINE="\n";
}

Scanner类

  • 扫描指定路径下的.java文件并获取该类信息
/*** @Auther: Parsifal* @Date: 2021/03/30/21:25* @Description: 扫描指定路径下的实体*/
public class Scanner {private String path;private File file;public Scanner(String path) {this.path = path;file = new File(path);}/*** 获取src目录下的指定路径的实体类信息* 路径格式(src开头): src\EntityMapping\Entity* @return* @throws ClassNotFoundException*/public List<Class<?>> getEntity() throws ClassNotFoundException {//        获得该文件下的作用子文件对象String[] list = file.list();List<Class<?>> classes  =new ArrayList<>();
//       path 替换/为 .this.path=  path.replace('\\','.');//去除文件后的后缀名  '.java'this.path = path.substring(4);if (list == null){return null;}for (String s : list) {s =s.split("\\.")[0];//获得实体的类信息classes.add(Class.forName(path+"."+s));}return classes;}//测试public static void main(String[] args) throws ClassNotFoundException {Scanner scanner = new Scanner("src\\EntityMapping\\Entity");List<Class<?>> entity = scanner.getEntity();System.out.println(entity);}
}

ColumInfo类

  • 储存数据库中表的某一字段的信息,即是类中需要映射的属性信息
/*** @Auther: Parsifal* @Date: 2021/03/30/20:26* @Description:* 用于描述数据库中某一字段的信息*/
public class ColumnInfo {//字段名称private String columnName;//字段类型private Class<?> type;//是否是主键private boolean isID =false;//是否可为空private boolean nullable=true;//字段长度private int length=32;//该字段是否需要保存到数据库中private boolean needPersist = false;/*** 根据Field对象,解析该字段信息* @param field 字段* @return*/public ColumnInfo parse(Field field){this.columnName =field.getName();this.type = field.getType();Annotation[] annotations = field.getAnnotations();for (Annotation annotation : annotations) {//如果注解是@Column,则获取字段信息if (annotation.annotationType().equals(Column.class)){this.needPersist=true;Column column = (Column) annotation;if (!column.value().equals("")){//如果字段的名字不为空,则获取该字段的名字this.columnName=column.value();}this.nullable=column.nullable();if (column.length()!=-1){//如果该字段的长度不为默认值-1,则获取该长度this.length = column.length();}}//如果该注解是@IDelse if (annotation.annotationType().equals(ID.class)){this.needPersist=true;ID id = (ID)annotation;this.isID = true;//如果用户设置了value值,则以value值作为字段if (!id.value().equals("")){this.columnName =id.value();}}}if (this.needPersist){return this;}else {return null;}}/*** 重写toString方法返回字段信息的sql语句* @return*/@Overridepublic String toString() {StringBuilder sql = new StringBuilder(columnName);if (this.type.equals(String.class)){sql.append(Symbol.BLANK + "VARCHAR(").append(this.length).append(")");}else if(this.type.equals(Integer.class)){sql.append(Symbol.BLANK+"INT");}if (this.isID){sql.append(Symbol.BLANK+"PRIMARY KEY");}if(!this.nullable){sql.append(Symbol.BLANK+"NOT NULL");}return sql.toString();}
}

ColumnInfo 类解析解析的流程

  • 获取Field对象的名称,作为字段名称
  • 获取Field对象的类型,作为字段的类型
  • 获取该属性上声明的注解集合,并遍历这些注解
  • 如果注解是@Column,则表明该属性应映射成数据库中的字段
  • 如果注解是@ID,则表明该属性作为数据库中表的主键
  • 判断该属性是否需要持久化,如需要返回解析后的字段信息对象,否则返回nul1

TableInfo 类

  • 储存数据库中的表的信息
/*** @Auther: Parsifal* @Date: 2021/03/30/22:29* @Description: 储存数据库中表的信息*/
public class TableInfo {//表的名字private String tableName;//表对应的实体的信息private Class<?> clazz;//是否需要持久化储存private boolean needPersist = false;//该表的所有字段信息private Map<String,ColumnInfo> columns = new HashMap<>();public  TableInfo parse(Class<?> clazz){this.clazz = clazz;this.tableName=this.clazz.getSimpleName();Annotation[] annotations = this.clazz.getAnnotations();for (Annotation annotation : annotations) {if (annotation.annotationType().equals(Entity.class)){//如果包含@Entity注解,则表明实体需要持久化储存this.needPersist =true;Entity entity = (Entity) annotation;if (!entity.value().equals("")){this.tableName = entity.value();}break;}}if (this.needPersist){//如果需要永久化储存Field[] fields = this.clazz.getDeclaredFields();for (Field field : fields) {ColumnInfo column = new ColumnInfo();column=column.parse(field);if (column!=null){this.columns.put(field.getName(),column);}}return this;}else {return null;}}@Overridepublic String toString() {StringBuilder sql  =new StringBuilder();sql.append(Symbol.LINE).append("CREATE TABLE").append(Symbol.BLANK).append(this.tableName).append(Symbol.BLANK).append("(");for (ColumnInfo value : this.columns.values()) {sql.append(Symbol.LINE).append(Symbol.TAB).append(value.toString()).append(",");}sql.delete(sql.length()-1,sql.length());sql.append(Symbol.LINE).append(");");return sql.toString();}
}

TableInfo 类解析实体的主要流程:

  • 根据类型信息,获取实体类的简单名称作为表名。
  • 获取在该类上使用的注解集合。
  • 遍历这些集合。
  • @ Entity注解的参数value.
  • 如果参数不为空,则将表名设为此参数值,跳出循环。
  • 如果没有找到该注解,则说明此实体不需要持久化存储,则返回null.
  • 如果该实体需要持久化存储,则遍历该实体类型信息的所有属性描述对象列表,并将它们转换成表的字段信息对象,添加到字段信息map中。
  • 返回解析好的表信息实体。

四、测试类

/*** @Auther: Parsifal* @Date: 2021/03/31/15:38* @Description:*/
public class MappingTest {public static void main(String[] args)  {TableProcessor tp = new TableProcessor();Connection connection = null;PreparedStatement ps = null;try {String sql = tp.process("src\\EntityMapping\\Entity");System.out.println(sql);connection = JDBCUtil.getConnection();if (connection != null) {ps = connection.prepareStatement(sql);}if (ps != null) {int i = ps.executeUpdate();}} catch (Exception e) {e.printStackTrace();} finally {JDBCUtil.close(ps, connection);}}
}

文件路径

Person实体


@Entity("Person")
public class Person{@ID@Column(nullable = false)Integer id;@Column(nullable = false,length = 16)String name;}

JDBCUtil类是我封装的一个工具类
详情请见: https://blog.csdn.net/m0_49647974/article/details/115285852

结果

  • sql语句
  • 数据库

java+mysql 实现实体的映射与翻译相关推荐

  1. mysql test 映射到实体_MyBatis实体关系映射

    作者:知了汇智-刘阳 MyBatis既然是一个ORM框架,则它也有像Hibernate那样的一对多,多对多,多对一的实体关系映射功能.下面我们就来介绍一下如何使用MyBatis的实体关系映射1.MyB ...

  2. Mybatis实现存取Mysql的Json字段映射Java对象

    Mybatis实现存取Mysql的Json字段映射Java对象 一.需求 二.解决方案 一.需求 在业务比较复杂的项目模块,为了应对多样化的场景,我们通常会在mysql中采用json格式来存储相应的信 ...

  3. mysql数据库对象关系映射

    http://www.2cto.com/database/201310/248690.html mysql数据库对象关系映射 1.对"对象关系映射"的理解 a.对象:可以理解为ja ...

  4. Hibernate 实体关联关系映射----总结

    http://lavasoft.blog.51cto.com/62575/39398 Hibernate 实体关联关系映射----总结 花了三天的业余时间,终于写完了Hibernate关联关系映射的所 ...

  5. 【Hibernate】Hibernate实体关系映射实例解析

    //刘梦冰发表于2015-6-18 1.使用XML配置 Cat.java(实体类) public classCat {private Integerid;private Stringname;priv ...

  6. eclipse mysql生成实体类_Eclipse实现数据库反向生成实体类(pojo)-------(插件安装和实现步骤的说明)...

    一.插件安装 1.下载插件: http://jaist.dl.sourceforge.net/sourceforge/jboss/HibernateTools-3.2.4.Beta1-R2008103 ...

  7. java mysql geometry,扩展mybatis和通用mapper,支持mysql的geometry类型字段,mybatis用mapper...

    扩展mybatis和通用mapper,支持mysql的geometry类型字段,mybatis用mapper 因项目中需要用到地理位置信息的存储.查询.计算等,经过研究决定使用mysql(5.7版本) ...

  8. java Mysql人事管理系统zip_java毕业设计_springboot框架的企业行政人事管理系统

    这是一个基于java的毕业设计项目,毕设课题为springboot框架的企业行政人事管理系统, 是一个采用b/s结构的javaweb项目, 开发工具eclipsei/eclipse, 项目框架jsp+ ...

  9. Java中的实体类(VO、PO、DO、DTO、BO、QO、DAO、POJO)

    Java中的实体类(VO.PO.DO.DTO.BO.QO.DAO.POJO) PO(persistant object) 持久对象 DO(Domain Object)领域对象 TO(Transfer ...

最新文章

  1. python 第六章 函数
  2. java收费对.net_网上订货商城系统是怎么收费的?大概需要多少费用?
  3. Java 8中java.util.function包中的谓词和使用者接口
  4. oracle 11.2.4联机文档,ORACLE 11G 联机文档partition_extended_name的一个错误
  5. sarscape 将dem文件转化成stl_SARscape与SARProz软件中的重要缩写
  6. MapXtreme开发(二)
  7. 学习面试题Day09
  8. python中qt有哪些控件_使用PyQt5调用Qt程序,基础PythonQt控件的使用方法
  9. 鸿蒙系统麒麟970芯片支持,受鸿蒙系统影响,众多华为手机或要说再见,包括麒麟970机型!...
  10. 【结课报告】游戏中的知识产权
  11. 基于差分进化算法的函数寻优算法
  12. 按键精灵手机助手之实战篇(一)需求理论分析
  13. 二维码是什么?java生成二维码
  14. sklearn.neighbors常用API介绍
  15. 美通企业周刊 | 中国全球化品牌50强榜单发布;酩帝诗威士忌拍出近21万美元天价...
  16. 二十四式长生图——清手抄本(扫描版)
  17. Arduino(三)——按钮控制数码管
  18. SLAM本质剖析番外-李群李代数的微分和导数
  19. 标准cpci接口定义_cpci定义
  20. 出现单边帐,该如何处理!

热门文章

  1. Yolov8详解与实战
  2. 半夜看小说伤眼睛怎么办?
  3. cv.waitKey
  4. java多线程并发及线程池
  5. daemon not running.starting it now on port 5037 问题解决
  6. Selenium爬虫实战丨Python爬虫实战系列(8)
  7. 鸿蒙系统首批机型,首批支持鸿蒙系统的手机有哪些-华为鸿蒙系统支持机型全一览...
  8. Springboot 指定自定义模板导出Excel文件
  9. django后台管理系统
  10. 什么是死锁?死锁产生的条件?