目錄
1.說明
2.示例
3.總結
1.說明
平時使用easyexcel進行導出時,標題的名字通過在表的實體類上添加注解的方式進行實現,然后傳入表的實體類的集合進行下載即可。
有這么一個需求,用戶可以自定義導出的模板,也就是說導出的模板的列信息時變化的,并且要根據對應的列信息實現列的下拉選擇。
2.示例
easyexcel版本
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.1</version></dependency>
service
List<String> colId = dowDomain.getColId();// 獲取列的詳細信息List<ColEntryEntity> colList = colEntryMsapi.getColList(colId);// 生成標題List<List<String>> heads = new ArrayList<>();colList.forEach(item -> {heads.add(Arrays.asList(item.getDisplayName(), item.getColId(), item.getDbName()));});// list類型的列生成下拉選擇List<String> listColIdList = colList.stream().filter(item -> ColumnTypeEnum.LIST.type.equals(item.getColType())).map(ColEntryEntity::getColId).collect(Collectors.toList());List<ColEntryListEntity> colValList = new ArrayList<>();if (CollUtil.isNotEmpty(listColIdList)) {colValList = colEntryMsapi.getColValList(listColIdList);}Map<Integer, List<String>> valList = new HashMap<>();for (int i = 0; i < colList.size(); i++) {ColEntryEntity colEntry = colList.get(i);if (ColumnTypeEnum.LIST.type.equals(colEntry.getColType())) {List<String> list = colValList.stream().filter(x -> x.getColId().equals(colEntry.getColId())).map(ColEntryListEntity::getListValue).collect(Collectors.toList());valList.put(i, list);}}domain.setHeads(heads);domain.setValList(valList);return domain;
controller?
String fileName = "導入模板" + DateFormatUtils.format(new Date(), CommonContants.DATE_TYPE) + CommonContants.TYPE_XLSX;response.setContentType(CommonContants.CONTENT_TYPE);response.setCharacterEncoding(CommonContants.UTF8);response.setHeader(Header.CONTENT_DISPOSITION.getValue(), CommonContants.CONTENT_TYPE + URLEncoder.encode(fileName, CommonContants.UTF8));DowloadDomain dowloadDomain = attributeCustomizeService.dowloadTemplate(dowDomain);List<List<Object>> total = new ArrayList<>();EasyExcel.write(response.getOutputStream()).head(dowloadDomain.getHeads()).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).registerWriteHandler(new CustomSheetWriteHandler(dowloadDomain.getValList())).sheet("模板").doWrite(total);
?通過自定義攔截器實現下拉選擇
package com.kingagroot.info.handler;import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import lombok.extern.slf4j.Slf4j;
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.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddressList;import java.util.*;/*** 自定義攔截器.對第一列第一行和第二行的數據新增下拉框,顯示 測試1 測試2** @author Jiaju Zhuang*/
@Slf4j
public class CustomSheetWriteHandler implements SheetWriteHandler {private Map<Integer, List<String>> optionGroupMap;public CustomSheetWriteHandler(Map<Integer, List<String>> mapList) {Map<Integer, List<String>> data = new HashMap<>(mapList);optionGroupMap = data;}@Overridepublic void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {}/*** 自定義攔截器.填充下拉選項 key 就是 第幾列(從0開始),value 就是這一列 你的下拉數據*/@Overridepublic void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {Sheet sheet = writeSheetHolder.getSheet();// 區間設置 第一列第一行和第二行的數據。由于第一行是頭,所以第一、二行的數據實際上是第二三行Optional.ofNullable(optionGroupMap).orElse(new HashMap<>()).forEach((columnIndex, options) -> {// 區間設置 第一列第一行和第二行的數據。由于第一行是頭,所以第一、二行的數據實際上是第二三行CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(3, 65535, columnIndex, columnIndex);DataValidationHelper helper = sheet.getDataValidationHelper();DataValidationConstraint constraint = helper.createExplicitListConstraint(options.toArray(new String[options.size()]));DataValidation dataValidation = helper.createValidation(constraint, cellRangeAddressList);// 這行代碼是用于設置數據驗證時是否顯示錯誤提示框的,為true,如果用戶在單元格中輸入了不符合數據驗證條件的數值,會彈出提示dataValidation.setShowErrorBox(true);// 這行代碼是用于設置數據驗證中的錯誤提示框的樣式。當設置為DataValidation.ErrorStyle.STOP時,表示如果用戶輸入了不符合數據驗證條件的數值,將阻止用戶繼續輸入并彈出錯誤提示框,防止不合規范的數據被輸入。dataValidation.setErrorStyle(DataValidation.ErrorStyle.STOP);// 這行代碼表示設置數據驗證時是否允許空單元格。當將參數設置為false時,即不允許空單元格// dataValidation.setEmptyCellAllowed(false);// 這行代碼表示設置數據驗證時是否顯示下拉箭頭。當將參數設置為false時,會在具有數據驗證的單元格中顯示下拉箭頭,以提示用戶可以從預定義的選項中進行選擇。如果設置為true,則不會顯示下拉箭頭。// dataValidation.setSuppressDropDownArrow(false);// 這行代碼表示設置數據驗證時是否顯示提示框。當將參數設置為true時,如果用戶選擇了擁有數據驗證的單元格,會彈出一個提示框,向用戶提供關于該單元格數據輸入的指導或說明// dataValidation.setShowPromptBox(true);// 這行代碼是用于創建數據驗證的錯誤提示框。其中,第一個參數"錯誤"表示錯誤提示框的標題,第二個參數"請從下拉列表中選擇一個選項!"是具體的錯誤提示信息。當用戶輸入了不符合數據驗證條件的數值時,將會彈出這個錯誤提示框,提醒用戶輸入的數據不符合規定,并給出相應的錯誤說明。dataValidation.createErrorBox("錯誤", "請從下拉列表中選擇一個選項!");// 這行代碼用于設置數據驗證的標題和提示信息。第一個參數"下拉選擇限制"表示數據驗證對話框的標題,第二個參數"請在下拉列表中選擇一個選項!"是具體的提示信息。當用戶在單元格輸入了不符合數據驗證條件的數值時,會彈出一個警告框,其中包含了設置的標題和提示信息,以提醒用戶必須從下拉列表中進行選擇。// 有的版本可能沒有這個設置,需要升級到對應的版本// dataValidation.setTitle("下拉選擇限制", "請在下拉列表中選擇一個選項!");writeSheetHolder.getSheet().addValidationData(dataValidation);});}
}
說明
?①獲取要下載模板中的列信息,生成標題,代碼如下:
// 生成標題List<List<String>> heads = new ArrayList<>();colList.forEach(item -> {heads.add(Arrays.asList(item.getDisplayName(), item.getColId(), item.getDbName()));});
?動態標題的信息需要存儲到一個List<List<String>>集合中,集合中的數據是一個string類型的集合,代表第一列標題的信息,上面中每列標題中存儲了3個值,代表每列的標題行有3行。通過循環處理生成導出文件的標題。
②動態下拉的實現
? 要做到哪一列可以進行下拉選擇,哪一列沒有下拉選擇,首先要獲取下拉選擇列表,循環列信息,進行匹配,存儲到Map<Integer, List<String>>集合中,key代表是哪一列,從0開始,value則代表下拉選擇列表。
然后通過上面的自定義攔截器,將集合內容傳遞到攔截器中進行循環處理,設置下拉選擇
使用了Optional.ofNullable(optionGroupMap).orElse(new HashMap<>())方法進行處理避免空指針的問題。
③下拉選擇輸入內容不正確時可以進行校驗處理,主要是下面這三行代碼,分別是開啟數據驗證,輸入錯誤時阻止輸入并彈出信息以及彈出信息的內容設置
// 這行代碼是用于設置數據驗證時是否顯示錯誤提示框的,為true,如果用戶在單元格中輸入了不符合數據驗證條件的數值,會彈出提示dataValidation.setShowErrorBox(true);// 這行代碼是用于設置數據驗證中的錯誤提示框的樣式。當設置為DataValidation.ErrorStyle.STOP時,表示如果用戶輸入了不符合數據驗證條件的數值,將阻止用戶繼續輸入并彈出錯誤提示框,防止不合規范的數據被輸入。dataValidation.setErrorStyle(DataValidation.ErrorStyle.STOP);// 這行代碼是用于創建數據驗證的錯誤提示框。其中,第一個參數"錯誤"表示錯誤提示框的標題,第二個參數"請從下拉列表中選擇一個選項!"是具體的錯誤提示信息。當用戶輸入了不符合數據驗證條件的數值時,將會彈出這個錯誤提示框,提醒用戶輸入的數據不符合規定,并給出相應的錯誤說明。dataValidation.createErrorBox("錯誤", "請從下拉列表中選擇一個選項!");
④導出數據的設置
?格式為List<List<Object>> ,集合中的每條數據代表一行數據,注意順序要和列一一對應。
3.總結
自定義導出模板,注意標題的設置,下拉選擇的設置及內容的設置
不同的easyexcel的版本,在下拉選擇的設置存在不同,使用時需要注意