一、首先新建一个包annotation,在这个包下面写一个类MyColumn
package hry.utils.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 拓展下Column
*
*/
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface MyColumn {
String name() default "";
boolean unique() default false;
boolean nullable() default true;
boolean insertable() default true;
boolean updatable() default true;
String columnDefinition() default "";
String table() default "";
int length() default 255;
int precision() default 0;
int scale() default 0;
String comment() default "";
String type() default "varchar";
}
这个类就相当于数据库的实体
二、再建一个mybatis的包 里面新建4个类分别是AnnotationUtil、ClassUtil、DBHelper、MybatisGeneration
AnnotationUtil类
package hry.utils.mybatis;
import org.apache.log4j.Logger;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Properties;
public class AnnotationUtil {
public static Properties jdbc;
private static Logger logger = Logger.getLogger(AnnotationUtil.class);
public static void validAnnotation(List<Class<?>> clsList) {
InputStream insjdbc = AnnotationUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
jdbc = new Properties();
try {
jdbc.load(insjdbc);
} catch (IOException e) {
e.printStackTrace();
}
//开始加字段
Long start = System.currentTimeMillis();
if (clsList != null && clsList.size() > 0) {
for (Class<?> forName : clsList) {
if (forName != null) {
Field[] fs = forName.getDeclaredFields();
//先拿到@Table
Table annotationTable = forName.getAnnotation(Table.class);
String columns = "";
if (annotationTable != null) {
String name = "";
try {
name = annotationTable.name();
columns = DBHelper.getColumns(name);
} catch (Exception e) {
e.printStackTrace();
logger.error(name);
continue;
}
} else {//如果不是实体类直接跳过
continue;
}
if (!"".equals(columns) && null != columns) {
for (Field field : fs) {
if (!field.isAccessible()) {
field.setAccessible(true);
}
StringBuffer sb = new StringBuffer("ALTER TABLE " + annotationTable.name() + " ADD ");
//取字段上@Column的name
Column annotationColumn = field.getAnnotation(Column.class);
if (annotationColumn != null) {
try {
if (!"".equals(annotationColumn.name()) && !columns.contains(annotationColumn.name()) && annotationColumn.columnDefinition() != null && (!"".equals(annotationColumn.columnDefinition()))) {
//如果不包含,说明这个字段实体有,数据库没有
logger.error(annotationColumn.name());
//先创建这个字段
sb.append(annotationColumn.name() + " ");
//判断类型
sb.append(annotationColumn.columnDefinition());
//是否为空
/*if (annotationColumn.nullable()) {
sb.append("DEFAULT NULL ");
} else {
sb.append("DEFAULT NOT NULL ");
}*/
//是否唯一
/*if (annotationColumn.unique()) {
sb.append("UNIQUE ");
}
*/
logger.error("sql == " + sb.toString());
DBHelper.execute(sb.toString());
//logger.error(sb);
//字段上是否含有@Id 和 @GeneratedValue,一般这两个字段是一起用的
Id annotationId = field.getAnnotation(Id.class);
GeneratedValue annotationGeneratedValue = field.getAnnotation(GeneratedValue.class);
if (annotationId != null && annotationGeneratedValue != null) {
String sql = "alter table " + annotationTable.name() + " change " + annotationColumn.name() + " " + annotationColumn.name() + " " + annotationColumn.columnDefinition() + " AUTO_INCREMENT PRIMARY KEY";
DBHelper.execute(sql.toString());
logger.error(sql);
}
}
} catch (Exception e) {
//e.printStackTrace();
logger.error(annotationTable.name());
}
}
}
}
}
}
}
logger.error("加字段结束,耗时" + (System.currentTimeMillis() - start) / 1000 + "秒");
}
}
ClassUtil类
package hry.utils.mybatis;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.regex.Pattern;
public class ClassUtil {
/**
* 通过包名获取包内所有类
*
* @param pkg
* @return
*/
public static List<Class<?>> getAllClassByPackageName(String pkg) {
//String packageName = pkg.getName();
// 获取当前包下以及子包下所以的类
List<Class<?>> returnClassList = getClasses(pkg);
return returnClassList;
}
/**
* 通过接口名取得某个接口下所有实现这个接口的类
*/
public static List<Class<?>> getAllClassByInterface(Class<?> c) {
List<Class<?>> returnClassList = null;
if (c.isInterface()) {
// 获取当前的包名
String packageName = c.getPackage().getName();
// 获取当前包下以及子包下所以的类
List<Class<?>> allClass = getClasses(packageName);
if (allClass != null) {
returnClassList = new ArrayList<Class<?>>();
for (Class<?> cls : allClass) {
// 判断是否是同一个接口
if (c.isAssignableFrom(cls)) {
// 本身不加入进去
if (!c.equals(cls)) {
returnClassList.add(cls);
}
}
}
}
}
return returnClassList;
}
/**
* 取得某一类所在包的所有类名 不含迭代
*/
public static String[] getPackageAllClassName(String classLocation, String packageName) {
// 将packageName分解
String[] packagePathSplit = packageName.split("[.]");
String realClassLocation = classLocation;
int packageLength = packagePathSplit.length;
for (int i = 0; i < packageLength; i++) {
realClassLocation = realClassLocation + File.separator + packagePathSplit[i];
}
File packeageDir = new File(realClassLocation);
if (packeageDir.isDirectory()) {
String[] allClassName = packeageDir.list();
return allClassName;
}
return null;
}
/**
* 从包package中获取所有的Class
*
* @param
* @return
*/
private static List<Class<?>> getClasses(String packageName) {
// 第一个class类的集合
List<Class<?>> classes = new ArrayList<Class<?>>();
// 是否循环迭代
boolean recursive = true;
// 获取包的名字 并进行替换
String packageDirName = packageName.replace('.', '/');
// 定义一个枚举的集合 并进行循环来处理这个目录下的things
Enumeration<URL> dirs;
try {
dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
// 循环迭代下去
while (dirs.hasMoreElements()) {
// 获取下一个元素
URL url = dirs.nextElement();
// 得到协议的名称
String protocol = url.getProtocol();
// 如果是以文件的形式保存在服务器上
if ("file".equals(protocol)) {
// 获取包的物理路径
String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
// 以文件的方式扫描整个包下的文件 并添加到集合中
findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);
} else if ("jar".equals(protocol)) {
// 如果是jar包文件
// 定义一个JarFile
JarFile jar;
try {
// 获取jar
jar = ((JarURLConnection) url.openConnection()).getJarFile();
// 从此jar包 得到一个枚举类
Enumeration<JarEntry> entries = jar.entries();
// 同样的进行循环迭代
while (entries.hasMoreElements()) {
// 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
JarEntry entry = entries.nextElement();
String name = entry.getName();
// 如果是以/开头的
if (name.charAt(0) == '/') {
// 获取后面的字符串
name = name.substring(1);
}
// 如果前半部分和定义的包名相同
if (name.startsWith(packageDirName)) {
int idx = name.lastIndexOf('/');
// 如果以"/"结尾 是一个包
if (idx != -1) {
// 获取包名 把"/"替换成"."
packageName = name.substring(0, idx).replace('/', '.');
}
// 如果可以迭代下去 并且是一个包
if ((idx != -1) || recursive) {
// 如果是一个.class文件 而且不是目录
String pattern = "hry/[a-zA-Z]*/[a-zA-Z]*/model/[a-zA-Z]*\\.class";
if (name.endsWith(".class") && !entry.isDirectory()) {
if(!name.contains("model")){
continue;
}
if(!Pattern.matches(pattern, name)){
continue;
}
// 去掉后面的".class" 获取真正的类名
String className = name.substring(packageName.length() + 1, name.length() - 6);
try {
// 添加到classes
classes.add(Class.forName(packageName + '.' + className));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return classes;
}
/**
* 以文件的形式来获取包下的所有Class
*
* @param packageName
* @param packagePath
* @param recursive
* @param classes
*/
private static void findAndAddClassesInPackageByFile(String packageName, String packagePath, final boolean recursive, List<Class<?>> classes) {
// 获取此包的目录 建立一个File
File dir = new File(packagePath);
// 如果不存在或者 也不是目录就直接返回
if (!dir.exists() || !dir.isDirectory()) {
return;
}
// 如果存在 就获取包下的所有文件 包括目录
File[] dirfiles = dir.listFiles(new FileFilter() {
// 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
public boolean accept(File file) {
return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));
}
});
// 循环所有文件
for (File file : dirfiles) {
// 如果是目录 则继续扫描
if (file.isDirectory()) {
findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes);
} else {
// 如果是java类文件 去掉后面的.class 只留下类名
String name = file.getPath();
if(!name.contains("model")){
continue;
}
String pattern = "hry/[a-zA-Z]*/[a-zA-Z]*/model/[a-zA-Z]*\\.class";
String clName = name.replace("\\","/").split("classes")[1].substring(1);
if(!Pattern.matches(pattern,clName)){
continue;
}
String className = file.getName().substring(0, file.getName().length() - 6);
try {
// 添加到集合中去
classes.add(Class.forName(packageName + '.' + className));
} catch (ClassNotFoundException e) {
//e.printStackTrace();
//System.out.println("类"+className+"不存在");
}
}
}
}
public static void main(String[] args) {
List<Class<?>> clsList = ClassUtil.getAllClassByPackageName("hry");
AnnotationUtil.validAnnotation(clsList);
}
}
DBHelper类
package hry.utils.mybatis;
import org.apache.log4j.Logger;
import java.sql.*;
public class DBHelper {
public static final String name = "com.mysql.jdbc.Driver";
private static Logger logger = Logger.getLogger(DBHelper.class);
public Connection conn = null;
public PreparedStatement pst = null;
public DBHelper(String sql) {
try {
Class.forName(name);//指定连接类型
conn = DriverManager.getConnection(AnnotationUtil.jdbc.getProperty("jdbc.url"), AnnotationUtil.jdbc.getProperty("jdbc.username"), AnnotationUtil.jdbc.getProperty("jdbc.password"));//获取连接
pst = conn.prepareStatement(sql);//准备执行语句
} catch (Exception e) {
e.printStackTrace();
}
}
public void close() {
try {
this.conn.close();
this.pst.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void execute(String sql){
try {
DBHelper db = new DBHelper(sql);
db.pst.execute();
db.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public static String getColumns(String tableName){
DBHelper db = new DBHelper("show full columns from "+tableName+" ");
StringBuffer sb = new StringBuffer();
try {
ResultSet ret = db.pst.executeQuery();
while (ret.next()) {
sb.append(ret.getString(1) + ",");
}
ret.close();
db.close();//关闭连接
return sb.deleteCharAt(sb.length()-1).toString();
} catch (SQLException e) {
//e.printStackTrace();
logger.error("表"+tableName+"不存在");
}
return null;
}
}
MybatisGeneration类
package hry.utils.mybatis;
import hry.utils.annotation.MyColumn;
import org.apache.log4j.Logger;
import org.springframework.util.StringUtils;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.Properties;
/**
*
* MybatisGeneration.java
*/
public class MybatisGeneration {
private static Logger logger = Logger.getLogger(MybatisGeneration.class);
public static Properties jdbc;
public static void generation(){
InputStream insjdbc = MybatisGeneration.class.getClassLoader().getResourceAsStream("jdbc.properties");
jdbc = new Properties();
try {
jdbc.load(insjdbc);
} catch (IOException e) {
e.printStackTrace();
}
InputStream ins = MybatisGeneration.class.getClassLoader().getResourceAsStream("code.properties");
Properties pro = new Properties();
try {
pro.load(ins);
} catch (IOException e) {
e.printStackTrace();
}
String modelUrl = pro.getProperty("modelUrl");
if(!StringUtils.isEmpty(modelUrl)){
logger.error("modelUrl == " + modelUrl);
String[] str = modelUrl.split(",");
if(str.length>0){
try {
for(int i=0;i<str.length;i++){
Class<?> forName = Class.forName(str[i]);
if(forName!=null){
Field[] fs = forName.getDeclaredFields();
//先拿到@Table
Table annotationTable = forName.getAnnotation(Table.class);
String columns = "";
if(annotationTable!=null){
columns = DBHelper.getColumns(annotationTable.name());
}
if(!"".equals(columns)){
for(Field field : fs){
if(!field.isAccessible()){
field.setAccessible(true);
}
StringBuffer sb = new StringBuffer("ALTER TABLE "+ annotationTable.name() +" ADD ");
//取字段上@MyColumn的name
MyColumn annotationColumn = field.getAnnotation(MyColumn.class);
if(annotationColumn!=null){
if(!"".equals(annotationColumn.name()) && !columns.contains(annotationColumn.name())){
//如果不包含,说明这个字段实体有,数据库没有
//先创建这个字段
sb.append(annotationColumn.name() +" ");
//判断类型
if("text".equals(annotationColumn.type())){
sb.append(annotationColumn.type());
}else if("datetime".equals(annotationColumn.type())){
sb.append("datetime ");
}else if("decimal".equals(annotationColumn.type())){
sb.append("DECIMAL(" + annotationColumn.precision() + "," + annotationColumn.scale() + ") ");
}else{
sb.append("" + annotationColumn.type() + "("+ annotationColumn.length() +") ");
}
//是否为空
if(annotationColumn.nullable()){
sb.append("DEFAULT NULL ");
}else{
sb.append("DEFAULT NOT NULL ");
}
//是否唯一
if(annotationColumn.unique()){
sb.append("UNIQUE ");
}
//注释
if(!"".equals(annotationColumn.comment())){
sb.append("COMMENT '"+ annotationColumn.comment() +"'");
}
logger.error("sql == " + sb.toString());
DBHelper.execute(sb.toString());
//字段上是否含有@Id 和 @GeneratedValue,一般这两个字段是一起用的
Id annotationId = field.getAnnotation(Id.class);
GeneratedValue annotationGeneratedValue = field.getAnnotation(GeneratedValue.class);
if(annotationId!=null && annotationGeneratedValue!=null){
String sql = "alter table "+ annotationTable.name() +" change "+ annotationColumn.name() +" "+ annotationColumn.name() +" "+ annotationColumn.type() +" AUTO_INCREMENT PRIMARY KEY";
DBHelper.execute(sql.toString());
}
}
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
MybatisGeneration.generation();
}
}
三、在定时器中添加代码如下
//扫描实体类,配置注解可生成字段
List<Class<?>> clsList = ClassUtil.getAllClassByPackageName("hry");
AnnotationUtil.validAnnotation(clsList);
、
这个“”里面填你的总包名 例如本地的main中新建有hry包,这个就会扫描你这个包里面的所有实体类
四、在实体类中添加注解属性
然后只要在实体类中配有属性columnDefinition 就能根据类去生成字段了
@Column(name= “address”, columnDefinition= “varchar(255) DEFAULT NULL COMMENT ‘地址’”)