由于最近的项目老是修改,需求变一下,其他同事改了对象,别的同事表里又没有添加该字段,每次更新项目都得去看有没有新添加sql,领导觉得麻烦,让我找找有没有没有什么注解可以标在上面,新加的对象属性自己去生成库。花了一个小时,也终于写好,但不知道怎么样。。。。。
启动时执行的办法
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class TestSql {
/*
*
* tiny
* 2021/01/14
* 使用该功能,需要配置tinypath路径(entity全路径)
* 在新建的字段上面加上@Newfield注解,启动应用时会根据注解进行对新加的属性添加到对应的表中
*
* */
@Autowired
private SqlSession sqlSession;
@Value("${tinypath}")
private String tinypath;
/*
*
* 启动项目加载
* */
// @PostConstruct
public void mains() throws Throwable{
/*
*
* 通过包名获取到entity文件夹下的所有类名
*
* */
List<String> list=InitSql.getClassName(tinypath,true);
int len=list.size();
for (int i = 0; i < len; i++) {
/*
* 用反射获取到field
*
* */
Class clz=Class.forName(tinypath+"."+list.get(i));
Field[] fields=clz.getDeclaredFields();
for (Field f:fields) {
/*
*
* 通过反射检查每个实体对象的属性上面是否标有@Newfield我创建的注解
* 如果有证明新建属性,数据库没有改字段
*
* */
if(null!=f.getAnnotation(Newfield.class)){
if(connection(checktable(list.get(i),f.getName()))){
Map<String,String> map=getcoumltype();
String sql=addsql(gethump(list.get(i)),gethump(f.getName()),(String)getcoumltype().get(f.getType().getName()));
ex(sql);
};
}
}
}
}
/*
*检查该属性是否已经存再数据库
* */
public static String checktable(String tablaname,String filedsname){
StringBuffer stringBuffer=new StringBuffer();
stringBuffer.append("select table_name from information_schema.columns where table_name="+"'");
stringBuffer.append(gethump(tablaname)+"' and column_name='");
stringBuffer.append(filedsname+"'");
System.out.println(stringBuffer.toString()+"##########");
return stringBuffer.toString();
}
/*
* 还原驼峰命名
*
* */
public static String gethump(String classname){
char[] a=classname.toCharArray();
StringBuffer stringBuffer=new StringBuffer();
/*
*将首字母大写变小写
* */
if(a[0]>=65 && a[0]<=90){
stringBuffer.append((char)(a[0]+32));
}
else {
stringBuffer.append(a[0]);
}
for(int i=1;i<a.length;i++){
/*
* 大写变小写
* */
if(a[i]>=65 && a[i]<=91){stringBuffer.append("_"+(char)(a[i]+32));continue;}
stringBuffer.append(a[i]);
}
return stringBuffer.toString();
}
/*
* mybatis中直接获取connection执行非映射关系的sql
*
* */
public boolean connection(String sql){
ResultSet rs=null;
String str=null;
Connection connections=null;
try {
connections=sqlSession.getConfiguration().getEnvironment().getDataSource().getConnection();
Statement s=connections.createStatement();
rs= s.executeQuery(sql);
while (rs.next()){
str =rs.getString("table_name");
}
connections.close();
}catch (SQLException e){
}
if(null==str){
return true;
}
return false;
}
private void ex(String sql){
Connection connections=null;
try {
connections=sqlSession.getConfiguration().getEnvironment().getDataSource().getConnection();
Statement s=connections.createStatement();
s.execute(sql);
connections.close();
}catch (SQLException e){
}
}
/*
*
* 匹配类型
* */
public Map getcoumltype(){
Map<String,String> map=new HashMap<>();
map.put("int","int(0)");
map.put("java.lang.Integer","int(0)");
map.put("double","double(11,2)");
map.put("float","float(11,2)");
map.put("char","char(0)");
map.put("boolean","int(0)");
map.put("long","bigint(11)");
map.put("short","tinyint(0)");
map.put("byte","tinyint(0)");
map.put("java.lang.String","varchar(255)");
map.put("java.math.BigDecimal","decimal(12,3)");
map.put("java.time.LocalDateTime","datetime(0)");
return map;
}
/*
*
*添加字段sql
*
* */
public String addsql(String tablename ,String coumname,String type){
// ALTER TABLE settings ADD registerprotocol text COMMENT '邀请协议';
StringBuffer stringBuffer=new StringBuffer();
stringBuffer.append("ALTER TABLE ");
stringBuffer.append(tablename+" add ");
stringBuffer.append(coumname+" ");
stringBuffer.append(type+" NULL ;");
return stringBuffer.toString();
}
}
通过扫描拿到entiy包下的所有类名
package com.timecolor.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.net.URL;
import java.util.List;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@Component
public class InitSql {
private static final Logger log= LoggerFactory.getLogger(InitSql.class);
public static List<String> getClassName(String packageName) throws IOException {
return getClassName(packageName, true);
}
/*
*
*
* 类似spring包扫描,递归该包下所有的包的类名
*
* */
public static List<String> getClassName(String packageName, boolean childPackage) throws IOException {
List<String> fileNames = new ArrayList<>();
ClassLoader loader = Thread.currentThread().getContextClassLoader();
String packagePath = packageName.replace(".", "/");
Enumeration<URL> urls = loader.getResources(packagePath);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
log.info(url.toString()+"##########");
File file=new File(url.getFile());
File[] filelist=file.listFiles();
for (File f:filelist) {
if(f.isDirectory()){
getClassName(packageName+"."+file.getName());
}
else {
fileNames.add(f.getName().replace(".class",""));
}
} }
return fileNames;
}
}
新注解
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 Newfield {
String value() default "";
}
主要在对应的属性上标上该注解,启动的时候便自动建数据库字段