使用自定义注解,自动生成简易的SQL语句

使用反射+自定义注解实现自动生成简易的查询SQL语句

自定义注解:
@Target(ElementType.TYPE) //用于注释类或接口
@Retention(RetentionPolicy.RUNTIME) //运行时注解
@Inherited //允许被继承使用
@Documented
public @interface Table {
    /**
     * 数据库表名
     * @return java.lang.String
     * @author zhj
     * @date 2019/4/1
     */
    String value();
}

@Target(ElementType.FIELD) //用于字段注解
@Retention(RetentionPolicy.RUNTIME) //运行时注解
@Inherited
@Documented
public @interface Column {
    /**
     * 字段的名称
     * @return java.lang.String
     * @author zhj
     * @date 2019/4/1
     */
    String value();
}

↑自定义注解:@Table 和@Column

实体类:
@Data
@AllArgsConstructor
@NoArgsConstructor
@Table("user")
public class User {
    @Column("user_name")
    private String name;

    @Column("user_password")
    private String password;

    @Column("user_id")
    private Integer id;

    @Column("user_address")
    private String address;
}

↑实体类使用了自定义注解标注属性和类

工具类:
public class GenerateSQLUtil {
    private static GenerateSQLUtil gu = new GenerateSQLUtil();
    private GenerateSQLUtil(){}

    public static GenerateSQLUtil getInstance() {
        return gu;
    }

    /**
     *  <b>返回使用@Table注解的对象的查询sql语句</b><br/>
     *  使用方法:<br/>
     *  1.传入的Object类必须使用@Table注解<br/>
     *  2.Object类需要查询的字段应用@Column(表字段名)注解<br/>
     *  3.Object类需要有Getter方法<br/>
     * @param table 使用@Table注解的对象
     * @return java.lang.String
     * @author zhj
     * @creed: Talk is cheap,show me the code
     * @date 2019/4/1
     */
    public String query(Object table) throws Exception {
        //初始化SQL语句
        StringBuilder sb = new StringBuilder("select * form ");
        //通过反射,拿到class
        Class tab = table.getClass();
        //判断class是否有@Table注解
        boolean tExists = tab.isAnnotationPresent(Table.class);
        if (!tExists) {
            //没有注解,则抛出异常
            throw new Exception("该类没有使用相关注解");
        }
        //有@Table注解, 则通过注解拿到表名
        String tableName = ((Table)tab.getAnnotation(Table.class)).value();
        //拼接SQL语句
        sb.append(tableName).append(" where 1=1 ");
        appendColumnSql(table, sb, tab);
        return sb.toString();
    }

    private void appendColumnSql(Object table,StringBuilder sb, Class tab) {
        //取类的属性
        Field[] fields = tab.getDeclaredFields();
        //遍历属性是否有注解
        for (Field field : fields) {
            if (!field.isAnnotationPresent(Column.class)) {
                //该字段没有@Column注解,则continue
                continue;
            }
            Column fAnno = field.getAnnotation(Column.class);
            //拿到注解的value值,即表字段名
            String columnName = fAnno.value();
            //类属性名
            String fieldName = field.getName();
            //判断对象中该属性是否有值,有值则默认此为查询条件之一
            try {
                String methodName =  new StringBuffer("get").append(fieldName.substring(0,1).toUpperCase())
                        .append(fieldName.substring(1)).toString();
                Method getterMethod
                        = tab.getMethod(methodName);
                System.out.println("methodName:" + methodName);
                //调用getter方法拿到对象参数
                Object fieldValue = getterMethod.invoke(table);
                //拼接SQL
                //=null说明对象没有该参数,无需拼接
                if (fieldValue != null) {
                    sb.append(" and ").append(columnName);
                    //如果是String,并且包含“,”说明是多参数,应该拼接in
                    if (fieldValue.toString().contains(",") && fieldValue instanceof String) {
                        sb.append(" in (");
                        //切割参数
                        String[] propertys =((String) fieldValue).split(",");
                        for (int i = 0; i < propertys.length;) {
                            sb.append("`").append(propertys[i]).append("`");
                            if (++i == propertys.length) {
                                sb.append(")");
                                break;
                            }
                            sb.append(",");
                        }
                        //如果是String类型,则需要增加``符号
                    } else  if (fieldValue instanceof String) {
                        sb.append(" =`")
                                .append(fieldValue).append("`");
                        //其他情况,可以扩展
                    } else {
                        sb.append(" =").append(fieldValue);
                    }
                }
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
}
测试类:
public class GenerateSQLTest {
    public static void main(String[] args) {
        User u = new User();
        u.setAddress("厦门,泉州,福州");
        u.setId(55);
        try {
            String sql  = GenerateSQLUtil.getInstance().query(u);
            System.out.println("sql语句为:" + sql);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
运行结果:
methodName:getName
methodName:getPassword
methodName:getId
methodName:getAddress
sql语句为:select * form user where 1=1  and 
user_id =55 and user_address in (`厦门`,`泉州`,`福州`)

实现的原理:通过反射判断类中是否有使用自定义注解,有的话,则拿取注解的value以及拿取对象的属性值进行拼接sql语句,该demo只是做了简单的query语句,可以通过复杂的条件判断实现更复杂的sql语句生成。

1.反射
	获取所有属性:Field[] getDeclaredFields();
	获取所有方法:Method[] getMethods();
	获取对象的属性值:Object invoke(Object object)
	获取类对象:Class Class.forName(相对路径包className);
2.自定义注解:
	@Target(ElementType.FIELD) //用于字段注解
	@Retention(RetentionPolicy.RUNTIME) //运行时注解
	@Inherited //子类是否能继承
	@Documented //文档

猜你喜欢

转载自blog.csdn.net/weixin_43041241/article/details/88942508