# easyExcel-list-solve
**Repository Path**: javaxiaobear/easyExcel-list-solve
## Basic Information
- **Project Name**: easyExcel-list-solve
- **Description**: 解决EasyExcel不支持解析List以及实体类对象问题
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 2
- **Forks**: 0
- **Created**: 2021-09-09
- **Last Updated**: 2025-01-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# easyExcel-list-solve
#### 介绍
> 解决EasyExcel不支持解析List以及实体类对象问题
#### 需求说明
> 连表查询一对多的关系,fir_rating_material表与fir_ratingcard_template和fir_rating_card是一对多的关系
#### 解决方法
##### 方法一:采用Mybatis的继承关系
一对多的关系,就相当于一个`list`里面又包含另一个list集合,这时候我们可以将`list`集合进行解析,也就是说,easyExcel是不支持数据集合里面嵌套对象、`list`、`map`等集合数据的
1. 新建一个实体类来接收数据,当然,你用原来对象来继承也是可以的,这里我是把两个类的属性放在一起了,只继承一个类,主要是看起来方便一点,toString和set、get方法省略
```java
public class FirRatingcardTemplateVo extends FirRatingCard{
private static final long serialVersionUID = 1L;
/** 评分模板ID */
@ExcelIgnore
private Long ratingTemplateId;
/** 模板ID */
@ExcelIgnore
private Long templateId;
/** 模块 */
@ExcelProperty(value = "模块")
private String ratingModule;
/** 一级指标 */
@ExcelProperty(value = "一级指标")
private String ratingLevelFirst;
/** 二级指标 */
@ExcelProperty(value = "二级指标")
private String ratingLevelSecond;
/** 文件编号 */
@ExcelProperty(value = "对应资料调阅清单编号")
private Long ratingNum;
/** 评分内容ID */
@ExcelProperty(value = "评分内容ID")
private Integer ratingContentId;
/** 评价内容 */
@ExcelProperty(value = "评分内容")
private String ratingContent;
/** 评分方式 */
@ExcelProperty(value = "评分方式")
private String ratingType;
/** 评分资料ID */
@ExcelIgnore
private Long rmId;
/** 任务ID */
@ExcelIgnore
private String taskId;
/** 机构名称 */
@ExcelIgnore
private String deptName;
/** 机构类型 */
@ExcelIgnore
private String deptType;
/** 评级期数 */
@ExcelIgnore
private String ratingPhase;
/** 评级年份 */
@ExcelIgnore
private String ratingYear;
/** 所在地 */
@ExcelIgnore
private String location;
/** 删除标志 */
@ExcelIgnore
private String delFlag;
@ExcelIgnore
private FirRatingCard firRatingCard;
```
2. 对应的mapper.xml配置
```xml
select rm_id, task_id, template_id, dept_name, dept_type, rating_phase, rating_year, location, create_by, create_time, update_by, update_time from fir_rating_material
select DISTINCT frm.rm_id, frm.task_id, frm.dept_name, frm.dept_type, frm.rating_phase, frm.rating_year,frm.location, frm.template_id ,frt.rating_template_id, frt.rating_module, frt.rating_level_first, frt.rating_level_second,frt.rating_num, frt.rating_content_id, frt.rating_content, frt.rating_type, frt.remark,frc.verification_type,frc.rating,frc.rating_type,frc.rating_guide_list,frc.rating_doc_list,frc.ask_id
from fir_rating_material As frm
left join fir_ratingcard_template frt on frm.template_id = frt.template_id
left join fir_rating_card frc ON frc.rm_id = frm.rm_id and frc.template_id = frm.template_id and frc.rating_type_id = frt.rating_type_id
```
3. 这里的service,我是没有做任何数据处理的,代码我就不放了,具体看源码
4. 调用接口
```java
@Controller
public class ExcelController {
@Resource
private IFirRatingMaterialService iFirRatingMaterialService;
/**
*
* @param response
* @throws IOException
*/
@RequestMapping(value = "/getExcel", method = RequestMethod.GET)
public void getExcel(HttpServletResponse response) throws IOException {
//获取数据源
List list = iFirRatingMaterialService.selectFirRatingMaterialByRmId(2L);
//设置输入流,设置响应域
response.setContentType("application/ms-excel");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode(list.get(0).getRatingYear()+"年第"+list.get(0).getRatingPhase()+"期"+list.get(0).getDeptName()+"评级打分表.xlsx","utf-8");
response.setHeader("Content-disposition","attachment;filename="+fileName);
//需要合并的列
int[] mergeColumeIndex = {0, 1, 2, 3, 4, 5,6,7,8,9,10,11,12,13,14,16,17,18};
//需要从第一行开始,列头第一行
int mergeRowIndex = 1;
EasyExcel//将数据映射到DownloadDTO实体类并响应到浏览器
.write(new BufferedOutputStream(response.getOutputStream()), FirRatingcardTemplateVo.class)
//07的excel版本,节省内存
.excelType(ExcelTypeEnum.XLSX)
.head(head("评级打分",list.get(0).getDeptName(),list.get(0).getDeptType(),list.get(0).getRatingYear(),list.get(0).getRatingPhase(),list.get(0).getLocation()))
//是否自动关闭输入流
.autoCloseStream(Boolean.TRUE)
.registerWriteHandler(new CustomCellWriteHandler())
.registerWriteHandler(new ExcelFillCellMergeStrategy(mergeRowIndex, mergeColumeIndex))
// // 自定义列宽度,有数字会
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
//设置excel保护密码
// .password("123456")
.sheet().doWrite(list);
}
/**
* 自定义头
* @param headTitle 统一头
*
* @return 返回整个头list。 头部相同连续的单元格会自动合并。
*/
private static List> head(String headTitle, String deptName,String deptType,String ratingYear,String ratingPhase,String location){
List> list = new ArrayList>();
/* List head1 = new ArrayList();
head1.add(headTitle);
head1.add("金融机构名称:"+deptName);
head1.add("评分模板ID");
List head2 = new ArrayList();
head2.add(headTitle);
head2.add("");
head2.add("模板号");*/
List head1 = new ArrayList();
head1.add(headTitle);
head1.add("金融机构名称:"+deptName);
head1.add("模块");
List head2 = new ArrayList();
head2.add(headTitle);
head2.add("");
head2.add("一级指标");
List head3 = new ArrayList();
head3.add(headTitle);
head3.add("机构类型:"+deptType);
head3.add("二级指标");
List head4 = new ArrayList();
head4.add(headTitle);
head4.add("");
head4.add("对应资料调阅清单编号");
List head5 = new ArrayList();
head5.add(headTitle);
head5.add("评级年份:"+ratingYear);
head5.add("评分内容ID");
List head6 = new ArrayList();
head6.add(headTitle);
head6.add("");
head6.add("评分内容");
List head7 = new ArrayList();
head7.add(headTitle);
head7.add("评级期数:"+ratingPhase);
head7.add("评分方式");
List head8 = new ArrayList();
head8.add(headTitle);
head8.add("");
head8.add("问询");
List head9 = new ArrayList();
head9.add(headTitle);
head9.add("所在地:"+location);
head9.add("现场核查");
List head10 = new ArrayList();
head10.add(headTitle);
head10.add("");
head10.add("打分");
List head11 = new ArrayList();
head11.add(headTitle);
head11.add("");
head11.add("打分指引依据");
List head12 = new ArrayList();
head12.add(headTitle);
head12.add("");
head12.add("资料调阅依据");
list.add(head1);
list.add(head2);
list.add(head3);
list.add(head4);
list.add(head5);
list.add(head6);
list.add(head7);
list.add(head8);
list.add(head9);
list.add(head10);
list.add(head11);
list.add(head12);
return list;
}
}
```
5. 访问下载:http://localhost:8989/getExcel
##### 2、采用Vo的方式
1. 新建一个Vo类,把三个类的属性全部放进去
```java
public class EasyExcelDemoVo {
private static final long serialVersionUID = 1L;
/** 评分模板ID */
@ExcelIgnore
private Long ratingTemplateId;
/** 模板ID */
@ExcelIgnore
private Long templateId;
/** 模块 */
@ExcelProperty(value = "模块")
private String ratingModule;
/** 一级指标 */
@ExcelProperty(value = "一级指标")
private String ratingLevelFirst;
/** 二级指标 */
@ExcelProperty(value = "二级指标")
private String ratingLevelSecond;
/** 文件编号 */
@ExcelProperty(value = "对应资料调阅清单编号")
private Long ratingNum;
/** 评分内容ID */
@ExcelProperty(value = "评分内容ID")
private Integer ratingContentId;
/** 评价内容 */
@ExcelProperty(value = "评分内容")
private String ratingContent;
/** 评分方式 */
@ExcelProperty(value = "评分方式")
private String ratingType;
/*----------------------第二个类---------------------- */
/** 评分资料ID */
@ExcelIgnore
private Long rmId;
/** 任务ID */
@ExcelIgnore
private String taskId;
/** 机构名称 */
@ExcelIgnore
private String deptName;
/** 机构类型 */
@ExcelIgnore
private String deptType;
/** 评级期数 */
@ExcelIgnore
private String ratingPhase;
/** 评级年份 */
@ExcelIgnore
private String ratingYear;
/** 所在地 */
@ExcelIgnore
private String location;
/** 删除标志 */
@ExcelIgnore
private String delFlag;
@ExcelIgnore
private FirRatingCard firRatingCard;
/*----------------------第三个类---------------------- */
/** 评分卡ID */
@ExcelIgnore
private Long ratingCardId;
/** 问询ID */
@ExcelProperty("问询")
private Long askId;
/** 现场核查 */
@ExcelProperty("现场核查")
private String verificationType;
/** 打分 */
@ExcelProperty("打分")
private String rating;
/** 打分指引依据 */
@ExcelProperty("打分指引依据")
private String ratingGuideList;
/** 资料调阅依据 */
@ExcelProperty("资料调阅依据")
private String ratingDocList;
/** 搜索值 */
@ExcelIgnore
private String searchValue;
/** 创建者 */
@ExcelIgnore
private String createBy;
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ExcelIgnore
private Date createTime;
/** 更新者 */
@ExcelIgnore
private String updateBy;
/** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ExcelIgnore
private Date updateTime;
/** 备注 */
@ExcelIgnore
private String remark;
/** 开始时间 */
@JsonIgnore
@ExcelIgnore
private String beginTime;
/** 结束时间 */
@JsonIgnore
@ExcelIgnore
private String endTime;
/** 请求参数 */
@ExcelIgnore
private Map params;
}
```
2. 对应的mapper.xml配置
```java
select rm_id, task_id, template_id, dept_name, dept_type, rating_phase, rating_year, location, create_by, create_time, update_by, update_time from fir_rating_material
select DISTINCT frm.rm_id, frm.task_id, frm.dept_name, frm.dept_type, frm.rating_phase, frm.rating_year,frm.location, frm.template_id ,frt.rating_template_id, frt.rating_module, frt.rating_level_first, frt.rating_level_second,frt.rating_num, frt.rating_content_id, frt.rating_content, frt.rating_type, frt.remark,frc.verification_type,frc.rating,frc.rating_type,frc.rating_guide_list,frc.rating_doc_list,frc.ask_id
from fir_rating_material As frm
left join fir_ratingcard_template frt on frm.template_id = frt.template_id
left join fir_rating_card frc ON frc.rm_id = frm.rm_id and frc.template_id = frm.template_id and frc.rating_type_id = frt.rating_type_id
```
```java
public interface FirRatingMaterialMapper {
/**
* 第一种:采用继承的方式
* @param rmId
* @return 结果
*/
public List selectFirRatingMaterialByRmId(Long rmId);
/**
* 第二种:采用vo的方式来接收
* @param rmId
* @return
*/
public List selectDataByRmId(Long rmId);
}
```
3. 同样的,servcice我没有做任何的数据处理,你要处理也是可以的
4. 调用接口
```java
@Controller
public class ExcelController {
@Resource
private IFirRatingMaterialService iFirRatingMaterialService;
/**
*
* @param response
* @throws IOException
*/
@RequestMapping(value = "/getExcel", method = RequestMethod.GET)
public void getExcel(HttpServletResponse response) throws IOException {
//获取数据源
List list = iFirRatingMaterialService.selectDataByRmId(2L);
//设置输入流,设置响应域
response.setContentType("application/ms-excel");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode(list.get(0).getRatingYear()+"年第"+list.get(0).getRatingPhase()+"期"+list.get(0).getDeptName()+"评级打分表.xlsx","utf-8");
response.setHeader("Content-disposition","attachment;filename="+fileName);
//需要合并的列
int[] mergeColumeIndex = {0, 1, 2, 3, 4, 5,6,7,8,9,10,11,12,13,14,16,17,18};
//需要从第一行开始,列头第一行
int mergeRowIndex = 1;
EasyExcel//将数据映射到DownloadDTO实体类并响应到浏览器
.write(new BufferedOutputStream(response.getOutputStream()), EasyExcelDemoVo.class)
//07的excel版本,节省内存
.excelType(ExcelTypeEnum.XLSX)
.head(head("评级打分",list.get(0).getDeptName(),list.get(0).getDeptType(),list.get(0).getRatingYear(),list.get(0).getRatingPhase(),list.get(0).getLocation()))
//是否自动关闭输入流
.autoCloseStream(Boolean.TRUE)
.registerWriteHandler(new CustomCellWriteHandler())
.registerWriteHandler(new ExcelFillCellMergeStrategy(mergeRowIndex, mergeColumeIndex))
// // 自定义列宽度,有数字会
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
//设置excel保护密码
// .password("123456")
.sheet().doWrite(list);
}
/**
* 自定义头
* @param headTitle 统一头
*
* @return 返回整个头list。 头部相同连续的单元格会自动合并。
*/
private static List> head(String headTitle, String deptName,String deptType,String ratingYear,String ratingPhase,String location){
List> list = new ArrayList>();
/* List head1 = new ArrayList();
head1.add(headTitle);
head1.add("金融机构名称:"+deptName);
head1.add("评分模板ID");
List head2 = new ArrayList();
head2.add(headTitle);
head2.add("");
head2.add("模板号");*/
List head1 = new ArrayList();
head1.add(headTitle);
head1.add("金融机构名称:"+deptName);
head1.add("模块");
List head2 = new ArrayList();
head2.add(headTitle);
head2.add("");
head2.add("一级指标");
List head3 = new ArrayList();
head3.add(headTitle);
head3.add("机构类型:"+deptType);
head3.add("二级指标");
List head4 = new ArrayList();
head4.add(headTitle);
head4.add("");
head4.add("对应资料调阅清单编号");
List head5 = new ArrayList();
head5.add(headTitle);
head5.add("评级年份:"+ratingYear);
head5.add("评分内容ID");
List head6 = new ArrayList();
head6.add(headTitle);
head6.add("");
head6.add("评分内容");
List head7 = new ArrayList();
head7.add(headTitle);
head7.add("评级期数:"+ratingPhase);
head7.add("评分方式");
List head8 = new ArrayList();
head8.add(headTitle);
head8.add("");
head8.add("问询");
List head9 = new ArrayList();
head9.add(headTitle);
head9.add("所在地:"+location);
head9.add("现场核查");
List head10 = new ArrayList();
head10.add(headTitle);
head10.add("");
head10.add("打分");
List head11 = new ArrayList();
head11.add(headTitle);
head11.add("");
head11.add("打分指引依据");
List head12 = new ArrayList();
head12.add(headTitle);
head12.add("");
head12.add("资料调阅依据");
list.add(head1);
list.add(head2);
list.add(head3);
list.add(head4);
list.add(head5);
list.add(head6);
list.add(head7);
list.add(head8);
list.add(head9);
list.add(head10);
list.add(head11);
list.add(head12);
return list;
}
}
```
5. 访问下载:http://localhost:8989/getExcel
关于EasyExcel自定义表头可查看:https://blog.csdn.net/Y_hanxiong/article/details/108686528
源码:https://gitee.com/Xiao_bear/easyExcel-list-solve
#### 总结
1. 其实第一种方法也有第二种的部分,只是我当时候并不知道可以全部用vo类来进行接收,所以采用继承的方式,还是太年轻了,学的太浅了