mysql sql model_model自动生成对应crud sql语句

该博客介绍了如何通过自定义Annotation和Annotation Processing Tool (APT) 实现根据Model类自动创建增删改查的SQL语句。作者创建了DbInfo、Id、Columns三个Annotation,并在User类中使用它们,然后通过APT读取并处理这些信息,生成对应的SQL文件。博客还包含了创建数据库表、插入数据、删除数据、更新数据和查询数据的SQL示例。
摘要由CSDN通过智能技术生成

前言:在写《来!认识一下强大的Annotation》的时候我说大家喜欢我就再写一篇详细介绍和一篇实例文章。

现在我兑现了我的承诺,并且写了2篇实例文章,感谢大家的支持和关注~

1.本例我们做了生么?

根据model的相关信息生成增删改查的sql语句(通用型的哦~)

保证通用的前提是您的model必须使用DbInfo、Id、columns 三个annotation进行标记

2.步骤:

创建三个annotation(DbInfo、Id、columns)

创建User类,并用上面三个annotation对相应元素进行标记

创建我们自己的APT,让它读取User类的相关信息,并生成对应信息的sql语句

创建一个bat文件让其编译这些java文件(附件提供大家可以下载试用)

通用性测试,编写一个新的类来测试其通用性

3.说明:

本例实际上是在做一个APT(Annotation Processing Tool),采用继承AbstractProcessor实现process方法的方式实现。

执行的时候使用的是命令行 cmd进行执行,本例制作了一个批处理文件,大家直接运行就可以看到生成的sql文件。

本例抛砖引玉,顺着这个思路想 你可以自己做出一个辅助你今后工作的工具助手,不多说勒,自己动脑琢磨琢磨吧。

对程序不多做解释了,需要注意的地方,注释写的很清楚了。

程序存在不完善的地方,有兴趣的朋友可以自己进行完善。

1.采用的是hashmap 所以遍历出来的字段顺序并不是想像中的顺序。

2.本例能对单个类进行生成sql的操作,不能批量对多个类文件进行分析生成,有需要的可以顺着本文思路修改完善。

3.本例对id的生成策略只实现了uuid的方式,可以自行扩展多种方式。

4.insert语句的map遍历没有任何保证。

5.并没有对无字段情况进行判断,可能会引发截字错误。

4.为什么我总爱说 抛砖引玉?

写一个完善的成型的程序 是需要花费大量时间的,这也是例子存在很多不完善的原因。

一个完善的程序势必会包含很多独特的业务逻辑和验证,会使得代码庞大且复杂 不利于学习。

所以我的文章总爱说 抛砖引玉,技术和思路分享给你,怎么用就是各位的事了~

定义三个annotation(DbInfo、Id、columns)

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(); //字段描述

}

定义User类,并用上面的三个annotation标记

/**

* @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 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;

}

}

创建我们自己的APT,让它读取User类的相关信息,并生成对应信息的sql语句

import java.io.FileOutputStream;

import java.util.HashMap;

import java.util.Map;

import java.util.Set;

import java.util.UUID;

import javax.annotation.processing.AbstractProcessor;

import javax.annotation.processing.RoundEnvironment;

import javax.annotation.processing.SupportedAnnotationTypes;

import javax.annotation.processing.SupportedSourceVersion;

import javax.lang.model.SourceVersion;

import javax.lang.model.element.Element;

import javax.lang.model.element.TypeElement;

@SupportedSourceVersion(SourceVersion.RELEASE_7)

@SupportedAnnotationTypes({"DbInfo","Id","columns"})

public class DbAp extends AbstractProcessor

{

Map dbInfo=new HashMap<>(); //用来存储数据库相关信息

Map pkInfo=new HashMap<>(); //主键信息

Map> columnInfo=new HashMap<>(); //字段信息

@Override

public boolean process(Set extends TypeElement> annotations,

RoundEnvironment roundEnv)

{

//它会循环处理每个程序对象,最后一个是空的用于结束的(不是我们主动创建的),我们这里不对其进行处理

if(roundEnv.getRootElements().isEmpty()){ return false;}

String annotationName="";

//遍历当前处理类的所有annotation

for(TypeElement t:annotations)

{

annotationName="@"+t.getSimpleName().toString();

//遍历被t(annotation)修饰的所有元素

for(Element e : roundEnv.getElementsAnnotatedWith(t))

{

//System.out.println("当前annotation是:"+annotationName);

//System.out.println("当前被修饰的元素是:"+e.getSimpleName());

//System.out.println("----------------------");

//获取数据库信息

if(annotationName.equals("@DbInfo"))

{

dbInfo.put("url",e.getAnnotation(DbInfo.class).url());

dbInfo.put("un",e.getAnnotation(DbInfo.class).un());

dbInfo.put("pw",e.getAnnotation(DbInfo.class).pw());

dbInfo.put("table",e.getAnnotation(DbInfo.class).tableName());

}

//获取主键信息

if(annotationName.equals("@Id"))

{

pkInfo.put("t",jtd(e.getClass().getSimpleName())+"(32)");

pkInfo.put("c",e.getAnnotation(Id.class).column());

pkInfo.put("d",e.getAnnotation(Id.class).describe());

pkInfo.put("u",e.getAnnotation(Id.class).generator());

}

//获取字段信息

Map tempOne=null;

if(annotationName.equals("@columns"))

{

tempOne =new HashMap<>();

tempOne.put("t", jtd(e.getAnnotation(columns.class).type()));

tempOne.put("c", e.getAnnotation(columns.class).column());

tempOne.put("d", e.getAnnotation(columns.class).describe());

tempOne.put("l", e.getAnnotation(columns.class).length());

columnInfo.put(e.getSimpleName().toString(), tempOne);

}

}

}

System.out.println("annotation信息获取结束。");

System.out.println(dbInfo);

System.out.println(pkInfo);

System.out.println(columnInfo);

try

{

FileOutputStream fos=new FileOutputStream("mysql.sql");

fos.write(createSql().toString().getBytes());

fos.close();

} catch (Exception e)

{

e.printStackTrace();

}

return true; //annotations是否被这个处理器声明,如果是的话随后的处理器将不再处理这些annotation

}

/**

* 创建数据表

* @throws Exception

*/

public String createSql() throws Exception

{

String uuid=UUID.randomUUID().toString().replaceAll("-", "");

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(" ); \r\n");

//拼装insert语句

sql.append("insert into "+dbInfo.get("table")+" ("+pkInfo.get("c")+",");

for(String one : columnInfo.keySet())

{

sql.append(one+",");

}

sql.delete(sql.length()-1, sql.length());

sql.append(") VALUES ('"+uuid+"'," );

for(String one : columnInfo.keySet())

{

if(columnInfo.get(one).get("t").equals("varchar"))

{

sql.append("'?',");

}

if(columnInfo.get(one).get("t").equals("int"))

{

sql.append("?,");

}

}

sql.delete(sql.length()-1, sql.length());

sql.append( ");\r\n");

//拼装删除语句

sql.append("delete from "+dbInfo.get("table")+" where "+pkInfo.get("c")+"='"+uuid+"';\r\n");

//拼装修改语句

sql.append("UPDATE "+dbInfo.get("table")+" set ");

for(String one : columnInfo.keySet())

{

if(columnInfo.get(one).get("t").equals("varchar"))

{

sql.append(one+"='?',");

}

if(columnInfo.get(one).get("t").equals("int"))

{

sql.append(one+"=?,");

}

}

sql.delete(sql.length()-1, sql.length());

sql.append(" where "+pkInfo.get("c")+"='"+uuid+"';\r\n");

//查询语句

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"));

return sql.toString();

}

/** javaTypeToDbType、java类型和数据库类型的转换

* @param type String

* @return VARCHAR

*/

public String jtd(String type)

{

if("String".equals(type))return "varchar";

if("int".equals(type))return "int";

//其他的自己扩展吧

return "varchar";

}

}

写一个bat文件来使用apt(附件有这个bat)

5ed0d7253fc0fe960e3c46455d929742.png

最后写另一个测试类来测试其通用型

/** 文章类 用于测试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 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;

}

}

结果图:

bf82c0a5b8a96e34c71b0b85cd26e4f9.png

声明:

1.原创文章,转载请标明并加本文连接。

2.文章反映个人愚见,如有异议欢迎讨论指正

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值