JAVA自定义注解实现SQL语句自动生成DEMO

时间:2021-12-09 11:59:22
缘起:好久没写博客了,最近工作写了一些,服务的接口,自己写白盒测试进行测试,全部通过,
          但是部署到线上会导致一些服务调不通追下问题,发现是自己粗心忘记加了一些注解,
          最后把注解加上了,BUG消除,仔细思考一下,自己对注解知知甚少。

Java注解:
     1、@Target     2、@Retention     3、@Documented     4、@Inherited 5、自定义注解

每个注解对应含义再次做过多描述,只简单的列举1、2、对应的含义:@Target:      作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)    取值(ElementType)有:    1、CONSTRUCTOR:用于描述构造器    2、FIELD 用于描述域    3、LOCAL_VARIABLE 用于描述局部变量    4、METHOD 用于描述方法    5、PACKAGE 用于描述包    6、PARAMETER 用于描述参数    7、TYPE 用于描述类、接口(包括注解类型) 或enum声明
@Retention:      作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)      取值(RetentionPoicy)有:    1、SOURCE 在源文件中有效(即源文件保留)    2、CLASS 在class文件中有效(即class保留)             3、RUNTIME 在运行时有效(即运行时保留)

自己简单的看过类似相关注解,再结合一些demo自己模仿的写了一点,sql语句的自动生成小工具Util代码,先展示一下测试代码:
public class test {
public static void main(String[] args){
System.out.println(SqlUtil.create(Person.class));
System.out.println(SqlUtil.insert(Person.class));
}
}

测试结果输出:
CREATE TABLE person(name String not null,id int primary key auto_increment)INSERT INTO person (name,id) VALUES(?,?)

只有简单的几行代码,会对应生成指定类的create table,inset 语句,
用法只需要对应新建Person类的时候加入指定注解即可Person类如下所示:
@Table(name="person")public class Person {    @PrimaryKey(name="id")    public int id;    @Column(name="name",isNull = false)    public String name;    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}

下面为@Table注解实现,主要用来获取对应table 名称

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface Table {    public String name() default "";}

下面为@Column注解实现,主要获取对应Column字段信息,

@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface Column {    public String name() default "";    public int length() default 255;    public boolean isNull() default true;}


下面就是重头戏啦 SqlUtil工具类
package com.ucky.annotation.hibernate;import java.lang.reflect.Field;import java.util.Date;import java.util.HashMap;import java.util.Map;/** * 生成建表语句 */public class SqlUtil {    /*    * 生成创建table语句    * */    public static String create(Class<?> clazz) {        StringBuilder sb = new StringBuilder();        String tableName = getTableName(clazz);        if (null == tableName || "".equals(tableName)) {            return null;        }        sb.append("CREATE TABLE ").append(tableName).append("(");        Map<String, String> columnMap = getColumn(clazz);        for (Map.Entry<String, String> entry : columnMap.entrySet()) {            sb.append(entry.getKey());            sb.append(" ");            sb.append(entry.getValue());            sb.append(",");        }        sb.deleteCharAt(sb.length() - 1);        sb.append(")");        return sb.toString();    }    /*    * 生成插入语句    * */    public static String insert(Class<?> clazz) {        StringBuilder sb = new StringBuilder();        String tableName = getTableName(clazz);        sb.append("INSERT INTO ").append(tableName).append(" (");        Map<String, String> columnMap = getColumn(clazz);        for (Map.Entry<String, String> entry : columnMap.entrySet()) {            sb.append(entry.getKey());            sb.append(",");        }        sb.deleteCharAt(sb.length() - 1);        sb.append(") ").append("VALUES").append("(");        for (int i = 0; i < columnMap.size(); i++) {            sb.append("?").append(",");        }        sb.deleteCharAt(sb.length() - 1);        sb.append(")");        return sb.toString();    }    public static String delete() {        return null;    }    /*    * 获取表名称    * */    public static String getTableName(Class<?> clazz) {        //判断是否为Table注释类型是方法返回true,否则返回false        if (clazz.isAnnotationPresent(Table.class)) {            //获取注解信息            Table table = clazz.getAnnotation(Table.class);            if(!"".equals(table.name())){                return table.name();            }        }        return null;    }    /*    * 获取字段信息的Map    * */    public static Map<String, String> getColumn(Class<?> clazz) {        Map<String, String> columns = new HashMap<String, String>();        //通过反射取得所有Field,因为table那里是注解指定的注解,类型,column是对应方法上的所以不能class.isAnnotationPresent直接判断        Field[] fields = clazz.getDeclaredFields();        if (fields != null) {            String columnName, type;            Column column;            for (int i$ = 0; i$ < fields.length; i$++) {                //判断当前field是否为Column注解                if (fields[i$].isAnnotationPresent(Column.class)) {                    //获取注解对象                    column = fields[i$].getAnnotation(Column.class);                    columnName = column.name();                    if("".equals(columnName)){                        throw new RuntimeException("未找到对应字段名:" + i$);                    }                    //根据不同类型生成不同的SQL                    if (int.class.isAssignableFrom(fields[i$].getType())) {                        type = "int";                    } else if (String.class.isAssignableFrom(fields[i$].getType())) {                        type = "String";                    } else if (Date.class.isAssignableFrom(fields[i$].getType())) {                        type = "Date";                    } else {                        throw new RuntimeException("不支持数据类型:" + fields[i$].getType().getSimpleName());                    }                    type += (column.isNull() ? " " : " NOT NULL");                    columns.put(columnName, type);                } else if (fields[i$].isAnnotationPresent(PrimaryKey.class)) {                    PrimaryKey primaryKey = fields[i$].getAnnotation(PrimaryKey.class);                    //将一个类的成员变量置为private,其实我也不知道啥意思,有知道的指点一下 ,谢谢!                    fields[i$].setAccessible(true);                    columnName =  primaryKey.name();                    if("".equals(columnName)){                        throw new RuntimeException("未找到对应主键名" );                    }                    type = "INT PRIMARY KEY AUTO_INCREMENT";                    columns.put(columnName, type);                }            }        }        return columns;    }}

其实对于结果,表现的还不够理想,理想方法是把值,对应的Person对象也传入,返回sql语句插入带有具体的值,(一会写,来个BUG。。。。)