java对Excel的导入导出基本工具

1、开篇

在开发中总是有需求是要导出某些系统数据以及向系统中批量获取数据,为了快速开发这些功能,减少做重复的工作,特此封装成了常用工具。

---需要引入的模块---

<!--RabbitMQ依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
<dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.10</version>
        </dependency>

2、数据导出模块

实现思路利用反射做到注解标识字段的汇聚,将需要导出的字段进行标记,这里用到mybatis的注解。当传入数据为空数据集合的时候可以当做模板导出。

public static void createExcel(HttpServletRequest request, HttpServletResponse response, Class clazz, List<?> list, String fileName){

        ExcelWriter writer = ExcelUtil.getWriter();
        // 获取当前类字段
        Field[] fields = clazz.getDeclaredFields();
        // 字段名称集合
        List < String > fieldNames = new ArrayList< >();
        // 字段中文名称集合(获取实体中@ApiModelProperty注解value的值)
        List < String > cnNames = new ArrayList< >();
        String mimeType = request.getServletContext().getMimeType(fileName);
        if (mimeType != null && !"".equals(mimeType)) {
            response.setContentType(mimeType);
        }
        for(Field field: fields) {
            if(!field.isAccessible()) {
                // 关闭反射访问安全检查,为了提高速度
                field.setAccessible(true);
            }
            String fieldName = field.getName();
            // 判断是否有@ApiModelProperty注解
            boolean annotationPresent = field.isAnnotationPresent(ApiModelProperty.class);
            if(annotationPresent && !"deFlag".equals(fieldName) && !"createUser".equals(fieldName)
                    && !"updateUser".equals(fieldName) && !"updateTime".equals(fieldName)) {
                ApiModelProperty annotation = field.getAnnotation(ApiModelProperty.class);
                fieldNames.add(fieldName);
                String name = annotation.value();
                cnNames.add(name);
            } else {
                //排除字段操作(如果为true,则不设置alias的字段将不被输出)
                writer.setOnlyAlias(true);
            }
        }
        String[] fs = fieldNames.toArray(new String[0]);
        String[] ns = cnNames.toArray(new String[0]);
        for(int i = 0; i < ns.length; i++) {
            // 设置表头及字段名
            writer.addHeaderAlias(fs[i], ns[i]);
        }
        // 自动换行
        Workbook workbook = writer.getWorkbook();
        StyleSet styleSet = new StyleSet(workbook);
        styleSet.setWrapText();
        writer.setStyleSet(styleSet);
        writer.write(list, true);

        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()){
            for(int i = 0; i < fieldNames.size(); i++) {
                writer.setColumnWidth(i, 23);
            }
            writer.flush(baos, true);
            writer.close();
            StaticFileUtils.loadToStream(new ByteArrayInputStream(baos.toByteArray()),request,response,fileName);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

3、数据导入

将特定的数据导入,我们所知excel表格的表头肯定是中文,而我们实体类基本上使用英文来标记的这怎么让他们一一对应呢,没错还是用反射,根据注解上的中文绑定英文来进行反射写入数据。

 public List<T> importExcel(MultipartFile multipartFile, Class clazz) throws Exception{
        Workbook workbook = null;
        //实例对象
        List<T> list = new ArrayList<>();
        try (InputStream inputStream = multipartFile.getInputStream()) {
            String fileName = multipartFile.getOriginalFilename();
            if (fileName.endsWith(".xls")) {
                workbook = new HSSFWorkbook(inputStream);
            } else {
                //不是导入模板
                return null;
            }
        } catch (IOException e) {
            e.printStackTrace();
            //不是导入模板
            return null;
        }

        Sheet sheet = workbook.getSheetAt(0);
        //获取总行数
        int rows = sheet.getPhysicalNumberOfRows();
        if (rows < 2) {
            //没有数据
            return null;
        }
        //获取所有字段名
        Field[] fields = clazz.getDeclaredFields();
        //记录对应的中文和英文
        Map<String, String> cMap = new HashMap<>();
        Map<String, Map<String, Class<?>>> countMap = new HashMap<>(fields.length);
        for (Field field : fields) {
            if (!field.isAccessible()) {
                // 关闭反射访问安全检查,为了提高速度
                field.setAccessible(true);
            }
            String fieldName = field.getName();
            // 排除ID和序号
            if (!"deFlag".equals(fieldName) && !"serialVersionUID".equals(fieldName) && !"createUser".equals(fieldName)
                    && !"updateUser".equals(fieldName) && !"updateTime".equals(fieldName) && !"logId".equals(fieldName)) {
                // 判断是否有@ApiModelProperty注解
                boolean annotationPresent = field.isAnnotationPresent(ApiModelProperty.class);
                if (annotationPresent && !"deFlag".equals(fieldName) && !"createUser".equals(fieldName)
                        && !"updateUser".equals(fieldName) && !"updateTime".equals(fieldName)) {
                    ApiModelProperty annotation = field.getAnnotation(ApiModelProperty.class);
                    String name = annotation.value();
                    Class<?> type = field.getType();
                    Map<String, Class<?>> inMap = new HashMap<>();
                    inMap.put(fieldName, type);
                    countMap.put(name, inMap);
                    cMap.put(name, fieldName);
                }
            }
        }
        //获取表头
        Row rowHead = sheet.getRow(0);
        int headNum = rowHead.getPhysicalNumberOfCells();
        //遍历总条数
        for (int c = 1; c < rows; c++) {
            T obj = (T) clazz.newInstance();
            //获取该行数据
            Row rowDate = sheet.getRow(c);
            //根据头写入数据
            for (int h = 0; h < headNum; h++) {
                Cell cell = rowDate.getCell(h);
                if(cell != null) {
                    //获取实体对应方法
                    String typeName = rowHead.getCell(h).getStringCellValue();
                    Map<String, Class<?>> inMap = countMap.get(typeName);
                    String typeEName = cMap.get(typeName);
                    String typeztName = inMap.get(typeEName).getName();
                    Method method = obj.getClass().getMethod("set" + StringUtil.initcap(typeEName), inMap.get(typeEName));
                    //根据对象的不同属性字段转换单元格中的数据类型并调用 set 方法赋值
                    if ("java.lang.Integer".equals(typeztName) || "int".equals(typeztName)) {
                        Integer param = cell.getColumnIndex();
                        method.invoke(obj, param);
                    }  else if ("java.lang.Long".equals(typeztName)) {
                        cell.setCellType(CellType.STRING);
                        Long param = Long.valueOf(cell.getStringCellValue());
                        method.invoke(obj,  param);
                    }else if ("java.lang.Double".equals(typeztName)) {
                        cell.setCellType(CellType.STRING);
                        Double param = Double.valueOf(cell.getStringCellValue());
                        method.invoke(obj,  param);
                    }else if ("java.util.Date".equals(typeztName)) {
                        Date param = cell.getDateCellValue();
                        method.invoke(obj,  param);
                    } else if ("java.time.LocalDateTime".equals(typeztName)) {
                        LocalDateTime param = cell.getLocalDateTimeCellValue();
//                        String pattern = "yyyy-MM-dd HH:mm:ss";
                        method.invoke(obj, param);
                    } else if ("java.lang.String".equals(typeztName)) {
                        cell.setCellType(CellType.STRING);
                        String param = cell.getStringCellValue();
                        method.invoke(obj, param);
                    } else {
                        //不是上述类型
                    }
                }
            }
            //将实体写入集合
            list.add(obj);
        }
        return list;
    }

以上是主要代码部分和设计思路

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yzzzjj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值