Java poi导出LuckySheet在线表格

目前已经实现部分基于POI从零解析导出。(字体、边框、图片、数据验证(部分)、行列冻结、样式)

Java后台地址代码 :https://gitee.com/zzq100/luckysheet-demo

1.为啥使用Luckysheet?

Luckysheet(https://github.com/mengshukeji/Luckysheet)是一款轻量的在线Excel渲染框架,易集成使用。支持二次开发,最重要的是渲染真的很快、开源免费的!!!

2.Luckysheet目前使用

目前luckysheet虽然在渲染上很不错,但是毕竟是刚刚开源,使用上会有一些小BUG。关于导入导出官方有给出demo:https://github.com/mengshukeji/Luckyexcel

话不多说上干货

将官方的代码拉取下来自己创建一个页面 下载地址–>官方链接
布局代码如下,可以直接复制下来。但是注意下上传下载数据,只是个例子,需要自己修改。上传必须用post哦,因为数据太大了!

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
<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>在线表格</title>
</head>

 <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <!-- luckysheet -->
  <link rel='stylesheet' href='luckysheet/plugins/css/pluginsCss.css' />
  <link rel='stylesheet' href='luckysheet/plugins/plugins.css' />
  <link rel='stylesheet' href='luckysheet/css/luckysheet.css' />
  <link rel='stylesheet' href='luckysheet/assets/iconfont/iconfont.css' />
  <script src="luckysheet/plugins/js/plugin.js"></script>
  <script src="luckysheet/luckysheet.umd.js"></script>
 <!-- zTree -->
 <link rel="stylesheet" href="css/demo.css" type="text/css">
 <link rel="stylesheet" href="css/metroStyle.css" type="text/css">
 <!-- <script type="text/javascript" src="js/jquery-1.4.4.min.js"></script> luckysheet自带2.4.4版本jQuery-->
 <script type="text/javascript" src="js/jquery.ztree.core.min.js"></script>
 <script type="text/javascript" src="js/jquery.ztree.excheck.min.js"></script>
 <script type="text/javascript" src="js/jquery.ztree.exedit.min.js"></script>
<body>
<!--<button onclick="clicks()">保存</button>-->
<div id="luckysheet" style="margin:0px;padding:0px;position:absolute;width:100%;height:100%;left: 0px;top: 0px;"></div>
 
</body>
 <script src="luckysheet/demoData/demoFeature.js"></script>
 <script src="luckysheet/demoData/sheetFormula.js"></script>
 <script src="luckysheet/demoData/sheetCell.js"></script>
 <script src="luckysheet/demoData/sheetConditionFormat.js"></script>
 <script src="luckysheet/demoData/sheetTable.js"></script>
 <script src="luckysheet/demoData/sheetComment.js"></script>
 <script src="luckysheet/demoData/sheetPivotTableData.js"></script>
 <script src="luckysheet/demoData/sheetPivotTable.js"></script>
 <script src="luckysheet/demoData/sheetSparkline.js"></script>
 <script src="luckysheet/demoData/sheetChart.js"></script>
 <script src="luckysheet/demoData/sheetPicture.js"></script>
 <script src="luckysheet/demoData/sheetDataVerification.js"></script>
 
<script>
    //loadUrl是返回luckysheet 数据的后台api接口
    var options = {<!-- -->
        container: 'luckysheet', //luckysheet为容器id
        title: '生产日报表', // 设定表格名称
        lang: 'zh', // 设定表格语言
        allowEdit: true,//作用:是否允许前台编辑
        showinfobar: true,//作用:是否显示顶部信息栏
        myFolderUrl: "/getList",//作用:左上角<返回按钮的链接
        functionButton: '<button id="" class="btn btn-primary" οnclick="clicks()" style="padding:3px 6px;font-size: 12px;margin-right: 10px;">保存</button> <button id="" class="btn btn-primary btn-danger" style=" padding:3px 6px; font-size: 12px; margin-right: 85px;" οnclick="downExcelData()">下载</button>',
        loadUrl: "",
        }
    $(function () {<!-- -->
        //配置项
 
        luckysheet.create(options)
    })
 

 
    function uploadExcelData() {<!-- -->
        //console.log(luckysheet.getAllSheets());
        //console.log("lll=" + JSON.stringify(luckysheet.getAllSheets()));
        //上传例子,可以把这个数据保存到服务器上。下次可以从服务器直接加载luckysheet数据了。
        $.post("/excel/uploadData", {<!-- -->
            exceldatas: JSON.stringify(luckysheet.getAllSheets()),
            title: options.title,
        }, function (data) {<!-- -->
            //console.log("data = " + data)
            alert("保存成功!")
        });
    }
 
    function downExcelData() {<!-- -->
        //这里你要自己写个后台接口,处理上传上来的Excel数据,用post传输。我用的是Java后台处理导出!这里只是写了post请求的写法
        console.log("luckysheet.getAllSheets() = " + JSON.stringify(luckysheet.getAllSheets()))
        console.log("luckysheet.getRangeValue() = " + JSON.stringify(luckysheet.getRangeValue("A1:B3")))
        console.log("luckysheet.getRangeHtml() = " + luckysheet.getRangeHtml())
            var jsdata = new Array();
            var sheets = luckysheet.getAllSheets();
                    for (var i = 0; i < sheets.length; i++) {<!-- -->
                        jsdata.push({<!-- -->
                            "name": sheets[i].name,
                            "celldata": sheets[i].celldata,
                            "config": sheets[i].config,
                            "images": sheets[i].images,
                            "frozen": sheets[i].frozen,
                            "dataVerification": sheets[i].dataVerification
                        });
                    }
        console.log("JSON.stringify(jsdata) = " + JSON.stringify(jsdata))
        var form = document.createElement("form");  
        form.method = 'post';
        form.action = /equipment/excel/downfile';
        form.style = 'display:none';
        form.enctype = 'multipart/form-data';
        document.body.appendChild(form);
        var newElement = document.createElement("textarea");
        newElement.setAttribute("type","hidden");
        newElement.name = "exceldata";
        newElement.value = JSON.stringify(jsdata);        
        form.appendChild(newElement);
        form.submit();
    }
</script>
</html>

  1. 引入相关pom包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.12</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-scratchpad</artifactId>
            <version>3.12</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.12</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml-schemas</artifactId>
            <version>3.12</version>
        </dependency>

2. Java 服务器后台导出处理:基于POI解析导出:

后台Controller处理

1
2
3
4
5
6
7
    @ApiOperation(value = "导出报表")
    @ApiImplicitParam(name = "exceldata", value = "数据", required = true, dataType = DataTypeConstants.STRING,example = "10")
    @PostMapping("/excel/downfile")
    public void downExcelFile(@RequestParam(value = "exceldata") String exceldata,@ApiIgnore HttpServletRequest request,@ApiIgnore HttpServletResponse response) {<!-- -->
        exceldata = exceldata.replace("&#xA;", "\\r\\n");//去除luckysheet中 &#xA 的换行
        ExcelUtils.exportLuckySheetXlsx(exceldata,request,response);
    }

导出工具类

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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
package com.electronic.patrol.utils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.util.Units;
import org.apache.poi.xssf.usermodel.*;
import sun.misc.BASE64Decoder;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.Color;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;

/**
 * @author SKFC
 * @title: ExcelUtils
 * @projectName central-platform
 * @description: TODO
 * @date 2020/11/2410:06
 */
public class ExcelUtils {<!-- -->
    public static CellStyle createCellStyle(XSSFSheet sheet, XSSFWorkbook wb, JSONObject jsonObjectValue){<!-- -->
        XSSFCellStyle cellStyle = wb.createCellStyle();
        Map<Integer, String> fontMap = new HashMap<>();
        fontMap.put(-1, "Arial");
        fontMap.put(0, "Times New Roman");
        fontMap.put(1, "Arial");
        fontMap.put(2, "Tahoma");
        fontMap.put(3, "Verdana");
        fontMap.put(4, "微软雅黑");
        fontMap.put(5, "宋体");
        fontMap.put(6, "黑体");
        fontMap.put(7, "楷体");
        fontMap.put(8, "仿宋");
        fontMap.put(9, "新宋体");
        fontMap.put(10, "华文新魏");
        fontMap.put(11, "华文行楷");
        fontMap.put(12, "华文隶书");
        //合并单元格
        if (jsonObjectValue.get("mc") != null && ((JSONObject)jsonObjectValue.get("mc")).get("rs") != null && ((JSONObject)jsonObjectValue.get("mc")).get("cs") != null){<!-- -->
            int r = Integer.parseInt(((JSONObject)jsonObjectValue.get("mc")).get("r").toString());//主单元格的行号,开始行号
            int rs = Integer.parseInt(((JSONObject)jsonObjectValue.get("mc")).get("rs").toString());//合并单元格占的行数,合并多少行
            int c = Integer.parseInt(((JSONObject)jsonObjectValue.get("mc")).get("c").toString());//主单元格的列号,开始列号
            int cs = Integer.parseInt(((JSONObject)jsonObjectValue.get("mc")).get("cs").toString());//合并单元格占的列数,合并多少列
            CellRangeAddress region = new CellRangeAddress(r, r + rs - 1, c, c + cs - 1);
            sheet.addMergedRegion(region);
        }
        XSSFFont font = wb.createFont();
        //字体
        if(jsonObjectValue.get("ff") != null){<!-- -->
            if (jsonObjectValue.get("ff").toString().matches("^(-?\\d+)(\\.\\d+)?$")){<!-- -->
                font.setFontName(fontMap.get(jsonObjectValue.getInteger("ff")));
            }else {<!-- -->
                font.setFontName(jsonObjectValue.get("ff").toString());
            }
        }
        //字体颜色
        if (jsonObjectValue.get("fc") != null){<!-- -->
            String fc = jsonObjectValue.get("fc").toString();
            XSSFColor color = toColorFromString(fc);
            font.setColor(color);
        }
        //粗体
        if (jsonObjectValue.get("bl") != null){<!-- -->
            font.setBoldweight("1".equals(jsonObjectValue.get("bl").toString()) ? (short)HSSFFont.BOLDWEIGHT_BOLD : (short)HSSFFont.BOLDWEIGHT_NORMAL);
        }
        //斜体
        if (jsonObjectValue.get("it") != null){<!-- -->
            font.setItalic("1".equals(jsonObjectValue.get("it").toString()));
        }
        //删除线
        if (jsonObjectValue.get("cl") != null){<!-- -->
            font.setStrikeout("1".equals(jsonObjectValue.get("cl").toString()));
        }
        //下滑线
        if (jsonObjectValue.get("un") != null){<!-- -->
            font.setUnderline("1".equals(jsonObjectValue.get("un").toString()) ? FontUnderline.SINGLE : FontUnderline.NONE);
        }
        //字体大小
        if (jsonObjectValue.get("fs") != null){<!-- -->
            font.setFontHeightInPoints(new Short(jsonObjectValue.get("fs").toString()));
        }
        cellStyle.setFont(font);
        //水平对齐
        if (jsonObjectValue.get("ht") != null){<!-- -->
            switch (jsonObjectValue.getInteger("ht")) {<!-- -->
                case 0:
                    cellStyle.setAlignment(XSSFCellStyle.ALIGN_CENTER);
                    break;
                case 1:
                    cellStyle.setAlignment(XSSFCellStyle.ALIGN_LEFT);
                    break;
                case 2:
                    cellStyle.setAlignment(XSSFCellStyle.ALIGN_RIGHT);
                    break;
            }
        }
        //垂直对齐
        if (jsonObjectValue.get("vt") != null){<!-- -->
            switch (jsonObjectValue.getInteger("vt")) {<!-- -->
                case 0:
                    cellStyle.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);
                    break;
                case 1:
                    cellStyle.setVerticalAlignment(XSSFCellStyle.VERTICAL_TOP);
                    break;
                case 2:
                    cellStyle.setVerticalAlignment(XSSFCellStyle.VERTICAL_BOTTOM);
                    break;
            }
        }
        //背景颜色
        if (jsonObjectValue.get("bg") != null){<!-- -->
            String bg = jsonObjectValue.get("bg").toString();
            cellStyle.setFillForegroundColor(toColorFromString(bg));
            cellStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
        }
        cellStyle.setWrapText(true);
        return cellStyle;
    }

    /**
     * 字符串转换成Color对象
     * @param colorStr 16进制颜色字符串
     * @return Color对象
     * */
    public static XSSFColor toColorFromString(String colorStr) {<!-- -->
        if (colorStr.contains("#")){<!-- -->
            colorStr = colorStr.substring(1);
            Color color = new Color(Integer.parseInt(colorStr, 16));
            XSSFColor xssfColor = new XSSFColor(color);
            return xssfColor;
        }else {<!-- -->
            int strStartIndex = colorStr.indexOf("(");
            int strEndIndex = colorStr.indexOf(")");
            String[] strings = colorStr.substring(strStartIndex+1,strEndIndex).split(",");
            String R = Integer.toHexString(Integer.parseInt(strings[0].replaceAll(" ","")));
            R = R.length() < 2 ? ('0' + R) : R;
            String B = Integer.toHexString(Integer.parseInt(strings[1].replaceAll(" ","")));
            B = B.length() < 2 ? ('0' + B) : B;
            String G = Integer.toHexString(Integer.parseInt(strings[2].replaceAll(" ","")));
            G = G.length() < 2 ? ('0' + G) : G;
            String  cStr=  R + B + G;
            Color color1 = new Color(Integer.parseInt(cStr, 16));
            XSSFColor xssfColor = new XSSFColor(color1);
            return xssfColor;
        }
    }



    /**
     * 功能: LuckySheet导出方法
     * 开发:zzq
     * @param excelData    数据
     * @param response         用来获取输出流
     * @param request       针对火狐浏览器导出时文件名乱码的问题,也可以不传入此值
     * @throws IOException
     */
    public static void exportLuckySheetXlsx(String excelData,HttpServletRequest request, HttpServletResponse response)  {<!-- -->
        //解析对象,可以参照官方文档:https://mengshukeji.github.io/LuckysheetDocs/zh/guide/#%E6%95%B4%E4%BD%93%E7%BB%93%E6%9E%84
        JSONArray jsonArray = (JSONArray) JSONObject.parse(excelData);
        //如果只有一个sheet那就是get(0),有多个那就对应取下标
        List<JSONObject> jsonObjects = jsonArray.toJavaList(JSONObject.class);
        XSSFWorkbook wb = new XSSFWorkbook();
        for (int i=0 ;i<jsonObjects.size();i++){<!-- -->
            JSONObject jsonObject = (JSONObject) jsonArray.get(i);
            JSONArray jsonObjectList = jsonObject.getJSONArray("celldata");
            JSONObject images = jsonObject.getJSONObject("images");
            JSONObject dataVerification = jsonObject.getJSONObject("dataVerification");
            //默认高
            short defaultRowHeight = jsonObject.getShort("defaultRowHeight") == null ?20:jsonObject.getShort("defaultRowHeight");
            //默认宽
            short defaultColWidth = jsonObject.getShort("defaultColWidth") == null ?74:jsonObject.getShort("defaultColWidth");
            JSONObject config = jsonObject.getJSONObject("config");
            //行列冻结
            JSONObject frozen = jsonObject.getJSONObject("frozen");
            JSONObject columnlenObject = null;//表格列宽
            JSONObject rowlenObject = null;//表格行高
            JSONArray borderInfoObjectList = null;//边框样式
            if (config != null){<!-- -->
                columnlenObject = jsonObject.getJSONObject("config").getJSONObject("columnlen");//表格列宽
                rowlenObject = jsonObject.getJSONObject("config").getJSONObject("rowlen");//表格行高
                borderInfoObjectList = jsonObject.getJSONObject("config").getJSONArray("borderInfo");//边框样式
            }
            //读取了模板内所有sheet内容
            XSSFSheet sheet = wb.createSheet(jsonObject.get("name").toString());
            //如果这行没有了,整个公式都不会有自动计算的效果的
            sheet.setForceFormulaRecalculation(true);
            //固定行列
            setFreezePane(sheet,frozen);
            //设置行高列宽
            setCellWH(sheet,columnlenObject,rowlenObject);
            //图片插入
            setImages(wb,sheet,images,columnlenObject,rowlenObject,defaultRowHeight,defaultColWidth);
            //设置单元格值及格式
            setCellValue(wb,sheet,jsonObjectList,columnlenObject,rowlenObject,defaultRowHeight,defaultColWidth);
            //设置数据验证
            settDataValidation(dataVerification,sheet);
            if (borderInfoObjectList != null){<!-- -->
                //设置边框
                setBorder(borderInfoObjectList,sheet);
            }
        }
        try {<!-- -->
            String disposition = "attachment;filename=";
            if (request != null && request.getHeader("USER-AGENT") != null && StringUtils.contains(request.getHeader("USER-AGENT"), "Firefox")) {<!-- -->
                disposition += new String(("XXXX20201124.xlsx").getBytes(), "ISO8859-1");
            } else {<!-- -->
                disposition += URLEncoder.encode("XXXX20201124.xlsx", "UTF-8");
            }
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");
            response.setHeader("Content-Disposition", disposition);
            //修改模板内容导出新模板
            OutputStream out = null;
            out = response.getOutputStream();
            wb.write(out);
            out.close();
        } catch (FileNotFoundException e) {<!-- -->
            e.printStackTrace();
        } catch (IOException e) {<!-- -->
            e.printStackTrace();
        }

    }

    /**
     * 获取图片位置
     * dx1:起始单元格的x偏移量,如例子中的255表示直线起始位置距A1单元格左侧的距离;
     * dy1:起始单元格的y偏移量,如例子中的125表示直线起始位置距A1单元格上侧的距离;
     * dx2:终止单元格的x偏移量,如例子中的1023表示直线起始位置距C3单元格左侧的距离;
     * dy2:终止单元格的y偏移量,如例子中的150表示直线起始位置距C3单元格上侧的距离;
     * col1:起始单元格列序号,从0开始计算;竖
     * row1:起始单元格行序号,从0开始计算,如例子中col1=0,row1=0就表示起始单元格为A1;横
     * col2:终止单元格列序号,从0开始计算;
     * row2:终止单元格行序号,从0开始计算,如例子中col2=2,row2=2就表示起始单元格为C3;
     * @param imageDefault
     * @param defaultRowHeight
     * @param defaultColWidth
     * @param columnlenObject
     * @param rowlenObject
     */
    public static Map<String, Integer> getColRowMap(JSONObject imageDefault,short defaultRowHeight , short defaultColWidth ,JSONObject columnlenObject, JSONObject rowlenObject){<!-- -->
        int left =  (int) imageDefault.get("left");
        int top =  (int) imageDefault.get("top");
        int width =  (int) imageDefault.get("width");
        int height =  (int) imageDefault.get("height");
        //算起始最大列
        int colMax1 = (int)Math.ceil((double)left/defaultColWidth);
        //算起始最大行
        int rowMax1 = (int)Math.ceil((double)top/defaultRowHeight);
        //算终止最大列
        int colMax2 = (int)Math.ceil((double)(left+width)/defaultColWidth);
        //算终止最大行
        int rowMax2 = (int)Math.ceil((double)(top+height)/defaultRowHeight);
//        int dx1 = left;//宽 行
//        int dy1 = top; //高 列
//        int dx2 = left+width;
//        int dy2 = top+height;
        BigDecimal dx1 = new BigDecimal(left);//宽 行
        BigDecimal dy1 = new BigDecimal(top); //高 列
        BigDecimal dx2 = new BigDecimal(left+width);
        BigDecimal dy2 = new BigDecimal(top+height);
        int col1 = 0;
        int row1 = 0;
        int col2 = 0;
        int row2 = 0;
        //算起始列的序号和偏移量
        for (int index = 0;index <= colMax1;index++){<!-- -->
            BigDecimal col = null;
            if (columnlenObject != null && columnlenObject.getString(Integer.toString(index)) != null){<!-- -->
                col = new BigDecimal(columnlenObject.getString(Integer.toString(index)));//看当前列是否重新赋值
            }
            //算起始列
            if (col == null && dx1.compareTo(new BigDecimal(defaultColWidth)) < 0){<!-- -->
                col1 = index;
                break;
            }
            //算起始X偏移
            if (col == null && dx1.compareTo(new BigDecimal(defaultColWidth)) >= 0){<!-- -->
                dx1 =dx1.subtract(new BigDecimal(defaultColWidth)) ;
            }

            //算起始列
            if (col != null && dx1.compareTo(col) < 0){<!-- -->
                col1 = index;
                break;
            }
            //算起始X偏移
            if (col != null ){<!-- -->
                dx1 = dx1.subtract(col) ;
            }

        }

        //算起始行的序号和偏移量
        for (int index = 0;index <= rowMax1;index++){<!-- -->
            BigDecimal row = null;
            if (rowlenObject != null && rowlenObject.getString(Integer.toString(index)) != null){<!-- -->
                row = new BigDecimal(rowlenObject.getString(Integer.toString(index)));//看当前行是否重新赋值
            }
            //算起始行
            if (row == null && dy1.compareTo(new BigDecimal(defaultRowHeight)) < 0){<!-- -->
                row1 = index;
                break;
            }
            //算起始y偏移
            if (row == null && dy1.compareTo(new BigDecimal(defaultRowHeight)) >= 0){<!-- -->
                dy1 =dy1.subtract(new BigDecimal(defaultRowHeight));
            }
            //算起始行
            if (row != null && dy1.compareTo(row) < 0){<!-- -->
                row1 = index;
                break;
            }
            //算起始y偏移
            if (row != null){<!-- -->
                dy1 = dy1.subtract(row) ;
            }
        }

        //算最终列的序号和偏移量
        for (int index = 0;index <= colMax2;index++){<!-- -->
            BigDecimal col = null;
            if (columnlenObject != null && columnlenObject.getString(Integer.toString(index)) != null){<!-- -->
                col = new BigDecimal(columnlenObject.getString(Integer.toString(index)));//看当前列是否重新赋值
            }
            //算最终列
            if (col == null && dx2.compareTo(new BigDecimal(defaultColWidth)) < 0){<!-- -->
                col2 = index;
                break;
            }
            //算最终X偏移
            if (col == null && dx2.compareTo(new BigDecimal(defaultColWidth)) >= 0){<!-- -->
                dx2 =dx2.subtract(new BigDecimal(defaultColWidth)) ;
            }

            //算最终列
            if (col != null && dx2.compareTo(col) < 0){<!-- -->
                col2 = index;
                break;
            }
            //算最终X偏移
            if (col != null ){<!-- -->
                dx2 = dx2.subtract(col) ;
            }

        }

        //算最终行的序号和偏移量
        for (int index = 0;index <= rowMax2;index++){<!-- -->
            //行高
            BigDecimal row = null;
            if (rowlenObject != null && rowlenObject.getString(Integer.toString(index)) != null){<!-- -->
                row = new BigDecimal(rowlenObject.getString(Integer.toString(index)));//看当前行是否重新赋值
            }
            //算最终行
            if (row == null && dy2.compareTo(new BigDecimal(defaultRowHeight)) < 0){<!-- -->
                row2 = index;
                break;
            }
            //算最终y偏移
            if (row == null && dy2.compareTo(new BigDecimal(defaultRowHeight)) >= 0){<!-- -->
                dy2 =dy2.subtract(new BigDecimal(defaultRowHeight));
            }
            //算最终行
            if (row != null && dy2.compareTo(row) < 0){<!-- -->
                row2 = index;
                break;
            }
            //算最终Y偏移
            if (row != null){<!-- -->
                dy2 = dy2.subtract(row) ;
            }
        }
        Map<String, Integer> map =new HashMap<>();
        map.put("dx1",dx1.multiply(new BigDecimal(Units.EMU_PER_PIXEL)).setScale(0,BigDecimal.ROUND_HALF_UP).intValue());
        map.put("dy1",dy1.multiply(new BigDecimal(Units.EMU_PER_PIXEL)).setScale(0,BigDecimal.ROUND_HALF_UP).intValue());
        map.put("dx2",dx2.multiply(new BigDecimal(Units.EMU_PER_PIXEL)).setScale(0,BigDecimal.ROUND_HALF_UP).intValue());
        map.put("dy2",dy2.multiply(new BigDecimal(Units.EMU_PER_PIXEL)).setScale(0,BigDecimal.ROUND_HALF_UP).intValue());
        map.put("col1",col1);
        map.put("row1",row1);
        map.put("col2",col2);
        map.put("row2",row2);
        return map;
    }

    /**
     * 行列冻结
     * @param sheet
     * @param frozen
     */
    private static void setFreezePane(XSSFSheet sheet, JSONObject frozen) {<!-- -->
        if (frozen != null){<!-- -->
            Map<String, Object> frozenMap = frozen.getInnerMap();
                //首行
                if ("row".equals(frozenMap.get("type").toString())){<!-- -->
                    sheet.createFreezePane(0,1);
                }
                //首列
                if ("column".equals(frozenMap.get("type").toString())){<!-- -->
                    sheet.createFreezePane(1,0);
                }
                //行列
                if ("both".equals(frozenMap.get("type").toString())){<!-- -->
                    sheet.createFreezePane(1,1);
                }
                //几行
                if ("rangeRow".equals(frozenMap.get("type").toString()) ){<!-- -->
                    JSONObject value = (JSONObject) frozenMap.get("range");
                    sheet.createFreezePane(0,value.getInteger("row_focus")+1);
                }
                //几列
                if ("rangeColumn".equals(frozenMap.get("type").toString())){<!-- -->
                    JSONObject value = (JSONObject) frozenMap.get("range");
                    sheet.createFreezePane(value.getInteger("column_focus")+1,0);
                }
                //几行列
                if ("rangeBoth".equals(frozenMap.get("type").toString())){<!-- -->
                    JSONObject value = (JSONObject) frozenMap.get("range");
                    sheet.createFreezePane(value.getInteger("column_focus")+1,value.getInteger("row_focus")+1);
                }
        }
    }


    /**
     * 设置非默认宽高
     * @param sheet
     * @param columnlenObject
     * @param rowlenObject
     */
    private static void setCellWH(XSSFSheet sheet, JSONObject columnlenObject,JSONObject rowlenObject) {<!-- -->
        //我们都知道excel是表格,即由一行一行组成的,那么这一行在java类中就是一个XSSFRow对象,我们通过XSSFSheet对象就可以创建XSSFRow对象
        //如:创建表格中的第一行(我们常用来做标题的行)  XSSFRow firstRow = sheet.createRow(0); 注意下标从0开始
        //根据luckysheet创建行列
        //创建行和列
        if (rowlenObject != null){<!-- -->
            Map<String, Object> rowMap = rowlenObject.getInnerMap();
            for(Map.Entry<String, Object> rowEntry : rowMap.entrySet()) {<!-- -->
                XSSFRow row = sheet.createRow(Integer.parseInt(rowEntry.getKey()));//创建行
                BigDecimal hei=new BigDecimal(rowEntry.getValue() + "");
                //转化excle行高参数1
                BigDecimal excleHei1=new BigDecimal(72);
                //转化excle行高参数2
                BigDecimal excleHei2=new BigDecimal(96);
                row.setHeightInPoints(hei.multiply(excleHei1).divide(excleHei2).floatValue());//行高px值
                if (columnlenObject != null){<!-- -->
                    Map<String, Object> cloMap = columnlenObject.getInnerMap();
                    for(Map.Entry<String, Object> cloEntry : cloMap.entrySet()) {<!-- -->
                        BigDecimal wid=new BigDecimal(cloEntry.getValue().toString());
                        //转化excle列宽参数35.7   调试后我改为33   --具体多少没有算
                        BigDecimal excleWid=new BigDecimal(33);
                        sheet.setColumnWidth(Integer.parseInt(cloEntry.getKey()), wid.multiply(excleWid).setScale(0,BigDecimal.ROUND_HALF_UP).intValue());//列宽px值
                        row.createCell(Integer.parseInt(cloEntry.getKey()));//创建列
                    }
                }
            }
        }
    }

    /**
     *
     * @param wb
     * @param sheet
     * @param images 所有图片
     * @param columnlenObject
     * @param rowlenObject
     * @param defaultRowHeight
     * @param defaultColWidth
     */
    private static void setImages(XSSFWorkbook wb,XSSFSheet sheet, JSONObject images,JSONObject columnlenObject,JSONObject rowlenObject,short defaultRowHeight,short defaultColWidth){<!-- -->
        //图片插入
        if (images != null){<!-- -->
            Map<String, Object> map = images.getInnerMap();
            JSONObject finalColumnlenObject = columnlenObject;
            JSONObject finalRowlenObject = rowlenObject;
            for(Map.Entry<String, Object> entry : map.entrySet()) {<!-- -->
                XSSFDrawing patriarch = sheet.createDrawingPatriarch();
                //图片信息
                JSONObject iamgeData = (JSONObject) entry.getValue();
                //图片的位置宽 高 距离左 距离右
                JSONObject imageDefault = ((JSONObject) iamgeData.get("default"));
                //算坐标
                Map<String, Integer> colrowMap = getColRowMap(imageDefault, defaultRowHeight, defaultColWidth, finalColumnlenObject, finalRowlenObject);
                XSSFClientAnchor anchor = new XSSFClientAnchor(colrowMap.get("dx1"), colrowMap.get("dy1"), colrowMap.get("dx2"), colrowMap.get("dy2"), colrowMap.get("col1"), colrowMap.get("row1"), colrowMap.get("col2"), colrowMap.get("row2"));
                anchor.setAnchorType(Integer.parseInt(iamgeData.get("type").toString()));
                BASE64Decoder decoder = new BASE64Decoder();
                byte[] decoderBytes = new byte[0];
                boolean flag = true;
                try {<!-- -->
                    if (iamgeData.get("src") != null) {<!-- -->
                        decoderBytes = decoder.decodeBuffer(iamgeData.get("src").toString().split(";base64,")[1]);
                        flag = iamgeData.get("src").toString().split(";base64,")[0].contains("png");
                    }
                } catch (IOException e) {<!-- -->
                    e.printStackTrace();
                }
                if (flag) {<!-- -->
                    patriarch.createPicture(anchor, wb.addPicture(decoderBytes, HSSFWorkbook.PICTURE_TYPE_PNG));
                } else {<!-- -->
                    patriarch.createPicture(anchor, wb.addPicture(decoderBytes, HSSFWorkbook.PICTURE_TYPE_JPEG));
                }
            }
        }
    }

    /**
     * 设置单元格
     * @param wb
     * @param sheet
     * @param jsonObjectList
     * @param columnlenObject
     * @param rowlenObject
     * @param defaultRowHeight
     * @param defaultColWidth
     */
    private static void setCellValue(XSSFWorkbook wb,XSSFSheet sheet,JSONArray jsonObjectList,JSONObject columnlenObject,JSONObject rowlenObject,short defaultRowHeight,short defaultColWidth) {<!-- -->
        for (int index = 0; index < jsonObjectList.size(); index++) {<!-- -->
            JSONObject object = jsonObjectList.getJSONObject(index);
            JSONObject jsonObjectValue = ((JSONObject) object.get("v"));
            System.out.println(jsonObjectValue.toJSONString());
            String value = "";
            String m = "";
            if (jsonObjectValue != null && jsonObjectValue.get("m") != null && jsonObjectValue.get("v") != null) {<!-- -->
                m = jsonObjectValue.get("m") + "";
                value = jsonObjectValue.get("v") + "";
            }
            if (sheet.getRow((int) object.get("r")) == null){<!-- -->
                sheet.createRow((int) object.get("r"));
            }
            XSSFRow row = sheet.getRow((int) object.get("r"));
            if (row.getCell((int) object.get("c")) == null){<!-- -->
                row.createCell((int) object.get("c"));
            }
            XSSFCell cell = row.getCell((int) object.get("c"));
            //设置单元格样式
            CellStyle cellStyle = ExcelUtils.createCellStyle(sheet,wb,jsonObjectValue);
            //如果单元格内容是数值类型,涉及到金钱(金额、本、利),则设置cell的类型为数值型,设置data的类型为数值类型
            XSSFDataFormat df = wb.createDataFormat(); // 此处设置数据格式
            Boolean isNumber = false;
            Boolean isString = false;
            Boolean isDate = false;
            SimpleDateFormat sdf = null;
            if (jsonObjectValue.get("ct") != null){<!-- -->
                cellStyle.setDataFormat(df.getFormat(((JSONObject) jsonObjectValue.get("ct")).getString("fa")));
                String t = ((JSONObject) jsonObjectValue.get("ct")).getString("t");
                if ("n".equals(t)){<!-- -->
                    isNumber = true;
                }
                if ("d".equals(t)){<!-- -->
                    isDate = true;
                }
                if ("s".equals(t)){<!-- -->
                    isString = true;
                }
            }
            if (isNumber){<!-- -->
                // 设置单元格格式
                cell.setCellStyle(cellStyle);
                cell.setCellType(XSSFCell.CELL_TYPE_NUMERIC);
                cell.setCellValue(m);
            }
            else if (isDate){<!-- -->
                String fa = ((JSONObject) jsonObjectValue.get("ct")).getString("fa");
                if (fa.contains("AM/PM")){<!-- -->
                    sdf =  new SimpleDateFormat(fa.replaceAll("AM/PM","aa"), Locale.ENGLISH);
                }else {<!-- -->
                    sdf = new SimpleDateFormat(fa);
                }
                try {<!-- -->
                    Date date = sdf.parse(m);
                    cell.setCellStyle(cellStyle);
                    cell.setCellType(XSSFCell.CELL_TYPE_NUMERIC);
                    cell.setCellValue(date);
                } catch (ParseException e) {<!-- -->
                    e.printStackTrace();
                }
            }
            else if (isString){<!-- -->
                // 设置单元格格式
                cell.setCellStyle(cellStyle);
                cell.setCellType(XSSFCell.CELL_TYPE_STRING);
                cell.setCellValue(m);
            }else {<!-- -->
                //设置单元格格式
                cell.setCellStyle(cellStyle);
                cell.setCellValue(m);
            }
            //设置公式
            if (jsonObjectValue.get("f") != null){<!-- -->
                cell.setCellFormula(jsonObjectValue.get("f").toString().substring(1));
            }
            //设置批注
            if (jsonObjectValue.get("ps") != null){<!-- -->
                XSSFDrawing p = sheet.createDrawingPatriarch();
                //后四个坐标待定
                //前四个参数是坐标点,后四个参数是编辑和显示批注时的大小.
                JSONObject ps = (JSONObject)jsonObjectValue.get("ps");
                Map<String, Integer> colrowMapPS = getColRowMap(ps,defaultRowHeight,defaultColWidth, columnlenObject, rowlenObject);
                XSSFClientAnchor anchor = new XSSFClientAnchor(colrowMapPS.get("dx1"), colrowMapPS.get("dy1"), colrowMapPS.get("dx2"), colrowMapPS.get("dy2"), colrowMapPS.get("col1"), colrowMapPS.get("row1"), colrowMapPS.get("col2"), colrowMapPS.get("row2"));
                XSSFComment comment = p.createCellComment(anchor);
                // 输入批注信息
                comment.setString(new XSSFRichTextString(ps.getString("value")));
                // 添加状态
                comment.setVisible("true".equals(ps.getString("isshow")));
                // 将批注添加到单元格对象中
                cell.setCellComment(comment);
            }

        }
    }

    /**
     * 设置边框样式
     * @param borderInfoObjectList
     * @param sheet
     */
    private static void setBorder(JSONArray borderInfoObjectList, XSSFSheet sheet) {<!-- -->
        //设置边框样式map
        Map<Integer, BorderStyle> bordMap = new HashMap<>();
        bordMap.put(0, BorderStyle.NONE);
        bordMap.put(1, BorderStyle.THIN);
        bordMap.put(2, BorderStyle.HAIR);
        bordMap.put(3, BorderStyle.DOTTED);
        bordMap.put(4, BorderStyle.DASHED);
        bordMap.put(5, BorderStyle.DASH_DOT);
        bordMap.put(6, BorderStyle.DASH_DOT_DOT);
        bordMap.put(7, BorderStyle.DOUBLE);
        bordMap.put(8, BorderStyle.MEDIUM);
        bordMap.put(9, BorderStyle.MEDIUM_DASHED);
        bordMap.put(10, BorderStyle.MEDIUM_DASH_DOT);
        bordMap.put(11, BorderStyle.MEDIUM_DASH_DOT_DOTC);
        bordMap.put(12, BorderStyle.SLANTED_DASH_DOT);
        bordMap.put(13, BorderStyle.THICK);

        //一定要通过 cell.getCellStyle()  不然的话之前设置的样式会丢失
        //设置边框
        for (int i = 0; i < borderInfoObjectList.size(); i++) {<!-- -->
            JSONObject borderInfoObject = (JSONObject) borderInfoObjectList.get(i);
            if ("cell".equals(borderInfoObject.get("rangeType"))) {<!-- -->//单个单元格
                JSONObject borderValueObject = borderInfoObject.getJSONObject("value");

                JSONObject l = borderValueObject.getJSONObject("l");
                JSONObject r = borderValueObject.getJSONObject("r");
                JSONObject t = borderValueObject.getJSONObject("t");
                JSONObject b = borderValueObject.getJSONObject("b");


                int row = borderValueObject.getInteger("row_index");
                int col = borderValueObject.getInteger("col_index");

                XSSFCell cell = sheet.getRow(row).getCell(col);
                XSSFCellStyle xssfCellStyle = cell.getCellStyle();

                if (l != null) {<!-- -->
                    xssfCellStyle.setBorderLeft(bordMap.get((int) l.get("style"))); //左边框
                    XSSFColor color = toColorFromString(l.getString("color"));
                    xssfCellStyle.setLeftBorderColor(color);//左边框颜色
                }
                if (r != null) {<!-- -->
                    xssfCellStyle.setBorderRight(bordMap.get((int) r.get("style"))); //右边框
                    XSSFColor color=toColorFromString(r.getString("color"));
                    xssfCellStyle.setRightBorderColor(color);//右边框颜色
                }
                if (t != null) {<!-- -->
                    xssfCellStyle.setBorderTop(bordMap.get((int) t.get("style"))); //顶部边框
                    XSSFColor color=toColorFromString(t.getString("color"));
                    xssfCellStyle.setTopBorderColor(color);//顶部边框颜色
                }
                if (b != null) {<!-- -->
                    xssfCellStyle.setBorderBottom(bordMap.get((int) b.get("style"))); //底部边框
                    XSSFColor color=toColorFromString(b.getString("color"));
                    xssfCellStyle.setBottomBorderColor(color);
                }
                cell.setCellStyle(xssfCellStyle);
            } else if ("range".equals(borderInfoObject.get("rangeType"))) {<!-- -->//选区
                XSSFColor color=toColorFromString(borderInfoObject.getString("color"));
                int style_ = borderInfoObject.getInteger("style");

                JSONObject rangObject = (JSONObject) ((JSONArray) (borderInfoObject.get("range"))).get(0);

                JSONArray rowList = rangObject.getJSONArray("row");
                JSONArray columnList = rangObject.getJSONArray("column");


                for (int row_ = rowList.getInteger(0); row_ < rowList.getInteger(rowList.size() - 1) + 1; row_++) {<!-- -->
                    for (int col_ = columnList.getInteger(0); col_ < columnList.getInteger(columnList.size() - 1) + 1; col_++) {<!-- -->
                        if (sheet.getRow(row_) == null){<!-- -->
                            sheet.createRow(row_);
                        }
                        if (sheet.getRow(row_).getCell(col_) == null){<!-- -->
                            sheet.getRow(row_).createCell(col_);
                        }
                        XSSFCell cell = sheet.getRow(row_).getCell(col_);
                        XSSFCellStyle xssfCellStyle = cell.getCellStyle();
                        xssfCellStyle.setBorderLeft(bordMap.get(style_)); //左边框
                        xssfCellStyle.setLeftBorderColor(color);//左边框颜色
                        xssfCellStyle.setBorderRight(bordMap.get(style_)); //右边框
                        xssfCellStyle.setRightBorderColor(color);//右边框颜色
                        xssfCellStyle.setBorderTop(bordMap.get(style_)); //顶部边框
                        xssfCellStyle.setTopBorderColor(color);//顶部边框颜色
                        xssfCellStyle.setBorderBottom(bordMap.get(style_)); //底部边框
                        xssfCellStyle.setBottomBorderColor(color);//底部边框颜色 }
                        cell.setCellStyle(xssfCellStyle);
                    }
                }


            }
        }
    }

    /**
     * 设置数据筛选
     * @param dataVerification 数据筛选规则
     * @param sheet
     */
    private static void settDataValidation(JSONObject dataVerification, XSSFSheet sheet) {<!-- -->
        DataValidationHelper helper = sheet.getDataValidationHelper();
        Map<String, Integer> opTypeMap = new HashMap<>();
        opTypeMap.put("bw",DVConstraint.OperatorType.BETWEEN);//"bw"(介于)
        opTypeMap.put("nb",DVConstraint.OperatorType.NOT_BETWEEN);//"nb"(不介于)
        opTypeMap.put("eq",DVConstraint.OperatorType.EQUAL);//"eq"(等于)
        opTypeMap.put("ne",DVConstraint.OperatorType.NOT_EQUAL);//"ne"(不等于)
        opTypeMap.put("gt",DVConstraint.OperatorType.GREATER_THAN);//"gt"(大于)
        opTypeMap.put("lt",DVConstraint.OperatorType.LESS_THAN);//lt"(小于)
        opTypeMap.put("gte",DVConstraint.OperatorType.GREATER_OR_EQUAL);//"gte"(大于等于)
        opTypeMap.put("lte",DVConstraint.OperatorType.LESS_OR_EQUAL);//"lte"(小于等于)
        opTypeMap.put("number",DVConstraint.ValidationType.ANY);//数字
        opTypeMap.put("number_integer",DVConstraint.ValidationType.INTEGER);//整数
        opTypeMap.put("number_decimal",DVConstraint.ValidationType.DECIMAL);//小数
        opTypeMap.put("text_length",DVConstraint.ValidationType.TEXT_LENGTH);//文本长度
        opTypeMap.put("date",DVConstraint.ValidationType.DATE);//日期
        if (dataVerification != null){<!-- -->
            Map<String, Object> dataVe=dataVerification.getInnerMap();
            for(Map.Entry<String, Object> dataEntry : dataVe.entrySet()) {<!-- -->
                String[] colRow = dataEntry.getKey().split("_");
                CellRangeAddressList dstAddrList = new CellRangeAddressList(Integer.parseInt(colRow[0]), Integer.parseInt(colRow[0]), Integer.parseInt(colRow[1]), Integer.parseInt(colRow[1]));// 规则一单元格范围
                JSONObject dataVeValue = (JSONObject) dataEntry.getValue();
                DataValidation dstDataValidation = null;
                if ("dropdown".equals(dataVeValue.getString("type"))){<!-- -->
                    if(dataVeValue.getString("value1").contains(",")){<!-- -->
                        String[] textlist = dataVeValue.getString("value1").split(",");
                        dstDataValidation = helper.createValidation(helper.createExplicitListConstraint(textlist), dstAddrList);
                    }else {<!-- -->
                        dstDataValidation = helper.createValidation(helper.createFormulaListConstraint(dataVeValue.getString("value1")), dstAddrList);
                    }
                }
                if ("checkbox".equals(dataVeValue.getString("type"))){<!-- -->
                     TODO: 2020/11/30
                }
                if ("number".equals(dataVeValue.getString("type"))){<!-- -->
                    //number判断是整数还是小数
                    Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
                    Boolean booleanValue1 = false;
                    Boolean booleanValue2 = false;
                    booleanValue1 = pattern.matcher(dataVeValue.getString("value1")).matches();
                    booleanValue2 = pattern.matcher(dataVeValue.getString("value2")).matches();
                    DataValidationConstraint dvc = null;
                    if (booleanValue1 && booleanValue2){<!-- -->
                        dvc = helper.createIntegerConstraint(opTypeMap.get(dataVeValue.getString("type2")), dataVeValue.getString("value1"), dataVeValue.getString("value2"));
                    }else {<!-- -->
                        dvc = helper.createDecimalConstraint(opTypeMap.get(dataVeValue.getString("type2")), dataVeValue.getString("value1"), dataVeValue.getString("value2"));
                    }
                    dstDataValidation = helper.createValidation(dvc, dstAddrList);
                }
                if ("number_integer".equals(dataVeValue.getString("type"))
                        ||"number_decimal".equals(dataVeValue.getString("type"))
                        ||"text_length".equals(dataVeValue.getString("type"))){<!-- -->
                    DataValidationConstraint dvc = helper.createNumericConstraint(opTypeMap.get(dataVeValue.getString("type")), opTypeMap.get(dataVeValue.getString("type2")), dataVeValue.getString("value1"), dataVeValue.getString("value2"));
                    dstDataValidation = helper.createValidation(dvc, dstAddrList);
                }
                if ("date".equals(dataVeValue.getString("type"))){<!-- -->
                    //日期
                    DataValidationConstraint dvc = new XSSFDataValidationConstraint(opTypeMap.get(dataVeValue.getString("type")), opTypeMap.get(dataVeValue.getString("type2")), dataVeValue.getString("value1"), dataVeValue.getString("value2"));
                    dstDataValidation = helper.createValidation(dvc, dstAddrList);
                }
                if ("text_content".equals(dataVeValue.getString("type"))){<!-- -->
                    // TODO: 2020/11/30

                }
                if ("validity".equals(dataVeValue.getString("type"))){<!-- -->
                    // TODO: 2020/12/1
                }
                dstDataValidation.createPromptBox("提示:", dataVeValue.getString("hintText"));
                dstDataValidation.setShowErrorBox(dataVeValue.getBoolean("prohibitInput"));
                dstDataValidation.setShowPromptBox(dataVeValue.getBoolean("hintShow"));
                sheet.addValidationData(dstDataValidation);
            }
        }
//        CellReference cr = new CellReference("A1");
    }


}

其他资料参考:
1.使用exceljs导出luckysheet表格:https://blog.csdn.net/csdn_lsy/article/details/107179708
2.Luckysheet文档:https://mengshukeji.github.io/LuckysheetDocs/zh/guide/sheet.html
3.官方github issues:https://github.com/mengshukeji/Luckysheet/issues
4.Luckysheet导出实现 - Java后台处理:https://blog.csdn.net/u014632228/article/details/109738221