关于如何在项目中实现以注解的方式添加数据库字段

一、首先新建一个包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 ‘地址’”)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lamantin

地址:jackzero.eth

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值