ExcelFillUtils.java 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. package com.ruoyi.common.utils.poi;
  2. import org.apache.poi.ss.usermodel.*;
  3. import org.apache.poi.ss.util.CellUtil;
  4. import org.apache.poi.xssf.usermodel.XSSFWorkbook;
  5. import java.io.FileInputStream;
  6. import java.io.FileOutputStream;
  7. import java.io.IOException;
  8. import java.util.*;
  9. import java.util.regex.Pattern;
  10. public class ExcelFillUtils {
  11. // public static final String FILL_EXPRESSION_REGEX = "\\{\\.\\w+\\}";
  12. private static final String FILL_EXPRESSION_REGEX = "\\{\\.[\\p{L}\\p{M}\\S]+\\}";
  13. /**
  14. * 给定模板,指定某个页签,将数据填充到模板中的指定页签,并在模板所在目录生成新的副本文件。
  15. * @param template 模板文件地址
  16. * @param sheetName 页签名称
  17. * @param data 待填充的数据,数据格式如下
  18. * [
  19. * {"colName1":v1 ,"colName2":v2...},
  20. * {"colName1":v1 ,"colName2":v2...}
  21. * ,...
  22. * ]
  23. * @return 新生成的副本文件的地址
  24. *
  25. * */
  26. public static String fillOneSheet(String template ,String sheetName , List<Map<String,Object>> data) {
  27. return fillOneSheet(template ,FileUtils.getAvailableFullName(template) ,sheetName ,data);
  28. }
  29. /**
  30. * 给定模板,指定某个页签,将数据填充到模板中的指定页签,并将数据导入到指定文件上。
  31. * @param template 模板文件地址
  32. * @param outputFile 新生成的文件的地址
  33. * @param sheetName 页签名称
  34. * @param data 待填充的数据,数据格式如下
  35. * [
  36. * {"colName1":v1 ,"colName2":v2...},
  37. * {"colName1":v1 ,"colName2":v2...}
  38. * ,...
  39. * ]
  40. * @return 新生成的副本文件的地址
  41. *
  42. * */
  43. public static String fillOneSheet(String template , String outputFile,String sheetName , List<Map<String,Object>> data){
  44. try (Workbook workbook = new XSSFWorkbook(new FileInputStream(template))) {
  45. fill(workbook,sheetName,data);//填充数据
  46. refreshFormula(workbook);//刷新公式
  47. try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
  48. workbook.write(outputStream);
  49. }catch (Exception e){
  50. throw new RuntimeException(e);
  51. }
  52. }catch (IOException e){
  53. throw new RuntimeException(e);
  54. }
  55. return outputFile;
  56. }
  57. /**
  58. * 给定模板,将数据填充到模板中的多个页签,并在模板所在目录生成新的副本文件。
  59. * @param template 模板文件地址
  60. * @param datas 待填充的数据集,数据格式如下
  61. * {
  62. * "SheetName1":[
  63. * {"colName1":v1 ,"colName2":v2...},
  64. * {"colName1":v1 ,"colName2":v2...}
  65. * ,...
  66. * ],
  67. * "SheetName2":[
  68. * {"colName1":v1 ,"colName2":v2...}
  69. * {"colName1":v1 ,"colName2":v2...}
  70. * ,...
  71. * ],
  72. * ...
  73. * }
  74. *
  75. * */
  76. public static String fillMultipleSheet(String template ,Map<String,List<Map<String,Object>>> datas) {
  77. return fillMultipleSheet(template ,FileUtils.getAvailableFullName(template) ,datas);
  78. }
  79. /**
  80. * 给定模板,将数据填充到模板中的多个页签,并将数据导入到指定文件上。
  81. * @param template 模板文件地址
  82. * @param datas 待填充的数据集,数据格式如下
  83. * {
  84. * "SheetName1":[
  85. * {"colName1":v1 ,"colName2":v2...},
  86. * {"colName1":v1 ,"colName2":v2...}
  87. * ,...
  88. * ],
  89. * "SheetName2":[
  90. * {"colName1":v1 ,"colName2":v2...}
  91. * {"colName1":v1 ,"colName2":v2...}
  92. * ,...
  93. * ],
  94. * ...
  95. * }
  96. *
  97. * */
  98. public static String fillMultipleSheet(String template ,String outputFile ,Map<String,List<Map<String,Object>>> datas){
  99. try (Workbook workbook = new XSSFWorkbook(new FileInputStream(template))) {
  100. datas.forEach( (sheetName ,data)-> fill(workbook,sheetName,data) );//填充数据
  101. refreshFormula(workbook);//刷新公式
  102. try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
  103. workbook.write(outputStream);
  104. }catch (Exception e){
  105. throw new RuntimeException(e);
  106. }
  107. }catch (IOException e){
  108. throw new RuntimeException(e);
  109. }
  110. return outputFile;
  111. }
  112. private static Workbook fill(Workbook workbook ,String sheetName ,List<Map<String,Object>> data) {
  113. Sheet sheet = workbook.getSheet(sheetName);
  114. if (sheet == null) {
  115. throw new RuntimeException(String.format("sheet [%s] does not exist.",sheetName));
  116. }
  117. //找到所有的表达式单元格
  118. Map<String,Cell> expressionCellMap = new HashMap<>();
  119. for( int i = 0 ;i < sheet.getPhysicalNumberOfRows() ;i++){
  120. Row row = sheet.getRow(i);
  121. for( int j = 0 ;j< row.getPhysicalNumberOfCells() ;j++){
  122. Cell cell = row.getCell(j);
  123. cell.setCellType(CellType.STRING);
  124. if( !Objects.isNull(cell) && isFillExpression(cell.getStringCellValue()) ){//判断该单元格是否是填充公式
  125. expressionCellMap.put(getColNameFromEx(cell.getStringCellValue()),cell);
  126. }
  127. }
  128. }
  129. //填充数据
  130. for(int i = 0 ;i< data.size() ;i++){
  131. Map<String,Object> dataRow = data.get(i);
  132. for (Map.Entry<String,Object> entry : dataRow.entrySet()){
  133. String colName = entry.getKey();
  134. Object value = entry.getValue();
  135. if(expressionCellMap.containsKey(colName)){
  136. Cell cell = expressionCellMap.get(colName);//公式所在的单元格
  137. int rowID = cell.getRowIndex() + i;
  138. int colId = cell.getColumnIndex();
  139. Row fillRow = sheet.getRow(rowID);
  140. fillRow = Objects.isNull(fillRow) ? sheet.createRow(rowID) : fillRow;
  141. Cell fillCell = fillRow.getCell(colId);
  142. //创建的新单元格需要复制公式单元格的格式
  143. fillCell = Objects.isNull(fillCell) ? CellUtil.createCell(fillRow,colId,"", cell.getCellStyle()) : fillCell;
  144. if ( value instanceof String){
  145. fillCell.setCellValue( String.valueOf(value) );
  146. }else if( value instanceof Number ){
  147. fillCell.setCellValue( ((Number)value).doubleValue() );
  148. }else{
  149. throw new RuntimeException(String.format("Unsupported data type [%s].",value.getClass().toString()));
  150. }
  151. }
  152. }
  153. }
  154. return workbook;
  155. }
  156. private static void refreshFormula(Workbook workbook){
  157. FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
  158. evaluator.evaluateAll();
  159. }
  160. private static boolean isFillExpression(String ex){
  161. if (ex.isEmpty()) return false;
  162. return Pattern.matches(FILL_EXPRESSION_REGEX ,ex);
  163. }
  164. private static String getColNameFromEx(String ex){
  165. if (!isFillExpression(ex)) throw new RuntimeException("Illegal expression " + ex );
  166. return ex.substring(2,ex.length() - 1);
  167. }
  168. }