EasyExcel导入导出下载模板(带下拉)
EasyExcel导入导出网上资料很多,这里就不多做描述了,总之就是一款比较轻而小,易用的excel操作工具包;这里在项目中使用到,做下笔记。以及表格中下拉框的实现;声明:本文思路是借鉴于某大神的,然后自己进行二次改版而成的,用注解的方式来进行动态下拉列表的绑定。所以代码略微有点多。 还有另一种方式,则是将数据源传入进来直接进行绑定,这样可以做到真正的与业务分离,可以更加灵活。EasyExcel导
EasyExcel导入导出网上资料很多,这里就不多做描述了,总之就是一款比较轻而小,易用的excel操作工具包;这里在项目中使用到,做下笔记。以及表格中下拉框的实现;
声明:本文思路是借鉴于某大神的,然后自己进行二次改版而成的,用注解的方式来进行动态下拉列表的绑定。所以代码略微有点多。 还有另一种方式,则是将数据源传入进来直接进行绑定,这样可以做到真正的与业务分离,可以更加灵活。
EasyExcel导入
EasyExcel.read(file.getInputStream(), ImportSecurityPerson.class,
new PeronDataListener(securityPersonService, dto))
.sheet(0).doRead();
这里一句话就可以导入成功,参数为文件流,需要导出的表格的表头实体类,第三个是读取时的监听类即可。实体类如下:
@Data
@ToString(callSuper = true)
@ApiModel(value = " 安保人员导入 ", description = " 安保人员导入 ")
public class ImportSecurityPerson {
/** 安保公司name **/
@ApiModelProperty(value = "安保公司name")
@ExcelProperty(value = "公司名称(必填)",index = 0)
private String securityCompanyName;
/** 安保人员姓名 **/
@ApiModelProperty(value = "安保人员姓名")
@ExcelProperty(value = "人员姓名(必填)",index = 1)
private String securityPersonName;
/** 安保人员性别 **/
@ApiModelProperty(value = "安保人员性别")
@ExcelProperty(value = "性别(必填)",index = 2)
private String sexCode;
/** 在职状态 **/
@ApiModelProperty(value = "在职状态")
@ExcelProperty(value = "状态(必填)",index = 3)
private String inPostStatusCode;
/** 作业区 **/
@ApiModelProperty(value = "作业区")
@ExcelProperty(value = "作业区(必填)",index = 4)
private String workZoneCode;
/** 学历 **/
@ApiModelProperty(value = "学历")
@ExcelProperty(value = "学历",index = 5)
private String eduLevelCode;
@ApiModelProperty(value = "错误信息")
@ExcelIgnore
private String msg;
@ExcelIgnore
private String uuid;
}
ExcelProperty 需要导出的表格属性,ExcelIgnore 忽略此属性。index则是顺序,value是标题;监听类中有三个重要的方法:invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context):此方法可以进行头部标题判断,判断是否是需要导入的表格;invoke(ImportSecurityPerson data, AnalysisContext context):每解析一行便会回调此方法,可以在这个方法中做一些处理;doAfterAllAnalysed(AnalysisContext context):解析完成所有数据后执行此方法, 可以进行批量入库,导入成功,错误的信息反馈(如导入成功条数,错误条数)等。
EasyExcel导出
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode("安保人员", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
List<SecurityPersonVo> securityPersonVos = securityPersonService.listSecurityPersons(getUserCharacter(), dto);
EasyExcel.write(response.getOutputStream(), SecurityPersonVo.class)
.sheet(0).sheetName("人员").doWrite(securityPersonVos);
首先设置response的信息,securityPersonVos 为数据源。导出的参数为第一个:输出流;第二个:导出的实体类,和导入是一样的;导出非常简单,对于样式的话,也可以在write后进行调用registerWriteHandler方法,写自定义样式就可以满足。
EasyExcel下载模板
其实下载模板和导出是一样的,只是在这里加了一些初始化的数据,如下拉内容项。下载模板的实体类有一点点特殊,就是采用了注解方式进行绑定下拉的内容。进入正题:
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode("安保人员导入模板", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
//用作需要传入的入参,如无须参数,则为空
Map<String, String> map = new HashMap<>();
map.put("clientId", user.getCustomerId());
ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();
WriteSheet writeSheet = EasyExcelUtil.writeSelectedSheet(DownLoadSecurityPerson.class,
0, "安保人员", map);
//写
excelWriter.write(new ArrayList<String>(), writeSheet);
//手动关闭
excelWriter.finish();
以上是下载模板的代码,具体看下这个工具类:EasyExcelUtil
我们先看下表格实体类:
@Data
@ToString(callSuper = true)
@ApiModel(value = " 治安人员导入 ", description = " 治安人员导入 ")
public class DownLoadSecurityPerson {
/** 安保公司name **/
@ApiModelProperty(value = "安保公司name")
@ExcelProperty(value = "公司名称(必填)",index = 0)
private String securityCompanyName;
/** 安保人员姓名 **/
@ApiModelProperty(value = "安保人员姓名")
@ExcelProperty(value = "人员姓名(必填)",index = 1)
private String securityPersonName;
/** 安保人员性别 **/
@ApiModelProperty(value = "安保人员性别")
@ExcelSelected(source = {"男","女"})
@ExcelProperty(value = "性别(必填)",index = 2)
private String sexCode;
/** 在职状态 **/
@ApiModelProperty(value = "在职状态")
@ExcelSelected(source = {"在职","离职"})
@ExcelProperty(value = "状态(必填)",index = 3)
private String inPostStatusCode;
/** 作业区 **/
@ApiModelProperty(value = "作业区")
@ExcelSelected(sourceClass = ZoneExcelSelectImpl.class)
@ExcelProperty(value = "作业区(必填)",index = 4)
private String workZoneCode;
/** 学历 **/
@ApiModelProperty(value = "学历")
@ExcelSelected(sourceClass = EduExcelSelectImpl.class)
@ExcelProperty(value = "学历",index = 5)
private String eduLevelCode;
}
模板标题类属性使用了ExcelSelected注解,用来绑定下拉内容,如何是固定的值,则采用source 来赋予,如果是动态的,则动态获取绑定。
注解类
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ExcelSelected {
/**
* 固定下拉内容
*/
String[] source() default {};
/**
* 动态下拉内容
*/
Class<? extends ExcelDynamicSelect>[] sourceClass() default {};
/**
* 设置下拉框的起始行,默认为第二行
*/
int firstRow() default 1;
/**
* 设置下拉框的结束行,默认为最后一行
*/
int lastRow() default 0x10000;
}
注解解析类
@Data
@Slf4j
public class ExcelSelectedResolve {
/**
* 下拉内容
*/
private String[] source;
/**
* 设置下拉框的起始行,默认为第二行
*/
private int firstRow;
/**
* 设置下拉框的结束行,默认为最后一行
*/
private int lastRow;
public String[] resolveSelectedSource(ExcelSelected excelSelected, Map<String,String> map) {
if (excelSelected == null) {
return null;
}
// 获取固定下拉框的内容
String[] source = excelSelected.source();
if (source.length > 0) {
return source;
}
// 获取动态下拉框的内容
Class<? extends ExcelDynamicSelect>[] classes = excelSelected.sourceClass();
if (classes.length > 0) {
try {
ExcelDynamicSelect excelDynamicSelect = classes[0].newInstance();
String[] dynamicSelectSource = excelDynamicSelect.getSource(map);
if (dynamicSelectSource != null && dynamicSelectSource.length > 0) {
return dynamicSelectSource;
}
} catch (InstantiationException | IllegalAccessException e) {
log.error("解析动态下拉框数据异常", e);
}
}
return null;
}
}
动态数据源接口
public interface ExcelDynamicSelect {
/**
* 获取动态生成的下拉框可选数据
* @return 动态生成的下拉框可选数据
*/
String[] getSource(Map<String,String> map);
}
动态数据源实现类
public class EduExcelSelectImpl implements ExcelDynamicSelect{
@Override
public String[] getSource(Map<String,String> map) {
SecurityPersonService bean = SpringContextUtil.getBean(SecurityPersonService.class);
Map<String, String> stringStringMap = bean.mapDict();
Collection<String> values = stringStringMap.values();
return values.toArray(new String[values.size()]);
}
}
public class ZoneExcelSelectImpl implements ExcelDynamicSelect{
@Override
public String[] getSource(Map<String,String> map) {
SecurityPersonService bean = SpringContextUtil.getBean(SecurityPersonService.class);
Map<String, String> stringStringMap = bean.mapCustomerDict(map.get("clientId"));
Collection<String> values = stringStringMap.values();
return values.toArray(new String[values.size()]);
}
}
接下来是工具类
public class EasyExcelUtil {
/**
* 创建即将导出的sheet页(sheet页中含有带下拉框的列)
* @param head 导出的表头信息和配置
* @param sheetNo sheet索引
* @param sheetName sheet名称
* @param map 入参
* @return sheet页
*/
public static <T> WriteSheet writeSelectedSheet(Class<T> head, Integer sheetNo, String sheetName,Map<String,String> map) {
Map<Integer, ExcelSelectedResolve> selectedMap = this.resolveSelectedAnnotation(head,map);
return EasyExcel.writerSheet(sheetNo, sheetName)
.head(head)
.registerWriteHandler(new CommentWriteHandler()) //创建批注
.registerWriteHandler(new CustomColumnWidthStyle()) //自适应宽度
.registerWriteHandler(new CustomSheetWriteHandler(selectedMap)) //绑定下拉数据源
.build();
}
/**
* 解析表头类中的下拉注解
* @param head 表头类
* @param <T> 泛型
* @return Map<下拉框列索引, 下拉框内容> map
*/
private static <T> Map<Integer, ExcelSelectedResolve> resolveSelectedAnnotation(Class<T> head,Map<String,String> map) {
//用来存储对应的列与值对象
Map<Integer, ExcelSelectedResolve> selectedMap = new HashMap<>();
// getDeclaredFields(): 返回全部声明的属性;getFields(): 返回public类型的属性
Field[] fields = head.getDeclaredFields();
for (int i = 0; i < fields.length; i++){
Field field = fields[i];
// 解析注解信息
ExcelSelected selected = field.getAnnotation(ExcelSelected.class);
ExcelProperty property = field.getAnnotation(ExcelProperty.class);
if (selected != null) {
ExcelSelectedResolve excelSelectedResolve = new ExcelSelectedResolve();
String[] source = excelSelectedResolve.resolveSelectedSource(selected,map);
if (source != null && source.length > 0){
excelSelectedResolve.setSource(source);
excelSelectedResolve.setFirstRow(selected.firstRow());
excelSelectedResolve.setLastRow(selected.lastRow());
if (property != null && property.index() >= 0){
selectedMap.put(property.index(), excelSelectedResolve);
} else {
selectedMap.put(i, excelSelectedResolve);
}
}
}
}
return selectedMap;
}
}
最重要的在绑定类CustomSheetWriteHandler
@Data
@AllArgsConstructor
public class CustomSheetWriteHandler implements SheetWriteHandler {
private final Map<Integer, ExcelSelectedResolve> selectedMap;
@Override
public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
}
@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
// 区间设置 第一列第一行和第二行的数据。由于第一行是头,所以第一、二行的数据实际上是第二三行
// 这里可以对cell进行任何操作
Sheet sheet = writeSheetHolder.getSheet();
DataValidationHelper helper = sheet.getDataValidationHelper();
selectedMap.forEach((k, v) -> {
// 设置下拉列表的行: 首行,末行,首列,末列
CellRangeAddressList rangeList = new CellRangeAddressList(v.getFirstRow(), v.getLastRow(), k, k);
// 设置下拉列表的值
DataValidationConstraint constraint = helper.createExplicitListConstraint(v.getSource());
// 设置约束
DataValidation validation = helper.createValidation(constraint, rangeList);
// 阻止输入非下拉选项的值
validation.setErrorStyle(DataValidation.ErrorStyle.STOP);
validation.setShowErrorBox(true);
validation.setSuppressDropDownArrow(true);
validation.createErrorBox("提示", "请选择下拉选项中的内容");
sheet.addValidationData(validation);
});
}
}
至此,就完成了下载模板带有下拉选项的表格。
完整代码GitHub: https://github.com/qinyunsurd/EasyExcel
更多推荐
所有评论(0)