JavaExcel:自动生成数据表并插入数据

故事背景

出于好奇,当下扫描excel读取数据进数据库 or 导出数据库数据组成excel的功能层出不穷,代码也是前篇一律,poi或者easy excel两种SDK的二次利用带来了各种封装方法。

那么为何不能直接扫描excel后根据列的属性名与行数据的属性建立SQL数据表,并将数据插入到数据表中,再通过前端与用户交互进行SQL组装,得到用户想要的数据结果。

模块架构图

采取原始的数据库信息读取,配置编程式事务(代码块维度锁事务),封装原始的JDBC执行模板。

excel读取列属性名,转换成英文作为表的属性名,行解析器解析数据行数据属性作为表属性的数据类型。

代码构成

基础实体:

ColumnEntity.java
@Data
@EqualsAndHashCode
public class ColumnEntity {private String columnName;private String columnSqlInfo;public void clear(){setColumnName(null);setColumnSqlInfo(null);}
}
ValueEntity.java
@Data
public class ValueEntity{private String columnName;/*数据拼接到SQL上也是字符串类型*/private String valueOfString;public void clear(){setColumnName(null);setValueOfString(null);}
}
JsonResponse.java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class JsonResponse {private int code = -1;private String message;private String json;public static JsonResponse success(String json){JsonResponse jsonResponse = new JsonResponse();jsonResponse.setCode(0);jsonResponse.setJson(json);jsonResponse.setMessage("访问成功");return jsonResponse;}public static JsonResponse fail(String massage){JsonResponse jsonResponse = new JsonResponse();jsonResponse.setMessage(massage);return jsonResponse;}
}

api对前端提供特性:

WebMvcConfiguration.java
@Configuration
@Slf4j
public class WebMvcConfiguration implements WebMvcConfigurer , HandlerInterceptor {@Overridepublic void addInterceptors(@NonNull InterceptorRegistry registry) {registry.addInterceptor(this);WebMvcConfigurer.super.addInterceptors(registry);}@Overridepublic void addCorsMappings(@NonNull CorsRegistry registry) {WebMvcConfigurer.super.addCorsMappings(registry);}@Overridepublic void postHandle(@NonNull HttpServletRequest request,@NonNull  HttpServletResponse response,@NonNull  Object handler, ModelAndView modelAndView) throws Exception {HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);}@Overridepublic boolean preHandle(HttpServletRequest request,@NonNull HttpServletResponse response,@NonNull Object handler) throws Exception {String sql = request.getParameter("sql");String tableName = request.getParameter("tableName");if (StringUtils.isNotEmpty(sql)){if (!sql.contains("test") || !tableName.contains("test")){log.error("过滤非法请求:{}",sql);return false;}if (sql.contains("DELETE") || sql.contains("delete") || sql.contains("UPDATE") || sql.contains("update")){log.error("过滤非法请求:{}",sql);return false;}}return HandlerInterceptor.super.preHandle(request, response, handler);}@Overridepublic void afterCompletion(@NonNull HttpServletRequest request,@NonNull HttpServletResponse response,@NonNull Object handler, Exception ex) throws Exception {HandlerInterceptor.super.afterCompletion(request, response, handler, ex);}
}
ExcelDataController.java
@RestController
@RequestMapping("/data")
@CrossOrigin
@Slf4j
public class ExcelDataController {@Resourceprivate SqlDataProvider sqlDataProvider;@GetMapping("/handle/sql")@ResponseBodypublic JsonResponse handleData(@RequestParam String sql) {String executed = sqlDataProvider.executeQuerySql(sql);return Objects.equals("", executed)? JsonResponse.fail("sql执行错误"): JsonResponse.success(executed);}
}
ExcelResolveController.java
@RestController
@RequestMapping("/excel")
@CrossOrigin
@Slf4j
public class ExcelResolveController {@Resourceprivate ExcelEntityService excelEntityService;@RequestMapping("/createAndInsert")@ResponseBodypublic void uploadExcel(@RequestParam("fileName") MultipartFile file) {excelEntityService.createTable(file);excelEntityService.insertEntity(file);}@RequestMapping("/insert")@ResponseBodypublic void insertExcel(@RequestParam("fileName") MultipartFile file) {excelEntityService.insertEntity(file);}@RequestMapping("/drop")@ResponseBodypublic void delData(@RequestParam("fileName")String fileName){excelEntityService.dropTable(fileName);}}
ExcelEntityService.java
public interface ExcelEntityService {/*** 创建数据表** @param file 文件*/void createTable(MultipartFile file);/*** 插入数据实体** @param file 文件*/void insertEntity(MultipartFile file);/*** 删除数据表* @param fileName 文件名*/void dropTable(String fileName);
}
ExcelEntityServiceImpl.java
@Service
@Slf4j
@ConditionalOnBean({SqlDataProvider.class,SqlSpliceProvider.class})
public class ExcelEntityServiceImpl implements ExcelEntityService {@Resourceprivate SqlDataProvider sqlDataProvider;@Resourceprivate SqlSpliceProvider spliceProvider;@Resourceprivate ReadExcelService readExcelService;@Overridepublic void createTable(MultipartFile file) {String dropTableSql = spliceProvider.dropTableSql(file.getName());log.info("删表SQL:{}",dropTableSql);sqlDataProvider.executeSql(dropTableSql);List<ColumnEntity> excelColumnList = readExcelService.getExcelColumnList(file);StringBuffer stringBuffer = spliceProvider.spliceCreateTableSql(excelColumnList, file.getName());log.warn("建表SQL:{}", stringBuffer);sqlDataProvider.executeSql(stringBuffer.toString());}@Overridepublic void insertEntity(MultipartFile file) {String existsTableSql = spliceProvider.existsTableSql(file.getName());Object aReturn = sqlDataProvider.executeSqlAndGetReturn(existsTableSql);if (Objects.nonNull(aReturn)) {List<ColumnEntity> excelColumnList = readExcelService.getExcelColumnList(file);Map<Integer, List<ValueEntity>> excelRowDataMap = readExcelService.getExcelRowDataMap(file, excelColumnList);List<String> stringBuffer1 = spliceProvider.spliceInsertValueSql(excelRowDataMap, file.getName());stringBuffer1.forEach(s -> sqlDataProvider.executeSql(s));}else{log.warn("不存在数据表:{}",file.getName());}}@Overridepublic void dropTable(String fileName) {String dropTableSql = spliceProvider.dropTableSql(fileName);log.info("删表SQL:{}",dropTableSql);sqlDataProvider.executeSql(dropTableSql);}
}

 excel解析器:

ReadExcelService.java
public interface ReadExcelService {/*** 读取EXCEL的列属性列表** @param file 文件* @return 列属性实体列表(只含有列的属性)*/List<ColumnEntity> getExcelColumnList(MultipartFile file);/*** 读取每一行的行实体列表,一个LIST为一行** @param file             文件* @param columnEntityList 列实体列表* @return 全部的值MAP<行号 , 行的属性值LIST>*/Map<Integer, List<ValueEntity>> getExcelRowDataMap(MultipartFile file, List<ColumnEntity> columnEntityList);}
ReadExcel.java
@Slf4j
@Service
public class ReadExcel implements ReadExcelService {private static final Integer LIMIT_SCAN_NUM = 500 * 1000;/*** 根据文件名读取Excel文件获取列信息列表** @param file 文件* @return List<列实体>*/@Overridepublic List<ColumnEntity> getExcelColumnList(MultipartFile file) {List<ColumnEntity> list;Workbook workbook = getWorkbook(file);if (Objects.isNull(workbook)) {return new LinkedList<>();}list = getExcelColumnList(workbook);return list;}/*** 获取行数与对应行得值SQL实体列表** @param file             工作薄文件* @param columnEntityList 列信息对象* @return map<行号 , 行内每一个单元格得值SQL实体列表>*/@Overridepublic Map<Integer, List<ValueEntity>> getExcelRowDataMap(MultipartFile file, List<ColumnEntity> columnEntityList) {Workbook workbook = getWorkbook(file);if (Objects.isNull(workbook)) {return new HashMap<>();}Sheet sheet = workbook.getSheetAt(0);int lastRowNum = sheet.getLastRowNum();Map<Integer, List<ValueEntity>> map = new HashMap<>();if (lastRowNum <= LIMIT_SCAN_NUM) {for (int i = 1; i <= lastRowNum; i++) {Row row = sheet.getRow(i);List<ValueEntity> list = new LinkedList<>();for (int j = 0; j < row.getPhysicalNumberOfCells(); j++) {ValueEntity valueEntity = new ValueEntity();valueEntity.setColumnName(columnEntityList.get(j).getColumnName());valueEntity.setValueOfString(ExcelReadStringUtil.getValueSqlString(row.getCell(j)));list.add(valueEntity);}map.put(i, list);}}else{throw new RuntimeException("扫描的Excel文件数据量超过限定值,请检查核定容量");}return map;}/*** 解析返回excel数据表第一行属性信息列表数据** @param workbook 数据工作薄* @return List<列实体>*/private static List<ColumnEntity> getExcelColumnList(Workbook workbook) {/*默认取第一个工作表的第一行数据与第二行数据(第一行用来感知属性名称、第二行用来感知属性类型)*/Sheet dataSheet = workbook.getSheetAt(0);Row topRow = dataSheet.getRow(0);Row typeRow = dataSheet.getRow(1);if (topRow.getPhysicalNumberOfCells() != typeRow.getPhysicalNumberOfCells()) {log.error("数据表列行与数据行列数不一致!退出解析,请整理数据表格式!");throw new RuntimeException("DataSheet is error: com.runjing.resolve_excel_auto.excel.ReadExcel.getExcelColumnList(org.apache.poi.ss.usermodel.Workbook)");}List<ColumnEntity> columnEntityList = new LinkedList<>();for (int i = 0; i < topRow.getPhysicalNumberOfCells(); i++) {ColumnEntity columnEntity = new ColumnEntity();Cell nameCell = topRow.getCell(i);Cell typeRowCell = typeRow.getCell(i);columnEntity.setColumnName(ExcelReadStringUtil.transferPinYin(nameCell.getStringCellValue()));columnEntity.setColumnSqlInfo(ExcelReadStringUtil.switchCellDataSqlInfo(typeRowCell));columnEntityList.add(columnEntity);}return columnEntityList;}/*** 文件转换工作簿对象** @param file excel文件* @return 工作簿对象*/private static Workbook getWorkbook(MultipartFile file) {InputStream is = null;try {is = file.getInputStream();Workbook workbook;workbook = WorkbookFactory.create(is);return workbook;} catch (Exception ex) {ex.printStackTrace();return null;} finally {if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}}}
}

SQL拼接器:

ExcelReadStringUtil.java
public class ExcelReadStringUtil {/*获取构建表格数据属性SQL*/public static String switchCellDataSqlInfo(Cell dataCell) {return switch (dataCell.getCellType()) {case NUMERIC -> " double default 0.00 ";case STRING -> " varchar(100) default null";case FORMULA -> " varchar default null";case BOOLEAN -> " tinyint(1) default 0";default -> " varchar(64) default null";} + ",";}/*获取单元格值SQL*/public static String getValueSqlString(Cell dataCell) {return switch (dataCell.getCellType()) {case NUMERIC -> String.valueOf(dataCell.getNumericCellValue());case STRING -> quotesHandle(dataCell.getStringCellValue());case FORMULA -> quotesHandle(dataCell.getCellFormula());case BOOLEAN -> transferBool(dataCell.getBooleanCellValue());default -> "null";};}/*** 单引号包裹字段** @param fieldValue 字段值* @return 包裹后字段串*/public static String quotesHandle(String fieldValue) {return "'" + fieldValue + "'";}/*** 布尔类型转换** @param arg1 入参* @return 转换值*/public static String transferBool(Boolean arg1) {return arg1 ? "0" : "1";}/*** 将汉字串转成拼音串** @param columnChineseName 汉字字段名* @return 字段拼音*/public static String transferPinYin(String columnChineseName) {/*转换中文为简体拼音*/return LanguageUtil.convertChineseLan2PinYinAbbreviation(columnChineseName, LanguageUtil.CHINESE_CHAR_REG_SIMPLIFIED);}
}
SqlSpliceStringUtil.java
public class SqlSpliceStringUtil {/*** 反引号处理** @param fieldName 字段名称* @return 被反引号包裹得字段名称*/public static String quotesHandle(String fieldName) {return "`" + fieldName + "`";}/*** 将汉字串转成拼音串** @param columnChineseName 汉字字段名* @return 字段拼音*/public static String transferPinYin(String columnChineseName) {/*转换中文为简体拼音*/return LanguageUtil.convertChineseLan2PinYinAbbreviation(columnChineseName, LanguageUtil.CHINESE_CHAR_REG_SIMPLIFIED);}
}
LanguageUtil.java
@Slf4j
public class LanguageUtil {/*** 定义输出格式*/public static HanyuPinyinOutputFormat hpFormat = new HanyuPinyinOutputFormat();/*** 匹配所有东亚区的语言*/public static String CHINESE_CHAR_REG_SOUTHEAST_ASIA ="^[\u2E80-\u9FFF]+$";/*** 匹配简体和繁体*/public static String CHINESE_CHAR_REG_SIMPLIFIED_OR_TRADITIONAL ="^[\u4E00-\u9FFF]+$";/*** 匹配简体*/public static String CHINESE_CHAR_REG_SIMPLIFIED ="[\u4E00-\u9FA5]+$";static{// 大写格式输出hpFormat.setCaseType(HanyuPinyinCaseType.UPPERCASE);// 不需要语调输出hpFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);}/**** 将汉字转成拼音(取首字母或全拼)* @param singleChar 中文字符* @param full 是否全拼* @return 转换后拼音*/public static String convertChineseChar2Pinyin(String singleChar, boolean full,String regExp ) {StringBuffer sb = new StringBuffer();if (singleChar == null || "".equals(singleChar.trim())) {return "";}String pinyin = "";for (int i = 0; i < singleChar.length(); i++) {char unit = singleChar.charAt(i);//是汉字,则转拼音if (match(String.valueOf(unit), regExp)){pinyin = convertSingleChineseChar2Pinyin(unit);if (full) {sb.append(pinyin);} else {sb.append(pinyin.charAt(0));}} else {sb.append(unit);}}return sb.toString();}/**** 将单个汉字转成拼音* @param singleChar 中文汉字* @return 拼音*/private static String convertSingleChineseChar2Pinyin(char singleChar) {String[] res;StringBuffer sb = new StringBuffer();try {res = PinyinHelper.toHanyuPinyinStringArray(singleChar, hpFormat);//对于多音字,只用第一个拼音sb.append(res[0]);} catch (Exception e) {log.error("单个汉字转换成字符失败:{}",e.getMessage());return "";}return sb.toString();}/**** @param str 源字符串* @param regex 正则表达式* @return 是否匹配*/public static boolean match(String str, String regex) {Pattern pattern = Pattern.compile(regex);Matcher matcher = pattern.matcher(str);return matcher.find();}/*** 汉字字符串的的首拼拼成字符串* @param chineseLan 中文字符串* @return 拼音字符串*/public static String convertChineseLan2PinYinAbbreviation(String chineseLan,String regExp) {String ret = "";// 将汉字转换为字符数组char[] charChineseLan = chineseLan.toCharArray();try {for (int i = 0; i < charChineseLan.length; i++) {if(String.valueOf(charChineseLan[i]).matches(regExp)) {// 如果字符是中文,则将中文转为汉语拼音(获取全拼则去掉红色的代码即可)ret += PinyinHelper.toHanyuPinyinStringArray(charChineseLan[i], hpFormat)[0].substring(0, 1);} else {// 如果字符不是中文,则不转换ret += charChineseLan[i];}}} catch (BadHanyuPinyinOutputFormatCombination e) {log.error("获取汉字的的首拼失败:{}",e.getMessage());}return ret;}/*** 判断字符串中是否包含中文汉字** @param content 字符串内容* @return true至少包含1个*/public static boolean hasChinese(CharSequence content) {if (null == content) {return false;}String regex = "[\u2E80-\u2EFF\u2F00-\u2FDF\u31C0-\u31EF\u3400-\u4DBF\u4E00-\u9FFF\uF900-\uFAFF\uD840\uDC00-\uD869\uDEDF\uD869\uDF00-\uD86D\uDF3F\uD86D\uDF40-\uD86E\uDC1F\uD86E\uDC20-\uD873\uDEAF\uD87E\uDC00-\uD87E\uDE1F]+";Pattern pattern = Pattern.compile(regex);return pattern.matcher(content).find();}/*** 判断字符串是否为中文汉字** @param content 字符串内容* @return true都是汉字*/public static boolean isChinese(CharSequence content) {if (null == content) {return false;}String regex = "[\u2E80-\u2EFF\u2F00-\u2FDF\u31C0-\u31EF\u3400-\u4DBF\u4E00-\u9FFF\uF900-\uFAFF\uD840\uDC00-\uD869\uDEDF\uD869\uDF00-\uD86D\uDF3F\uD86D\uDF40-\uD86E\uDC1F\uD86E\uDC20-\uD873\uDEAF\uD87E\uDC00-\uD87E\uDE1F]+";Pattern pattern = Pattern.compile(regex);return pattern.matcher(content).matches();}
}
JsonUtil.java
public class JsonUtil {private final static String arg = "\"";/*** Map转成JSON字符串** @param map* @return JSON*/public static String mapToJsonString(Map<String, Object> map) {return CollectionUtils.isEmpty(map) ? "" : JSONObject.toJSONString(map).replace(arg,"'");}}

SQL配置与执行:

SqlConfiguration.java
@Component("SqlConfiguration")
@ConfigurationProperties(prefix = "jdbc-config")
@Data
public class SqlConfiguration {private String driver;private String url;private String userName;private String password;
}
SqlDataSourceConfiguration.java
@Configuration
@ConditionalOnBean(SqlConfiguration.class)
@Slf4j
public class SqlDataSourceConfiguration {@Resourceprivate SqlConfiguration sqlConfiguration;@Bean("DriverManagerDataSource")@Scope(value = "singleton")public DriverManagerDataSource getDataSource(){DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();driverManagerDataSource.setDriverClassName(sqlConfiguration.getDriver());driverManagerDataSource.setUrl(sqlConfiguration.getUrl());driverManagerDataSource.setUsername(sqlConfiguration.getUserName());driverManagerDataSource.setPassword(sqlConfiguration.getPassword());log.info("扫描生成自定义配置JDBC数据源:{}",sqlConfiguration.getUrl());return driverManagerDataSource;}
}
JdbcTransactionManagerConfiguration.java
@Configuration
@ConditionalOnBean({SqlDataSourceConfiguration.class})
@Slf4j
public class JdbcTransactionManagerConfiguration {@Resourceprivate DriverManagerDataSource driverManagerDataSource;@Bean("JdbcTransactionManager")@Scope("singleton")public JdbcTransactionManager getJdbcTransactionManager(){JdbcTransactionManager jdbcTransactionManager = new JdbcTransactionManager();log.info("开始配置JDBC事务管理者");jdbcTransactionManager.setDataSource(driverManagerDataSource);jdbcTransactionManager.setRollbackOnCommitFailure(true);jdbcTransactionManager.setFailEarlyOnGlobalRollbackOnly(true);jdbcTransactionManager.setGlobalRollbackOnParticipationFailure(true);return jdbcTransactionManager;}}
TransactionTemplateConfiguration.java
@Configuration
@Slf4j
public class TransactionTemplateConfiguration {@Resourceprivate JdbcTransactionManager jdbcTransactionManager;@Bean("ReadCommittedTransactionTemplate")@Scope("singleton")@ConditionalOnBean({JdbcTransactionManager.class})@Lazypublic TransactionTemplate getReadCommittedTransactionTemplate(){TransactionTemplate transactionTemplate = new TransactionTemplate();log.info("生成事务模板,注入事务管理器,设置事务隔离级别为读已提交");transactionTemplate.setTransactionManager(jdbcTransactionManager);transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);return transactionTemplate;}@Bean("ReadUnCommittedTransactionTemplate")@Scope("singleton")@ConditionalOnBean({JdbcTransactionManager.class})@Lazypublic TransactionTemplate getReadUnCommittedTransactionTemplate(){TransactionTemplate transactionTemplate = new TransactionTemplate();log.info("生成事务模板,注入事务管理器,设置事务隔离级别为读未提交");transactionTemplate.setTransactionManager(jdbcTransactionManager);transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);return transactionTemplate;}@Bean("RepeatableReadTransactionTemplate")@Scope("singleton")@ConditionalOnBean({JdbcTransactionManager.class})@Lazypublic TransactionTemplate getRepeatableReadTransactionTemplate(){TransactionTemplate transactionTemplate = new TransactionTemplate();log.info("生成事务模板,注入事务管理器,设置事务隔离级别为可重复读");transactionTemplate.setTransactionManager(jdbcTransactionManager);transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ);return transactionTemplate;}@Bean("SerializableTransactionTemplate")@Scope("singleton")@ConditionalOnBean({JdbcTransactionManager.class})@Lazypublic TransactionTemplate getSerializableTransactionTemplate(){TransactionTemplate transactionTemplate = new TransactionTemplate();log.info("生成事务模板,注入事务管理器,设置事务隔离级别为可串行化");transactionTemplate.setTransactionManager(jdbcTransactionManager);transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);return transactionTemplate;}}
SqlSpliceProvider.java
public interface SqlSpliceProvider {/*** 拼接建表SQL** @param columnEntityList excel的列属性列表* @param tableName        表名* @return SQL*/StringBuffer spliceCreateTableSql(List<ColumnEntity> columnEntityList, String tableName);/*** 拼接删表SQL** @param tableName 表名* @return SQL*/String dropTableSql(String tableName);/*** 拼接判断表存在SQL** @param tableName 表名* @return SQL*/String existsTableSql(String tableName);/*** 拼接插值SQL列表循环执行即可** @param map       值map<行号,对应行的值LIST>* @param tableName 表名* @return SQL*/List<String> spliceInsertValueSql(Map<Integer, List<ValueEntity>> map, String tableName);}
SqlSplicer.java
@Service
public class SqlSplicer implements SqlSpliceProvider {/*** 拼接建表SQL** @param columnEntityList 列信息实体列表* @param tableName        表格名称* @return SQL*/@Overridepublic StringBuffer spliceCreateTableSql(List<ColumnEntity> columnEntityList, String tableName) {StringBuffer stringBuffer = new StringBuffer();stringBuffer.append("CREATE TABLE ").append(SqlSpliceStringUtil.quotesHandle(SqlSpliceStringUtil.transferPinYin(tableName))).append(" ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自动主键',");/*扫描属性列表,填充建表SQL*/stringBuffer.append(scanColumnListToSql(columnEntityList));stringBuffer.append(" PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ");return stringBuffer;}/*** 删除数据表,防止表重复** @param tableName 表名称* @return SQL*/@Overridepublic  String dropTableSql(String tableName) {return "DROP TABLE IF EXISTS " + SqlSpliceStringUtil.quotesHandle(SqlSpliceStringUtil.transferPinYin(tableName));}/*** 查询数据表是否存在* @param tableName 表名称* @return SQL*/@Overridepublic  String existsTableSql(String tableName) {return "SELECT * FROM information_schema.TABLES WHERE TABLE_NAME = " + SqlSpliceStringUtil.quotesHandle(SqlSpliceStringUtil.transferPinYin(tableName));}/*** 拼接插值SQL(单插入SQL集合)** @param map       值实体列表Map* @param tableName 表名* @return 插值SQL*/@Overridepublic  List<String> spliceInsertValueSql(Map<Integer, List<ValueEntity>> map, String tableName) {List<String> sqlList = new LinkedList<>();map.values().forEach(valueEntityList -> sqlList.add(scanValueListToSql(tableName, valueEntityList)));return sqlList;}/*** 拼接单一数据行值SQL** @param tableName       表名* @param valueEntityList 一行数据值列表* @return SQL*/private static String scanValueListToSql(String tableName, List<ValueEntity> valueEntityList) {StringBuilder stringBuffer = new StringBuilder();stringBuffer.append("INSERT INTO ").append(SqlSpliceStringUtil.quotesHandle(SqlSpliceStringUtil.transferPinYin(tableName)));stringBuffer.append(" VALUES( null,");for (ValueEntity element : valueEntityList) {if ((valueEntityList.indexOf(element) + 1) != valueEntityList.toArray().length) {stringBuffer.append(element.getValueOfString()).append(",");} else {stringBuffer.append(element.getValueOfString());}}stringBuffer.append(");");return stringBuffer.toString();}/*** 将列信息实体列表转SQL** @param columnEntityList 列信息实体列表* @return 处理完成得列属性SQL串*/private static String scanColumnListToSql(List<ColumnEntity> columnEntityList) {StringBuilder fieldSql = new StringBuilder();for (ColumnEntity element : columnEntityList) {fieldSql.append(SqlSpliceStringUtil.quotesHandle(element.getColumnName())).append(element.getColumnSqlInfo());}return fieldSql.toString();}
}
SqlDataProvider.java
public interface SqlDataProvider {/*** 执行非查询SQL** @param sql*/void executeSql(String sql);/*** 执行查询判断某些存在SQL** @param sql* @return 是否存在的对象 为空则不存在*/Object executeSqlAndGetReturn(String sql);/*** 执行查询SQL** @param sql* @return 结果的Json字符串*/String executeQuerySql(String sql);
}
SqlDataService.java
@Service
@Slf4j
public class SqlDataService implements SqlDataProvider {@Resourceprivate JdbcTemplate jdbcTemplate;@Qualifier("ReadCommittedTransactionTemplate")@Resourceprivate TransactionTemplate transactionTemplate;@Overridepublic void executeSql(String sql) {log.info("执行非查询操作SQL,开启事务执行:{}", sql);transactionTemplate.executeWithoutResult(status -> {try {jdbcTemplate.execute(sql);} catch (Exception e) {log.error("事务异常,开启回滚:{}", e.getMessage());status.setRollbackOnly();}});}@Overridepublic Object executeSqlAndGetReturn(String sql) {log.info("执行查询SQL:{}", sql);return jdbcTemplate.queryForObject(sql, Object.class);}@Overridepublic String executeQuerySql(String sql) {log.info("执行查询SQL:{}", sql);List<Map<String, Object>> mapList = jdbcTemplate.queryForList(sql);if (CollectionUtils.isEmpty(mapList)) {return "";}List<String> result = new LinkedList<>();mapList.forEach(map -> result.add(JsonUtil.mapToJsonString(map)));return result.toString();}
}

具体的讲解就不说了,分享代码案例,感兴趣的同学可以gitee上搜git@gitee.com:huanglinchun/resolve_excel_auto.git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/119603.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

yolov5的pytorch配置

1. conda create -n rdd38 python3.82、pip install torch1.8.0 torchvision0.9.0 torchaudio0.8.0 -f https://download.pytorch.org/whl/cu113/torch_stable.html -i https://pypi.tuna.tsinghua.edu.cn/simple 3、conda install cudatoolkit10.2

使用Docker配置深度学习的运行环境

文章目录 推荐实验环境前言docker安装docker操作docker配置常见方法&#xff08;安装包、联网、程序管理器&#xff09;安装驱动的前提要求传统方法安装驱动程序程序管理器安装联网安装deb包安装 安装完成后的设置非传统方法安装-通过容器安装驱动的前提要求安装NVIDIA-Contain…

基于Django的博客管理系统

1、克隆仓库https://gitee.com/lylinux/DjangoBlog.git 若失效&#xff1a;https://gitee.com/usutdzxy/DjangoBlog.git 2、环境安装 pip install -Ur requirements.txt3、修改djangoblog/setting.py 修改数据库配置&#xff0c;其他的步骤就按照官方文档。 DATABASES {def…

在 Amazon 搭建无代码可视化的数据分析和建模平台

现代企业常常会有利用数据分析和机器学习帮助解决业务痛点的需求。如制造业中&#xff0c;利用设备采集上来的数据做预测性维护&#xff0c;质量控制&#xff1b;在零售业中&#xff0c;利用客户端端采集的数据做渠道转化率分析&#xff0c;个性化推荐等。 亚马逊云科技开发者…

低代码赋能| 绿色智慧矿山解决方案

在世界能源日趋紧张的背景下&#xff0c;能源产业的数字化升级是大势所趋。矿山行业作为国家能源安全的“压舱石”&#xff0c;也必须进行产业升级。一直以来&#xff0c;国家都在大力推动智慧矿山建设。通过大数据、GIS、物联网、云计算、人工智能等新兴技术&#xff0c;实现矿…

R语言图形的组合( par(),layout(),par(fig()) )

引入d.class进行画图 > d.class<-read.csv("D://class.csv",header T) > attach(d.class) > opar<-par(no.readonly TRUE)非常简单的数据&#xff0c;需要可自取 链接&#xff1a;https://pan.baidu.com/s/1zNx5z9JsaaRqFueRgGY3mQ 提取码&#x…

微信小程序新版隐私协议弹窗实现最新版

1. 微信小程序又双叒叕更新了 2023.08.22更新&#xff1a; 以下指南中涉及的 getPrivacySetting、onNeedPrivacyAuthorization、requirePrivacyAuthorize 等接口目前可以正常接入调试。调试说明&#xff1a; 在 2023年9月15号之前&#xff0c;在 app.json 中配置 __usePriva…

Vite打包性能优化及填坑

最近在使用 Vite4.0 构建一个中型前端项目的过程中&#xff0c;遇到了一些坑&#xff0c;也做了一些项目在构建生产环境时的优化&#xff0c;在这里做一个记录&#xff0c;以便后期查阅。(完整配置在后面) 上面是dist文件夹的截图&#xff0c;里面的内容已经有30mb了&#xff…

Revit SDK:SpatialFieldGradient 在面上显示渐变颜色(AVF)分析显示样式

前言 这个例子使用Revit显示样式功能将面显示成不同的颜色。分析显示样式参考官方文档。 内容 效果&#xff1a; 核心逻辑&#xff1a; 得到一个 SpatialFieldManager拾取一系列的面&#xff1a;uiDoc.Selection.PickObjects(ObjectType.Face)计算面上的 UV 值&#xff0c;…

COSCon'23 开源市集:共赴一场草坪上的开源派对

一年一度的开源盛会&#xff0c;第八届中国开源年会&#xff08;COSCon23 &#xff09;&#xff0c;将于10月28~29日&#xff0c;在四川成都市高新区菁蓉汇召开&#xff01;本次大会的主题是&#xff1a;“开源&#xff1a;川流不息、山海相映”&#xff01; 我们预期会有超过1…

更健康舒适更科技的照明体验!SUKER书客护眼台灯 L1上手体验

低价又好用的护眼台灯是多数人的需求&#xff0c;很多人只追求功能性护眼台灯&#xff0c;显色高、无频闪、无蓝光等基础需求。但是在较低价格中很难面面俱到&#xff0c;然而刚发布的SUKER书客L1护眼台灯却是一款不可多得的性价比护眼台灯&#xff0c;拥有高品质光源&#xff…

第63步 深度学习图像识别:多分类建模误判病例分析(Tensorflow)

基于WIN10的64位系统演示 一、写在前面 上两期我们基于TensorFlow和Pytorch环境做了图像识别的多分类任务建模。这一期我们做误判病例分析&#xff0c;分两节介绍&#xff0c;分别基于TensorFlow和Pytorch环境的建模和分析。 本期以健康组、肺结核组、COVID-19组、细菌性&am…

mp代码生成插件

mp代码生成插件 1.下载下面的插件 2.连接测试 3.生成代码的配置 4.生成代码 红色的是刚刚生成的。 我觉得不如官方的那个好用&#xff0c;唯一的好处就是勾选的选项能够看的懂得。

视频云存储/安防监控/AI视频智能分析网关V3:工服检测功能详解

在一些工地、后厨、化工、电力等特定的场景中&#xff0c;工服的穿戴是必不可少的。这不仅是安全制度的要求&#xff0c;更能降低工作风险、提高工作效率。TSINGSEE青犀AI 边缘计算网关硬件 —— 智能分析网关可以通过实时监测和识别工人的工装穿戴情况&#xff0c;确保他们符合…

什么是接口测试,如何做接口测试?

比起点点点的功能测试&#xff0c;“接口测试”显得专业又高大上&#xff0c;也因此让有些初级测试人员“望而生畏”。别担心&#xff0c;其实接口测试也是功能测试的一种&#xff0c;它是针对接口进行的功能测试。 写在前面&#xff1a;本文参考了茹炳晟老师的《测试工程师 全…

软件架构设计(三) B/S架构风格-层次架构(一)

层次架构风格从之前的两层C/S到三层C/S,然后演化为三层B/S架构,三层B/S架构之后仍然在往后面演化,我们来看一下层次架构演化过程中都有了哪些演化的架构风格呢? 而我们先简单了解一下之前的层次架构风格中分层的各个层次的作用。 表现层:由于用户进行交互,比如MVC,MVP,…

医院小程序如何在线搭建?实战解析

在当今数字化时代&#xff0c;移动应用程序成为我们生活中必不可少的一部分。特别是在医疗领域&#xff0c;移动应用程序的需求更为迫切。为了满足这一需求&#xff0c;开发一个医疗小程序成为了许多医疗机构的优先选择。 在本文中&#xff0c;我们将分享一个实战攻略&#xff…

大数据可视化大屏实战项目(3)图书销售展示全国地图可视化---HTML+CSS+JS【源码在文末】(可用于比赛项目或者作业参考中)

大数据可视化大屏实战项目&#xff08;3&#xff09;图书销售展示全国地图可视化---HTMLCSSJS【源码在文末】&#xff08;可用于比赛项目或者作业参考中&#x1f415;&#x1f415;&#x1f415;&#xff09; 一&#xff0c;项目概览 ☞☞☞☞☞☞项目演示链接&#xff1a;http…

实力认证!OceanBase获“鼎信杯”优秀技术支撑奖

6 月 30 日&#xff0c;2023 “鼎信杯”信息技术发展论坛在京隆重举办第二届“鼎信杯”大赛颁奖典礼。OceanBase 凭借完全自主研发的原生分布式数据库&#xff0c;以及丰富的核心系统国产数据库升级案例&#xff0c;斩获“优秀技术支撑奖”。 论坛上&#xff0c;国内首个基于在…

打车系统网约车系统开发支持APP公众号H5小程序版本源码

一、操作流程 二、业务模式 三、用户端 用户注册登录&#xff1a;未注册的手机号将自动创建账号 通过好友的邀请链接进行注册&#xff0c;将会绑定上下级关系 也可以注册的时候输入好友的邀请码&#xff0c;也可以绑定关系 用户充值&#xff1a; 用户下单支付时&#xff0c;可以…