控制层:
@GetMapping("/export-excel")
@Operation(summary = "导出安全培训-试题 Excel")
@PreAuthorize("@ss.hasPermission('sta:question:export')")
@OperateLog(type = EXPORT)
public void exportQuestionExcel(@Valid QuestionExportReqVO exportReqVO,
HttpServletResponse response) throws IOException {
List<QuestionDO> list = questionService.getQuestionListAll(exportReqVO);
// 导出 Excel
List<QuestionImportVO> datas = QuestionConvert.INSTANCE.convertList03(list);
ExportParams params = new ExportParams("试题台账", "试题信息");
params.setDictHandler(new IExcelDictHandlerImpl());
try {
Workbook workbook = ExcelExportUtil.exportExcel(params, QuestionImportVO.class, datas);
response.setHeader("Content-disposition", "attachment;filename=" + new String("试题信息表".getBytes("gb2312"), "ISO8859-1") + ".xls");
response.setContentType("multipart/form-data");
response.setCharacterEncoding("utf-8");
ServletOutputStream out = response.getOutputStream();
workbook.write(out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
实体类如下:
@Data
public class QuestionImportVO {
@ExcelIgnore
private Long id;
@Excel(name = "试题内容", needMerge = true, width = 30)
private String content;
@ExcelIgnore
private Long typeId;
@Excel(name = "试题分类", needMerge = true, width = 10)
private String typeName;
@Excel(name = "试题类型" , needMerge = true, width = 10, dict = DictTypeConstants.STA_QUESTION_TYPE, addressList = true)
private String quType;
@Excel(name = "答案", needMerge = true, width = 10)
private String answer;
@Excel(name = "分数", needMerge = true,type=10, width = 10)
private Double score;
@Excel(name = "解析", needMerge = true, width = 30)
private String analysis;
@Excel(name = "难度(1-5星)", needMerge = true,type=10, width = 15)
private Integer grade;
@ExcelIgnore
private Long knowId;
@Excel(name = "关联知识点", needMerge = true, width = 10)
private String knowName;
@ExcelCollection(name = "试题选项")
private List<QuOptionImportVO> options;
}
试题和试题选项为一对多的关系,试题采用@ExcelCollection注解 实现一对多,试题的字段在@Excel注释中加入needMerge = true 表示纵向合并,因为选项为多个就会生成多行,但是每行试题信息都一致就需要合并。
字典字段的处理:在@Excel注解上加入dict = DictTypeConstants.STA_QUESTION_TYPE, addressList = true;dict的值为字典类型,addressList=true表示导出的字典的单元格有字典所有数据的下拉框。要实现上述功能需要实现字典处理器,如下:
/**
* 支持字典参数设置
* 举例: @Excel(name = "性别", width = 15, dicCode = "sex")
* 1、导出的时候会根据字典配置,把值1,2翻译成:男、女;
* 2、导入的时候,会把男、女翻译成1,2存进数据库;
*
* @Author wh
*/
@Slf4j
@Component
public class IExcelDictHandlerImpl implements IExcelDictHandler {
// <字典分类编码 -- <字典数据编码 -- 字典数据名称>>
/**
* 根据输入的字典类型编码,获取对应字典map(封装在List中)
*
* @param typeCode
* @return
*/
@Override
public List<Map> getList(String typeCode) {
List<Map> result = new ArrayList<>();
List<DictDataRespDTO> dataList = DictFrameworkUtils.getDictList(typeCode);
Map<String, String> dictListMap = dataList.stream().collect(Collectors.toMap(DictDataRespDTO::getLabel, DictDataRespDTO::getValue));
if (CollUtil.isNotEmpty(dataList)) {
for (Map.Entry<String, String> stringStringEntry : dictListMap.entrySet()) {
Map<String, String> map = new HashMap<>();
map.put("dictKey", stringStringEntry.getValue());
map.put("dictValue", stringStringEntry.getKey());
result.add(map);
}
}
return result;
}
/**
* 从值翻译到名称
*
* @param dict 字典Key
* @param obj 对象
* @param name 属性名称
* @param value 属性值
* @return
*/
@Override
public String toName(String dict, Object obj, String name, Object value) {
return DictFrameworkUtils.getDictDataLabel(dict, String.valueOf(value));
}
/**
* 从名称翻译到值
*
* @param dict 字典Key
* @param obj 对象
* @param name 属性名称
* @param value 属性值
* @return
*/
@Override
public String toValue(String dict, Object obj, String name, Object value) {
return DictFrameworkUtils.parseDictDataValue(dict, String.valueOf(value));
}
}
导出的示例: