使用EasyExcel生成下拉列表
说明:本文介绍如何使用 EasyExcel 导出 excel 文件,并生成下拉列表
场景
如下,这是一个信息录入模板,通过接口提供给用户,用户在这个模板上填写学生信息,后再用接口上传文件,批量录入学生信息。
为了方便用户操作,也为了减少后端接口不必要的校验,我们希望在性别栏,生成一个下拉列表,只提供几个性别的备选项。
生成下拉列表
如下,是通过接口下载该模板的代码
@GetMapping("/get-template-1")public byte[] getTemplate() throws IOException {// 1.获取文件ClassPathResource resource = new ClassPathResource("template/excel/full/学生信息模板-填充.xlsx");// 2.构建响应头String fileName = "学生信息模板.xlsx";String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8);HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);headers.setContentDispositionFormData("attachment", encodedFileName);// 3.返回return ResponseEntity.ok().headers(headers).body(resource.getInputStream().readAllBytes()).getBody();}
生成下拉列表,我们需要先获取模板的文件流,再通过 EasyExcel 生成下拉列表,写入到一个新的流中,如下:
@GetMapping("/get-template-1")public byte[] getTemplate1() throws IOException {// 1.获取文件ClassPathResource resource = new ClassPathResource("template/excel/full/学生信息模板-填充.xlsx");// 2.构建响应头String fileName = "学生信息模板.xlsx";String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8);HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);headers.setContentDispositionFormData("attachment", encodedFileName);// 3.文件流处理ByteArrayOutputStream outputStream = new ByteArrayOutputStream();try (InputStream inputStream = resource.getInputStream()) {EasyExcelFactory.write(outputStream).withTemplate(inputStream).registerWriteHandler(new GenderDropDownColumnSheetWriteHandler()).sheet().doWrite(Collections.emptyList());}// 4.返回return ResponseEntity.ok().headers(headers).body(outputStream.toByteArray()).getBody();}
其中,GenderDropDownColumnSheetWriteHandler
是自定义拦截器,用于生成性别的下拉列表,代码如下:
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.handler.context.SheetWriteHandlerContext;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.util.CellRangeAddressList;/*** 性别列下拉列表拦截器*/
public class GenderDropDownColumnSheetWriteHandler implements SheetWriteHandler {@Overridepublic void afterSheetCreate(SheetWriteHandlerContext context) {// 区间设置:性别在第三列(序号是2),行数除开第一行(序号0,第二行从1开始)往后10万行(随便一点)CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(1, 100000, 2, 2);DataValidationHelper helper = context.getWriteSheetHolder().getSheet().getDataValidationHelper();// 下拉列表:男、女、其他DataValidationConstraint constraint = helper.createExplicitListConstraint(new String[] {"男", "女", "未知"});DataValidation dataValidation = helper.createValidation(constraint, cellRangeAddressList);context.getWriteSheetHolder().getSheet().addValidationData(dataValidation);}
}
执行,调用接口,查看生成后的模板文件,下拉列表成功生成了
另外
实际上,如果下拉列表的备选项是固定值,那么直接改模板就行了。用 excel 工具打开,手动设置。
但如果有的列,备选项不是固定的,需要查询数据库,或者根据其他逻辑动态生成,那么就可以用上面这种方式,在拦截器里定义一个字符类型的数组,外面 EasyExcel 关联拦截器的时候,将数据传进来,如下:
(拦截器里定义一个字符串数组,注意类上加了全参构造注解 @AllArgsConstructor
)
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.handler.context.SheetWriteHandlerContext;
import lombok.AllArgsConstructor;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.util.CellRangeAddressList;import java.util.List;/*** 性别列下拉列表拦截器*/
@AllArgsConstructor
public class GenderDropDownColumnSheetWriteHandler implements SheetWriteHandler {/*** 下拉列表备选项*/private List<String> options;@Overridepublic void afterSheetCreate(SheetWriteHandlerContext context) {// 区间设置:性别在第三列(序号是2),行数除开第一行(序号0,第二行从1开始)往后10万行(随便一点)CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(1, 100000, 2, 2);DataValidationHelper helper = context.getWriteSheetHolder().getSheet().getDataValidationHelper();// 下拉列表:男、女、其他DataValidationConstraint constraint = helper.createExplicitListConstraint(options.toArray(new String[0]));DataValidation dataValidation = helper.createValidation(constraint, cellRangeAddressList);context.getWriteSheetHolder().getSheet().addValidationData(dataValidation);}
}
关联拦截器的时候,将性别的备选项传入到拦截器里
// 性别下拉列表的备选项数据,可以来自业务逻辑或者数据库List<String> genderList = Arrays.asList("男", "女", "未知", "数据库动态新增了一个");// 3.文件流处理ByteArrayOutputStream outputStream = new ByteArrayOutputStream();try (InputStream inputStream = resource.getInputStream()) {EasyExcelFactory.write(outputStream).withTemplate(inputStream).registerWriteHandler(new GenderDropDownColumnSheetWriteHandler(genderList)).sheet().doWrite(Collections.emptyList());
这样返回的模板,性别列下拉列表的备选项就是根据业务逻辑动态生成的了。
关于 EasyExcel 关联拦截器,可以关联多个,如下,官方提供的例子