update 优化 !pr345 代码结构

This commit is contained in:
疯狂的狮子Li 2023-05-13 23:28:57 +08:00
parent 72882374be
commit 0f5603aed4
7 changed files with 57 additions and 123 deletions

View File

@ -52,6 +52,8 @@ public class ExcelEnumConvert implements Converter<Object> {
case BOOLEAN:
textValue = cellData.getBooleanValue();
break;
default:
throw new IllegalArgumentException("单元格类型异常!");
}
// 如果是空值
if (ObjectUtil.isNull(textValue)) {

View File

@ -63,11 +63,11 @@ public class DropDownOptions {
StringBuilder stringBuffer = new StringBuilder();
String regex = "^[\\S\\d\\u4e00-\\u9fa5]+$";
for (int i = 0; i < vars.length; i++) {
Object var = vars[i];
if (!var.toString().matches(regex)) {
String var = StrUtil.trimToEmpty(String.valueOf(vars[i]));
if (!var.matches(regex)) {
throw new ServiceException("选项数据不符合规则,仅允许使用中英文字符以及数字");
}
stringBuffer.append(StrUtil.trimToEmpty(var.toString()));
stringBuffer.append(var);
if (i < vars.length - 1) {
// 直至最后一个前都以_作为切割线
stringBuffer.append(DELIMITER);

View File

@ -1,5 +1,7 @@
package com.ruoyi.common.excel;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
@ -11,6 +13,7 @@ import com.ruoyi.common.annotation.ExcelDictFormat;
import com.ruoyi.common.annotation.ExcelEnumFormat;
import com.ruoyi.common.core.service.DictService;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StreamUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
@ -20,7 +23,6 @@ import org.apache.poi.xssf.usermodel.XSSFDataValidation;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;
/**
* <h1>Excel表格下拉选操作</h1>
@ -90,37 +92,24 @@ public class ExcelDownHandler implements SheetWriteHandler {
List<String> options = new ArrayList<>();
if (fields[i].isAnnotationPresent(ExcelDictFormat.class)) {
// 如果指定了@ExcelDictFormat则使用字典的逻辑
ExcelDictFormat thisFiledExcelDictFormat = fields[i].getDeclaredAnnotation(ExcelDictFormat.class);
String dictType = thisFiledExcelDictFormat.dictType();
String converterExp = thisFiledExcelDictFormat.readConverterExp();
ExcelDictFormat format = fields[i].getDeclaredAnnotation(ExcelDictFormat.class);
String dictType = format.dictType();
String converterExp = format.readConverterExp();
if (StrUtil.isNotBlank(dictType)) {
// 如果传递了字典名则依据字典建立下拉
options =
new ArrayList<>(
Optional.ofNullable(dictService.getAllDictByDictType(dictType))
Collection<String> values = Optional.ofNullable(dictService.getAllDictByDictType(dictType))
.orElseThrow(() -> new ServiceException(String.format("字典 %s 不存在", dictType)))
.values()
);
.values();
options = new ArrayList<>(values);
} else if (StrUtil.isNotBlank(converterExp)) {
// 如果指定了确切的值则直接解析确切的值
options = StrUtil.split(
converterExp,
thisFiledExcelDictFormat.separator(),
true,
true);
options = StrUtil.split(converterExp, format.separator(), true, true);
}
} else if (fields[i].isAnnotationPresent(ExcelEnumFormat.class)) {
// 否则如果指定了@ExcelEnumFormat则使用枚举的逻辑
ExcelEnumFormat thisFiledExcelEnumFormat = fields[i].getDeclaredAnnotation(ExcelEnumFormat.class);
options =
EnumUtil
.getFieldValues(
thisFiledExcelEnumFormat.enumClass(),
thisFiledExcelEnumFormat.textField()
)
.stream()
.map(String::valueOf)
.collect(Collectors.toList());
ExcelEnumFormat format = fields[i].getDeclaredAnnotation(ExcelEnumFormat.class);
List<Object> values = EnumUtil.getFieldValues(format.enumClass(), format.textField());
options = StreamUtils.toList(values, String::valueOf);
}
if (ObjectUtil.isNotEmpty(options)) {
// 仅当下拉可选项不为空时执行
@ -165,7 +154,7 @@ public class ExcelDownHandler implements SheetWriteHandler {
if (ObjectUtil.isEmpty(value)) {
return;
}
this.markOptionsToSheet(helper, sheet, celIndex, helper.createExplicitListConstraint(value.toArray(new String[0])));
this.markOptionsToSheet(helper, sheet, celIndex, helper.createExplicitListConstraint(ArrayUtil.toArray(value, String.class)));
}
/**
@ -206,9 +195,7 @@ public class ExcelDownHandler implements SheetWriteHandler {
// 本次循环的一级选项值
String thisFirstOptionsValue = firstOptions.get(columIndex);
// 创建第一行的数据
Optional
// 获取第一行
.ofNullable(linkedOptionsDataSheet.getRow(0))
Optional.ofNullable(linkedOptionsDataSheet.getRow(0))
// 如果不存在则创建第一行
.orElseGet(() -> linkedOptionsDataSheet.createRow(finalI))
// 第一行当前列
@ -218,7 +205,7 @@ public class ExcelDownHandler implements SheetWriteHandler {
// 第二行开始设置第二级别选项参数
List<String> secondOptions = secoundOptionsMap.get(thisFirstOptionsValue);
if (ObjectUtil.isEmpty(secondOptions)) {
if (CollUtil.isEmpty(secondOptions)) {
// 必须保证至少有一个关联选项否则将导致Excel解析错误
secondOptions = Collections.singletonList("暂无_0");
}
@ -251,8 +238,7 @@ public class ExcelDownHandler implements SheetWriteHandler {
int finalRowIndex = rowIndex + 1;
int finalColumIndex = columIndex;
Row row = Optional
.ofNullable(linkedOptionsDataSheet.getRow(finalRowIndex))
Row row = Optional.ofNullable(linkedOptionsDataSheet.getRow(finalRowIndex))
// 没有则创建
.orElseGet(() -> linkedOptionsDataSheet.createRow(finalRowIndex));
Optional
@ -315,9 +301,7 @@ public class ExcelDownHandler implements SheetWriteHandler {
/**
* 挂载下拉的列仅限一级选项
*/
private void markOptionsToSheet(DataValidationHelper helper,
Sheet sheet,
Integer celIndex,
private void markOptionsToSheet(DataValidationHelper helper, Sheet sheet, Integer celIndex,
DataValidationConstraint constraint) {
// 设置数据有效性加载在哪个单元格上,四个参数分别是起始行终止行起始列终止列
CellRangeAddressList addressList = new CellRangeAddressList(1, 1000, celIndex, celIndex);
@ -327,11 +311,8 @@ public class ExcelDownHandler implements SheetWriteHandler {
/**
* 挂载下拉的列仅限二级选项
*/
private void markLinkedOptionsToSheet(DataValidationHelper helper,
Sheet sheet,
Integer rowIndex,
Integer celIndex,
DataValidationConstraint constraint) {
private void markLinkedOptionsToSheet(DataValidationHelper helper, Sheet sheet, Integer rowIndex,
Integer celIndex, DataValidationConstraint constraint) {
// 设置数据有效性加载在哪个单元格上,四个参数分别是起始行终止行起始列终止列
CellRangeAddressList addressList = new CellRangeAddressList(rowIndex, rowIndex, celIndex, celIndex);
markDataValidationToSheet(helper, sheet, constraint, addressList);
@ -340,10 +321,8 @@ public class ExcelDownHandler implements SheetWriteHandler {
/**
* 应用数据校验
*/
private void markDataValidationToSheet(DataValidationHelper helper,
Sheet sheet,
DataValidationConstraint constraint,
CellRangeAddressList addressList) {
private void markDataValidationToSheet(DataValidationHelper helper, Sheet sheet,
DataValidationConstraint constraint, CellRangeAddressList addressList) {
// 数据有效性对象
DataValidation dataValidation = helper.createValidation(constraint, addressList);
// 处理Excel兼容性问题
@ -381,7 +360,7 @@ public class ExcelDownHandler implements SheetWriteHandler {
int thisCircleColumnIndex = columnIndex % 26;
// 26一循环的次数大于0则视为栏名至少两位
String columnPrefix = columnCircleCount == 0
? ""
? StrUtil.EMPTY
: StrUtil.subWithLength(EXCEL_COLUMN_NAME, columnCircleCount - 1, 1);
// 从26一循环内取对应的栏位名
String columnNext = StrUtil.subWithLength(EXCEL_COLUMN_NAME, thisCircleColumnIndex, 1);

View File

@ -85,7 +85,7 @@ public class ExcelUtil {
try {
resetResponse(sheetName, response);
ServletOutputStream os = response.getOutputStream();
exportExcel(list, sheetName, clazz, false, os);
exportExcel(list, sheetName, clazz, false, os, null);
} catch (IOException e) {
throw new RuntimeException("导出Excel异常");
}
@ -123,7 +123,7 @@ public class ExcelUtil {
try {
resetResponse(sheetName, response);
ServletOutputStream os = response.getOutputStream();
exportExcel(list, sheetName, clazz, merge, os);
exportExcel(list, sheetName, clazz, merge, os, null);
} catch (IOException e) {
throw new RuntimeException("导出Excel异常");
}
@ -158,7 +158,7 @@ public class ExcelUtil {
* @param os 输出流
*/
public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, OutputStream os) {
exportExcel(list, sheetName, clazz, false, os);
exportExcel(list, sheetName, clazz, false, os, null);
}
/**
@ -183,7 +183,8 @@ public class ExcelUtil {
* @param merge 是否合并单元格
* @param os 输出流
*/
public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, boolean merge, OutputStream os) {
public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, boolean merge,
OutputStream os, List<DropDownOptions> options) {
ExcelWriterSheetBuilder builder = EasyExcel.write(os, clazz)
.autoCloseStream(false)
// 自动适配
@ -195,28 +196,9 @@ public class ExcelUtil {
// 合并处理器
builder.registerWriteHandler(new CellMergeStrategy(list, true));
}
builder.doWrite(list);
}
/**
* 导出带有下拉框的Excel表格
*
* @param options 下拉框数据
*/
public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz,
boolean merge, OutputStream os, List<DropDownOptions> options) {
ExcelWriterSheetBuilder builder = EasyExcel.write(os, clazz)
.autoCloseStream(false)
// 自动适配
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
// 大数值自动转换 防止失真
.registerConverter(new ExcelBigNumberConvert())
if (CollUtil.isNotEmpty(options)) {
// 添加下拉框操作
.registerWriteHandler(new ExcelDownHandler(options))
.sheet(sheetName);
if (merge) {
// 合并处理器
builder.registerWriteHandler(new CellMergeStrategy(list, true));
builder.registerWriteHandler(new ExcelDownHandler(options));
}
builder.doWrite(list);
}

View File

@ -1,6 +1,5 @@
package com.ruoyi.demo.controller;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.core.collection.CollUtil;
import com.ruoyi.common.excel.ExcelResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
@ -90,7 +89,6 @@ public class TestExcelController {
*
* @param response /
*/
@SaIgnore
@GetMapping("/exportWithOptions")
public void exportWithOptions(HttpServletResponse response) {
exportExcelService.exportWithOptions(response);
@ -99,7 +97,6 @@ public class TestExcelController {
/**
* 导入表格
*/
@SaIgnore
@PostMapping(value = "/importWithOptions", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public List<ExportDemoVo> importWithOptions(@RequestPart("file") MultipartFile file) throws Exception {
// 处理解析结果

View File

@ -1,7 +1,9 @@
package com.ruoyi.demo.service.impl;
import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.enums.UserStatus;
import com.ruoyi.common.excel.DropDownOptions;
import com.ruoyi.common.utils.StreamUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.demo.domain.vo.ExportDemoVo;
import com.ruoyi.demo.service.IExportExcelService;
@ -55,52 +57,31 @@ public class ExportExcelServiceImpl implements IExportExcelService {
// 把所有的结果提取为规范的下拉选可选项
// 规范的一级省用于级联省-
List<String> provinceOptions =
provinceList.stream()
.map(everyProvince ->
DropDownOptions.createOptionValue(
everyProvince.getName(),
everyProvince.getId()
))
.collect(Collectors.toList());
List<String> provinceOptions = StreamUtils.toList(provinceList, everyProvince ->
DropDownOptions.createOptionValue(everyProvince.getName(), everyProvince.getId()));
// 规范的二级市用于级联省-
Map<String, List<String>> provinceToCityOptions = new HashMap<>();
cityList.stream()
.collect(Collectors.groupingBy(DemoCityData::getPData))
StreamUtils.groupByKey(cityList, DemoCityData::getPData)
.forEach((province, thisProvinceCityList) -> {
// 每个省下二级的市可选项
provinceToCityOptions.put(
DropDownOptions.createOptionValue(province.getName(), province.getId()),
thisProvinceCityList.stream()
.map(everyCity ->
DropDownOptions.createOptionValue(everyCity.getName(), everyCity.getId())
)
.collect(Collectors.toList())
);
String optionValue = DropDownOptions.createOptionValue(province.getName(), province.getId());
List<String> list = StreamUtils.toList(thisProvinceCityList, everyCity ->
DropDownOptions.createOptionValue(everyCity.getName(), everyCity.getId()));
provinceToCityOptions.put(optionValue, list);
});
// 规范的一级市用于级联市-
List<String> cityOptions = cityList.stream()
.map(everyCity ->
DropDownOptions.createOptionValue(
everyCity.getName(),
everyCity.getId()
))
.collect(Collectors.toList());
List<String> cityOptions = StreamUtils.toList(cityList, everyCity ->
DropDownOptions.createOptionValue(everyCity.getName(), everyCity.getId()));
// 规范的二级县用于级联市-
Map<String, List<String>> cityToAreaOptions = new HashMap<>();
areaList.stream()
.collect(Collectors.groupingBy(DemoCityData::getPData))
StreamUtils.groupByKey(areaList, DemoCityData::getPData)
.forEach((city, thisCityAreaList) -> {
// 每个市下二级的县可选项
cityToAreaOptions.put(
DropDownOptions.createOptionValue(city.getName(), city.getId()),
thisCityAreaList.stream()
.map(everyArea ->
DropDownOptions.createOptionValue(everyArea.getName(), everyArea.getId())
)
.collect(Collectors.toList())
);
String optionValue = DropDownOptions.createOptionValue(city.getName(), city.getId());
List<String> list = StreamUtils.toList(thisCityAreaList, everyCity ->
DropDownOptions.createOptionValue(everyCity.getName(), everyCity.getId()));
cityToAreaOptions.put(optionValue, list);
});
// 因为省市县三个都是联动省级联市市级联县因此需要创建两个级联下拉分别以省和市为判断依据创建
@ -129,14 +110,14 @@ public class ExportExcelServiceImpl implements IExportExcelService {
// 到此为止所有的下拉框可选项已全部配置完毕
// 接下来需要将Excel中的展示数据转换为对应的下拉选
List<ExportDemoVo> outList = excelDataList.stream().map(everyRowData -> {
List<ExportDemoVo> outList = StreamUtils.toList(excelDataList, everyRowData -> {
// 只需要处理没有使用@ExcelDictFormat注解的下拉框
// 一般来说可以直接在数据库查询即查询出省市县信息这里通过模拟操作赋值
everyRowData.setProvince(buildOptions(provinceList, everyRowData.getProvinceId()));
everyRowData.setCity(buildOptions(cityList, everyRowData.getCityId()));
everyRowData.setArea(buildOptions(areaList, everyRowData.getAreaId()));
return everyRowData;
}).collect(Collectors.toList());
});
ExcelUtil.exportExcel(outList, "下拉框示例", ExportDemoVo.class, response, options);
}
@ -148,7 +129,7 @@ public class ExportExcelServiceImpl implements IExportExcelService {
DemoCityData demoCityData = groupByIdMap.get(id).get(0);
return DropDownOptions.createOptionValue(demoCityData.getName(), demoCityData.getId());
} else {
return "";
return StrUtil.EMPTY;
}
}

View File

@ -281,14 +281,7 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService
@Override
public Map<String, String> getAllDictByDictType(String dictType) {
List<SysDictData> thisDictTypeDataList = selectDictDataByType(dictType);
Map<String, String> dictMap = null;
for (SysDictData everyDictData : thisDictTypeDataList) {
if (ObjectUtil.isNull(dictMap)) {
dictMap = new HashMap<>();
}
dictMap.put(everyDictData.getDictValue(), everyDictData.getDictLabel());
}
return dictMap;
List<SysDictData> list = selectDictDataByType(dictType);
return StreamUtils.toMap(list, SysDictData::getDictValue, SysDictData::getDictLabel);
}
}