前言:在写《来!认识一下强大的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<>(); //字段信息 @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<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 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; } }
结果图:
声明:
1.原创文章,转载请标明并加本文连接。
2.文章反映个人愚见,如有异议欢迎讨论指正
相关推荐
这种工具能够根据用户输入的表名,自动生成对应的FormBean类以及处理这些表数据的CRUD操作的Java代码,这在基于Java的MVC(Model-View-Controller)框架的开发中尤为常见。 生成SQL语句的工具通常具备以下功能: 1...
EF根据定义的模型类自动创建数据库表结构,并能根据这些模型生成相应的CRUD(Create, Read, Update, Delete)操作的SQL语句。这大大降低了开发难度,提高了开发效率。理解EF的工作原理,包括代码优先和数据库优先两...
这些代码会根据`qureyTabinfo.txt`中的信息,自动生成与数据库表对应的CRUD(创建、读取、更新、删除)操作。 自动生成访问SQL Server数据库的VC代码,通常涉及到以下技术点: 1. ADO(ActiveX Data Objects)或...
这个工具可能是用来配置数据库连接参数,并指定CRUD生成代码的目标模块包名,随后执行脚本来自动化生成对应的Java实体类、DAO层、Service层以及Controller层的代码。 首先,配置数据库和CRUD模块包名是使用此类工具...
本主题聚焦于如何利用C#和EF来根据模型动态生成SQL语句,这有助于提高开发效率,同时也让我们更深入地理解EF的工作原理。 在传统的开发模式中,开发者通常需要手动编写SQL语句来与数据库进行交互,这不仅费时,而且...
1. **SQL语句自动创建**:根据数据库中的表结构,自动生成增删改查(CRUD)操作的SQL语句,这些语句会被写入到Mapper接口和XML映射文件中。 2. **DAO接口和实现类**:自动创建对应的DAO接口和实现类,这些类包含了...
代码生成工具能够根据数据库表结构生成相应的CRUD(Create、Read、Update、Delete)SQL语句,包括插入、查询、更新和删除操作,减少了手动编写SQL的工作量。 3. **数据访问对象(DAO)**: DAO层是介于业务逻辑层和...
自动生成MODEL的工具或框架可以解析数据库结构,根据数据库表或视图的信息自动创建对应的C#类,这些类通常包含了属性,这些属性与数据库中的字段相对应。这种方式使得开发者无需手动编写每个数据实体的代码,大大...
MybatisTool会为每个Mapper接口生成对应的XML文件,内含插入、查询、更新和删除等SQL语句。 4. **灵活的配置**:MybatisTool通常允许开发者自定义生成规则,比如字段命名规则、是否生成注释等,以满足不同项目的...
3. **配置Repository**:定义一个接口继承自JpaRepository,该接口将自动提供CRUD(创建、读取、更新、删除)操作。也可以自定义更复杂的查询方法。 4. **创建Freemarker模板**:在src/main/resources/templates...
开发者只需要提供待插入的数据对象,代码生成器会自动生成对应的SQL语句并执行。 2. Update():更新已存在的数据记录。通过指定的主键值找到需要更新的记录,并根据提供的数据对象更新对应字段。 3. GetByID():...
它们是ORM(对象关系映射)框架的基础,使得开发者可以使用面向对象的编程方式来操作数据库,而无需关心底层的SQL语句。SQLServer是微软提供的一款强大、可靠的关系型数据库管理系统,广泛应用于各种业务系统。当...
在生成的XML文件中,通常包含了SQL的增删改查(CRUD)操作,这些操作与Model类对应,使得开发人员可以通过简单的Java调用来执行数据库操作。DAO文件则是Java接口,提供了一组方法,这些方法的实现由MyBatis框架自动...
2. 指定实体类:提供需要生成CRUD代码的实体类(Model)信息,这些类通常对应数据库中的表。 3. 执行生成:运行JAR文件,根据配置和指定的实体类,工具会自动生成对应的Mapper接口、Mapper XML文件、Service接口和...
XML文件中包含了具体的SQL语句,而接口方法则对应着这些SQL语句的执行逻辑。通过这样的设计,开发者可以灵活地定制SQL,同时保持代码的整洁。 五、配置文件 MBG的运行需要一个配置文件(通常为`generatorConfig.xml...
JPA通过提供一套标准API,使得开发者无需关注底层SQL语句,而是通过定义实体类、注解以及Repository接口,即可完成数据的CRUD(创建、读取、更新、删除)操作。例如,一个简单的User实体类可能如下所示: ```java @...
在实际开发中,为了提高开发效率,我们会使用代码生成工具来自动生成Model、Mapper和DAO等基础代码,避免手动编写重复的 CRUD(创建、读取、更新、删除)操作。标题和描述中提到的“mybatis书库据自动生成代码工具”...
MBG会为每个接口生成对应的XML文件,里面包含对应的SQL语句,实现了接口方法与SQL的绑定。 3. **DAO(Data Access Object)**:DAO层是数据库操作的抽象,通常包含了一些通用的CRUD操作。MBG会自动生成DAO接口及其...
MBG会根据表的结构自动生成基本的CRUD操作的SQL语句,开发者可以在此基础上进行扩展和定制。 在使用MBG时,首先需要创建一个配置文件(通常为`generatorConfig.xml`),在其中指定数据库连接信息、表名、生成的Java...