出于好奇,当下扫描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 {
@Override
public void addInterceptors(@NonNull InterceptorRegistry registry) {
registry.addInterceptor(this);
WebMvcConfigurer.super.addInterceptors(registry);
}
@Override
public void addCorsMappings(@NonNull CorsRegistry registry) {
WebMvcConfigurer.super.addCorsMappings(registry);
}
@Override
public void postHandle(@NonNull HttpServletRequest request,@NonNull HttpServletResponse response,@NonNull Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public 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);
}
@Override
public 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 {
@Resource
private SqlDataProvider sqlDataProvider;
@GetMapping("/handle/sql")
@ResponseBody
public 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 {
@Resource
private ExcelEntityService excelEntityService;
@RequestMapping("/createAndInsert")
@ResponseBody
public void uploadExcel(@RequestParam("fileName") MultipartFile file) {
excelEntityService.createTable(file);
excelEntityService.insertEntity(file);
}
@RequestMapping("/insert")
@ResponseBody
public void insertExcel(@RequestParam("fileName") MultipartFile file) {
excelEntityService.insertEntity(file);
}
@RequestMapping("/drop")
@ResponseBody
public 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 {
@Resource
private SqlDataProvider sqlDataProvider;
@Resource
private SqlSpliceProvider spliceProvider;
@Resource
private ReadExcelService readExcelService;
@Override
public void createTable(MultipartFile file) {
String dropTableSql = spliceProvider.dropTableSql(file.getName());
log.info("删表SQL:{}",dropTableSql);
sqlDataProvider.executeSql(dropTableSql);
List excelColumnList = readExcelService.getExcelColumnList(file);
StringBuffer stringBuffer = spliceProvider.spliceCreateTableSql(excelColumnList, file.getName());
log.warn("建表SQL:{}", stringBuffer);
sqlDataProvider.executeSql(stringBuffer.toString());
}
@Override
public void insertEntity(MultipartFile file) {
String existsTableSql = spliceProvider.existsTableSql(file.getName());
Object aReturn = sqlDataProvider.executeSqlAndGetReturn(existsTableSql);
if (Objects.nonNull(aReturn)) {
List excelColumnList = readExcelService.getExcelColumnList(file);
Map> excelRowDataMap = readExcelService.getExcelRowDataMap(file, excelColumnList);
List stringBuffer1 = spliceProvider.spliceInsertValueSql(excelRowDataMap, file.getName());
stringBuffer1.forEach(s -> sqlDataProvider.executeSql(s));
}else{
log.warn("不存在数据表:{}",file.getName());
}
}
@Override
public 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 getExcelColumnList(MultipartFile file);
/**
* 读取每一行的行实体列表,一个LIST为一行
*
* @param file 文件
* @param columnEntityList 列实体列表
* @return 全部的值MAP<行号 , 行的属性值LIST>
*/
Map> getExcelRowDataMap(MultipartFile file, List columnEntityList);
}
ReadExcel.java
@Slf4j
@Service
public class ReadExcel implements ReadExcelService {
private static final Integer LIMIT_SCAN_NUM = 500 * 1000;
/**
* 根据文件名读取Excel文件获取列信息列表
*
* @param file 文件
* @return List<列实体>
*/
@Override
public List getExcelColumnList(MultipartFile file) {
List 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实体列表>
*/
@Override
public Map> getExcelRowDataMap(MultipartFile file, List columnEntityList) {
Workbook workbook = getWorkbook(file);
if (Objects.isNull(workbook)) {
return new HashMap<>();
}
Sheet sheet = workbook.getSheetAt(0);
int lastRowNum = sheet.getLastRowNum();
Map> map = new HashMap<>();
if (lastRowNum <= LIMIT_SCAN_NUM) {
for (int i = 1; i <= lastRowNum; i++) {
Row row = sheet.getRow(i);
List 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 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 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 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 {
@Resource
private 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 {
@Resource
private 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 {
@Resource
private JdbcTransactionManager jdbcTransactionManager;
@Bean("ReadCommittedTransactionTemplate")
@Scope("singleton")
@ConditionalOnBean({JdbcTransactionManager.class})
@Lazy
public 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})
@Lazy
public 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})
@Lazy
public 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})
@Lazy
public 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 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 spliceInsertValueSql(Map> map, String tableName);
}
SqlSplicer.java
@Service
public class SqlSplicer implements SqlSpliceProvider {
/**
* 拼接建表SQL
*
* @param columnEntityList 列信息实体列表
* @param tableName 表格名称
* @return SQL
*/
@Override
public StringBuffer spliceCreateTableSql(List 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
*/
@Override
public String dropTableSql(String tableName) {
return "DROP TABLE IF EXISTS " + SqlSpliceStringUtil.quotesHandle(SqlSpliceStringUtil.transferPinYin(tableName));
}
/**
* 查询数据表是否存在
* @param tableName 表名称
* @return SQL
*/
@Override
public 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
*/
@Override
public List spliceInsertValueSql(Map> map, String tableName) {
List 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 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 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 {
@Resource
private JdbcTemplate jdbcTemplate;
@Qualifier("ReadCommittedTransactionTemplate")
@Resource
private TransactionTemplate transactionTemplate;
@Override
public void executeSql(String sql) {
log.info("执行非查询操作SQL,开启事务执行:{}", sql);
transactionTemplate.executeWithoutResult(status -> {
try {
jdbcTemplate.execute(sql);
} catch (Exception e) {
log.error("事务异常,开启回滚:{}", e.getMessage());
status.setRollbackOnly();
}
});
}
@Override
public Object executeSqlAndGetReturn(String sql) {
log.info("执行查询SQL:{}", sql);
return jdbcTemplate.queryForObject(sql, Object.class);
}
@Override
public String executeQuerySql(String sql) {
log.info("执行查询SQL:{}", sql);
List
具体的讲解就不说了,分享代码案例,感兴趣的同学可以gitee上搜[email protected]:huanglinchun/resolve_excel_auto.git