最近要实现一个导出Excel,实现动态列导出,记录一下
数据的大概结构如下
要实现如果总分数大于0 那么要把原因下的具体原因 作为表头 ,值则是原因下的分数,有多个原因就加入多少个,最终结果如下
首先把当前所有数据的全部的原因加入到set中去重,再转为List
Set<String> set = new HashSet<>();
for (VO vo : VOS) {
for (GroupVo groupVo : vo.getGroupVos()) {
//把具体原因名称放到set内去重
if (groupVo.getGroupName()!=null) {
set.add(groupVo.getGroupName());
}
}
}
List<String> strings = new ArrayList<>(set);
再把去重后的具体原因存到List<HeadVO>中
@Data
@Builder
public class HeadVO implements Comparable<HeadVO>{
/**
* 列头名
*/
private List<String> headTitle;
/**
* 字段名
*/
private String key;
/**
* 主排序
*/
private int index;
@Override
public int compareTo(HeadVO o) {
return this.index - o.getIndex();
}
}
List<HeadVO> headVOS = new ArrayList<>();
int j = 0;
for ( ;j < strings.size(); j++) {
headVOS.add(HeadVO.builder().headTitle(Arrays.asList("具体原因",strings.get(j))).index(3+j+1).key(strings.get(j)).build());
//index是3加一的原因是我前面还有四个字段
}
headVOS.add(HeadVO.builder().headTitle(Arrays.asList("总分","总分")).index(4+j+2).key("score").build());
excelHelper(response,VO.class,headVOS,keysAndValues);
最终导出
/**
* 动态导出列
* @param entityClass 实体类的class对象
* @param customizeHeads 要动态生成的表头
* @param list 查出的数据
* @author furao
*/
public void excelHelper(HttpServletResponse response,Class entityClass, List<HeadVO> customizeHeads, List<Map<String, Object>> list,int moum, int year ){
//获取声明字段
Field[] fields = entityClass.getDeclaredFields();
// 获取类的注解
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
ReflectionUtils.makeAccessible(field);// 设置些属性是可以访问的
//判断当前字段注解是否ExcelProperty
boolean annotationPresent = field.isAnnotationPresent(ExcelProperty.class);
if (annotationPresent) {
//获取注解
ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
//获取注解内的值变为表头
List<String> head = Arrays.asList(excelProperty.value());
//获取第几个下标
int index = excelProperty.index();
//添加 表头 下标 字段名称
HeadVO headVO = HeadVO.builder().headTitle(head).index(index).key(field.getName()).build();
//添加到集合内
customizeHeads.add(headVO);
}
}
//按照下标排序
Collections.sort(customizeHeads);
//定义一个list 存放所有表头
List<List<String>> heads = new ArrayList<>();
//存放字段名
List<String> keys = new ArrayList<>();
//一共有多少个表头循环多少次
for (int i = 0; i <= customizeHeads.size() - 1; i++) {
//获取每一个表头的名称
heads.add(customizeHeads.get(i).getHeadTitle());
//获取每一个表头的字段名
keys.add(customizeHeads.get(i).getKey());
}
//存放所有导出的数据
List<List<Object>> objs = new ArrayList<>();
//循环数据
list.forEach(e -> {
//
List<Object> obj = new ArrayList<>();
//把每个数据内的groupVos数组取出来
List<Object> groupVos= (List<Object>) e.get("groupVos");
List<Map<String, Object>> keysAndValues = getKeysAndValues(acpRuleGroupVos);
//List<Object>转为List<Map<String,Object>>
//循环每个字段
for (int i = 0; i < keys.size(); i++) {
//在数据集合中找到每个字段相对应的值并添加 一一对应
Object o = e.get(keys.get(i));
//数据为null,当前keys.get(i)可能是具体原因
if (o==null){
boolean add=false;
//循环当前数据下的GroupVos数组
for (int j = 0; j < keysAndValues.size(); j++) {
Map<String, Object> map = keysAndValues.get(j);
//把具体原因取出来
Object GroupName= map.get("GroupName");
//判断GroupName值(具体原因)是否跟当前key相等
if (GroupName.equals(keys.get(i))){
//相等置为true
add=true;
//相等把得分获取到 直接返回
Object score = map.get("score");
obj.add(score);
break;
}
}
//GroupVos数组循环结束还未添加数据表示此数据内不存在当前的原因补0
if (!add) {
obj.add(0);
}
}else {
obj.add(o);
}
}
//添加数据到集合中
objs.add(obj);
});
try {
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
//设置下载信息
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
//这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = "分数明细.xlsx";
String encode = URLEncoder.encode(fileName, "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + encode + ".xlsx");
//设置头字体
WriteFont headWriteFont = new WriteFont();
headWriteFont.setFontHeightInPoints((short) 13);
headWriteFont.setBold(true);
headWriteCellStyle.setWriteFont(headWriteFont);
//设置头居中
headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
//内容策略
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
//设置 水平居中
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
EasyExcel.write(response.getOutputStream())
.head(heads)
.registerWriteHandler(new SimpleColumnWidthStyleStrategy(20))
.registerWriteHandler(horizontalCellStyleStrategy)
.sheet("明细")
.doWrite(objs);
} catch (IOException e) {
// 重置response
response.reset();
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
Map<String, String> map = new HashMap<String, String>();
map.put("status", "failure");
map.put("message", "下载文件失败" + e.getMessage());
log.info("导出文件失败");
try {
response.getWriter().println(JSON.toJSONString(map));
} catch (IOException ioException) {
log.info("IO异常");
}
}
}
由于我们查询到的数据大部分都是List<vo>,但是这个方法需要的结果数据是List<Map<String,Object>>
在提供一份List<Object>转List<Map<String,Object>>
/**
* List<Object>转为List<Map<string,objct>
* @param object
* @return
* @author furao
*/
public static List<Map<String, Object>> getKeysAndValues(List<Object> object) {
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
for (Object obj : object) {
Class userCla;
// 得到类对象
userCla = obj.getClass();
/* 得到类中的所有属性集合 */
Field[] fs = userCla.getDeclaredFields();
Map<String, Object> listChild = new HashMap<String, Object>();
for (int i = 0; i < fs.length; i++) {
Field f = fs[i];
ReflectionUtils.makeAccessible(f);// 设置些属性是可以访问的
Object val = new Object();
try {
val = f.get(obj);
// 得到此属性的值
listChild.put(f.getName(), val);// 设置键值
} catch (IllegalArgumentException e) {
log.info("非法参数异常");
} catch (IllegalAccessException e) {
log.info("非法访问异常");
}
}
list.add(listChild);// 将map加入到list集合中
}
log.info("多个(列表)对象的所有键值====" + list.toString());
return list;
}