|
|
@@ -4,12 +4,14 @@ import java.io.IOException;
|
|
4
|
4
|
import java.io.InputStream;
|
|
5
|
5
|
import java.lang.reflect.Field;
|
|
6
|
6
|
import java.lang.reflect.Method;
|
|
|
7
|
+import java.lang.reflect.ParameterizedType;
|
|
7
|
8
|
import java.math.BigDecimal;
|
|
8
|
9
|
import java.text.DecimalFormat;
|
|
9
|
10
|
import java.time.LocalDate;
|
|
10
|
11
|
import java.time.LocalDateTime;
|
|
11
|
12
|
import java.util.ArrayList;
|
|
12
|
13
|
import java.util.Arrays;
|
|
|
14
|
+import java.util.Collection;
|
|
13
|
15
|
import java.util.Comparator;
|
|
14
|
16
|
import java.util.Date;
|
|
15
|
17
|
import java.util.HashMap;
|
|
|
@@ -20,6 +22,7 @@ import java.util.stream.Collectors;
|
|
20
|
22
|
import javax.servlet.http.HttpServletResponse;
|
|
21
|
23
|
import org.apache.commons.lang3.ArrayUtils;
|
|
22
|
24
|
import org.apache.commons.lang3.RegExUtils;
|
|
|
25
|
+import org.apache.commons.lang3.reflect.FieldUtils;
|
|
23
|
26
|
import org.apache.poi.ss.usermodel.BorderStyle;
|
|
24
|
27
|
import org.apache.poi.ss.usermodel.Cell;
|
|
25
|
28
|
import org.apache.poi.ss.usermodel.CellStyle;
|
|
|
@@ -127,6 +130,26 @@ public class ExcelUtil<T>
|
|
127
|
130
|
private short maxHeight;
|
|
128
|
131
|
|
|
129
|
132
|
/**
|
|
|
133
|
+ * 合并后最后行数
|
|
|
134
|
+ */
|
|
|
135
|
+ private int subMergedLastRowNum = 0;
|
|
|
136
|
+
|
|
|
137
|
+ /**
|
|
|
138
|
+ * 合并后开始行数
|
|
|
139
|
+ */
|
|
|
140
|
+ private int subMergedFirstRowNum = 1;
|
|
|
141
|
+
|
|
|
142
|
+ /**
|
|
|
143
|
+ * 对象的子列表方法
|
|
|
144
|
+ */
|
|
|
145
|
+ private Method subMethod;
|
|
|
146
|
+
|
|
|
147
|
+ /**
|
|
|
148
|
+ * 对象的子列表属性
|
|
|
149
|
+ */
|
|
|
150
|
+ private List<Field> subFields;
|
|
|
151
|
+
|
|
|
152
|
+ /**
|
|
130
|
153
|
* 统计列表
|
|
131
|
154
|
*/
|
|
132
|
155
|
private Map<Integer, Double> statistics = new HashMap<Integer, Double>();
|
|
|
@@ -175,6 +198,7 @@ public class ExcelUtil<T>
|
|
175
|
198
|
createExcelField();
|
|
176
|
199
|
createWorkbook();
|
|
177
|
200
|
createTitle();
|
|
|
201
|
+ createSubHead();
|
|
178
|
202
|
}
|
|
179
|
203
|
|
|
180
|
204
|
/**
|
|
|
@@ -184,19 +208,54 @@ public class ExcelUtil<T>
|
|
184
|
208
|
{
|
|
185
|
209
|
if (StringUtils.isNotEmpty(title))
|
|
186
|
210
|
{
|
|
|
211
|
+ subMergedFirstRowNum++;
|
|
|
212
|
+ subMergedLastRowNum++;
|
|
|
213
|
+ int titleLastCol = this.fields.size() - 1;
|
|
|
214
|
+ if (isSubList())
|
|
|
215
|
+ {
|
|
|
216
|
+ titleLastCol = titleLastCol + subFields.size() - 1;
|
|
|
217
|
+ }
|
|
187
|
218
|
Row titleRow = sheet.createRow(rownum == 0 ? rownum++ : 0);
|
|
188
|
219
|
titleRow.setHeightInPoints(30);
|
|
189
|
220
|
Cell titleCell = titleRow.createCell(0);
|
|
190
|
221
|
titleCell.setCellStyle(styles.get("title"));
|
|
191
|
222
|
titleCell.setCellValue(title);
|
|
192
|
|
- sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), titleRow.getRowNum(),
|
|
193
|
|
- this.fields.size() - 1));
|
|
|
223
|
+ sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), titleRow.getRowNum(), titleLastCol));
|
|
|
224
|
+ }
|
|
|
225
|
+ }
|
|
|
226
|
+
|
|
|
227
|
+ /**
|
|
|
228
|
+ * 创建对象的子列表名称
|
|
|
229
|
+ */
|
|
|
230
|
+ public void createSubHead()
|
|
|
231
|
+ {
|
|
|
232
|
+ if (isSubList())
|
|
|
233
|
+ {
|
|
|
234
|
+ subMergedFirstRowNum++;
|
|
|
235
|
+ subMergedLastRowNum++;
|
|
|
236
|
+ Row subRow = sheet.createRow(rownum);
|
|
|
237
|
+ int excelNum = 0;
|
|
|
238
|
+ for (Object[] objects : fields)
|
|
|
239
|
+ {
|
|
|
240
|
+ Excel attr = (Excel) objects[1];
|
|
|
241
|
+ Cell headCell1 = subRow.createCell(excelNum);
|
|
|
242
|
+ headCell1.setCellValue(attr.name());
|
|
|
243
|
+ headCell1.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
|
|
|
244
|
+ excelNum++;
|
|
|
245
|
+ }
|
|
|
246
|
+ int headFirstRow = excelNum - 1;
|
|
|
247
|
+ int headLastRow = headFirstRow + subFields.size() - 1;
|
|
|
248
|
+ if (headLastRow > headFirstRow)
|
|
|
249
|
+ {
|
|
|
250
|
+ sheet.addMergedRegion(new CellRangeAddress(rownum, rownum, headFirstRow, headLastRow));
|
|
|
251
|
+ }
|
|
|
252
|
+ rownum++;
|
|
194
|
253
|
}
|
|
195
|
254
|
}
|
|
196
|
255
|
|
|
197
|
256
|
/**
|
|
198
|
257
|
* 对excel表单默认第一个索引名转换成list
|
|
199
|
|
- *
|
|
|
258
|
+ *
|
|
200
|
259
|
* @param is 输入流
|
|
201
|
260
|
* @return 转换后集合
|
|
202
|
261
|
*/
|
|
|
@@ -207,7 +266,7 @@ public class ExcelUtil<T>
|
|
207
|
266
|
|
|
208
|
267
|
/**
|
|
209
|
268
|
* 对excel表单默认第一个索引名转换成list
|
|
210
|
|
- *
|
|
|
269
|
+ *
|
|
211
|
270
|
* @param is 输入流
|
|
212
|
271
|
* @param titleNum 标题占用行数
|
|
213
|
272
|
* @return 转换后集合
|
|
|
@@ -219,7 +278,7 @@ public class ExcelUtil<T>
|
|
219
|
278
|
|
|
220
|
279
|
/**
|
|
221
|
280
|
* 对excel表单指定表格索引名转换成list
|
|
222
|
|
- *
|
|
|
281
|
+ *
|
|
223
|
282
|
* @param sheetName 表格索引名
|
|
224
|
283
|
* @param titleNum 标题占用行数
|
|
225
|
284
|
* @param is 输入流
|
|
|
@@ -378,7 +437,6 @@ public class ExcelUtil<T>
|
|
378
|
437
|
* @param list 导出数据集合
|
|
379
|
438
|
* @param sheetName 工作表的名称
|
|
380
|
439
|
* @return 结果
|
|
381
|
|
- * @throws IOException
|
|
382
|
440
|
*/
|
|
383
|
441
|
public void exportExcel(HttpServletResponse response, List<T> list, String sheetName)
|
|
384
|
442
|
{
|
|
|
@@ -393,7 +451,6 @@ public class ExcelUtil<T>
|
|
393
|
451
|
* @param sheetName 工作表的名称
|
|
394
|
452
|
* @param title 标题
|
|
395
|
453
|
* @return 结果
|
|
396
|
|
- * @throws IOException
|
|
397
|
454
|
*/
|
|
398
|
455
|
public void exportExcel(HttpServletResponse response, List<T> list, String sheetName, String title)
|
|
399
|
456
|
{
|
|
|
@@ -431,7 +488,7 @@ public class ExcelUtil<T>
|
|
431
|
488
|
|
|
432
|
489
|
/**
|
|
433
|
490
|
* 对list数据源将其里面的数据导入到excel表单
|
|
434
|
|
- *
|
|
|
491
|
+ *
|
|
435
|
492
|
* @return 结果
|
|
436
|
493
|
*/
|
|
437
|
494
|
public void exportExcel(HttpServletResponse response)
|
|
|
@@ -468,8 +525,20 @@ public class ExcelUtil<T>
|
|
468
|
525
|
// 写入各个字段的列头名称
|
|
469
|
526
|
for (Object[] os : fields)
|
|
470
|
527
|
{
|
|
|
528
|
+ Field field = (Field) os[0];
|
|
471
|
529
|
Excel excel = (Excel) os[1];
|
|
472
|
|
- this.createCell(excel, row, column++);
|
|
|
530
|
+ if (Collection.class.isAssignableFrom(field.getType()))
|
|
|
531
|
+ {
|
|
|
532
|
+ for (Field subField : subFields)
|
|
|
533
|
+ {
|
|
|
534
|
+ Excel subExcel = subField.getAnnotation(Excel.class);
|
|
|
535
|
+ this.createHeadCell(subExcel, row, column++);
|
|
|
536
|
+ }
|
|
|
537
|
+ }
|
|
|
538
|
+ else
|
|
|
539
|
+ {
|
|
|
540
|
+ this.createHeadCell(excel, row, column++);
|
|
|
541
|
+ }
|
|
473
|
542
|
}
|
|
474
|
543
|
if (Type.EXPORT.equals(type))
|
|
475
|
544
|
{
|
|
|
@@ -481,32 +550,71 @@ public class ExcelUtil<T>
|
|
481
|
550
|
|
|
482
|
551
|
/**
|
|
483
|
552
|
* 填充excel数据
|
|
484
|
|
- *
|
|
|
553
|
+ *
|
|
485
|
554
|
* @param index 序号
|
|
486
|
555
|
* @param row 单元格行
|
|
487
|
556
|
*/
|
|
|
557
|
+ @SuppressWarnings("unchecked")
|
|
488
|
558
|
public void fillExcelData(int index, Row row)
|
|
489
|
559
|
{
|
|
490
|
560
|
int startNo = index * sheetSize;
|
|
491
|
561
|
int endNo = Math.min(startNo + sheetSize, list.size());
|
|
|
562
|
+ int rowNo = (1 + rownum) - startNo;
|
|
492
|
563
|
for (int i = startNo; i < endNo; i++)
|
|
493
|
564
|
{
|
|
494
|
|
- row = sheet.createRow(i + 1 + rownum - startNo);
|
|
|
565
|
+ rowNo = i > 1 ? rowNo + 1 : rowNo + i;
|
|
|
566
|
+ row = sheet.createRow(rowNo);
|
|
495
|
567
|
// 得到导出对象.
|
|
496
|
568
|
T vo = (T) list.get(i);
|
|
|
569
|
+ Collection<?> subList = null;
|
|
|
570
|
+ if (isSubListValue(vo))
|
|
|
571
|
+ {
|
|
|
572
|
+ subList = getListCellValue(vo);
|
|
|
573
|
+ subMergedLastRowNum = subMergedLastRowNum + subList.size();
|
|
|
574
|
+ }
|
|
|
575
|
+
|
|
497
|
576
|
int column = 0;
|
|
498
|
577
|
for (Object[] os : fields)
|
|
499
|
578
|
{
|
|
500
|
579
|
Field field = (Field) os[0];
|
|
501
|
580
|
Excel excel = (Excel) os[1];
|
|
502
|
|
- this.addCell(excel, row, vo, field, column++);
|
|
|
581
|
+ if (Collection.class.isAssignableFrom(field.getType()) && StringUtils.isNotNull(subList))
|
|
|
582
|
+ {
|
|
|
583
|
+ boolean subFirst = false;
|
|
|
584
|
+ for (Object obj : subList)
|
|
|
585
|
+ {
|
|
|
586
|
+ if (subFirst)
|
|
|
587
|
+ {
|
|
|
588
|
+ rowNo++;
|
|
|
589
|
+ row = sheet.createRow(rowNo);
|
|
|
590
|
+ }
|
|
|
591
|
+ List<Field> subFields = FieldUtils.getFieldsListWithAnnotation(obj.getClass(), Excel.class);
|
|
|
592
|
+ int subIndex = 0;
|
|
|
593
|
+ for (Field subField : subFields)
|
|
|
594
|
+ {
|
|
|
595
|
+ if (subField.isAnnotationPresent(Excel.class))
|
|
|
596
|
+ {
|
|
|
597
|
+ subField.setAccessible(true);
|
|
|
598
|
+ Excel attr = subField.getAnnotation(Excel.class);
|
|
|
599
|
+ this.addCell(attr, row, (T) obj, subField, column + subIndex);
|
|
|
600
|
+ }
|
|
|
601
|
+ subIndex++;
|
|
|
602
|
+ }
|
|
|
603
|
+ subFirst = true;
|
|
|
604
|
+ }
|
|
|
605
|
+ this.subMergedFirstRowNum = this.subMergedFirstRowNum + subList.size();
|
|
|
606
|
+ }
|
|
|
607
|
+ else
|
|
|
608
|
+ {
|
|
|
609
|
+ this.addCell(excel, row, vo, field, column++);
|
|
|
610
|
+ }
|
|
503
|
611
|
}
|
|
504
|
612
|
}
|
|
505
|
613
|
}
|
|
506
|
614
|
|
|
507
|
615
|
/**
|
|
508
|
616
|
* 创建表格样式
|
|
509
|
|
- *
|
|
|
617
|
+ *
|
|
510
|
618
|
* @param wb 工作薄对象
|
|
511
|
619
|
* @return 样式列表
|
|
512
|
620
|
*/
|
|
|
@@ -634,7 +742,7 @@ public class ExcelUtil<T>
|
|
634
|
742
|
/**
|
|
635
|
743
|
* 创建单元格
|
|
636
|
744
|
*/
|
|
637
|
|
- public Cell createCell(Excel attr, Row row, int column)
|
|
|
745
|
+ public Cell createHeadCell(Excel attr, Row row, int column)
|
|
638
|
746
|
{
|
|
639
|
747
|
// 创建列
|
|
640
|
748
|
Cell cell = row.createCell(column);
|
|
|
@@ -642,12 +750,21 @@ public class ExcelUtil<T>
|
|
642
|
750
|
cell.setCellValue(attr.name());
|
|
643
|
751
|
setDataValidation(attr, row, column);
|
|
644
|
752
|
cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
|
|
|
753
|
+ if (isSubList())
|
|
|
754
|
+ {
|
|
|
755
|
+ // 填充默认样式,防止合并单元格样式失效
|
|
|
756
|
+ sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format("data_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor())));
|
|
|
757
|
+ if (attr.needMerge())
|
|
|
758
|
+ {
|
|
|
759
|
+ sheet.addMergedRegion(new CellRangeAddress(rownum - 1, rownum, column, column));
|
|
|
760
|
+ }
|
|
|
761
|
+ }
|
|
645
|
762
|
return cell;
|
|
646
|
763
|
}
|
|
647
|
764
|
|
|
648
|
765
|
/**
|
|
649
|
766
|
* 设置单元格信息
|
|
650
|
|
- *
|
|
|
767
|
+ *
|
|
651
|
768
|
* @param value 单元格值
|
|
652
|
769
|
* @param attr 注解相关
|
|
653
|
770
|
* @param cell 单元格信息
|
|
|
@@ -749,6 +866,11 @@ public class ExcelUtil<T>
|
|
749
|
866
|
{
|
|
750
|
867
|
// 创建cell
|
|
751
|
868
|
cell = row.createCell(column);
|
|
|
869
|
+ if (isSubListValue(vo) && attr.needMerge())
|
|
|
870
|
+ {
|
|
|
871
|
+ CellRangeAddress cellAddress = new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column);
|
|
|
872
|
+ sheet.addMergedRegion(cellAddress);
|
|
|
873
|
+ }
|
|
752
|
874
|
cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor())));
|
|
753
|
875
|
|
|
754
|
876
|
// 用于读取对象中的属性
|
|
|
@@ -839,7 +961,7 @@ public class ExcelUtil<T>
|
|
839
|
961
|
for (String item : convertSource)
|
|
840
|
962
|
{
|
|
841
|
963
|
String[] itemArray = item.split("=");
|
|
842
|
|
- if (StringUtils.containsAny(separator, propertyValue))
|
|
|
964
|
+ if (StringUtils.containsAny(propertyValue, separator))
|
|
843
|
965
|
{
|
|
844
|
966
|
for (String value : propertyValue.split(separator))
|
|
845
|
967
|
{
|
|
|
@@ -863,7 +985,7 @@ public class ExcelUtil<T>
|
|
863
|
985
|
|
|
864
|
986
|
/**
|
|
865
|
987
|
* 反向解析值 男=0,女=1,未知=2
|
|
866
|
|
- *
|
|
|
988
|
+ *
|
|
867
|
989
|
* @param propertyValue 参数值
|
|
868
|
990
|
* @param converterExp 翻译注解
|
|
869
|
991
|
* @param separator 分隔符
|
|
|
@@ -876,7 +998,7 @@ public class ExcelUtil<T>
|
|
876
|
998
|
for (String item : convertSource)
|
|
877
|
999
|
{
|
|
878
|
1000
|
String[] itemArray = item.split("=");
|
|
879
|
|
- if (StringUtils.containsAny(separator, propertyValue))
|
|
|
1001
|
+ if (StringUtils.containsAny(propertyValue, separator))
|
|
880
|
1002
|
{
|
|
881
|
1003
|
for (String value : propertyValue.split(separator))
|
|
882
|
1004
|
{
|
|
|
@@ -1049,6 +1171,13 @@ public class ExcelUtil<T>
|
|
1049
|
1171
|
field.setAccessible(true);
|
|
1050
|
1172
|
fields.add(new Object[] { field, attr });
|
|
1051
|
1173
|
}
|
|
|
1174
|
+ if (Collection.class.isAssignableFrom(field.getType()))
|
|
|
1175
|
+ {
|
|
|
1176
|
+ subMethod = getSubMethod(field.getName(), clazz);
|
|
|
1177
|
+ ParameterizedType pt = (ParameterizedType) field.getGenericType();
|
|
|
1178
|
+ Class<?> subClass = (Class<?>) pt.getActualTypeArguments()[0];
|
|
|
1179
|
+ this.subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class);
|
|
|
1180
|
+ }
|
|
1052
|
1181
|
}
|
|
1053
|
1182
|
|
|
1054
|
1183
|
// 多注解
|
|
|
@@ -1097,7 +1226,7 @@ public class ExcelUtil<T>
|
|
1097
|
1226
|
|
|
1098
|
1227
|
/**
|
|
1099
|
1228
|
* 创建工作表
|
|
1100
|
|
- *
|
|
|
1229
|
+ *
|
|
1101
|
1230
|
* @param sheetNo sheet数量
|
|
1102
|
1231
|
* @param index 序号
|
|
1103
|
1232
|
*/
|
|
|
@@ -1114,7 +1243,7 @@ public class ExcelUtil<T>
|
|
1114
|
1243
|
|
|
1115
|
1244
|
/**
|
|
1116
|
1245
|
* 获取单元格值
|
|
1117
|
|
- *
|
|
|
1246
|
+ *
|
|
1118
|
1247
|
* @param row 获取的行
|
|
1119
|
1248
|
* @param column 获取单元格列号
|
|
1120
|
1249
|
* @return 单元格值
|
|
|
@@ -1174,7 +1303,7 @@ public class ExcelUtil<T>
|
|
1174
|
1303
|
|
|
1175
|
1304
|
/**
|
|
1176
|
1305
|
* 判断是否是空行
|
|
1177
|
|
- *
|
|
|
1306
|
+ *
|
|
1178
|
1307
|
* @param row 判断的行
|
|
1179
|
1308
|
* @return
|
|
1180
|
1309
|
*/
|
|
|
@@ -1227,4 +1356,61 @@ public class ExcelUtil<T>
|
|
1227
|
1356
|
}
|
|
1228
|
1357
|
return str;
|
|
1229
|
1358
|
}
|
|
|
1359
|
+
|
|
|
1360
|
+ /**
|
|
|
1361
|
+ * 是否有对象的子列表
|
|
|
1362
|
+ */
|
|
|
1363
|
+ public boolean isSubList()
|
|
|
1364
|
+ {
|
|
|
1365
|
+ return StringUtils.isNotNull(subFields) && subFields.size() > 0;
|
|
|
1366
|
+ }
|
|
|
1367
|
+
|
|
|
1368
|
+ /**
|
|
|
1369
|
+ * 是否有对象的子列表,集合不为空
|
|
|
1370
|
+ */
|
|
|
1371
|
+ public boolean isSubListValue(T vo)
|
|
|
1372
|
+ {
|
|
|
1373
|
+ return StringUtils.isNotNull(subFields) && subFields.size() > 0 && StringUtils.isNotNull(getListCellValue(vo)) && getListCellValue(vo).size() > 0;
|
|
|
1374
|
+ }
|
|
|
1375
|
+
|
|
|
1376
|
+ /**
|
|
|
1377
|
+ * 获取集合的值
|
|
|
1378
|
+ */
|
|
|
1379
|
+ public Collection<?> getListCellValue(Object obj)
|
|
|
1380
|
+ {
|
|
|
1381
|
+ Object value;
|
|
|
1382
|
+ try
|
|
|
1383
|
+ {
|
|
|
1384
|
+ value = subMethod.invoke(obj, new Object[] {});
|
|
|
1385
|
+ }
|
|
|
1386
|
+ catch (Exception e)
|
|
|
1387
|
+ {
|
|
|
1388
|
+ return new ArrayList<Object>();
|
|
|
1389
|
+ }
|
|
|
1390
|
+ return (Collection<?>) value;
|
|
|
1391
|
+ }
|
|
|
1392
|
+
|
|
|
1393
|
+ /**
|
|
|
1394
|
+ * 获取对象的子列表方法
|
|
|
1395
|
+ *
|
|
|
1396
|
+ * @param name 名称
|
|
|
1397
|
+ * @param pojoClass 类对象
|
|
|
1398
|
+ * @return 子列表方法
|
|
|
1399
|
+ */
|
|
|
1400
|
+ public Method getSubMethod(String name, Class<?> pojoClass)
|
|
|
1401
|
+ {
|
|
|
1402
|
+ StringBuffer getMethodName = new StringBuffer("get");
|
|
|
1403
|
+ getMethodName.append(name.substring(0, 1).toUpperCase());
|
|
|
1404
|
+ getMethodName.append(name.substring(1));
|
|
|
1405
|
+ Method method = null;
|
|
|
1406
|
+ try
|
|
|
1407
|
+ {
|
|
|
1408
|
+ method = pojoClass.getMethod(getMethodName.toString(), new Class[] {});
|
|
|
1409
|
+ }
|
|
|
1410
|
+ catch (Exception e)
|
|
|
1411
|
+ {
|
|
|
1412
|
+ log.error("获取对象异常{}", e.getMessage());
|
|
|
1413
|
+ }
|
|
|
1414
|
+ return method;
|
|
|
1415
|
+ }
|
|
1230
|
1416
|
}
|