model自动生成对应crud sql语句

来源:转载

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

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

阅读此文前建议先看《来!认识一下强大的Annotation》、《Annotation详细介绍》两篇文章。

另一篇实例《annotation实现数据映射》

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<String,String> dbInfo=new HashMap<>(); //用来存储数据库相关信息Map<String,String> pkInfo=new HashMap<>(); //主键信息Map<String,Map<String,Object>> columnInfo=new HashMap<>(); //字段信息@Overridepublic boolean process(Set<? extends TypeElement> annotations,RoundEnvironment roundEnv){//它会循环处理每个程序对象,最后一个是空的用于结束的(不是我们主动创建的),我们这里不对其进行处理if(roundEnv.getRootElements().isEmpty()){ return false;} String annotationName="";//遍历当前处理类的所有annotationfor(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<String,Object> 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)


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

/** 文章类 用于测试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 s; //文章[email protected](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;}}

结果图:



声明:

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

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

大小: 48.2 KB 大小: 70.2 KB APT.rar (4.4 KB) 下载次数: 46



分享给朋友:
您可能感兴趣的文章:
随机阅读: