前言
在大一上学期的寒假和大一下学期的一个月时间里,学完了java基础的我只知道java基础中的基础,对于集合等容器也是只会用,而多线程和反射更是只知道有这东西,不会用啊.学完了mybatis和hibernate,依旧菜鸟的我发出了感叹:逆向工程真的好强大啊,只要有个库名就可以自动生成表.并且经常写crud也没意思,于是我感觉我似乎可以试试.因此我就自己写了一个简陋的建表逆向工程,这东西浪费了我4个小时.不多说,
开搞
用到的包
项目结构
1.首先要在数据库中建个库
2.连接数据库(这里可以用连接池,也可以不用,我用的Druid连接池)
3.DBSource用于解析配置文件并返回一个Connection
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;
import javax.sql.DataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
public class DBSource {
public Connection getConnection(Properties pp) {
try {
pp = new Properties();
InputStream is = ClassLoader.getSystemResourceAsStream("druid.properties");
pp.load(is);
DataSource createDataSource = DruidDataSourceFactory.createDataSource(pp);
return createDataSource.getConnection();
} catch (Exception e) {
e.getStackTrace();
}
return null;
}
}
4.写Table和Colume注解类
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD,ElementType.LOCAL_VARIABLE,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
String name() default "";//表名
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Colume {
String columeName() default "";//字段名字
boolean isId() default false;//是否是id
boolean isNull() default true;//是否为空
boolean isKey() default false;//是否是主键
boolean isAutoIncrement() default false;//是否自增
int howBig() default 0;//大小
}
5.写两个实体类,并将要用的注解标注上去
import org.vector.annotation.Colume;
import org.vector.annotation.Table;
@Table(name = "mytest")
public class MyTest {
@Colume(columeName = "tid", isAutoIncrement = true, howBig = 10, isKey = true, isId = true, isNull = false)
private int tid;
@Colume(columeName = "tname", isAutoIncrement = false, howBig = 255, isKey = false, isId = false, isNull = true)
private String tname;
@Colume(columeName = "tsex", isAutoIncrement = false, howBig = 2, isKey = false, isId = false, isNull = true)
private String tsex;
public MyTest() {
super();
}
public MyTest(int tid, String tname, String tsex) {
this.tid = tid;
this.tname = tname;
this.tsex = tsex;
}
/*对应的get和set方法,toString方法*/
}
import org.vector.annotation.Colume;
import org.vector.annotation.Table;
@Table(name = "test")
public class Test {
@Colume(columeName = "tid", isAutoIncrement = true, howBig = 10, isKey = true, isId = true, isNull = false)
private int tid;
@Colume(columeName = "tname", isAutoIncrement = false, howBig = 255, isKey = false, isId = false, isNull = true)
private String tname;
@Colume(columeName = "tsex", isAutoIncrement = false, howBig = 2, isKey = false, isId = false, isNull = true)
private String tsex;
public Test() {
super();
}
public Test(int tid, String tname, String tsex) {
this.tid = tid;
this.tname = tname;
this.tsex = tsex;
}
/*对应的get和set方法,toString方法*/
}
6.写一个表的字段对应的各种属性的实体类
public class ColumeDomain {
private String columeName;//表名
private boolean isAutoIncrement;//是否自增
private int howBig;//大小
private boolean isKey;//是否为主键
private boolean isId;//是否为id
private boolean isNull;//是否为空
private String type;//数据类型
public ColumeDomain() {
super();
}
public ColumeDomain(String columeName, boolean isAutoIncrement, int howBig, boolean isKey, boolean isId,
boolean isNull, String type) {
this.columeName = columeName;
this.isAutoIncrement = isAutoIncrement;
this.howBig = howBig;
this.isKey = isKey;
this.isId = isId;
this.isNull = isNull;
this.type = type;
}
/*对应的get和set方法,toString方法*/
}
7.要创建一个表,肯定要用到表头和各个字段,创建一个工具类AnnotationUtils
7.1写一个获取表头的方法
public static String getTableName(Class<?> clazz) {//反射获取标注注解的实体类
Table table = clazz.getAnnotation(Table.class);//获取实体类上的注解
if (table != null) {//如果有注解
return table.name().toLowerCase();//获取表名并小写
} else {
return clazz.getSimpleName().toLowerCase();//如果没注解就获取实体类名并小写
}
}
7.2写一个获取各个字段的方法
public static Map<String, ColumeDomain> getFieldName(Class<?> clazz) {//返回是一个map集合
Field[] fields = clazz.getDeclaredFields();//通过反射获取所有字段
Map<String, ColumeDomain> list = new HashMap<String, ColumeDomain>();//键为字段名,值是封装的字段的属性类
for (Field field : fields) {//遍历每一个字段
Class<?> type = field.getType();//获取字段的类型
String n_name, n_type;
boolean n_isAutoIncrement, n_isKey, n_isId, n_isNull;
int n_howBig;
ColumeDomain cd = new ColumeDomain();//创建字段的属性类
field.setAccessible(true);//为了防止需要更改字段的值,设置字段可更改
String substring = String.valueOf(field)
.substring(String.valueOf(field).lastIndexOf("."), String.valueOf(field).length()).replace(".", "");//截取字段,让他是一个需要的字符串,不然带着数据类型很麻烦
// System.out.println("substring --> " +substring);
Colume colum = field.getAnnotation(Colume.class);//获取字段上的注解
//判断字段的数据类型,封装到属性类的Type字段中
if (type == int.class || type == Integer.class) {
cd.setType("int");
} else if (type == Long.class || type == long.class) {
cd.setType("bigint");
} else if (type == float.class || type == Float.class) {
cd.setType("float");
} else if (type == double.class || type == Double.class) {
cd.setType("double");
} else if (type == String.class) {
cd.setType("varchar");
} else if (type == Date.class) {
cd.setType("datetime");
}
//如果colum注解类的columeName没写
if (colum.columeName() == "") {
n_name = field.getName();//就获取字段名
} else {
n_name = colum.columeName().toLowerCase();//写了就获取columeName的小写作为字段名
}
if (String.valueOf(colum.isAutoIncrement()) == "") {
n_isAutoIncrement = false;
} else {
n_isAutoIncrement = colum.isAutoIncrement();
}
if (colum.howBig() == 0) {
n_howBig = 255;
} else {
n_howBig = colum.howBig();
}
if (String.valueOf(colum.isKey()) == "") {
n_isKey = false;
} else {
n_isKey = colum.isKey();
}
if (String.valueOf(colum.isId()) == "") {
n_isId = false;
} else {
n_isId = colum.isId();
}
if (String.valueOf(colum.isNull()) == "") {
n_isNull = false;
} else {
n_isNull = colum.isNull();
}
//集体封装到属性类中
cd.setAutoIncrement(n_isAutoIncrement);
cd.setColumeName(n_name);
cd.setHowBig(n_howBig);
cd.setId(n_isId);
cd.setKey(n_isKey);
cd.setNull(n_isNull);
//把每一个字段和属性类放到map集合中
list.put(substring, cd);
}
return list;
}
8.写个工厂类DBSourceFactory,并在工厂类中写一个表示缓存(实际上就是一个名字)的类DBSession,
8.1在工厂类刚创建的时候就获取数据库的连接,就是构造函数
private Connection connection;
public DBSourceFactory() {
DBSource dbSource = new DBSource();
Properties pp = new Properties();
connection = dbSource.getConnection(pp);
}
8.2创建DBSession类的时候就要在他加载的时候获取数据库连接,就是构造函数
private Connection conn;
public DBSession(Connection connection) {
this.conn = connection;
}
8.3要想使用DBSession,那么就要new这个DBSession对象,有了工厂类,并且DBSession类还在工厂类中,那么就可以用一个方法返回带数据库连接的DBSession对象,就像这样
public class DBSourceFactory {
private Connection connection;
public DBSourceFactory() {
DBSource dbSource = new DBSource();
Properties pp = new Properties();
connection = dbSource.getConnection(pp);
}
public DBSession opSession() {
return new DBSession(connection);
}
public class DBSession {
private Connection conn;
public DBSession(Connection connection) {
this.conn = connection;
}
}
}
8.4在DBSession中写用于创建表的方法create(Class<?> clazz),传入的是一个类
8.4.1写大概的SQL语句
String sql = "create table %s (%s)engine=innodb;";
8.4.2获取表名
String tableName = AnnotationUtils.getTableName(clazz);
8.4.3获取字段集合
Map<String, ColumeDomain> fieldName = AnnotationUtils.getFieldName(clazz);
8.4.4遍历每一个字段集合
int i = 0;
String parame = "";
for (String str : fieldName.keySet()) {//map集合遍历
String key, isNull, isAutoIncrement;
ColumeDomain columeDomain = fieldName.get(str);//通过字段获取字段的属性类
// System.out.println(str + " ---> " + columeDomain);
if (columeDomain.isKey()) {//如果isKey是true
key = "primary key";//主键
isAutoIncrement = "auto_increment";//自增
} else {//不是得话就
key = "";
isAutoIncrement = "";
}
if (!columeDomain.isNull()) {//如果isNull是false
isNull = "not null";
} else {//如果isNull是true
isNull = "";
}
//字段名+数据类型+大小+是否为主键+是否空+是否自增
parame += columeDomain.getColumeName() + " " + columeDomain.getType() + "("
+ columeDomain.getHowBig() + ") " + key + " " + isNull + " " + isAutoIncrement;
if (i <= fieldName.keySet().size()) {//拼接逗号
parame += ",";
}
i++;
}
parame = (String) parame.subSequence(0, parame.length() - 1);//最后拼接的语句会有一个逗号,这个用于截取
sql = String.format(sql, tableName, parame);//将SQL语句拼接完整
PreparedStatement prepareStatement = conn.prepareStatement(sql);//预处理类处理
int executeUpdate = prepareStatement.executeUpdate();//开始执行
System.out.println(executeUpdate);//打印结果
整个方法
public void create(Class<?> clazz) {
try {
String sql = "create table %s (%s)engine=innodb;";
String tableName = AnnotationUtils.getTableName(clazz);
// System.out.println(tableName);
Map<String, ColumeDomain> fieldName = AnnotationUtils.getFieldName(clazz);
int i = 0;
String parame = "";
for (String str : fieldName.keySet()) {//map集合遍历
String key, isNull, isAutoIncrement;
ColumeDomain columeDomain = fieldName.get(str);//通过字段获取字段的属性类
// System.out.println(str + " ---> " + columeDomain);
if (columeDomain.isKey()) {//如果isKey是true
key = "primary key";//主键
isAutoIncrement = "auto_increment";//自增
} else {//不是得话就
key = "";
isAutoIncrement = "";
}
if (!columeDomain.isNull()) {//如果isNull是false
isNull = "not null";
} else {//如果isNull是true
isNull = "";
}
//字段名+数据类型+大小+是否为主键+是否空+是否自增
parame += columeDomain.getColumeName() + " " + columeDomain.getType() + "("
+ columeDomain.getHowBig() + ") " + key + " " + isNull + " " + isAutoIncrement;
if (i <= fieldName.keySet().size()) {//拼接逗号
parame += ",";
}
i++;
}
parame = (String) parame.subSequence(0, parame.length() - 1);//最后拼接的语句会有一个逗号,这个用于截取
sql = String.format(sql, tableName, parame);//将SQL语句拼接完整
PreparedStatement prepareStatement = conn.prepareStatement(sql);//预处理类处理
int executeUpdate = prepareStatement.executeUpdate();//开始执行
System.out.println(executeUpdate);//打印结果
} catch (Exception e) {
e.printStackTrace();
}
}
9.测试类
public static void main(String[] args) {
DBSourceFactory dbs = new DBSourceFactory();
DBSession opSession = dbs.opSession();
opSession.create(Test.class);
opSession.create(MyTest.class);
}
网友评论