1. 程式人生 > >Java根據模板匯出Excel並生成多個Sheet

Java根據模板匯出Excel並生成多個Sheet

因為最近用報表匯出比較多,所有就提成了一個工具類,本工具類使用的場景為  根據提供的模板來匯出Excel報表

並且可根據提供的模板Sheet頁進行復制 從而實現多個Sheet頁的需求,

使用本工具類時,如果需求是每個Sheet頁中的資料都不一致,但是表格樣式和模板都一樣

那麼只需要在實際情況中根據 sql 來查詢要新增的資料來源 (只需更改資料來源即可)

採用的技術為 POI 匯出,因為類的緣故,目前只支援2003版本的Excel.

使用前請先下載相應jar包!

後期有時間的話會進行進一步完善,初次寫工具類,若有不完善的地方還請包涵!

先看看模板樣式和執行結果,然後直接上程式碼

這是Excel的模板樣式

這是匯出結果

具體實現看demo

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

package com.sgcc.xyz.util;

import java.io.File;

import java.io.FileInputStream;

import java.io.OutputStream;

import java.util.List;

import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.apache.poi.hssf.usermodel.HSSFCell;

import org.apache.poi.hssf.usermodel.HSSFCellStyle;

import org.apache.poi.hssf.usermodel.HSSFRow;

import org.apache.poi.hssf.usermodel.HSSFSheet;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;

import org.apache.poi.hssf.util.HSSFColor;

import org.apache.poi.hssf.util.Region;

import org.apache.poi.poifs.filesystem.POIFSFileSystem;

import com.sgcc.uap.persistence.impl.HibernateDaoImpl;

/**

 * 報表匯出工具類

 *

 * @author JYLiu

 @巴黎的雨季

 本工具是根據POI對Excel2003進行報表匯出 本工具類可根據模板進行Excel的匯出

 *  並且可根據提供的模板Sheet頁進行復制 從而實現多個Sheet頁的需求

 *  使用本工具類時,如果需求是每個Sheet頁中的資料都不一致,但是表格樣式和模板都一樣

 *  那麼只需要在實際情況中根據 sql 來查詢要新增的資料來源 (只需更改資料來源即可)

 */

public class ExcelUtil {

 /**

  * 根據模板匯出報表,可匯出多個Sheet頁

  *

  * @param 匯出的Excel檔名

  * @param 模板路徑 (全路徑)

  * @param 資料來源

  * @param 返回請求

  * @param 生成的Sheet頁的名稱集合

  * @param 資料來源中Map集合的key值 (key值對應的value值順序要列名順序一致)

  * @param 開始 迴圈寫入資料 的行數(從第幾行開始寫入資料)

  */

 public static void ExcelByModel(String ExcelName, String ModelURl, List<Map<String, String>> dataSource,

   HttpServletResponse response, String[] sheetNames, String[] keyNames, int rowNum) throws Exception {

  // 設定匯出Excel報表的匯出形式

  response.setContentType("application/vnd.ms-excel");

  // 設定匯出Excel報表的響應檔名

  String fileName = new String(ExcelName.getBytes("utf-8"), "ISO-8859-1");

  response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xls");

  // 建立一個輸出流

  OutputStream fileOut = response.getOutputStream();

  // 讀取模板檔案路徑

  File file = new File(ModelURl);

  FileInputStream fins = new FileInputStream(file);

  POIFSFileSystem fs = new POIFSFileSystem(fins);

  // 讀取Excel模板

  HSSFWorkbook wb = new HSSFWorkbook(fs);

  // 設定邊框樣式

  HSSFCellStyle style = wb.createCellStyle();

  style.setBorderBottom(HSSFCellStyle.BORDER_THIN);

  style.setBorderLeft(HSSFCellStyle.BORDER_THIN);

  style.setBorderRight(HSSFCellStyle.BORDER_THIN);

  style.setBorderTop(HSSFCellStyle.BORDER_THIN);

  // 設定邊框樣式的顏色

  style.setBottomBorderColor(HSSFColor.BLACK.index);

  style.setLeftBorderColor(HSSFColor.BLACK.index);

  style.setRightBorderColor(HSSFColor.BLACK.index);

  style.setTopBorderColor(HSSFColor.BLACK.index);

  // 模板頁

  HSSFSheet sheetModel = null;

  // 新建的Sheet頁

  HSSFSheet newSheet = null;

  // 建立行

  HSSFRow row = null;

  // 建立列

  HSSFCell cell = null;

  // 迴圈建立Sheet頁

  for (int i = 0; i < sheetNames.length; i++) {

   // 讀取模板中模板Sheet頁中的內容

   sheetModel = wb.getSheetAt(0);

   // 設定新建Sheet的頁名

   newSheet = wb.createSheet(sheetNames[i]);

   // 將模板中的內容複製到新建的Sheet頁中

   copySheet(wb, sheetModel, newSheet, sheetModel.getFirstRowNum(), sheetModel.getLastRowNum());

   //獲取到新建Sheet頁中的第一行為其中的列賦值

   row=newSheet.getRow(0);

   row.getCell(1).setCellValue("這是為表程式碼賦的值");

   //注意 合併的單元格也要按照合併前的格數來算

   row.getCell(6).setCellValue("這是為外部程式碼賦的值");

   //獲取模板中的第二列,並賦值

   row=newSheet.getRow(1);

   row.getCell(1).setCellValue("表名稱賦值");

   //注意 合併的單元格也要按照合併前的格數來算

   row.getCell(6).setCellValue("這是為是否系統表賦的值");

   // 遍歷資料來源 開始寫入資料(因為Excel中是從0開始,所以減一)

   int num = rowNum - 1;

   for (Map<String, String> item : dataSource) {

    // 迴圈遍歷,新建行

    row = newSheet.createRow((short) num);

    //判斷有多少列資料

    for (int j = 0; j < keyNames.length; j++) {

     // 設定每列的資料   設定每列的樣式   設定每列的值

     cell = row.createCell(j); cell.setCellStyle(style); cell.setCellValue(item.get(keyNames[j]));

    }

    num++;

   }

   // break 加break可以測試只新增一個Sheet頁的情況

  }

  // 寫入流

  wb.write(fileOut);

  // 關閉流

  fileOut.close();

 }

 /**

  *

  * @param Excel工作簿物件

  * @param 模板Sheet頁

  * @param 新建Sheet頁

  * @param 模板頁的第一行

  * @param 模板頁的最後一行

  */

 private static void copySheet(HSSFWorkbook wb, HSSFSheet fromsheet, HSSFSheet newSheet, int firstrow, int lasttrow) {

  // 複製一個單元格樣式到新建單元格

  if ((firstrow == -1) || (lasttrow == -1) || lasttrow < firstrow) {

   return;

  }

  // 複製合併的單元格

  Region region = null;

  for (int i = 0; i < fromsheet.getNumMergedRegions(); i++) {

   region = fromsheet.getMergedRegionAt(i);

   if ((region.getRowFrom() >= firstrow) && (region.getRowTo() <= lasttrow)) {

    newSheet.addMergedRegion(region);

   }

  }

  HSSFRow fromRow = null;

  HSSFRow newRow = null;

  HSSFCell newCell = null;

  HSSFCell fromCell = null;

  // 設定列寬

  for (int i = firstrow; i < lasttrow; i++) {

   fromRow = fromsheet.getRow(i);

   if (fromRow != null) {

    for (int j = fromRow.getLastCellNum(); j >= fromRow.getFirstCellNum(); j--) {

     int colnum = fromsheet.getColumnWidth((short) j);

     if (colnum > 100) {

      newSheet.setColumnWidth((short) j, (short) colnum);

     }

     if (colnum == 0) {

      newSheet.setColumnHidden((short) j, true);

     } else {

      newSheet.setColumnHidden((short) j, false);

     }

    }

    break;

   }

  }

  // 複製行並填充資料

  for (int i = 0; i < lasttrow; i++) {

   fromRow = fromsheet.getRow(i);

   if (fromRow == null) {

    continue;

   }

   newRow = newSheet.createRow(i - firstrow);

   newRow.setHeight(fromRow.getHeight());

   for (int j = fromRow.getFirstCellNum(); j < fromRow.getPhysicalNumberOfCells(); j++) {

    fromCell = fromRow.getCell((short) j);

    if (fromCell == null) {

     continue;

    }

    newCell = newRow.createCell((short) j);

    newCell.setCellStyle(fromCell.getCellStyle());

    int cType = fromCell.getCellType();

    newCell.setCellType(cType);

    switch (cType) {

     case HSSFCell.CELL_TYPE_STRING:

      newCell.setCellValue(fromCell.getRichStringCellValue());

      break;

     case HSSFCell.CELL_TYPE_NUMERIC:

      newCell.setCellValue(fromCell.getNumericCellValue());

      break;

     case HSSFCell.CELL_TYPE_FORMULA:

      newCell.setCellValue(fromCell.getCellFormula());

      break;

     case HSSFCell.CELL_TYPE_BOOLEAN:

      newCell.setCellValue(fromCell.getBooleanCellValue());

      break;

     case HSSFCell.CELL_TYPE_ERROR:

      newCell.setCellValue(fromCell.getErrorCellValue());

      break;

     default:

      newCell.setCellValue(fromCell.getRichStringCellValue());

      break;

    }

   }

  }

 }

}

以上便是整個工具類的核心程式碼了

測試資料如下

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

/**

  * 測試多Sheet頁匯出資料表格方法

  */

 public static void ExcelTest(HttpServletResponse response){

  //構建資料來源

  List<Map<String, String>> dataSourceList=new ArrayList<Map<String,String>>(){

   {

    add(new HashMap<String, String>(){{

     put("欄位編號", "1");

     put("欄位程式碼", "BUSINESS_ID");

     put("欄位含義", "業務id");

     put("資料型別", "VARCHAR");

     put("長度", "64");

     put("主鍵", "是");

     put("主碼", "");

    }});

    add(new HashMap<String, String>(){{

     put("欄位編號", "2");

     put("欄位程式碼", "PROC_INST_ID");

     put("欄位含義", "流程例項編號");

     put("資料型別", "VARCHAR");

     put("長度", "64");

     put("主鍵", "");

     put("主碼", " ");

    }});

    add(new HashMap<String, String>(){{

     put("欄位編號", "3");

     put("欄位程式碼", "PROC_STATE");

     put("欄位含義", "流程狀態");

     put("資料型別", "VARCHAR");

     put("長度", "64");

     put("主鍵", " ");

     put("主碼", " ");

    }});

    add(new HashMap<String, String>(){{

     put("欄位編號", "4");

     put("欄位程式碼", "APPLICANT");

     put("欄位含義", "申請人");

     put("資料型別", "VARCHAR");

     put("長度", "64");

     put("主鍵", " ");

     put("主碼", " ");

    }});

    add(new HashMap<String, String>(){{

     put("欄位編號", "5");

     put("欄位程式碼", "LEAVE_TYPE");

     put("欄位含義", "請假型別");

     put("資料型別", "VARCHAR");

     put("長度", "64");

     put("主鍵", " ");

     put("主碼", " ");

    }});

    add(new HashMap<String, String>(){{

     put("欄位編號", "6");

     put("欄位程式碼", "REASON");

     put("欄位含義", "請假事因");

     put("資料型別", "VARCHAR");

     put("長度", "64");

     put("主鍵", " ");

     put("主碼", " ");

    }});

    add(new HashMap<String, String>(){{

     put("欄位編號", "7");

     put("欄位程式碼", "BEGIN_TIME");

     put("欄位含義", "起始時間");

     put("資料型別", "TIMESTAMP");

     put("長度", "");

     put("主鍵", " ");

     put("主碼", " ");

    }});

    add(new HashMap<String, String>(){{

     put("欄位編號", "8");

     put("欄位程式碼", "END_TIME");

     put("欄位含義", "結束時間");

     put("資料型別", "TIMESTAMP");

     put("長度", "");

     put("主鍵", " ");

     put("主碼", " ");

    }});

    add(new HashMap<String, String>(){{

     put("欄位編號", "9");

     put("欄位程式碼", "INSERT_PERSON");

     put("欄位含義", "登記人");

     put("資料型別", "VARCHAR");

     put("長度", "64");

     put("主鍵", " ");

     put("主碼", " ");

    }});

    add(new HashMap<String, String>(){{

     put("欄位編號", "10");

     put("欄位程式碼", "APPROVEDBY");

     put("欄位含義", "批准人");

     put("資料型別", "VARCHAR");

     put("長度", "64");

     put("主鍵", " ");

     put("主碼", " ");

    }});

   }

  };

  //構建資料來源中的key值

  String[] keysStrings={"欄位編號","欄位程式碼","欄位含義","資料型別","長度","主鍵","主碼"};

  //每頁的名稱

  String [] sheetNameStrings={"Sheet1","Sheet2","Sheet3","Sheet4","Sheet5","Sheet6"};

  String modelURLString="D:\\model\\model.xls";

  try {

   ExcelUtil.ExcelByModel("測試模板匯出", modelURLString, dataSourceList, response, sheetNameStrings, keysStrings, 6);

  } catch (Exception e) {

   e.printStackTrace();

  }

 }

以上就是關於Excel報表根據模板匯出並生成多個Sheet也的小工具了,需要的可以參考程式碼,根據實際業務需求進行程式碼調整。

 分享一個網上看到的列子,使用的是EasyPoi,其實是對poi的一個封裝使其更簡單易用,簡單的匯入匯出可直接使用複雜坑較多

EasyPoi教程地址:  http://easypoi.mydoc.io/#text_197818

個人在專案中使用了easypoi和poi結合使用,因為easypoi使用確實簡單一些,後續做簡單的案例介紹!