分享

java

 hongjing_z 2019-07-31
                                                     先开始接到这个需求的时候,第一想法是这得要多复杂的算才能实现,因为不是每一列的合并的行数一样,比如第一列1-4行的内容都相同,那么需要合并,而第二列1-2相同,所以1和2合并,3-4相同,3和4合并;然后一层一层的,就和树一样,逐层向下;
      毋庸置疑,通过算法肯定能实现,但是我觉得太绕了,一下子也想不出来什么好的算法;后来我就想到约瑟夫环的问题,一个典型的java面向对象的例子;后来就通过建一个单元格对象,属性有单元格内容,与单元格同一列的上一行内容,起始行,起始列,就这四个属性;详细解释我放在代码中:

model对象:

  1. /**
  2. * Created by zelei.fan on 2017/3/20.
  3. */
  4. public class PoiModel {
  5. private String content;
  6. private String oldContent;
  7. private int rowIndex;
  8. private int cellIndex;
  9. public String getOldContent() {
  10. return oldContent;
  11. }
  12. public void setOldContent(String oldContent) {
  13. this.oldContent = oldContent;
  14. }
  15. public String getContent() {
  16. return content;
  17. }
  18. public void setContent(String content) {
  19. this.content = content;
  20. }
  21. public int getRowIndex() {
  22. return rowIndex;
  23. }
  24. public void setRowIndex(int rowIndex) {
  25. this.rowIndex = rowIndex;
  26. }
  27. public int getCellIndex() {
  28. return cellIndex;
  29. }
  30. public void setCellIndex(int cellIndex) {
  31. this.cellIndex = cellIndex;
  32. }
  33. }
Test:
  1. import cn.yoho.perf.common.model.PoiModel;
  2. import com.beust.jcommander.internal.Maps;
  3. import com.google.common.collect.Lists;
  4. import org.apache.poi.ss.usermodel.Cell;
  5. import org.apache.poi.ss.usermodel.Row;
  6. import org.apache.poi.ss.usermodel.Sheet;
  7. import org.apache.poi.ss.usermodel.Workbook;
  8. import org.apache.poi.ss.util.CellRangeAddress;
  9. import org.apache.poi.xssf.usermodel.XSSFWorkbook;
  10. import java.io.File;
  11. import java.io.FileOutputStream;
  12. import java.io.IOException;
  13. import java.util.*;
  14. /**
  15. * Created by zelei.fan on 2017/3/14.
  16. */
  17. public class Test{
  18. /**
  19. * @param title 标题集合 tilte的长度应该与list中的model的属性个数一致
  20. * @param maps 内容集合
  21. * @param mergeIndex 合并单元格的列
  22. */
  23. public static String createExcel(String[] title, Map<String/*sheet名*/, List<Map<String/*对应title的值*/, String>>> maps, int[] mergeIndex){
  24. if (title.length==0){
  25. return null;
  26. }
  27. /*初始化excel模板*/
  28. Workbook workbook = new XSSFWorkbook();
  29. Sheet sheet = null;
  30. int n = 0;
  31. /*循环sheet页*/
  32. for(Map.Entry<String, List<Map<String/*对应title的值*/, String>>> entry : maps.entrySet()){
  33. /*实例化sheet对象并且设置sheet名称,book对象*/
  34. try {
  35. sheet = workbook.createSheet();
  36. workbook.setSheetName(n, entry.getKey());
  37. workbook.setSelectedTab(0);
  38. }catch (Exception e){
  39. e.printStackTrace();
  40. }
  41. /*初始化head,填值标题行(第一行)*/
  42. Row row0 = sheet.createRow(0);
  43. for(int i = 0; i<title.length; i++){
  44. /*创建单元格,指定类型*/
  45. Cell cell_1 = row0.createCell(i, Cell.CELL_TYPE_STRING);
  46. cell_1.setCellValue(title[i]);
  47. }
  48. /*得到当前sheet下的数据集合*/
  49. List<Map<String/*对应title的值*/, String>> list = entry.getValue();
  50. /*遍历该数据集合*/
  51. List<PoiModel> poiModels = Lists.newArrayList();
  52. if(null!=workbook){
  53. Iterator iterator = list.iterator();
  54. int index = 1;/*这里1是从excel的第二行开始,第一行已经塞入标题了*/
  55. while (iterator.hasNext()){
  56. Row row = sheet.createRow(index);
  57. /*取得当前这行的map,该map中以key,value的形式存着这一行值*/
  58. Map<String, String> map = (Map<String, String>)iterator.next();
  59. /*循环列数,给当前行塞值*/
  60. for(int i = 0; i<title.length; i++){
  61. String old = "";
  62. /*old存的是上一行统一位置的单元的值,第一行是最上一行了,所以从第二行开始记*/
  63. if(index > 1){
  64. old = poiModels.get(i)==null?"":poiModels.get(i).getContent();
  65. }
  66. /*循环需要合并的列*/
  67. for(int j = 0; j < mergeIndex.length; j++){
  68. if(index == 1){
  69. /*记录第一行的开始行和开始列*/
  70. PoiModel poiModel = new PoiModel();
  71. poiModel.setOldContent(map.get(title[i]));
  72. poiModel.setContent(map.get(title[i]));
  73. poiModel.setRowIndex(1);
  74. poiModel.setCellIndex(i);
  75. poiModels.add(poiModel);
  76. break;
  77. }else if(i > 0 && mergeIndex[j] == i){/*这边i>0也是因为第一列已经是最前一列了,只能从第二列开始*/
  78. /*当前同一列的内容与上一行同一列不同时,把那以上的合并, 或者在当前元素一样的情况下,前一列的元素并不一样,这种情况也合并*/
  79. /*如果不需要考虑当前行与上一行内容相同,但是它们的前一列内容不一样则不合并的情况,把下面条件中||poiModels.get(i).getContent().equals(map.get(title[i])) && !poiModels.get(i - 1).getOldContent().equals(map.get(title[i-1]))去掉就行*/
  80. if(!poiModels.get(i).getContent().equals(map.get(title[i])) || poiModels.get(i).getContent().equals(map.get(title[i])) && !poiModels.get(i - 1).getOldContent().equals(map.get(title[i-1]))){
  81. /*当前行的当前列与上一行的当前列的内容不一致时,则把当前行以上的合并*/
  82. CellRangeAddress cra=new CellRangeAddress(poiModels.get(i).getRowIndex()/*从第二行开始*/, index - 1/*到第几行*/, poiModels.get(i).getCellIndex()/*从某一列开始*/, poiModels.get(i).getCellIndex()/*到第几列*/);
  83. //在sheet里增加合并单元格
  84. sheet.addMergedRegion(cra);
  85. /*重新记录该列的内容为当前内容,行标记改为当前行标记,列标记则为当前列*/
  86. poiModels.get(i).setContent(map.get(title[i]));
  87. poiModels.get(i).setRowIndex(index);
  88. poiModels.get(i).setCellIndex(i);
  89. }
  90. }
  91. /*处理第一列的情况*/
  92. if(mergeIndex[j] == i && i == 0 && !poiModels.get(i).getContent().equals(map.get(title[i]))){
  93. /*当前行的当前列与上一行的当前列的内容不一致时,则把当前行以上的合并*/
  94. CellRangeAddress cra=new CellRangeAddress(poiModels.get(i).getRowIndex()/*从第二行开始*/, index - 1/*到第几行*/, poiModels.get(i).getCellIndex()/*从某一列开始*/, poiModels.get(i).getCellIndex()/*到第几列*/);
  95. //在sheet里增加合并单元格
  96. sheet.addMergedRegion(cra);
  97. /*重新记录该列的内容为当前内容,行标记改为当前行标记*/
  98. poiModels.get(i).setContent(map.get(title[i]));
  99. poiModels.get(i).setRowIndex(index);
  100. poiModels.get(i).setCellIndex(i);
  101. }
  102. /*最后一行没有后续的行与之比较,所有当到最后一行时则直接合并对应列的相同内容*/
  103. if(mergeIndex[j] == i && index == list.size()){
  104. CellRangeAddress cra=new CellRangeAddress(poiModels.get(i).getRowIndex()/*从第二行开始*/, index/*到第几行*/, poiModels.get(i).getCellIndex()/*从某一列开始*/, poiModels.get(i).getCellIndex()/*到第几列*/);
  105. //在sheet里增加合并单元格
  106. sheet.addMergedRegion(cra);
  107. }
  108. }
  109. Cell cell = row.createCell(i, Cell.CELL_TYPE_STRING);
  110. cell.setCellValue(map.get(title[i]));
  111. /*在每一个单元格处理完成后,把这个单元格内容设置为old内容*/
  112. poiModels.get(i).setOldContent(old);
  113. }
  114. index++;
  115. }
  116. }
  117. n++;
  118. }
  119. /*生成临时文件*/
  120. FileOutputStream out = null;
  121. String localPath = null;
  122. File tempFile = null;
  123. String fileName = String.valueOf(new Date().getTime()/1000);
  124. try {
  125. tempFile = File.createTempFile(fileName, ".xlsx");
  126. localPath = tempFile.getAbsolutePath();
  127. out = new FileOutputStream(localPath);
  128. workbook.write(out);
  129. }catch (IOException e){
  130. e.printStackTrace();
  131. }finally {
  132. try {
  133. out.flush();
  134. out.close();
  135. }catch (IOException e){
  136. e.printStackTrace();
  137. }
  138. }
  139. return localPath;
  140. }
  141. public static void main(String[] args) throws IOException{
  142. /*此处标题的数组则对应excel的标题*/
  143. String[] title = {"id","标题","描述","负责人","开始时间"};
  144. List<Map<String, String>> list = Lists.newArrayList();
  145. /*这边是制造一些数据,注意每个list中map的key要和标题数组中的元素一致*/
  146. for(int i = 0; i<10; i++){
  147. HashMap<String, String> map = com.google.common.collect.Maps.newHashMap();
  148. if(i > 5){
  149. if(i<7){
  150. map.put("id","333");
  151. map.put("标题","mmmm");
  152. }else {
  153. map.put("id","333");
  154. map.put("标题","aaaaa");
  155. }
  156. }else if (i >3){
  157. map.put("id","222");
  158. map.put("标题","哈哈哈哈");
  159. }else if (i>1 && i<3){
  160. map.put("id","222");
  161. map.put("标题","hhhhhhhh");
  162. }else {
  163. map.put("id","222");
  164. map.put("标题","bbbb");
  165. }
  166. map.put("描述","sssssss");
  167. map.put("负责人","vvvvv");
  168. map.put("开始时间","2017-02-27 11:20:26");
  169. list.add(map);
  170. }
  171. Map<String/*此处的key为每个sheet的名称,一个excel中可能有多个sheet页*/, List<Map<String/*此处key对应每一列的标题*/, String>>/*该list为每个sheet页的数据*/> map = Maps.newHashMap();
  172. map.put("测试合并数据", list);
  173. System.out.println(createExcel(title, map, new int[]{0,1,2}/*此处数组为需要合并的列,可能有的需求是只需要某些列里面相同内容合并*/));
  174. }
  175. }

生成的文件效果(两种情况的):



    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多