• spring boot数据导出excel


    Controller:

    1. @PostMapping(value = "/export",
    2. produces = {MediaType.APPLICATION_OCTET_STREAM_VALUE, MediaType.APPLICATION_JSON_VALUE})
    3. public void RApiExport(HttpServletResponse response, @RequestBody SearchListReqDto reqDto) throws Exception {
    4. rapiSearchConfigService.exportData(response, reqDto);
    5. }

    service

    1. public void exportData(HttpServletResponse response, SearchListReqDto reqDto) throws IOException, IllegalAccessException {
    2. //excel对应多sheet实体类
    3. ExportRApiDataTemplate exportRApiDataTemplate = new ExportRApiDataTemplate();
    4. String statisticalStart = reqDto.getStatisticalStart();
    5. String statisticalEnd = reqDto.getStatisticalEnd();
    6. List keywords = getKeywords(reqDto);
    7. List searchUserInfoList = new ArrayList<>();
    8. List searchUserList = rapiSearchUserDao.selectByCreateTime(statisticalStart, statisticalEnd, null, null, keywords);
    9. searchUserList.forEach(r -> {
    10. SearchUserInfo searchUserInfo = BeanConvertUtils.convertTo(r, SearchUserInfo::new);
    11. searchUserInfo.setCreateTime(DateUtil.toString(r.getCreateTime(), DateUtil.yyyy_MM_ddHHmmss_format));
    12. searchUserInfo.setUserHomePage(getUserShareUrl(r.getSearchUserInfo()));
    13. searchUserInfoList.add(searchUserInfo);
    14. });
    15. exportRApiDataTemplate.setSearchUserInfoList(searchUserInfoList);
    16. String nowDate = DateUtil.toString(new Date(), DateUtil.yyMMddHHmmss_format);
    17. //调用工具类导出
    18. EasyPoiUtils.exportMultiSheetWorkbook(nowDate + "RApi数据统计", exportRApiDataTemplate, response);
    19. }

    excel导出模版对应实体类(注:子类不序列化会抛错)

    1. @Data
    2. @AllArgsConstructor
    3. @NoArgsConstructor
    4. @Accessors(chain = true)
    5. public class ExportRApiDataTemplate {
    6. @SheetName(name = "人员信息")
    7. private List searchUserInfoList;
    8. /* @SheetName(name = "帖子信息")
    9. private List searchPostsInfoList;
    10. @SheetName(name = "标签信息")
    11. private List searchHashTagInfoList;
    12. */
    13. }
    1. @JsonIgnoreProperties(ignoreUnknown = true)
    2. @Data
    3. public class SearchUserInfo implements Serializable {
    4. @Excel(name = "用户id")
    5. private String uid;
    6. @Excel(name = "用户名称",width = 30)
    7. private String name;
    8. @Excel(name = "已关注数量")
    9. private String followingCount;
    10. @Excel(name = "点赞数")
    11. private String totalFavorited;
    12. @Excel(name = "粉丝数量")
    13. private String followerCount;
    14. @Excel(name = "insId")
    15. private String insId;
    16. @Excel(name = "邮箱")
    17. private String email;
    18. @Excel(name = "用户主页链接")
    19. private String userHomePage;
    20. @Excel(name = "统计时间")
    21. private String createTime;
    22. @Excel(name = "数据抓取关键字",width = 50)
    23. private String dataSource;
    24. }

    EasyPoiUtils 工具类

    1. package com.seezoon.admin.modules.sys.utils;
    2. import cn.afterturn.easypoi.excel.ExcelExportUtil;
    3. import cn.afterturn.easypoi.excel.ExcelImportUtil;
    4. import cn.afterturn.easypoi.excel.entity.ExportParams;
    5. import cn.afterturn.easypoi.excel.entity.ImportParams;
    6. import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
    7. import cn.afterturn.easypoi.exception.excel.ExcelExportException;
    8. import cn.afterturn.easypoi.exception.excel.ExcelImportException;
    9. import com.google.common.collect.Lists;
    10. import com.google.common.collect.Maps;
    11. import com.seezoon.admin.modules.sys.dto.excel.kol.SheetName;
    12. import org.apache.commons.lang3.StringUtils;
    13. import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
    14. import org.apache.poi.hssf.usermodel.HSSFRichTextString;
    15. import org.apache.poi.hssf.usermodel.HSSFWorkbook;
    16. import org.apache.poi.ss.usermodel.*;
    17. import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
    18. import org.apache.poi.xssf.usermodel.XSSFRichTextString;
    19. import org.apache.poi.xssf.usermodel.XSSFWorkbook;
    20. import org.slf4j.Logger;
    21. import org.slf4j.LoggerFactory;
    22. import org.springframework.web.multipart.MultipartFile;
    23. import javax.servlet.http.HttpServletResponse;
    24. import java.io.BufferedOutputStream;
    25. import java.io.File;
    26. import java.io.IOException;
    27. import java.io.OutputStream;
    28. import java.lang.reflect.Field;
    29. import java.lang.reflect.ParameterizedType;
    30. import java.lang.reflect.Type;
    31. import java.net.URLEncoder;
    32. import java.util.*;
    33. import java.util.zip.ZipEntry;
    34. import java.util.zip.ZipOutputStream;
    35. /**
    36. * @Classname EasyPoiUtils
    37. * @Description
    38. * @Date 2023/8/31 11:59
    39. * @Created by jyl
    40. */
    41. public class EasyPoiUtils {
    42. static final Logger logger = LoggerFactory.getLogger(EasyPoiUtils.class);
    43. private static final String XLS = "xls";
    44. private static final String XLSX = "xlsx";
    45. private static final String SPLIT = ".";
    46. public static void newExportExcel(List> list, String fileName, HttpServletResponse response){
    47. newExport(list, fileName, response);
    48. }
    49. private static void newDownLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) {
    50. try {
    51. response.setCharacterEncoding("UTF-8");
    52. response.setHeader("content-Type", "application/vnd.ms-excel");
    53. response.setHeader("Content-Disposition",
    54. "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
    55. workbook.write(response.getOutputStream());
    56. } catch (IOException e) {
    57. throw new RuntimeException(e.getMessage());
    58. }
    59. }
    60. private static void newExport(List> list, String fileName, HttpServletResponse response) {
    61. Workbook workbook = ExcelExportUtil.exportExcel(list, ExcelType.HSSF);
    62. if (workbook != null);
    63. newDownLoadExcel(fileName, response, workbook);
    64. }
    65. public static List newImportExcelMore(MultipartFile file, Class pojoClass, ImportParams params){
    66. if (file == null){
    67. return null;
    68. }
    69. List list = null;
    70. try {
    71. list = ExcelImportUtil.importExcel(file.getInputStream(), pojoClass, params);
    72. }catch (NoSuchElementException e){
    73. throw new RuntimeException("excel文件不能为空");
    74. } catch (Exception e) {
    75. throw new RuntimeException(e.getMessage());
    76. }
    77. return list;
    78. }
    79. public static Workbook newGetWorkbook(MultipartFile file) {
    80. Workbook workbook=null;
    81. try {
    82. // 获取Excel后缀名
    83. String fileName = file.getOriginalFilename();
    84. if (StringUtils.isEmpty(fileName) || fileName.lastIndexOf(SPLIT) < 0) {
    85. logger.warn("解析Excel失败,因为获取到的Excel文件名非法!");
    86. return null;
    87. }
    88. String fileType = fileName.substring(fileName.lastIndexOf(SPLIT) + 1, fileName.length());
    89. // 获取Excel工作簿
    90. if (fileType.equalsIgnoreCase(XLS)) {
    91. workbook = new HSSFWorkbook(file.getInputStream());
    92. } else if (fileType.equalsIgnoreCase(XLSX)) {
    93. workbook = new XSSFWorkbook(file.getInputStream());
    94. }
    95. } catch (IOException e) {
    96. e.printStackTrace();
    97. }
    98. return workbook;
    99. }
    100. public static void exportExcel(List list, String title, String sheetName, Class pojoClass, String fileName, boolean isCreateHeader, HttpServletResponse response) {
    101. ExportParams exportParams = new ExportParams(title, sheetName);
    102. exportParams.setCreateHeadRows(isCreateHeader);
    103. defaultExport(list, pojoClass, fileName, response, exportParams);
    104. }
    105. /**
    106. * 导出excel
    107. *
    108. * @param list 数据list
    109. * @param title 标题
    110. * @param sheetName sheet名称
    111. * @param pojoClass 实体class
    112. * @param fileName 文件名
    113. * @param response 响应
    114. */
    115. public static void exportExcel(List list, String title, String sheetName, Class pojoClass, String fileName, HttpServletResponse response) {
    116. response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=GBK");
    117. try {
    118. response.setHeader("content-disposition",
    119. "attachment;filename=" + java.net.URLEncoder.encode(fileName, "GBK")
    120. + ";filename*=GBK''" + java.net.URLEncoder.encode(fileName, "GBK"));
    121. } catch (Exception e) {
    122. // ...
    123. }
    124. defaultExport(list, pojoClass, fileName, response, new ExportParams(title, sheetName));
    125. }
    126. /**
    127. * 导出excel
    128. *
    129. * @param list 多个Map key title 对应表格Title key entity 对应表格对应实体 key data
    130. * @param fileName 标题
    131. * @param response 响应
    132. */
    133. public static void exportExcel(List> list, String fileName, HttpServletResponse response) {
    134. defaultExport(list, fileName, response);
    135. }
    136. /**
    137. * 导出多个excel
    138. *
    139. * @param workbooks 多个excel文件 通过ExcelExportUtil.exportExcel往workbooks内放入excel
    140. * @param fileNames 文件名 每个excel文件的名称顺序必须一致且名称请务必保证不重复
    141. * @param fileName 压缩包文件名
    142. * @param response 标题
    143. */
    144. public static void exportExcels(List workbooks, List fileNames, String fileName, HttpServletResponse response) {
    145. try {
    146. response.setHeader("Content-Disposition",
    147. "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".zip");
    148. OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
    149. ZipOutputStream zipOut = new ZipOutputStream(toClient);
    150. for (int i = 0; i < workbooks.size(); i++) {
    151. ZipEntry entry = new ZipEntry(fileNames.get(i) + ".xls");
    152. zipOut.putNextEntry(entry);
    153. workbooks.get(i).write(zipOut);
    154. }
    155. zipOut.flush();
    156. zipOut.close();
    157. } catch (IOException e) {
    158. throw new ExcelExportException(e.getMessage());
    159. }
    160. }
    161. /**
    162. * 导出excel
    163. *
    164. * @param list 数据list
    165. * @param pojoClass 实体class
    166. * @param fileName 文件名
    167. * @param response 响应
    168. */
    169. private static void defaultExport(List list, Class pojoClass, String fileName, HttpServletResponse response, ExportParams exportParams) {
    170. Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, list);
    171. downLoadExcel(fileName, response, workbook);
    172. }
    173. private static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) {
    174. try {
    175. response.setCharacterEncoding("UTF-8");
    176. response.setHeader("content-Type", "application/vnd.ms-excel");
    177. response.setHeader("Content-Disposition",
    178. "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
    179. workbook.write(response.getOutputStream());
    180. workbook.close();
    181. } catch (IOException e) {
    182. throw new ExcelImportException(e.getMessage());
    183. }
    184. }
    185. private static void defaultExport(List> list, String fileName, HttpServletResponse response) {
    186. Workbook workbook = ExcelExportUtil.exportExcel(list, ExcelType.HSSF);
    187. downLoadExcel(fileName, response, workbook);
    188. }
    189. public static List importExcel(String filePath, Integer titleRows, Integer headerRows, Class pojoClass) {
    190. if (StringUtils.isBlank(filePath)) {
    191. return null;
    192. }
    193. ImportParams params = new ImportParams();
    194. params.setTitleRows(titleRows);
    195. params.setHeadRows(headerRows);
    196. List list = null;
    197. try {
    198. list = ExcelImportUtil.importExcel(new File(filePath), pojoClass, params);
    199. } catch (NoSuchElementException e) {
    200. throw new ExcelImportException("模板不能为空");
    201. } catch (Exception e) {
    202. e.printStackTrace();
    203. throw new ExcelImportException(e.getMessage());
    204. }
    205. return list;
    206. }
    207. public static List importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Class pojoClass) {
    208. if (file == null) {
    209. return null;
    210. }
    211. ImportParams params = new ImportParams();
    212. params.setTitleRows(titleRows);//标题占几行,从哪行开始读取
    213. params.setHeadRows(headerRows);//header占几行
    214. params.setSheetNum(1);
    215. List list = null;
    216. try {
    217. list = ExcelImportUtil.importExcel(file.getInputStream(), pojoClass, params);
    218. } catch (NoSuchElementException e) {
    219. throw new ExcelImportException("excel文件不能为空");
    220. } catch (Exception e) {
    221. throw new ExcelImportException(e.getMessage());
    222. }
    223. return list;
    224. }
    225. /**
    226. * 多Sheet导出,不需要批注
    227. * @param fileName 文件名
    228. * @param exportDataSet 导出的类对象
    229. * @param response
    230. * @throws IllegalAccessException
    231. * @throws IOException
    232. */
    233. public static void exportMultiSheetWorkbook(String fileName,T exportDataSet, HttpServletResponse response) throws IOException, IllegalAccessException {
    234. exportMultiSheetWorkbook(fileName,exportDataSet,response,null);
    235. }
    236. /**
    237. * 多Sheet导出,需要批注
    238. * @param fileName 文件名
    239. * @param exportDataSet 导出的类对象
    240. * @param response
    241. * @throws IllegalAccessException
    242. * @throws IOException
    243. */
    244. public static void exportMultiSheetWorkbook(String fileName,T exportDataSet, HttpServletResponse response,String remake) throws IllegalAccessException, IOException {
    245. // 多个sheet配置参数
    246. final List> sheetsList = Lists.newArrayList();
    247. Class aClass = exportDataSet.getClass();
    248. Field[] declaredFields = aClass.getDeclaredFields();
    249. for (Field field : declaredFields) {
    250. field.setAccessible(true);
    251. SheetName annotation = field.getAnnotation(SheetName.class);
    252. final String sheetName = annotation.name();
    253. Map exportMap = Maps.newHashMap();
    254. final ExportParams exportParams = new ExportParams(null, sheetName);
    255. // 以下3个参数为API中写死的参数名 分别是sheet配置/导出类(注解定义)/数据集
    256. exportMap.put("title", exportParams);
    257. // 获取list中?的泛型
    258. if (field.getType().isAssignableFrom(List.class)){
    259. Type fc = field.getGenericType(); //如果是List类型,得到其Generic的类型
    260. if(fc instanceof ParameterizedType){
    261. ParameterizedType pt = (ParameterizedType) fc;
    262. //得到泛型里的class类型对象。
    263. Class genericClazz = (Class)pt.getActualTypeArguments()[0];
    264. exportMap.put("entity", genericClazz);
    265. }
    266. exportMap.put("data", field.get(exportDataSet));
    267. }else {
    268. exportMap.put("entity", field.getType());
    269. exportMap.put("data", new ArrayList<>(Collections.singletonList(field.get(exportDataSet))));
    270. }
    271. // 加入多sheet配置列表
    272. sheetsList.add(exportMap);
    273. }
    274. // 导出文件
    275. // 核心方法:导出含多个sheet的excel文件 【注意,该方法第二个参数必须与上述的ExportParams对象指定的导出类型一致,默认ExcelType.HSSF格式,否则执行此方法时会报错!!!】
    276. final Workbook workbook = ExcelExportUtil.exportExcel(sheetsList, ExcelType.HSSF);
    277. // 添加批注格式 :0#姓名不能为空__1#学生性别 1:男 2:女__2#出生日期:yyyy-MM-dd__3#图片不能为空
    278. if(StringUtils.isNotBlank(remake)){
    279. buildComment(workbook,0,remake);
    280. }
    281. response.setCharacterEncoding("UTF-8");
    282. response.setHeader("content-Type", "application/vnd.ms-excel");
    283. response.setHeader("Content-Disposition",
    284. "attachment;filename=" + URLEncoder.encode(fileName + ".xls", "UTF-8"));
    285. workbook.write(response.getOutputStream());
    286. // 写完数据关闭流
    287. workbook.close();
    288. }
    289. public static void buildComment(Workbook workbook, int titleRowsIndex, String commentStr) {
    290. Sheet sheet = workbook.getSheetAt(0);
    291. //创建一个图画工具
    292. Drawing drawing = sheet.createDrawingPatriarch();
    293. Row row = sheet.getRow(titleRowsIndex);
    294. if (StringUtils.isNotBlank(commentStr)) {
    295. //解析批注,并传换成map
    296. Map commentMap = getCommentMap(commentStr);
    297. for (Map.Entry entry : commentMap.entrySet()) {
    298. Cell cell = row.getCell(entry.getKey());
    299. //创建批注
    300. Comment comment = drawing.createCellComment(newClientAnchor(workbook));
    301. //输入批注信息
    302. comment.setString(newRichTextString(workbook, entry.getValue()));
    303. //将批注添加到单元格对象中
    304. cell.setCellComment(comment);
    305. if (entry.getValue().contains("必填项")){
    306. //设置单元格背景颜色
    307. CellStyle cellStyle = workbook.createCellStyle();
    308. //通过workbook获得文字处理类
    309. Font font = workbook.createFont();
    310. font.setColor(Font.COLOR_RED);
    311. //水平居中
    312. cellStyle.setAlignment(HorizontalAlignment.CENTER);
    313. //垂直居中
    314. cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
    315. cellStyle.setFont(font);
    316. cell.setCellStyle(cellStyle);
    317. }
    318. }
    319. }
    320. }
    321. /**
    322. * 批注信息,默认解析:批注#列索引,比如用户名不允许重复#0。可覆盖此方法,解析自定义的批注格式
    323. *
    324. * @param commentStr 当前行的所有批注信息
    325. * @return key:列索引,value:对应列的所有批注信息
    326. */
    327. protected static Map getCommentMap(String commentStr) {
    328. //每行的所有单元格的批注都在commentStr里,并用”__”分隔
    329. String[] split = commentStr.split("__");
    330. Map commentMap = new HashMap<>();
    331. for (String msg : split) {
    332. String[] cellMsg = msg.split("#");
    333. //如果当前列没有批注,会将该列的索引作为key存到map里;已有批注,以“,“分隔继续拼接
    334. int cellIndex = Integer.parseInt(cellMsg[0]);
    335. if (commentMap.get(cellIndex) == null) {
    336. commentMap.put(cellIndex, cellMsg[1]);
    337. } else {
    338. commentMap.replace(cellIndex, commentMap.get(cellIndex) + "," + cellMsg[1]);
    339. }
    340. }
    341. return commentMap;
    342. }
    343. private static ClientAnchor newClientAnchor(Workbook workbook) {
    344. //xls
    345. if (workbook instanceof HSSFWorkbook) {
    346. return new HSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6);
    347. }
    348. //xlsx
    349. else {
    350. return new XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6);
    351. }
    352. }
    353. private static RichTextString newRichTextString(Workbook workbook, String msg) {
    354. //xls
    355. if (workbook instanceof HSSFWorkbook) {
    356. return new HSSFRichTextString(msg);
    357. }
    358. //xlsx
    359. else {
    360. return new XSSFRichTextString(msg);
    361. }
    362. }
    363. }

    若需要合并单元格可使用@ExcelCollection注解 

    注:标记该注解的类型必须是list,且list类型里的属性须有@Excel注解标记

  • 相关阅读:
    Java时间复杂度和空间复杂度(详解)
    把Mybatis Generator生成的代码加上想要的注释
    C语言练习:输入日期输出该日期为当年第几天
    Android系统的特性
    C++是不是最容易产生猪队友的编程语言之一?
    淘宝/天猫、1688、京东API接口—item_search - 按关键字搜索淘宝商品
    Java-1116
    sparksql 中的concat_ws 和sort_array 和collect_list的使用方法
    jQuery的选择器与自带函数详解
    Android T(13)-- Looper 的实现(二)
  • 原文地址:https://blog.csdn.net/qq_41808386/article/details/133694487