我之前发发布了《解决EasyExcel不支持解析List以及实体类对象问题》后,很多人不知道该怎么继承,怎么用vo来进行接收,现在完整版+代码来了。
介绍
解决EasyExcel不支持解析List以及实体类对象问题
需求说明
连表查询一对多的关系,fir_rating_material表与fir_ratingcard_template和fir_rating_card是一对多的关系
解决方法
方法一:采用Mybatis的继承关系
一对多的关系,就相当于一个list
里面又包含另一个list集合,这时候我们可以将list
集合进行解析,也就是说,easyExcel是不支持数据集合里面嵌套对象、list
、map
等集合数据的
-
新建一个实体类来接收数据,当然,你用原来对象来继承也是可以的,这里我是把两个类的属性放在一起了,只继承一个类,主要是看起来方便一点,toString和set、get方法省略
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;
-
对应的mapper.xml配置
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.xiaobear.excel.mapper.FirRatingMaterialMapper"> <resultMap type="FirRatingMaterial" id="FirRatingMaterialResult"> <result property="rmId" column="rm_id" /> <result property="taskId" column="task_id" /> <result property="templateId" column="template_id" /> <result property="deptName" column="dept_name" /> <result property="deptType" column="dept_type" /> <result property="ratingPhase" column="rating_phase" /> <result property="ratingYear" column="rating_year" /> <result property="location" column="location" /> <result property="createBy" column="create_by" /> <result property="createTime" column="create_time" /> <result property="updateBy" column="update_by" /> <result property="updateTime" column="update_time" /> </resultMap> <!--继承解决问题--> <resultMap type="FirRatingcardTemplateVo" id="FirRatingMaterialResultVo" extends="FirRatingcardTemplateResultW1"> <result property="rmId" column="rm_id" /> <result property="taskId" column="task_id" /> <result property="templateId" column="template_id" /> <result property="deptName" column="dept_name" /> <result property="deptType" column="dept_type" /> <result property="ratingPhase" column="rating_phase" /> <result property="ratingYear" column="rating_year" /> <result property="location" column="location" /> <result property="createBy" column="create_by" /> <result property="createTime" column="create_time" /> <result property="updateBy" column="update_by" /> <result property="updateTime" column="update_time" /> </resultMap> <resultMap type="FirRatingcardTemplateVo" id="FirRatingcardTemplateResultW1" extends="FirRatingCardResult"> <result property="ratingTemplateId" column="rating_template_id" /> <result property="templateId" column="template_id" /> <result property="ratingModule" column="rating_module" /> <result property="ratingLevelFirst" column="rating_level_first" /> <result property="ratingLevelSecond" column="rating_level_second" /> <result property="ratingNum" column="rating_num" /> <result property="ratingContentId" column="rating_content_id" /> <result property="ratingContent" column="rating_content" /> <result property="ratingType" column="rating_type" /> <result property="remark" column="remark" /> <result property="delFlag" column="del_flag" /> <result property="createBy" column="create_by" /> <result property="createTime" column="create_time" /> <result property="updateBy" column="update_by" /> <result property="updateTime" column="update_time" /> </resultMap> <resultMap type="FirRatingCard" id="FirRatingCardResult"> <result property="ratingCardId" column="rating_card_id" /> <result property="templateId" column="template_id" /> <result property="rmId" column="rm_id" /> <result property="ratingContent" column="rating_content" /> <result property="verificationType" column="verification_type" /> <result property="rating" column="rating" /> <result property="ratingType" column="rating_type" /> <result property="ratingGuideList" column="rating_guide_list" /> <result property="ratingDocList" column="rating_doc_list" /> <result property="remark" column="remark" /> <result property="askId" column="ask_id" /> <result property="createBy" column="create_by" /> <result property="createTime" column="create_time" /> <result property="updateBy" column="update_by" /> <result property="updateTime" column="update_time" /> </resultMap> <sql id="selectFirRatingMaterialVo"> 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 </sql> <sql id="selectFirRatingMaterialVoWithAll"> 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 </sql> <!--第一种:采用继承的方式--> <select id="selectFirRatingMaterialByRmId" parameterType="FirRatingcardTemplateVo" resultMap="FirRatingMaterialResultVo"> <include refid="selectFirRatingMaterialVoWithAll"/> where frm.rm_id = #{rmId} </select> </mapper>
-
这里的service,我是没有做任何数据处理的,代码我就不放了,具体看源码
-
调用接口
@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<FirRatingcardTemplateVo> 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<List<String>> head(String headTitle, String deptName,String deptType,String ratingYear,String ratingPhase,String location){ List<List<String>> list = new ArrayList<List<String>>(); /* List<String> head1 = new ArrayList<String>(); head1.add(headTitle); head1.add("金融机构名称:"+deptName); head1.add("评分模板ID"); List<String> head2 = new ArrayList<String>(); head2.add(headTitle); head2.add(""); head2.add("模板号");*/ List<String> head1 = new ArrayList<String>(); head1.add(headTitle); head1.add("金融机构名称:"+deptName); head1.add("模块"); List<String> head2 = new ArrayList<String>(); head2.add(headTitle); head2.add(""); head2.add("一级指标"); List<String> head3 = new ArrayList<String>(); head3.add(headTitle); head3.add("机构类型:"+deptType); head3.add("二级指标"); List<String> head4 = new ArrayList<String>(); head4.add(headTitle); head4.add(""); head4.add("对应资料调阅清单编号"); List<String> head5 = new ArrayList<String>(); head5.add(headTitle); head5.add("评级年份:"+ratingYear); head5.add("评分内容ID"); List<String> head6 = new ArrayList<String>(); head6.add(headTitle); head6.add(""); head6.add("评分内容"); List<String> head7 = new ArrayList<String>(); head7.add(headTitle); head7.add("评级期数:"+ratingPhase); head7.add("评分方式"); List<String> head8 = new ArrayList<String>(); head8.add(headTitle); head8.add(""); head8.add("问询"); List<String> head9 = new ArrayList<String>(); head9.add(headTitle); head9.add("所在地:"+location); head9.add("现场核查"); List<String> head10 = new ArrayList<String>(); head10.add(headTitle); head10.add(""); head10.add("打分"); List<String> head11 = new ArrayList<String>(); head11.add(headTitle); head11.add(""); head11.add("打分指引依据"); List<String> head12 = new ArrayList<String>(); 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; } }
-
访问下载:http://localhost:8989/getExcel
2、采用Vo的方式
-
新建一个Vo类,把三个类的属性全部放进去
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<String, Object> params; }
-
对应的mapper.xml配置
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.xiaobear.excel.mapper.FirRatingMaterialMapper"> <resultMap type="FirRatingMaterial" id="FirRatingMaterialResult"> <result property="rmId" column="rm_id" /> <result property="taskId" column="task_id" /> <result property="templateId" column="template_id" /> <result property="deptName" column="dept_name" /> <result property="deptType" column="dept_type" /> <result property="ratingPhase" column="rating_phase" /> <result property="ratingYear" column="rating_year" /> <result property="location" column="location" /> <result property="createBy" column="create_by" /> <result property="createTime" column="create_time" /> <result property="updateBy" column="update_by" /> <result property="updateTime" column="update_time" /> </resultMap> <!--新建vo解决 三个类的对应字段属性--> <resultMap type="EasyExcelDemoVo" id="EasyExcelDemoResultVo"> <result property="rmId" column="rm_id" /> <result property="taskId" column="task_id" /> <result property="templateId" column="template_id" /> <result property="deptName" column="dept_name" /> <result property="deptType" column="dept_type" /> <result property="ratingPhase" column="rating_phase" /> <result property="ratingYear" column="rating_year" /> <result property="location" column="location" /> <result property="ratingTemplateId" column="rating_template_id" /> <result property="templateId" column="template_id" /> <result property="ratingModule" column="rating_module" /> <result property="ratingLevelFirst" column="rating_level_first" /> <result property="ratingLevelSecond" column="rating_level_second" /> <result property="ratingNum" column="rating_num" /> <result property="ratingContentId" column="rating_content_id" /> <result property="ratingContent" column="rating_content" /> <result property="ratingType" column="rating_type" /> <result property="remark" column="remark" /> <result property="ratingCardId" column="rating_card_id" /> <result property="ratingContent" column="rating_content" /> <result property="verificationType" column="verification_type" /> <result property="rating" column="rating" /> <result property="ratingType" column="rating_type" /> <result property="ratingGuideList" column="rating_guide_list" /> <result property="ratingDocList" column="rating_doc_list" /> <result property="remark" column="remark" /> <result property="askId" column="ask_id" /> <result property="createBy" column="create_by" /> <result property="createTime" column="create_time" /> <result property="updateBy" column="update_by" /> <result property="updateTime" column="update_time" /> </resultMap> <sql id="selectFirRatingMaterialVo"> 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 </sql> <!--显示所有评价打分页面显示接口--> <sql id="selectFirRatingMaterialVoWithAll"> 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 </sql> <!--第二种:采用vo方式--> <select id="selectDataByRmId" parameterType="EasyExcelDemoVo" resultMap="EasyExcelDemoResultVo"> <include refid="selectFirRatingMaterialVoWithAll"/> where frm.rm_id = #{rmId} </select> </mapper>
public interface FirRatingMaterialMapper { /** * 第一种:采用继承的方式 * @param rmId * @return 结果 */ public List<FirRatingcardTemplateVo> selectFirRatingMaterialByRmId(Long rmId); /** * 第二种:采用vo的方式来接收 * @param rmId * @return */ public List<EasyExcelDemoVo> selectDataByRmId(Long rmId); }
-
同样的,servcice我没有做任何的数据处理,你要处理也是可以的
-
调用接口
@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<EasyExcelDemoVo> 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<List<String>> head(String headTitle, String deptName,String deptType,String ratingYear,String ratingPhase,String location){ List<List<String>> list = new ArrayList<List<String>>(); /* List<String> head1 = new ArrayList<String>(); head1.add(headTitle); head1.add("金融机构名称:"+deptName); head1.add("评分模板ID"); List<String> head2 = new ArrayList<String>(); head2.add(headTitle); head2.add(""); head2.add("模板号");*/ List<String> head1 = new ArrayList<String>(); head1.add(headTitle); head1.add("金融机构名称:"+deptName); head1.add("模块"); List<String> head2 = new ArrayList<String>(); head2.add(headTitle); head2.add(""); head2.add("一级指标"); List<String> head3 = new ArrayList<String>(); head3.add(headTitle); head3.add("机构类型:"+deptType); head3.add("二级指标"); List<String> head4 = new ArrayList<String>(); head4.add(headTitle); head4.add(""); head4.add("对应资料调阅清单编号"); List<String> head5 = new ArrayList<String>(); head5.add(headTitle); head5.add("评级年份:"+ratingYear); head5.add("评分内容ID"); List<String> head6 = new ArrayList<String>(); head6.add(headTitle); head6.add(""); head6.add("评分内容"); List<String> head7 = new ArrayList<String>(); head7.add(headTitle); head7.add("评级期数:"+ratingPhase); head7.add("评分方式"); List<String> head8 = new ArrayList<String>(); head8.add(headTitle); head8.add(""); head8.add("问询"); List<String> head9 = new ArrayList<String>(); head9.add(headTitle); head9.add("所在地:"+location); head9.add("现场核查"); List<String> head10 = new ArrayList<String>(); head10.add(headTitle); head10.add(""); head10.add("打分"); List<String> head11 = new ArrayList<String>(); head11.add(headTitle); head11.add(""); head11.add("打分指引依据"); List<String> head12 = new ArrayList<String>(); 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; } }
-
访问下载:http://localhost:8989/getExcel
关于EasyExcel自定义表头可查看:easyExcel导出自定义表头以及自定义合并单元格
源码:https://gitee.com/Xiao_bear/easyExcel-list-solve
总结
- 其实第一种方法也有第二种的部分,只是我当时候并不知道可以全部用vo类来进行接收,所以采用继承的方式,还是太年轻了,学的太浅了