目录
- 需求分析
- 解决方案
- 数据问题
- 数据导入
需求分析
公司数据比较特殊有一部分数据需要动态修改导致信息导入时表头是不确定的,但其中又有一部分表头是固定的,如下图所示,如果表头全部是固定的话可以通过EasyExcel实体类的注解很轻松的解决,但由于部分数据动态改变,所以无法完全依靠注解实现。
解决方案
自定义方法通过反射获取实体类@ExcelProperty注解的值,同时在方法中获取动态表头信息共同组合成表头List数据。
//模板下载接口实现
public void downloadExcelTemplate(HttpServletResponse response) throws IOException {
String filename = URLEncoder.encode("物料信息导入模板"+System.currentTimeMillis(),"utf-8");
//设置响应头信息:将响应内容类型设置为 Excel 文件,并指定文件名和编码方式
response.setHeader("Content-Disposition","attachment;filename=" + filename + ".xlsx");
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
//获取响应的输出流,用于将数据写入响应。
OutputStream outputStream = response.getOutputStream();
//创建一个 ExcelWriter 对象,用于写入 Excel 文件。
ExcelWriter excelWriter = EasyExcel.write(outputStream).build();
//gaugeOutfit.getItemHead()返回了表头List数据,也是动态表头的核心
WriteSheet sheet = EasyExcel.writerSheet("sheet1").head(gaugeOutfit.getItemHead()).build();
//向数据表中写入空数据
excelWriter.write((Collection<?>) null, sheet);
excelWriter.finish();
}
//实体类
@TableName(value = "import_item",autoResultMap = true)
@Data
public class ImportItem implements Serializable {
private static final long serialVersionUID = 1L;
@TableId
@ExcelIgnore
private Long id;
/**
* 域动态信息,用于导入时集合所有的动态表头的信息,导入时使用
*/
@TableField(typeHandler = JacksonTypeHandler.class , value = "dynamic_information")
@ExcelIgnore
private JSONObject dynamicInformation;
@TableField("code")
@ExcelProperty("物料编码")
private String code;
@TableField("name")
@ExcelProperty("产品名称")
@NotBlank(message = "产品名称字段不能为空")
private String name;
@TableField("category")
@ExcelProperty("产品分类")
private String category;
@TableField("format")
@ExcelProperty("产品规格")
private String format;
@TableField("life_cycle")
@ExcelProperty("生命周期")
private Integer lifeCycle;
@TableField("brand")
@ExcelProperty("品牌")
private String brand;
@TableField("sort")
@ExcelProperty("排序")
private Integer sort;
@TableField("price_cost")
@ExcelProperty("成本价")
private BigDecimal priceCost;
@TableField("price_line")
@ExcelProperty("划线价")
private BigDecimal priceLine;
@TableField("length")
@ExcelProperty("长度")
private BigDecimal length;
@TableField("width")
@ExcelProperty("宽度")
private BigDecimal width;
@TableField("height")
@ExcelProperty("高度")
private BigDecimal height;
@TableField("create_time")
@ExcelIgnore
private Date createTime;
@ExcelIgnore
private Date updateTime;
}
package com.ruoyi.plm.util;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.plm.mapper.AttributeKeyMapper;
import com.ruoyi.plm.mapper.DomainMapper;
import com.ruoyi.plm.model.entity.AttributeKey;
import com.ruoyi.plm.model.entity.Domain;
import com.ruoyi.plm.model.entity.ImportItem;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.*;
/**
* @Author weijunliang
* @CreateTime 2023/10/16 8:43
* @Description TODO
*/
@Component
public class ExportExcelGaugeOutfit {
@Resource
private DomainMapper domainMapper;
@Resource
private AttributeKeyMapper keyMapper;
public List<List<String>> getItemHead(){
List<List<String>> list = new ArrayList<>();
//反射获取@ExcelProperty注解字段
Class<ImportItem> importItemClass = ImportItem.class;
Field[] fields = importItemClass.getDeclaredFields();
for(Field field :fields){
if(field.isAnnotationPresent(ExcelProperty.class)){
ExcelProperty fieldAnnotation = field.getAnnotation(ExcelProperty.class);
String headName = Arrays.toString(fieldAnnotation.value()).replace("[", "").replace("]", "");
List<String> head0 = new ArrayList<String>();
//之所以加固定数据是为了后续导出数据时方便
head0.add("固定数据");
head0.add(headName);
list.add(head0);
}
}
//动态数据
List<Domain> domainList = domainMapper.selectList(null);
for (Domain domain : domainList){
String domainName = domain.getName();
QueryWrapper<AttributeKey> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("domain_id",domain.getId());
List<AttributeKey> keyList = keyMapper.selectList(queryWrapper);
for (AttributeKey key : keyList){
ArrayList<String> head1 = new ArrayList<>();
head1.add(domainName);
head1.add(key.getName());
list.add(head1);
}
}
return list;
}
}
数据问题
虽然上述方法解决了动态表头的问题,但当需要导出数据时把动态数据对应到表中的动态表头也需要把所有数据转换为相同List才行,这也就使得导出数据时需要手动进行处理而无法完全依靠EasyExcel的注解实现,颇费一番手脚。
//获取所有数据
private ArrayList<List<Object>> getAllData() throws IllegalAccessException {
List<Item> items = itemMapper.selectList(null);
ArrayList<List<Object>> importItemArrayList = new ArrayList<>();
importItemArrayList.addAll(itemTransferList(items));
return importItemArrayList;
}
//物料信息转换为List
private List<List<Object>> itemTransferList(List<Item> itemList) throws IllegalAccessException {
ArrayList<List<Object>> lists = new ArrayList<>();
for (Item item : itemList){
ImportItem importItem = new ImportItem();
BeanUtils.copyProperties(item,importItem);
//处理其它数据
//通过反射在hashMap中添加固定字段信息
HashMap<String, Object> hashMap = new HashMap<>();
Class<ImportItem> importItemClass = ImportItem.class;
Field[] fields = importItemClass.getDeclaredFields();
for(Field field :fields){
if(field.isAnnotationPresent(ExcelProperty.class)){
field.setAccessible(true);
ExcelProperty fieldAnnotation = field.getAnnotation(ExcelProperty.class);
String headName = Arrays.toString(fieldAnnotation.value()).replace("[", "").replace("]", "");
hashMap.put(headName, field.get(importItem));
}
}
//hashMap添加动态字段信息,根据自己的业务逻辑修改
List<Domain> domainList = domainMapper.selectList(null);
for (Domain domain : domainList){
/**
******
**/
hashMap.put(headName,headValue);
}
//hashMap对应表头数据并转换为list
List<List<String>> itemHead = gaugeOutfit.getItemHead();
ArrayList<Object> list = new ArrayList<>();
for (List<String> head : itemHead){
Object o = hashMap.get(head.get(1));
list.add(o);
}
lists.add(list);
}
return lists;
}
数据导入
参考文章:EasyExcel复杂表头数据导入