• Java实现Excel导入导出


    一、导入

    前言:导入必须用post请求

    具体原因在2中叙述

    1、Excel导入

    总结一下目标,就是要将excel中的数据行、逐一提取,最后得到一个list,这个list的每个元素就是excel的每个数据行的实例,之后的操作就是常规的java逻辑处理了。

    可以把这个过程分为三步:

    1)接收数据
    后台使用 MultipartFile 接收文件数据(这里复习一下,springmvc接收参数的几种方式)。

    前端如果是前后端分离项目我们不用管,
    如果是jsp项目可以用文件标签传参。

    2)提取数据
    提取数据的底层是用IO流实现的,我们这里使用封装好的工具类。excel工具类有很多、很多,我一般是使用适配性最好的,不然一会儿springboot项目、一会儿spring项目等等,还得换不同的工具类;效率什么的不是首要考虑项。
    使用工具类后,我们就得到了一个List>:Excel的每个数据行组成一个List,多个数据行就组成了List>

    这里有一个小坑,说明一下;有时候你导入的数据,如果是数字比如32位的卡号等等,用工具类提取出来成了科学计数法、或者后面加了小数点;这就说明你用的这个工具类没有将数字类型数据进行处理,你需要在工具类中找到数字类型,添加toText()方法。
    当然你也可以使用我后面提供的工具类,这个问题已经作了处理。

    3)将list的元素处理成实例对象,方便后续处理
    在作转换的时候,还可以加一些校验、限制,比如限制excel导入总行数不得超过多少、限制某列参数不能重复等等。

    下面提供一下我用的excel导入工具类,springboot或者spring项目都可以用

    public class ImportExeclUtil {
    
        private static int totalRows = 0;// 总行数
    
        private static int totalCells = 0;// 总列数
    
        private static String errorInfo;// 错误信息
    
        /** 无参构造方法 */
        public ImportExeclUtil()
        {
        }
    
        public static int getTotalRows()
        {
            return totalRows;
        }
    
        public static int getTotalCells()
        {
            return totalCells;
        }
    
        public static String getErrorInfo()
        {
            return errorInfo;
        }
    
        /**
         *
         * 根据流读取Excel文件
         *
         *
         * @param inputStream
         * @param isExcel2003
         * @return
         * @see [类、类#方法、类#成员]
         */
        public List<List<String>> read(InputStream inputStream, boolean isExcel2003)
                throws IOException
        {
    
            List<List<String>> dataLst = null;
    
            /** 根据版本选择创建Workbook的方式 */
            Workbook wb = null;
    
            if (isExcel2003)
            {
                wb = new HSSFWorkbook(inputStream);
            }
            else
            {
                wb = new XSSFWorkbook(inputStream);
            }
            dataLst = readDate(wb);
    
            return dataLst;
        }
    
        /**
         *
         * 读取数据
         *
         * @param wb
         * @return
         * @see [类、类#方法、类#成员]
         */
        private List<List<String>> readDate(Workbook wb)
        {
    
            List<List<String>> dataLst = new ArrayList<List<String>>();
    
            /** 得到第一个shell */
            Sheet sheet = wb.getSheetAt(0);
    
            /** 得到Excel的行数 */
            totalRows = sheet.getPhysicalNumberOfRows();
    
            /** 得到Excel的列数 */
            if (totalRows >= 1 && sheet.getRow(0) != null)
            {
                totalCells = sheet.getRow(0).getPhysicalNumberOfCells();
            }
    
            /** 循环Excel的行 */
            for (int r = 1; r < totalRows; r++)
            {
                Row row = sheet.getRow(r);
                if (row == null)
                {
                    continue;
                }
    
                List<String> rowLst = new ArrayList<String>();
    
                /** 循环Excel的列 */
                for (int c = 0; c < getTotalCells(); c++)
                {
    
                    Cell cell = row.getCell(c);
                    String cellValue = "";
    
                    if (null != cell)
                    {
                        // 以下是判断数据的类型
                        switch (cell.getCellTypeEnum())
                        {
                            case NUMERIC: // 数字
                                //如果是日期的话
                                if(cell != null && HSSFDateUtil.isCellDateFormatted(cell)){
                                    Date d = cell.getDateCellValue();
                                    DateFormat formater = new SimpleDateFormat("yyyy/MM/dd");
                                    String da = formater.format(d);
                                    cellValue = da;
                                    break;
                                }
                                cellValue = NumberToTextConverter.toText(cell.getNumericCellValue());
                                break;
    
                            case STRING: // 字符串
                                cellValue = cell.getStringCellValue();
                                break;
    
                            case BOOLEAN: // Boolean
                                cellValue = cell.getBooleanCellValue() + "";
                                break;
    
                            case FORMULA: // 公式
                                cellValue = cell.getCellFormula() + "";
                                break;
    
                            case BLANK: // 空值
                                cellValue = "";
                                break;
    
                            case ERROR: // 故障
                                cellValue = "非法字符";
                                break;
    
                            default:
                                cellValue = "未知类型";
                                break;
                        }
                    }
    
                    rowLst.add(cellValue);
                }
    
                /** 保存第r行的第c列 */
                dataLst.add(rowLst);
            }
    
            return dataLst;
        }
    
        /**
         *
         * 根据Excel表格中的数据判断类型得到值
         *
         * @param cell
         * @return
         * @see [类、类#方法、类#成员]
         */
        /*private static String getCellValue(Cell cell)
        {
            String cellValue = "";
    
            if (null != cell)
            {
                // 以下是判断数据的类型
                switch (cell.getCellType())
                {
                    case HSSFCell.CELL_TYPE_NUMERIC: // 数字
                        ;: // 数字
                        if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell))
                        {
                            Date theDate = cell.getDateCellValue();
                            SimpleDateFormat dff = new SimpleDateFormat("yyyy-MM-dd");
                            cellValue = dff.format(theDate);
                        }
                        else
                        {
                            DecimalFormat df = new DecimalFormat("0");
                            cellValue = df.format(cell.getNumericCellValue());
                        }
                        break;
                    case HSSFCell.CELL_TYPE_STRING: // 字符串
                        cellValue = cell.getStringCellValue();
                        break;
    
                    case HSSFCell.CELL_TYPE_BOOLEAN: // Boolean
                        cellValue = cell.getBooleanCellValue() + "";
                        break;
    
                    case HSSFCell.CELL_TYPE_FORMULA: // 公式
                        cellValue = cell.getCellFormula() + "";
                        break;
    
                    case HSSFCell.CELL_TYPE_BLANK: // 空值
                        cellValue = "";
                        break;
    
                    case HSSFCell.CELL_TYPE_ERROR: // 故障
                        cellValue = "非法字符";
                        break;
    
                    default:
                        cellValue = "未知类型";
                        break;
                }
    
            }
            return cellValue;
        }*/
    
        /**
         *
         * 根据实体成员变量的类型得到成员变量的值
         *
         * @param realValue
         * @param fields
         * @param f
         * @param cellValue
         * @return
         * @see [类、类#方法、类#成员]
         */
        private static Object getEntityMemberValue(Object realValue, Field[] fields, int f, String cellValue)
        {
            String type = fields[f].getType().getName();
            switch (type)
            {
                case "char":
                case "java.lang.Character":
                case "java.lang.String":
                    realValue = cellValue;
                    break;
                case "java.util.Date":
                    realValue = StringUtils.isBlank(cellValue) ? null : DateUtil.strToDate(cellValue, DateUtil.YYYY_MM_DD);
                    break;
                case "java.lang.Integer":
                    realValue = StringUtils.isBlank(cellValue) ? null : Integer.valueOf(cellValue);
                    break;
                case "int":
                case "float":
                case "double":
                case "java.lang.Double":
                case "java.lang.Float":
                case "java.lang.Long":
                case "java.lang.Short":
                case "java.math.BigDecimal":
                    realValue = StringUtils.isBlank(cellValue) ? null : new BigDecimal(cellValue);
                    break;
                default:
                    break;
            }
            return realValue;
        }
    
        /**
         *
         * 根据路径或文件名选择Excel版本
         *
         *
         * @param filePathOrName
         * @param in
         * @return
         * @throws IOException
         * @see [类、类#方法、类#成员]
         */
        public static Workbook chooseWorkbook(String filePathOrName, InputStream in)
                throws IOException
        {
            /** 根据版本选择创建Workbook的方式 */
            Workbook wb = null;
            boolean isExcel2003 = ExcelVersionUtil.isExcel2003(filePathOrName);
    
            if (isExcel2003)
            {
                wb = new HSSFWorkbook(in);
            }
            else
            {
                wb = new XSSFWorkbook(in);
            }
    
            return wb;
        }
    
        static class ExcelVersionUtil
        {
    
            /**
             *
             * 是否是2003的excel,返回true是2003
             *
             *
             * @param filePath
             * @return
             * @see [类、类#方法、类#成员]
             */
            public static boolean isExcel2003(String filePath)
            {
                return filePath.matches("^.+\\.(?i)(xls)$");
    
            }
    
            /**
             *
             * 是否是2007的excel,返回true是2007
             *
             *
             * @param filePath
             * @return
             * @see [类、类#方法、类#成员]
             */
            public static boolean isExcel2007(String filePath)
            {
                return filePath.matches("^.+\\.(?i)(xlsx)$");
    
            }
    
        }
    
        public static class DateUtil
        {
    
            // ======================日期格式化常量=====================//
    
            public static final String YYYY_MM_DDHHMMSS = "yyyy-MM-dd HH:mm:ss";
    
            public static final String YYYY_MM_DD = "yyyy-MM-dd";
    
            public static final String YYYY_MM = "yyyy-MM";
    
            public static final String YYYY = "yyyy";
    
            public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
    
            public static final String YYYYMMDD = "yyyyMMdd";
    
            public static final String YYYYMM = "yyyyMM";
    
            public static final String YYYYMMDDHHMMSS_1 = "yyyy/MM/dd HH:mm:ss";
    
            public static final String YYYY_MM_DD_1 = "yyyy/MM/dd";
    
            public static final String YYYY_MM_1 = "yyyy/MM";
    
            /**
             *
             * 自定义取值,Date类型转为String类型
             *
             * @param date 日期
             * @param pattern 格式化常量
             * @return
             * @see [类、类#方法、类#成员]
             */
            public static String dateToStr(Date date, String pattern)
            {
                SimpleDateFormat format = null;
    
                if (null == date)
                    return null;
                format = new SimpleDateFormat(pattern, Locale.getDefault());
    
                return format.format(date);
            }
    
            /**
             * 将字符串转换成Date类型的时间
             * 
    * * @param s 日期类型的字符串
    * datePattern :YYYY_MM_DD
    * @return java.util.Date */
    public static Date strToDate(String s, String pattern) { if (s == null) { return null; } Date date = null; SimpleDateFormat sdf = new SimpleDateFormat(pattern); try { date = sdf.parse(s); } catch (ParseException e) { e.printStackTrace(); } return date; } } }
    • 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

    再提供一个应用实例

    	@ApiOperation(value = "以导入excel方式,上传要申请学分的用户")
        @GetMapping(value = "/uuApplyUserInfo")
        public AjaxResult uuApplyUserInfo(@RequestParam(value = "files",required = false) MultipartFile files) {
            try {
                //工具类
                ImportExeclUtil readExcelUtil = new ImportExeclUtil();
                List<List<String>> read = readExcelUtil.read(files.getInputStream(), true);
    
                if (CollectionUtils.isNotEmpty(read)){
    
                    List<ApplyCreditUserDto> importList = read.stream().map(e -> {
                        ApplyCreditUserDto importDto = new ApplyCreditUserDto();
                        importDto.setUserName(e.get(0));
                        importDto.setCreditCardNo(e.get(1));
                        importDto.setCreditCardPwd(e.get(2));
                        return importDto;
                    }).collect(Collectors.toList());
    
                    if (CollectionUtils.isEmpty(importList)){
                        return AjaxResult.error("不能导入空文件");
                    }
    
                    //最多导入1W条
                    final int maxInt = 10000;
                    if (importList.size() > maxInt){
                        return AjaxResult.error("导入最多修改1W条");
                    }
    
                    List<String> orderIds = importList.stream()
                            .map(ApplyCreditUserDto::getUserName)
                            .distinct()
                            .collect(Collectors.toList());
                    if (!Objects.equals(orderIds.size(),importList.size())){
                        return AjaxResult.error("导入信息中,有用户");
                    }
    
                    //调用业务层
                    return applyCreditLogService.uuApplyUserInfo(importList);
    
                }else{
                    return AjaxResult.error("不能导入空文件");
                }
    
            } catch (Exception e) {
                e.printStackTrace();
                return AjaxResult.error("导入失败,更新数据库时报错!报错信息:" + e.toString());
            }
        }
    
    • 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

    2、开发中遇到的问题

    1)报错"Unable to process parts as no multi-part configuration has been provided "

    报错信息截取
    “MultipartException: Could not parse multipart servlet request; nested exception is java.lang.IllegalStateException: Unable to process parts as no multi-part configuration has been provided
    a、如果你在网上搜这个问题,搜到的回答大多是让你在servlet配置中加配置

    <multipart-config>
    	<max-file-size>20848820</max-file-size>
    	<max-request-size>418018841</max-request-size>
    	<file-size-threshold>1048576</file-size-threshold>
    </multipart-config>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    b、但是采用这个答案前,你要看你的项目是否适用上述情况。
    SpringMVC处理multipart请求(解析文件请求),有两种实现:CommonsMultipartResolver和StandardServletMultipartResolver。
    他们的区别我这里不作详细叙述,就讲一点:
    在servlet中配置,是StandardServletMultipartResolver的配置方式;
    而CommonsMultipartResolver的配置方式,是在applicationContext中配置

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="defaultEncoding" value="UTF-8" />
        <property name="maxUploadSize" value="31457280" />
        <property name="maxInMemorySize" value="4194304" />
    </bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    两种配置的目标基本一致,但是配置位置、对象不一样,搞混了不仅解决不了问题,还会导致其他问题。
    c、我这样说,是因为上传文件是基础配置,对于已经运行很久的项目,上传配置前辈们应该早已配置完好,后来人遇到的问题,大多不是缺少“基础”配置引起的,望大家谨慎修改。
    d、回到的我的问题,项目采用的是CommonsMultipartResolver解析文件流,我给大家看一下我发现问题的过程:
    请求来了先去MultipartFilter过滤器,检测请求是否为包含文件流的请求,打断点可以看到
    在这里插入图片描述
    我不知道人家业务逻辑是咋处理的,只能step over一步一步往下运行,走到下图这里我大概明白了一点
    在这里插入图片描述
    这里是判断这个请求是否为“multipart”类型请求,也就是判断是否需要专门解析文件流的部件出手,结果我这儿走到了else里边!
    说明检测结论是,我的请求不是multipart请求,或者不符合人家的规范;
    于是我重新请求,进入它的判断方法multipartResolver.isMultipart(processedRequest)
    里边是

    	@Override
    	public boolean isMultipart(HttpServletRequest request) {
    		return (request != null && ServletFileUpload.isMultipartContent(request));
    	}
    
    • 1
    • 2
    • 3
    • 4

    又一层判断,接着往里边方法看ServletFileUpload.isMultipartContent(request))
    在这里插入图片描述
    看到这里,我才看明白,人家要求请求必须是Post请求,我尼玛!浪费足足一天时间啊。

    之所以没记住这个限制,是因为“知其然而不知其所以然”,以前只是知道、听说过,但不知道为什么。
    其实原因很简单,get请求有大小限制,所以上传功能需要用post请求。
    get请求有大小限制这种说法其实也不准确,其实http协议对get请求没有大小、长度限制,限制产生在浏览器和服务器。
    服务器一般限制get请求大小在8kb以内;
    而浏览器又随型号不通、限制也各不相同,MSIE和Safari的长度限制是2kb,Opear是4kb,Firefox是8KB…
    这也解释了,为什么我搜“get请求大小限制是多少”这个问题,回答都各不一样,大家都是“知其然而不知其所以然”、得过且过、断章取义、管中窥豹,我们这种得过且过的态度,就会使本来简单的问题变得越来越复杂,因为它本身已经叠加了太多其他地方的问题。

    根据浏览器限制不同,为了保险你可以取限制最小值2kb,然后说“get请求大小限制为2kb”;
    又因为一般浏览器限制在4kb,所以又可以说“get请求大小限制为4kb”;
    又又因为实际http协议对get请求没有限制,所以有人说“get请求没有大小限制”。。。

    嗟乎!希望我们程序员,对自己写的技术类文档,都适当严谨一些,这样才能营造出更好的社区环境。

    二、导出

    前言

    导出excel可以分为两类:
    一类是导出excel,里边有我们查询的数据,多用于导出数据;
    另一类是导出excel文件,多用于导出模板、而且对模板格式有要求,这时我们提前建一个模板文件,然后存到服务器,导出的时候直接把这个文件传给用户,这种方法其实已经无所谓是什么格式的文件了。

    为了方便描述,我们把第一类叫导出excel,第二类叫导出excel模板

    1、导出excel

    实际运用示例:

        @PostMapping("/export")
        @ResponseBody
        public void export(HttpServletResponse response, @RequestBody JcWecomTag param){
            // 设置response的上下文类型
            response.setContentType("octets/stream");
            String excelName = "标签数据";
            try {
                // 创建一个文件对象
                HSSFWorkbook workbook = new HSSFWorkbook();
                // 用文件对象创建一个sheet页,并给sheet页命名
                HSSFSheet sheet0 = workbook.createSheet("标签");
                // 用sheet对象创建一个行对象
                HSSFRow rowm0 = sheet0.createRow(0);
    
                // 用行对象创建单元格,给单元格赋值
                HSSFCell cellColName0 = rowm0.createCell(0);
                cellColName0.setCellType(CellType.STRING);
                HSSFRichTextString text0 = new HSSFRichTextString("标签ID");
                cellColName0.setCellValue(text0);
    
                HSSFCell cellColName1 = rowm0.createCell(1);
                cellColName1.setCellType(CellType.STRING);
                HSSFRichTextString text1 = new HSSFRichTextString("标签名称");
                cellColName1.setCellValue(text1);
    
                HSSFCell cellColName2 = rowm0.createCell(2);
                cellColName2.setCellType(CellType.STRING);
                HSSFRichTextString text2 = new HSSFRichTextString("标签分组ID");
                cellColName2.setCellValue(text2);
    
                HSSFCell cellColName3 = rowm0.createCell(3);
                cellColName3.setCellType(CellType.STRING);
                HSSFRichTextString text3 = new HSSFRichTextString("标签分组名称");
                cellColName3.setCellValue(text3);
    
                HSSFCell cellColName4 = rowm0.createCell(4);
                cellColName4.setCellType(CellType.STRING);
                HSSFRichTextString text4 = new HSSFRichTextString("bdp字典编码");
                cellColName4.setCellValue(text4);
    
                HSSFCell cellColName5 = rowm0.createCell(5);
                cellColName5.setCellType(CellType.STRING);
                HSSFRichTextString text5 = new HSSFRichTextString("bdp字典名称");
                cellColName5.setCellValue(text5);
    
                // 查数据
                List<JcWecomTag> tagList = wecomTagService.mulitQueryTag(param);
    
                // 将查询到的数据设置到sheet对应的单元格中
                for (int i = 0; i < tagList.size(); i++) {
                    JcWecomTag tag = tagList.get(i);
                    HSSFRow row = sheet0.createRow(i + 1);// 创建所需的行数
                    HSSFCell cell = null;
    
                    cell = row.createCell(0, CellType.STRING);
                    cell.setCellValue(tag.getTagId());
    
                    cell = row.createCell(1, CellType.STRING);
                    cell.setCellValue(tag.getTagName());
    
                    cell = row.createCell(2, CellType.STRING);
                    cell.setCellValue(tag.getTagGroupId());
    
                    cell = row.createCell(3, CellType.STRING);
                    cell.setCellValue(tag.getTagGroupName());
    
                    cell = row.createCell(4, CellType.STRING);
                    cell.setCellValue(tag.getDicCode());
                }
    
                // 转码防止乱码
                response.addHeader("Content-Disposition", "attachment;filename="
                        + new String(excelName.getBytes("UTF-8"), "ISO8859-1")
                        + ".xls");
                OutputStream out = response.getOutputStream();
                ExcelUtil.writeBySheetAndRow(workbook, out);
                out.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    • 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

    1)示例是SpringMVC项目,Controller接口必须加@ResponseBody注解,否则返回值会被SpringMVC视为视图、会报404错误;

    2)最后用到了一个excel工具ExcelUtil.writeBySheetAndRow(workbook, out);

    这个工具去网上搜一下就行(估计你们项目本身就有)。导出功能的核心是:配置好Excel工作簿对象HSSFWorkbook ,对象包含标题行、数据行、单元格数据;以及配置好输出流OutputStream;这两个的配置,如上面示例所示配置即可。
    这两个对象都弄好之后,剩下的、一般Excel工具类都能处理,不用担心。

    2、使用自定义注解-导出excel

    1)引入依赖

    这里用的是poi导出excel,版本如下

    <!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
          <dependency>
              <groupId>org.apache.poi</groupId>
              <artifactId>poi</artifactId>
              <version>4.1.1</version>
          </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2)自定义注解

    为了方便,提高复用效率,这里自定义2个注解;
    第一个:@EnableExcel,用来开启Excel表格的导出,用在装导出数据的实体类上;

    /**
     *  标记类是否开启Excel
     * @Author: Sunlong
     * @date: 2020/5/10 20:29
     */
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface EnableExcel {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    第二个:@ExcelRow,用在装导出数据的实体类的属性上,用来映射字段与excel的对应关系;

    /**
     *  excel 表格 列名注解
     *
     * @author sunlong
     */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ExcelRow {
    
        /**
         *  Excel 对应列名
         * @return
         */
        String name();
    
        /**
         *  excel 列名备注
         * @return
         */
        String note() default "";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    3)代码逻辑—提取导出工具类

    a、通过反射获取自定义注解EnableExcel 判断是否开启Excel导出

    b、通过反射获取自定义注解ExcelRow 获取列对应的属性

    c、把属性对应的列下标取出来,属性名做为key,下标做为value放到map中

    d、遍历要导出的数据集合,通过属性描述器PropertyDescriptor获取对应属性下标及属性值并设置到cell单元格中

    还是为了方便,已经提高复用效率,我们将上述代码提取成一个工具类,如下:

    public class ExportExcelUtils {
    
        /**
         *  workbook
         * @param titleList
         * @return
         */
        public static HSSFWorkbook getWorkBook(List<String> titleList){
            //第一步,创建一个workbook,对应一个Excel文件
            HSSFWorkbook wb = new HSSFWorkbook();
            // 一个sheet
            HSSFSheet sheet = wb.createSheet("sheet1");
    
            HSSFRow rowTitle = sheet.createRow(0); // 第一行 标题
    
            // 设置标题
            for (int i = 0; i < titleList.size(); i++) {
                HSSFCell cell = rowTitle.createCell(i);
                cell.setCellValue(titleList.get(i));
            }
            //合并单元格CellRangeAddress构造参数依次表示起始行,截至行,起始列, 截至列
            /*sheet.addMergedRegion(new CellRangeAddress(0,0,0,4));
            sheet.addMergedRegion(new CellRangeAddress(titleList.size()-1,titleList.size()-1,titleList.size()-1,titleList.size()+1));*/
            return wb;
        }
    
    
        public static <T> HSSFWorkbook getWorkBook(List<String> titleList , List<T> dataList) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
            if (CollectionUtils.isNotEmpty(dataList)) {
                T t1 = dataList.get(0);
                Class<?> t1Class = t1.getClass();
                EnableExcel enableExcel = t1Class.getAnnotation(EnableExcel.class);
                if (enableExcel == null) {
                    throw new IllegalArgumentException("EnableExcel 注解没有在实体类启用");
                }
                Field[] fields = t1Class.getDeclaredFields();
                if (fields != null && fields.length > 0) {
                    Map<String , Integer> titleMap = new HashMap<>(titleList.size()); // 存放属性名称对应的下标
    
                    int fieldExcelSize = 0; // 类中ExcelRow 注解的数量
                    for (Field field : fields) {
                        field.setAccessible(true);
                        String fieldName = field.getName();
                        ExcelRow excelRow = field.getAnnotation(ExcelRow.class);
                        if (excelRow != null) {
                            String name = excelRow.name();
                            if (StringUtils.isEmpty(name)) {
                                throw new IllegalArgumentException("ExcelRow 注解name属性不能为空");
                            }
    
                            int index = titleList.indexOf(name.trim());
                            if (index != -1) {
                                fieldExcelSize++;
                                titleMap.put(fieldName , index);
                            }
                        }
                    }
    
                    if (!(titleList.size() == fieldExcelSize)) {
                        throw new IllegalArgumentException("ExcelRow 注解name属性对应的列数不对");
                    }
    
                    HSSFWorkbook workBook = getWorkBook(titleList);
                    HSSFSheet sheet = workBook.getSheetAt(0);
    
                    for (T t : dataList) {
                        int lastRowNum = sheet.getLastRowNum();
                        HSSFRow row = sheet.createRow(lastRowNum + 1);
                        BeanInfo beanInfo = Introspector.getBeanInfo(t.getClass());
                        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
                        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
                            String fieldName = propertyDescriptor.getName();
                            if (titleMap.containsKey(fieldName)) {
                                Method readMethod = propertyDescriptor.getReadMethod();
                                if (readMethod != null) {
                                    Class<?> returnType = readMethod.getReturnType();
                                    String simpleName = returnType.getSimpleName();
    
                                    Object invoke = readMethod.invoke(t);
                                    String value = "";
                                    // 可以根据不同的类型返回不同的数据
                                    if ("date".equalsIgnoreCase(simpleName)) {
                                        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                        if (invoke != null) {
                                            value = simpleDateFormat.format(invoke);
                                        }
                                    }
                                    if (invoke != null && "".equals(value)) {
                                        value = invoke.toString();
                                    }
                                    row.createCell(titleMap.get(fieldName)).setCellValue(value);
                                }
                            }
                        }
                    }
                    return workBook;
                }
            }
            return null;
        }
    }
    
    • 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

    4)应用实例

    创建一个用来装导出数据的类(为了不与项目其他功能冲突,我一般都是新建一个专门做导出的实体类)

    @EnableExcel
    @Data
    public class UserEntity {
    
        @ExcelRow(name = "name")
        private String username;
    
        @ExcelRow(name = "pass")
        private String password;
    
        @ExcelRow(name = "date")
        private Date createDate;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    模拟导出功能:

    public class Test {
        public static void main(String[] args) throws IllegalAccessException, IntrospectionException, InvocationTargetException, IOException {
    
            List<String> titleList = new ArrayList<>();
            titleList.add("name");
            titleList.add("pass");
            titleList.add("date");
    
            List<UserEntity> userEntities = new ArrayList<>();
            for (int i = 0; i < 10; i++) {
                UserEntity userEntity1 = new UserEntity();
                userEntity1.setUsername("username"+i);
                userEntity1.setPassword("password"+i);
                userEntity1.setCreateDate(new Date());
                userEntities.add(userEntity1);
            }
    
            HSSFWorkbook workBook = ExportExcelUtils.getWorkBook(titleList, userEntities);
            if (workBook != null) {
                File file = new File("D:\\test_export.xlsx");
                workBook.write(file);
            }
            
        }
    }
    
    • 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

    3、使用easyPOI–导出excel

    1)easyPOI简介

    easyPOI是一个以Apache poi为基础的工具包、一款开源框架,用于实现excel,word,pdf的导入导出;开发者为Lemur。

    特性
    基于注解的导入导出,修改注解就可以修改Excel
    支持常用的样式自定义
    基于map可以灵活定义的表头字段
    支持一对多的导入、导出
    支持模板的导出,一些常见的标签,自定义标签
    支持HTML/Excel转换
    支持word的导出,支持图片,Excel

    2)导出Excel使用实例

    a)添加依赖
    		<dependency>
                <groupId>cn.easyproject</groupId>
                <artifactId>orai18n</artifactId>
            </dependency>
    
    • 1
    • 2
    • 3
    • 4

    需要注意的是由于easypoi的依赖内部依赖原生的poi,所以,引入了easypoi的依赖之后,需要把原生的poi的依赖删掉

    b)需要引入一个easyPoi导入导出工具类
    /**
     * 描述:easyPoi导入导出类
     * @author 梅西库里RNG
     */
    @Slf4j
    public class EasyPoiExcelUtil {
    
        public static String dictColIndex="colIndex";
        public static String dictColValue="colDicts";
    
        /**
         * 常用普通导出
         * @param list
         * @param sheetName
         * @param pojoClass
         * @return
         */
        public static Workbook exportExcel(List<?> list, String sheetName,Class<?> pojoClass) {
            return exportExcel(list,sheetName,pojoClass,null);
        }
    
        /**
         * 常用普通导出 带字典
         * @param list
         * @param sheetName
         * @param pojoClass
         * @param dicts
         * @return
         */
        public static Workbook exportExcel(List<?> list, String sheetName,Class<?> pojoClass,List<Map<String,Object>> dicts) {
            return exportExcel(list,null,sheetName,pojoClass,true,dicts);
        }
    
        /**
         * 常用普通导入
         * @auther zhangdongsheng
         * @param file
         * @param pojoClass
         * @param <T>
         * @return
         */
        public static <T> List<T> importExcel(MultipartFile file,Class<T> pojoClass) {
            return importExcel(file,0,1,pojoClass);
        }
    
    
        /**
         * 得到Workbook对象
         *
         * @param file
         * @return
         * @throws IOException
         */
        private static Workbook getWorkBook(MultipartFile file) throws IOException {
            //这样写  excel 能兼容03和07
            InputStream is = file.getInputStream();
            Workbook hssfWorkbook = null;
            try {
                hssfWorkbook = new HSSFWorkbook(is);
            } catch (Exception ex) {
                is = file.getInputStream();
                hssfWorkbook = new XSSFWorkbook(is);
            }
            return hssfWorkbook;
        }
    
        /**
         * 得到错误信息
         *
         * @param sb
         * @param list
         * @param i
         * @param obj
         * @param name 用哪个属性名去表明不和规定的数据
         * @param msg
         * @throws Exception
         */
        private static void getWrongInfo(StringBuilder sb, List list, int i, Object obj, String name, String msg) {
            Class clazz = obj.getClass();
            Object str = null;
            //得到属性名数组
            Field[] fields = clazz.getDeclaredFields();
            try{
                for (Field f : fields) {
                    if (f.getName().equals(name)) {
                        //用来得到属性的get和set方法
                        PropertyDescriptor pd = new PropertyDescriptor(f.getName(), clazz);
                        //得到get方法
                        Method getMethod = pd.getReadMethod();
                        str = getMethod.invoke(obj);
                    }
                }
                if (i == 0) {
                    sb.append(msg + str + ";");
                } else if (i == (list.size() - 1)) {
                    sb.append(str + "
    "
    ); } else { sb.append(str + ";"); } }catch (Exception e){ log.error("程序异常:{}",e); } } public static Workbook exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, boolean isCreateHeader,List<Map<String,Object>> dicts) { ExportParams exportParams = new ExportParams(); exportParams.setSheetName(sheetName); if (title!=null){ exportParams.setTitle(sheetName); } exportParams.setCreateHeadRows(isCreateHeader); return defaultExport(list, pojoClass, exportParams,dicts); } public static Workbook exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass) { return defaultExport(list, pojoClass, new ExportParams(title, sheetName,ExcelType.XSSF)); } public static Workbook exportExcel(List<Map<String, Object>> list) { return defaultExport(list); } private static Workbook defaultExport(List<?> list, Class<?> pojoClass, ExportParams exportParams) { return ExcelExportUtil.exportExcel(exportParams, pojoClass, list); } private static Workbook defaultExport(List<?> list, Class<?> pojoClass, ExportParams exportParams,List<Map<String,Object>> dicts) { int rowCnt=list!=null&&list.size()>0?list.size():0; Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, list); if(dicts!=null&&dicts.size()>0){ if(workbook!=null&&workbook.getNumberOfSheets()>0){ Sheet sheet =workbook.getSheetAt(0); if(rowCnt>0){ int curRow=1;//一般会带头部 从第1行开始 for (int i = 0; i < rowCnt; i++) { int firstRow=i+curRow; for(Map<String,Object> map:dicts) { int firstCol=(int)map.get(dictColIndex); String[] dict=(String[])map.get(dictColValue); CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(firstRow, firstRow, firstCol, firstCol); DVConstraint dvConstraint = DVConstraint.createExplicitListConstraint(dict); HSSFDataValidation dataValidation = new HSSFDataValidation(cellRangeAddressList, dvConstraint); sheet.addValidationData(dataValidation); } } } } } return workbook; } private static Workbook defaultExport(List<Map<String, Object>> list) { return ExcelExportUtil.exportExcel(list, ExcelType.XSSF); } private static <T> List<T> importExcel(String filePath, Integer titleRows, Integer headerRows, Class<T> pojoClass) { if (StringUtils.isBlank(filePath)) { return new ArrayList<>(); } ImportParams params = new ImportParams(); params.setTitleRows(titleRows); params.setHeadRows(headerRows); List<T> list = null; try { list = ExcelImportUtil.importExcel(new File(filePath), pojoClass, params); }catch (Exception e) { log.error("程序异常",e); } return list; } private static <T> List<T> importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Class<T> pojoClass) { if (file == null) { return new ArrayList<>(); } ImportParams params = new ImportParams(); params.setTitleRows(titleRows); params.setHeadRows(headerRows); List<T> list = null; try { list = ExcelImportUtil.importExcel(file.getInputStream(), pojoClass, params); } catch (Exception e) { log.error("程序异常",e); } return list; } /** * 根据接收的Excel文件来导入Excel,并封装成实体类 * * @param file 上传的文件 * @param titleRows 表标题的行数 * @param headerRows 表头行数 * @param pojoClass Excel实体类 */ private static <T> ExcelImportResult<T> importExcelVerify(MultipartFile file, Integer titleRows, Integer headerRows, Class<T> pojoClass) { if (ObjectUtil.isNull(file)) { return null; } ImportParams params = new ImportParams(); params.setTitleRows(titleRows); params.setHeadRows(headerRows); //是否开启校验 params.setNeedVerify(true); List<T> list = null; try { return ExcelImportUtil.importExcelMore(file.getInputStream(), pojoClass, params); } catch (Exception e) { log.error(">>> 导入数据异常:{}", e.getMessage()); return null; } } }
    • 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
    c)Controller方法
    	@ApiOperation("列表 导出")
        @PostMapping (value="/search/export")
        public void exportOrgList(HttpServletResponse response, @RequestBody CustomerVo customerVo) throws Exception {
        	//查询
            List<CustomerAdminVo> list = customerService.searchAdmin(customerVo);
    		//调用工具,生成workbook工作簿对象
            Workbook workbook=HysExcelUtil.exportExcel(list,"行政用户-列表",CustomerAdminVo.class);
    		//配置response对象
            response.setContentType("application/x-excel");
            response.setCharacterEncoding("UTF-8");
            response.setHeader("Content-Disposition","attachment; filename=customer_admin_export.xls");
    		//生成输出流对象,并把工作薄写入到输出流
            OutputStream oStream = response.getOutputStream();// 输出流
            workbook.write(oStream);//把工作薄写入到输出流
            //关闭流
            try {
                oStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    上面代码中的

    HysExcelUtil.exportExcel(list,"行政用户-列表",CustomerAdminVo.class);
    
    • 1

    第三个参数CustomerAdminVo.class,是用来设定导出excel的列名、列顺序、与数据的映射关系、列的宽度、日期格式等;最好给每一个导出模板,配一个独立的vo类,用以个性化配置。

    @ApiModel(value = "CustomerAdminVo", description = "用户")
    @Data
    public class CustomerAdminVo implements Serializable {
    
        private static final long serialVersionUID = -3477299713883180124L;
    
        @Excel(name = "账户名称", orderNum = "0", width = 30)
        @ApiModelProperty(value = "账户名称 不为空在账号表有记录",dataType ="String",required = true)
        private String accountName;
    
        @Excel(name = "真实姓名", orderNum = "1", width = 30)
        @ApiModelProperty(value = "真实姓名")
        private String realName;
    
        @Excel(name = "手机号码", orderNum = "2", width = 30)
        @ApiModelProperty(name = "mobilNumber",value = "手机号码",dataType ="String")
        private String mobilNumber;
    
    	@Excel(name = "添加时间", orderNum = "14", expertFormat =  "yyyy-MM-dd HH:mm:ss")
        private Date createTime;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    其中,用于设置上述内容的@Excel注解,就是easyPOI提供的注解

    import cn.afterturn.easypoi.excel.annotation.Excel;
    
    • 1

    注解的属性中,
    name 列名,orderNum 顺序,width 列宽,expertFormat 时间字段导出格式(不为空时,按指定格式格式化时间)

    d)导出结果

    在这里插入图片描述

    4、导出excel模板(其实导出word、pdf都可以,就是导出文件的方法)

    1)首先,文件要提前放在对应的位置,如下图:
    在这里插入图片描述
    2)导出的controller方法示例:

    @RequestMapping("/downloadTemp")
    public void downloadFile(HttpServletRequest request, HttpServletResponse response) throws Exception {
    		String fileName = "org_import.xls"; // 下载的文件名(前提:下载的文件需要存放在服务器对应的位置上)
            
            response.setContentType("text/html;charset=UTF-8");
            BufferedInputStream in = null;
            BufferedOutputStream out = null;
            request.setCharacterEncoding("UTF-8");
            String rootpath = request.getSession().getServletContext()
                    .getRealPath("/");
            try {
                File f = new File(rootpath + "res/" + fileName);//这里文件名,要和文件放的位置对应
                response.setContentType("application/x-excel");
                response.setCharacterEncoding("UTF-8");
                response.setHeader(
                        "Content-Disposition",
                        "attachment; filename="
                                + new String("机构导入.xls".getBytes("gbk"),
                                "iso-8859-1"));
                response.setHeader("Content-Length", String.valueOf(f.length()));
                in = new BufferedInputStream(new FileInputStream(f));
                out = new BufferedOutputStream(response.getOutputStream());
                byte[] data = new byte[1024];
                int len = 0;
                while (-1 != (len = in.read(data, 0, data.length))) {
                    out.write(data, 0, len);
                }
            } catch (Exception e) {
                out.write(e.toString().getBytes());
                e.printStackTrace();
            } finally {
                if (in != null) {
                    in.close();
                }
                if (out != null) {
                    out.close();
                }
            }
    
        }
    
    • 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
  • 相关阅读:
    python(进阶篇)——自动化操作Excel(xlrd和xlwt)
    【前端】CSS定位
    SpringBoot之yaml
    Python正则表达式
    APUS成为深圳市人工智能行业协会理事单位,CEO李涛受聘专家
    玩转 PI 系列-如何在 Rockchip Arm 开发板上安装 Docker Tailscale K3s Cilium?
    LeetCode单周赛第320场 && AcWing周赛第78场总结
    勒索软件频繁升级,了解常见勒索软件很有必要
    计算机毕业设计Java蛋糕网店(源码+系统+mysql数据库+lw文档)
    数据结构与算法设计分析—— 数据结构及常用算法
  • 原文地址:https://blog.csdn.net/Derek7117/article/details/127287322