update 优化 !pr345 代码结构
This commit is contained in:
parent
72882374be
commit
0f5603aed4
@ -52,6 +52,8 @@ public class ExcelEnumConvert implements Converter<Object> {
|
||||
case BOOLEAN:
|
||||
textValue = cellData.getBooleanValue();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("单元格类型异常!");
|
||||
}
|
||||
// 如果是空值
|
||||
if (ObjectUtil.isNull(textValue)) {
|
||||
|
@ -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);
|
||||
|
@ -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))
|
||||
.orElseThrow(() -> new ServiceException(String.format("字典 %s 不存在", dictType)))
|
||||
.values()
|
||||
);
|
||||
Collection<String> values = Optional.ofNullable(dictService.getAllDictByDictType(dictType))
|
||||
.orElseThrow(() -> new ServiceException(String.format("字典 %s 不存在", dictType)))
|
||||
.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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 {
|
||||
// 处理解析结果
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user