涉及到的Maven依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>4.2</version>
</dependency>
<dependency>
<groupId>net.lingala.zip4j</groupId>
<artifactId>zip4j</artifactId>
<version>2.11.5</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
1、定义数据类型枚举
public enum DataType {
VARCHAR,NUMERIC,DECIMAL,DATE,DATE_TIME;
}
2、添加申明的表格
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Table {
String value() ;
}
3、添加声明数据库列的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Column {
/**
* 表里的列名
* @return
*/
String column() ;
/**
* 列的数据类型
*/
DataType type() default DataType.VARCHAR ;
/**
* 是否允许为空
*/
boolean allowNull() default false ;
/**
* 时间的格式化
*/
String pattern() default "yyyy-MM-dd HH:mm:ss" ;
}
4、添加关键字
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Key {
}
5、定义抽象的基础实体
public abstract class BaseModel {
//年度
@ExcelProperty("年度编码(year_code)")
@Column(column = "year_code",type = DataType.NUMERIC,allowNull = false)
@Key
private String yearCode ;
//数字产品码(product_code)
@ExcelProperty("数字产品码(product_code)")
@Column(column = "product_code",type = DataType.VARCHAR,allowNull = false)
@Key
private String productCode ;
//价值编码(value_code) . 作为一条数据的唯一标识
@ExcelProperty("价值编码(value_code)")
@Column(column = "value_code",type = DataType.VARCHAR,allowNull = false)
@Key
private String valueCode ;
//忽略getter和setter方法
}
6、添加一个实体类
@Table("mcp_measure_base_improve")
public class MeasureBaseImprove extends BaseModel {
//提效科目编码(subject_code)
@ExcelProperty("提效科目编码(subject_code)")
@Column(column = "subject_code",type = DataType.VARCHAR)
private String subjectCode ;
//提效科目(subject)
@ExcelProperty("提效科目(subject)")
@Column(column = "subject",type = DataType.VARCHAR)
private String subject ;
//无数字化工时(no_digit_manhour)
@ExcelProperty("无数字化工时(no_digit_manhour)")
@Column(column = "no_digit_manhour",type = DataType.DECIMAL)
private String noDigitManhour ;
//有数字化工时(digit_manhour)
@ExcelProperty("有数字化工时(digit_manhour)")
@Column(column = "digit_manhour",type = DataType.DECIMAL)
private String digitManhour ;
//预估提效单量(estimate_improve_num)
@ExcelProperty("预估提效单量(estimate_improve_num)")
@Column(column = "estimate_improve_num",type = DataType.DECIMAL)
private String estimateImproveNum ;
//提效目标(improve_target)
@ExcelProperty("提效目标(improve_target)")
@Column(column = "improve_target",type = DataType.DECIMAL)
private String improveTarget ;
//忽略getter和setter方法
}
7、创建生成SQL的工具
public class SqlBuilder {
/**
* 获取本类及其父类的字段属性
* @param clazz 当前类对象
* @return 字段数组
*/
public static List<Field> getAllFields(Class<?> clazz) {
List<Field> fieldList = new ArrayList<>();
while (clazz != null){
clazz = clazz.getSuperclass();
fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
}
return fieldList ;
}
public static class FiledInfo{
protected final Map<Field,Column> fileColumnMap ;
protected final Map<Field,Key> keyMap ;
protected final String tableName ;
public FiledInfo(String tableName,Map<Field,Column> fileColumnMap,Map<Field,Key> keyMap){
this.tableName = tableName ;
this.fileColumnMap = fileColumnMap ;
this.keyMap = keyMap ;
}
}
public static final <T> FiledInfo getFiledInfo(Class<T> clazz){
Table table = clazz.getAnnotation(Table.class) ;
if(table == null){
throw new IllegalArgumentException("类型上没有Table注解") ;
}
//获取当前类的所有字段
List<Field> fieldList = getAllFields(clazz) ;
Map<Field,Column> fileColumnMap = new HashMap<>() ;
Map<Field,Key> keyMap = new HashMap<>() ;
//遍历每个字段上的注解
fieldList.forEach(field -> {
Column column = field.getAnnotation(Column.class) ;
if(column == null){
return;
}
if(StringUtils.isBlank(column.column())){
throw new IllegalArgumentException("注解属性有误") ;
}
field.setAccessible(true);
fileColumnMap.put(field,column) ;
Key key = field.getAnnotation(Key.class) ;
if(key != null){
keyMap.put(field,key) ;
}
});
return new FiledInfo(table.value(),fileColumnMap,keyMap) ;
}
public static class SQLResult{
public final List<String> insertSqlList ;
public final List<String> updateSqlList ;
public final List<String> deleteSqlList ;
public SQLResult(List<String> insertSqlList ,List<String> updateSqlList,List<String> deleteSqlList){
this.insertSqlList = insertSqlList ;
this.updateSqlList = updateSqlList ;
this.deleteSqlList = deleteSqlList ;
}
}
public static final <T> SQLResult buildSQL(List<T> dataList,Class<T> clazz){
//获取注解信息
FiledInfo filedInfo = getFiledInfo(clazz) ;
Map<Field,Column> fileColumnMap = filedInfo.fileColumnMap ;
Map<Field,Key> keyMap = filedInfo.keyMap ;
final List<String> insertSqlList = new ArrayList<>() ;
final List<String> updateSqlList = new ArrayList<>() ;
final List<String> deleteSqlList = new ArrayList<>() ;
List<Insert> insertList = new ArrayList<>() ;
List<Update> updateList = new ArrayList<>() ;
List<Delete> deleteList = new ArrayList<>() ;
dataList.forEach(item->{
Insert insert = new Insert().withTable(new net.sf.jsqlparser.schema.Table(filedInfo.tableName)) ;
Update update = new Update().withTable(new net.sf.jsqlparser.schema.Table(filedInfo.tableName)) ;
Delete delete = new Delete().withTable(new net.sf.jsqlparser.schema.Table(filedInfo.tableName)) ;
//列
List<net.sf.jsqlparser.schema.Column> columnList = new ArrayList<>() ;
//列所对应的值
//MultiExpressionList valueList = new MultiExpressionList();
ExpressionList valueList = new ExpressionList();
//where条件表达式,可用于更新和删除
List<Expression> whereList = new ArrayList<>() ;
fileColumnMap.forEach((field,column)->{
//数据的值
Object value = null ;
try {
value = field.get(item) ;
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
Expression valueExpression = getValueExpression(field,column,value) ;
//////////////////更新数据的SQL//////////////
Key key = keyMap.get(field) ;
if(key != null) {
EqualsTo equalsTo = new EqualsTo(); // 等于表达式
equalsTo.setLeftExpression(new net.sf.jsqlparser.schema.Column(column.column()));
equalsTo.setRightExpression(valueExpression);
whereList.add(equalsTo) ;
}else{
update.addUpdateSet(new net.sf.jsqlparser.schema.Column(column.column()),valueExpression);
}
///////////新增数据的SQL////////
columnList.add(new net.sf.jsqlparser.schema.Column().withColumnName(column.column())) ;
valueList.addExpressions(getValueExpression(field,column,value)) ;
});
if(whereList.size() > 0) {
updateList.add(update.withWhere(buildAndExpression(whereList)));
deleteList.add(delete.withWhere(buildAndExpression(whereList)));
}else{
updateList.add(update);
deleteList.add(delete);
}
insertList.add(insert.withColumns(columnList).withItemsList(valueList)) ;
});
insertList.forEach(insert -> {
insertSqlList.add(insert.toString()+";") ;
});
updateList.forEach(insert -> {
updateSqlList.add(insert.toString()+";") ;
});
deleteList.forEach(insert -> {
deleteSqlList.add(insert.toString()+";") ;
});
return new SQLResult(insertSqlList,updateSqlList,deleteSqlList) ;
}
public static Expression buildAndExpression(List<Expression> expressionList){
Assert.notEmpty(expressionList,"创建AND标识的是子表达式不能为空");
if(expressionList.size() == 1){
return expressionList.get(0) ;
}
AndExpression andExpression = new AndExpression() ;
andExpression.withLeftExpression(expressionList.get(0)).withRightExpression(expressionList.get(1)) ;
for(int i=2;i<expressionList.size();i++){
AndExpression itemExpression = new AndExpression() ;
itemExpression.withLeftExpression(andExpression).withRightExpression(expressionList.get(i));
andExpression = itemExpression ;
}
return andExpression ;
}
private static Expression getValueExpression(Field field, Column column, Object value){
//字段的类型
String typeName = field.getGenericType().getTypeName() ;
if(value == null){
//如果对象中的值为空,则先判断列是否允许为空
if(!column.allowNull()){
throw new IllegalArgumentException("列"+column.column()+"不允许为空") ;
}
return new NullValue();
}
//数据库中列的值
if(column.type() == DataType.VARCHAR){
return new StringValue(value.toString());
}
if(column.type() == DataType.NUMERIC){
return new LongValue(value.toString()) ;
}
if(column.type() == DataType.DECIMAL){
return new DoubleValue(value.toString()) ;
}
if(column.type() == DataType.DATE){
return getDateExpression(field,column,value) ;
}
if(column.type() == DataType.DATE_TIME){
return getDateTimeExpression(field,column,value) ;
}
throw new RuntimeException("不支持的类型") ;
}
private static Expression getDateExpression(Field field,Column column,Object value){
//字段的类型
String typeName = field.getGenericType().getTypeName() ;
if(StringUtils.equals(typeName,"java.util.Date")){
long t = ((Date)value).getTime() ;
return new DateValue().withValue(new java.sql.Date(t));
}
if(StringUtils.equals(typeName,"java.sql.Date")){
return new DateValue().withValue((java.sql.Date)value);
}
if(StringUtils.equals(typeName,"java.lang.String")){
//格式
String format = column.pattern() ;
Assert.notNull(format,"时间格式化模型不能为空");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format) ;
TemporalAccessor temporal = formatter.parse(value.toString()) ;
//解析出的时间
LocalDateTime localDateTime = LocalDateTime.from(temporal) ;
return new DateValue()
.withValue(new java.sql.Date(localDateTime.toEpochSecond(ZoneOffset.from(temporal))));
}
throw new RuntimeException("不支持的时间类型") ;
}
private static Expression getDateTimeExpression(Field field,Column column,Object value){
//字段的类型
String typeName = field.getGenericType().getTypeName() ;
if(StringUtils.equals(typeName,"java.util.Date")){
long t = ((Date)value).getTime() ;
return new TimestampValue().withValue(new java.sql.Timestamp(t));
}
if(StringUtils.equals(typeName,"java.sql.Timestamp")){
return new TimestampValue().withValue((java.sql.Timestamp)value);
}
if(StringUtils.equals(typeName,"java.lang.String")){
//格式
String format = column.pattern() ;
Assert.notNull(format,"时间格式化模型不能为空");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format) ;
TemporalAccessor temporal = formatter.parse(value.toString()) ;
//解析出的时间
LocalDateTime localDateTime = LocalDateTime.from(temporal) ;
return new TimestampValue()
.withValue(new java.sql.Timestamp(localDateTime.toEpochSecond(ZoneOffset.from(temporal))));
}
throw new RuntimeException("不支持的时间类型") ;
}
}
8、创建解析Excel的工具
public class ResolverUtil {
//以同步的方式读取指定名称的sheet,并将解析的结果生成指定类型的对象
public static <T> List<T> listModel(File file,String sheetName,Class<T> clazz){
List<T> dataList = EasyExcel.read(file, clazz,new CommEventListener())
.autoCloseStream(false)
.ignoreEmptyRow(true)
.autoTrim(true)
.sheet(sheetName)
.headRowNumber(1)
.doReadSync() ; //同步方式执行
return dataList ;
}
/**
* 解析成LinkedHashMap
*/
public static List<Map<Integer,String>> listMapData(File file){
//解析文件
List<Map<Integer,String>> result = EasyExcel.read(file, new AnalysisEventListener<Map<Integer, String>>() {
//此处为得到一行后的数据转换为实体类
@Override
public void invoke(Map<Integer, String> rowData, AnalysisContext analysisContext) {
}
//全部读取完成之后执行函数
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
}
}).autoCloseStream(true)
.ignoreEmptyRow(true)
.autoTrim(true)
.doReadAllSync(); //同步的方式读取所有sheet
return result ;
}
}
9、解析文件并生成SQL
final List<String> insertSqlList = new ArrayList<>() ;
final List<String> updateSqlList = new ArrayList<>() ;
final List<String> deleteSqlList = new ArrayList<>() ;
//解析表格的指定sheet
List<MeasureBaseProductVal> productValList = ResolverUtil.listModel(targetFile,"04-数字化产品价值",MeasureBaseProductVal.class)
.stream().filter(item->StringUtils.isNotBlank(item.getYearCode())).collect(Collectors.toList()) ;
//生成SQL语句
SqlBuilder.SQLResult sqlResult = SqlBuilder.buildSQL(productValList,MeasureBaseProductVal.class) ;
insertSqlList.addAll(Optional.ofNullable(sqlResult.insertSqlList).orElse(new ArrayList<>())) ;
updateSqlList.addAll(Optional.ofNullable(sqlResult.updateSqlList).orElse(new ArrayList<>())) ;
deleteSqlList.addAll(Optional.ofNullable(sqlResult.deleteSqlList).orElse(new ArrayList<>())) ;
//写入文件
////新增语句////
File insertSqlFile=new File(dirFile,"dml-insert.sql");
FileUtils.writeLines(insertSqlFile,"UTF-8",insertSqlList);
////更新语句////
File updateSqlFile=new File(dirFile,"dml-update.sql");
FileUtils.writeLines(updateSqlFile,"UTF-8",updateSqlList);
////删除语句////
File deleteSqlFile=new File(dirFile,"dml-delete.sql");
FileUtils.writeLines(deleteSqlFile,"UTF-8",deleteSqlList);
///添加到压缩文件
ZipParameters zipParameters = new ZipParameters();
// 压缩方式
zipParameters.setCompressionMethod(CompressionMethod.DEFLATE);
// 压缩级别
zipParameters.setCompressionLevel(CompressionLevel.NORMAL);
//压缩文件
ZipFile zipFile = new ZipFile(dirFile + File.separator + ZIP_FILE_NAME ) ;
zipFile.addFiles(Arrays.asList(insertSqlFile,updateSqlFile,deleteSqlFile),zipParameters) ;