SpringBoot整合EasyExcel实现文件导入导出

准备工作

注意:点击查看官网Demo

1. 引入pom依赖

        <!--easyExcel-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
        </dependency>

2. 实现功能

  • 结合Vue前端,实现浏览器页面直接导出日志文件
  • 实现文件的导入

Excel文件下载

3. 日志实体类

实体类里有自定义转换器:用于Java类型数据和Excel类型数据的转换,非常使用。结合注解,可以非常方便的进行Excel文件导出。

/**
 * <p>
 * 操作日志信息
 * </p>
 *
 * @author horse
 * @since 2020-09-08
 * 注意: 实体类中如果使用@Accessory(chain=true),那么导入的数据无法填充到实例中,导出数据不受影响
 */
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("tb_operational_log")
@ApiModel(value = "OperationalLog对象", description = "操作日志信息")
public class OperationalLog implements Serializable {

    private static final long serialVersionUID = 1L;

    @ExcelProperty({"操作日志", "日志ID"})
    @ApiModelProperty(value = "日志ID")
    @TableId(value = "id", type = IdType.ASSIGN_ID)
    private String id;

    @ExcelProperty({"操作日志", "操作类型"})
    @ApiModelProperty(value = "操作类型")
    private String operType;

    @ExcelProperty({"操作日志", "操作描述"})
    @ApiModelProperty(value = "操作描述")
    private String operDesc;

    @ExcelProperty({"操作日志", "操作员ID"})
    @ApiModelProperty(value = "操作员ID")
    private String operUserId;

    @ExcelProperty({"操作日志", "操作员名称"})
    @ApiModelProperty(value = "操作员名称")
    private String operUserName;

    @ExcelProperty({"操作日志", "操作方法"})
    @ApiModelProperty(value = "操作方法")
    private String operMethod;

    @ExcelProperty({"操作日志", "请求方法"})
    @ApiModelProperty(value = "请求方法")
    private String operRequWay;

    @ExcelProperty(value = {"操作日志", "请求耗时:单位-ms"}, converter = CustomRequestTimeConverter.class)
    @ApiModelProperty(value = "请求耗时:单位-ms")
    private Long operRequTime;

    @ExcelProperty({"操作日志", "请求参数"})
    @ApiModelProperty(value = "请求参数")
    private String operRequParams;

    @ExcelProperty({"操作日志", "请求Body"})
    @ApiModelProperty(value = "请求Body")
    private String operRequBody;

    @ExcelProperty({"操作日志", "请求IP"})
    @ApiModelProperty(value = "请求IP")
    private String operRequIp;

    @ExcelProperty({"操作日志", "请求URL"})
    @ApiModelProperty(value = "请求URL")
    private String operRequUrl;

    @ExcelProperty(value = {"操作日志", "日志标识"}, converter = CustomLogFlagConverter.class)
    @ApiModelProperty(value = "日志标识: 1-admin,0-portal")
    private Boolean logFlag;

    @ExcelProperty({"操作日志", "操作状态"})
    @ApiModelProperty(value = "操作状态:1-成功,0-失败")
    @TableField(value = "is_success")
    private Boolean success;

    @ExcelIgnore
    @ApiModelProperty(value = "逻辑删除 1-未删除, 0-删除")
    @TableField(value = "is_deleted")
    @TableLogic(value = "1", delval = "0")
    private Boolean deleted;

    @ExcelProperty(value = {"操作日志", "创建时间"}, converter = CustomTimeFormatConverter.class)
    @ApiModelProperty(value = "创建时间")
    private Date gmtCreate;
}

4. 接口和具体实现

4.1 接口

    @OperatingLog(operType = BlogConstants.EXPORT, operDesc = "导出操作日志,写出到响应流中")
    @ApiOperation(value = "导出操作日志", hidden = true)
    @PostMapping("/oper/export")
    public void operLogExport(@RequestBody List<String> logIds, HttpServletResponse response) {
        operationalLogService.operLogExport(logIds, response);
    }

4.2 具体实现

  • 自定义导出策略HorizontalCellStyleStrategy
  • 自定义导出拦截器CellWriteHandler,更加精确的自定义导出策略
    /**
     * 导出操作日志(可以考虑分页导出)
     *
     * @param logIds
     * @param response
     */
    @Override
    public void operLogExport(List<String> logIds, HttpServletResponse response) {
        OutputStream outputStream = null;
        try {
            List<OperationalLog> operationalLogs;
            LambdaQueryWrapper<OperationalLog> queryWrapper = new LambdaQueryWrapper<OperationalLog>()
                    .orderByDesc(OperationalLog::getGmtCreate);
            // 如果logIds不为null,按照id查询信息,否则查询全部
            if (!CollectionUtils.isEmpty(logIds)) {
                operationalLogs = this.listByIds(logIds);
            } else {
                operationalLogs = this.list(queryWrapper);
            }
            outputStream = response.getOutputStream();

            // 获取单元格样式
            HorizontalCellStyleStrategy strategy = MyCellStyleStrategy.getHorizontalCellStyleStrategy();

            // 写入响应输出流数据
            EasyExcel.write(outputStream, OperationalLog.class).excelType(ExcelTypeEnum.XLSX).sheet("操作信息日志")
                    // .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 自适应列宽(不是很适应,效果并不佳)
                    .registerWriteHandler(strategy) // 注册上面设置的格式策略
                    .registerWriteHandler(new CustomCellWriteHandler()) // 设置自定义格式策略
                    .doWrite(operationalLogs);
        } catch (Exception e) {
            log.error(ExceptionUtils.getMessage(e));
            throw new BlogException(ResultCodeEnum.EXCEL_DATA_EXPORT_ERROR);
        } finally {
            IoUtil.close(outputStream);
        }
    }

自定义导出策略简单如下:

/**
 * @author Mr.Horse
 * @version 1.0
 * @description: 单元格样式策略
 * @date 2021/4/30 8:43
 */

public class MyCellStyleStrategy {

    /**
     * 设置单元格样式(仅用于测试)
     *
     * @return 样式策略
     */
    public static HorizontalCellStyleStrategy getHorizontalCellStyleStrategy() {
        // 表头策略
        WriteCellStyle headerCellStyle = new WriteCellStyle();
        // 表头水平对齐居中
        headerCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        // 背景色
        headerCellStyle.setFillForegroundColor(IndexedColors.SKY_BLUE.getIndex());
        WriteFont headerFont = new WriteFont();
        headerFont.setFontHeightInPoints((short) 14);
        headerCellStyle.setWriteFont(headerFont);
        // 自动换行
        headerCellStyle.setWrapped(Boolean.FALSE);

        // 内容策略
        WriteCellStyle contentCellStyle = new WriteCellStyle();
        // 设置数据允许的数据格式,这里49代表所有可以都允许设置
        contentCellStyle.setDataFormat((short) 49);
        // 设置背景色: 需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定
        contentCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
        contentCellStyle.setFillForegroundColor(IndexedColors.GREY_40_PERCENT.getIndex());
        // 设置内容靠左对齐
        contentCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
        // 设置字体
        WriteFont contentFont = new WriteFont();
        contentFont.setFontHeightInPoints((short) 12);
        contentCellStyle.setWriteFont(contentFont);
        // 设置自动换行
        contentCellStyle.setWrapped(Boolean.FALSE);
        // 设置边框样式和颜色
        contentCellStyle.setBorderLeft(MEDIUM);
        contentCellStyle.setBorderTop(MEDIUM);
        contentCellStyle.setBorderRight(MEDIUM);
        contentCellStyle.setBorderBottom(MEDIUM);
        contentCellStyle.setTopBorderColor(IndexedColors.RED.getIndex());
        contentCellStyle.setBottomBorderColor(IndexedColors.GREEN.getIndex());
        contentCellStyle.setLeftBorderColor(IndexedColors.YELLOW.getIndex());
        contentCellStyle.setRightBorderColor(IndexedColors.ORANGE.getIndex());

        // 将格式加入单元格样式策略
        return new HorizontalCellStyleStrategy(headerCellStyle, contentCellStyle);
    }
}

自定义导出拦截器简单如下:

/**
 * @author Mr.Horse
 * @version 1.0
 * @description 实现CellWriteHandler接口, 实现对单元格样式的精确控制
 * @date 2021/4/29 21:11
 */
public class CustomCellWriteHandler implements CellWriteHandler {

    private static Logger logger = LoggerFactory.getLogger(CustomCellWriteHandler.class);

    @Override
    public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row,
                                 Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {

    }

    /**
     * 单元格创建之后(没有写入值)
     *
     * @param writeSheetHolder
     * @param writeTableHolder
     * @param cell
     * @param head
     * @param relativeRowIndex
     * @param isHead
     */
    @Override
    public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell,
                                Head head, Integer relativeRowIndex, Boolean isHead) {

    }

    @Override
    public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
                                       CellData cellData, Cell cell, Head head, Integer relativeRowIndex,
                                       Boolean isHead) {

    }

    /**
     * 单元格处理后(已写入值): 设置第一行第一列的头超链接到EasyExcel的官网(本系统的导出的excel 0,1两行都是头,所以只设置第一行的超链接)
     * 这里再进行拦截的单元格样式设置的话,前面该样式将全部失效
     *
     * @param writeSheetHolder
     * @param writeTableHolder
     * @param cellDataList
     * @param cell
     * @param head
     * @param relativeRowIndex
     * @param isHead
     */
    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
                                 List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex,
                                 Boolean isHead) {
        // 设置超链接
        if (isHead && cell.getRowIndex() == 0 && cell.getColumnIndex() == 0) {
            logger.info(" ==> 第{}行,第{}列超链接设置完成", cell.getRowIndex(), cell.getColumnIndex());
            CreationHelper helper = writeSheetHolder.getSheet().getWorkbook().getCreationHelper();
            Hyperlink hyperlink = helper.createHyperlink(HyperlinkType.URL);
            hyperlink.setAddress("https://github.com/alibaba/easyexcel");
            cell.setHyperlink(hyperlink);
        }
        // 精确设置单元格格式
        boolean bool = isHead && cell.getRowIndex() == 1 &&
                (cell.getStringCellValue().equals("请求参数") || cell.getStringCellValue().equals("请求Body"));
        if (bool) {
            logger.info("第{}行,第{}列单元格样式设置完成。", cell.getRowIndex(), cell.getColumnIndex());
            // 获取工作簿
            Workbook workbook = writeSheetHolder.getSheet().getWorkbook();
            CellStyle cellStyle = workbook.createCellStyle();

            Font cellFont = workbook.createFont();
            cellFont.setBold(Boolean.TRUE);
            cellFont.setFontHeightInPoints((short) 14);
            cellFont.setColor(IndexedColors.SEA_GREEN.getIndex());
            cellStyle.setFont(cellFont);
            cell.setCellStyle(cellStyle);
        }
    }
}

4.3 前端请求

前端在基于Vue+Element的基础上实现了点击导出按钮,在浏览器页面进行下载。

// 批量导出
    batchExport() {
      // 遍历获取id集合列表
      const logIds = []
      this.multipleSelection.forEach(item => {
        logIds.push(item.id)
      })
       // 请求后端接口
      axios({
        url: this.BASE_API + '/admin/blog/log/oper/export',
        method: 'post',
        data: logIds,
        responseType: 'arraybuffer',
        headers: { 'token': getToken() }
      }).then(response => {
        // type类型可以设置为文本类型,这里是新版excel类型
        const blob = new Blob([response.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8' })
        const pdfUrl = window.URL.createObjectURL(blob)
        const fileName = 'HorseBlog操作日志' // 下载文件的名字
        // 对于<a>标签,只有 Firefox 和 Chrome(内核)支持 download 属性
        if ('download' in document.createElement('a')) {
          const link = document.createElement('a')
          link.href = pdfUrl
          link.setAttribute('download', fileName)
          document.body.appendChild(link)
          link.click()
          window.URL.revokeObjectURL(pdfUrl) // 释放URL 对象
        } else {
          // IE 浏览器兼容方法
          window.navigator.msSaveBlob(blob, fileName)
        }
      })
    }

测试结果:还行,基本实现了页面下载的功能

Excel文件导入

5. 文件读取配置

本配置基于泛型的方式编写,可扩展性较强。

/**
 * @author Mr.Horse
 * @version 1.0
 * @description: EasyExcel文件读取配置(不能让spring管理)
 * @date 2021/4/27 13:24
 */

public class MyExcelImportConfig<T> extends AnalysisEventListener<T> {

    private static Logger logger = LoggerFactory.getLogger(MyExcelImportConfig.class);

    /**
     * 每次读取的最大数据条数
     */
    private static final int MAX_BATCH_COUNT = 10;

    /**
     * 泛型bean属性
     */
    private T dynamicService;

    /**
     * 可接收任何参数的泛型List集合
     */
    List<T> list = new ArrayList<>();

    /**
     * 构造函数注入bean(根据传入的bean动态注入)
     *
     * @param dynamicService
     */
    public MyExcelImportConfig(T dynamicService) {
        this.dynamicService = dynamicService;
    }

    /**
     * 解析每条数据都进行调用
     *
     * @param data
     * @param context
     */
    @Override
    public void invoke(T data, AnalysisContext context) {
        logger.info(" ==> 解析一条数据: {}", JacksonUtils.objToString(data));
        list.add(data);
        if (list.size() > MAX_BATCH_COUNT) {
            // 保存数据
            saveData();
            // 清空list
            list.clear();
        }
    }

    /**
     * 所有数据解析完成后,会来调用一次
     * 作用: 避免最后集合中小于 MAX_BATCH_COUNT 条的数据没有被保存
     *
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        saveData();
        logger.info(" ==> 数据解析完成 <==");
    }

    /**
     * 保存数据: 正式应该插入数据库,这里用于测试
     */
    private void saveData() {
        logger.info(" ==> 数据保存开始: {}", list.size());
        list.forEach(System.out::println);
        logger.info(" ==> 数据保存结束 <==");
    }

    /**
     * 在转换异常 获取其他异常下会调用本接口。我们如果捕捉并手动抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。
     *
     * @param exception
     * @param context
     * @throws Exception
     */
    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        logger.error(" ==> 数据解析失败,但是继续读取下一行:{}", exception.getMessage());
        //  如果是某一个单元格的转换异常 能获取到具体行号
        if (exception instanceof ExcelDataConvertException) {
            ExcelDataConvertException convertException = (ExcelDataConvertException) exception;
            logger.error("第{}行,第{}列数据解析异常", convertException.getRowIndex(), convertException.getColumnIndex());
        }
    }

}

6. 读取测试

    @ApiOperation(value = "数据导入测试", notes = "操作日志导入测试[OperationalLog]", hidden = true)
    @PostMapping("/import")
    public R excelImport(@RequestParam("file") MultipartFile file) throws IOException {
        EasyExcel.read(file.getInputStream(), OperationalLog.class, new MyExcelImportConfig<>(operationalLogService))
                .sheet().doRead();
        return R.ok().message("文件导入成功");
    }

7. 附上自定义属性转换器

转换器的属性内容转换,需要根据自己的实际业务需求而定,这里仅作为简单示例

/**
 * @author Mr.Horse
 * @version 1.0
 * @description: 自定义excel转换器: 将操作日志的请求耗时加上单位 "ms"
 * @date 2021/4/27 10:25
 */

public class CustomRequestTimeConverter implements Converter<Long> {

    /**
     * 读取数据时: 属性对应的java数据类型
     *
     * @return
     */
    @Override
    public Class<Long> supportJavaTypeKey() {
        return Long.class;
    }

    /**
     * 写入数据时: excel内部的数据类型,因为请求耗时是long类型,对应excel是NUMBER类型,但是加上"ms后对应的是STRING类型"
     *
     * @return
     */
    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    /**
     * 读取回调
     *
     * @param cellData
     * @param contentProperty
     * @param globalConfiguration
     * @return
     * @throws Exception
     */
    @Override
    public Long convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        // 截取字符串: "ms",转换为long类型
        String value = cellData.getStringValue();
        return Long.valueOf(value.substring(0, value.length() - 2));
    }

    @Override
    public CellData<Long> convertToExcelData(Long value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        // 添加字符串: "ms"
        return new CellData<>(String.valueOf(value).concat("ms"));
    }
}

格式化时间

/**
 * @author Mr.Horse
 * @version 1.0
 * @description: {description}
 * @date 2021/4/27 14:01
 */

public class CustomTimeFormatConverter implements Converter<Date> {

    @Override
    public Class<Date> supportJavaTypeKey() {
        return Date.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    @Override
    public Date convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        String value = cellData.getStringValue();
        return DateUtil.parse(value, DatePattern.NORM_DATETIME_PATTERN);
    }

    @Override
    public CellData<Date> convertToExcelData(Date value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        return new CellData<>(DateUtil.format(value, DatePattern.NORM_DATETIME_PATTERN));
    }
}

EasyExcel简单使用,到此结束,打完收功。

以上就是SpringBoot整合EasyExcel实现文件导入导出的详细内容,更多关于SpringBoot整合EasyExcel的资料请关注我们其它相关文章!

(0)

相关推荐

  • SpringBoot中EasyExcel实现Excel文件的导入导出

    前言 在我们日常的开发过程中经常会使用Excel文件的形式来批量地上传下载系统数据,我们最常用的工具是Apache poi,但是如果数据到底上百万时,将会造成内存溢出的问题,那么我们怎么去实现百万数据批量导入导出. 正文 Easyexcel Easyexcel 是阿里巴巴的开源项目,用来优化Excel文件处理过程: poi消耗内存严重:Java解析.生成Excel比较有名的框架有Apache poi.jxl.但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的

  • SpringBoot实现Excel文件批量上传导入数据库

    Spring boot + Spring data jpa + Thymeleaf 批量插入 + POI读取 + 文件上传 pom.xml: <!-- https://mvnrepository.com/artifact/org.apache.poi/poi --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <versi

  • SpringBoot集成EasyExcel实现Excel导入的方法

    第一次正式的写文章进行分享,如果文章中有什么问题,欢迎大家在文末的群内反馈. 一.背景 为什么会用Easyexcel来做Excel上传 平时项目中经常使用EasyExcel从本地读取Excel中的数据,还有一个前端页面对需要处理的数据进行一些配置(如:Excel所在的文件夹,Excel的文件名,以及Sheet列名.处理数据需要的某些参数),由于每次都是读取的本地的文件,我就在想,如果某一天需要通过前端上传excel给我,让我来进行处理我又应该怎么办呢?我怎么才能在尽量少修改代码的前提下实现这个功

  • SpringBoot整合EasyExcel实现文件导入导出

    准备工作 注意:点击查看官网Demo 1. 引入pom依赖 <!--easyExcel--> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> </dependency> 2. 实现功能 结合Vue前端,实现浏览器页面直接导出日志文件 实现文件的导入 Excel文件下载 3. 日志实体类 实体类里有自定义转换器:用于

  • SpringBoot整合EasyExcel实现Excel表格导出功能

    目录 栗子 1.组件介绍 2.配置文件 SpringBoot项目pom.xml 3.项目代码 项目结构 ExportController.java Mock.java CitySheet.java CompanySheet.java UserSheet.java SpringBootEasyexcelApplication.java 4.效果展示 单个sheet导出 多个sheet导出 5.总结 栗子 在后端管理系统的开发中,经常有需要导出当前表格数据的功能,有些前端表格组件可以直接做到,但是不

  • SpringBoot整合EasyExcel实现导入导出数据

    目录 前言 1.前端 2.数据库 3.后端 3.1 contrller 3.2 mapper 3.3 bean 3.4 listener 3.5 config 3.6 配置文件 4.启动测试 前言 创建一个普通的maven项目即可 项目目录结构 1.前端 存放在resources/static 下 index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF

  • Spring Boot + EasyExcel实现数据导入导出

    目录 背景 SpringBoot项目集成 依赖集成 实体类实现 业务逻辑实现 MemberService实现 简单导出实现 自定义导入实现 同步获取结果导入实现 基于监听导入实现 小结 背景 老项目主要采用的POI框架来进行Excel数据的导入和导出,但经常会出现OOM的情况,导致整个服务不可用.后续逐步转移到EasyExcel,简直不能太好用了. EasyExcel是阿里巴巴开源插件之一,主要解决了poi框架使用复杂,sax解析模式不容易操作,数据量大起来容易OOM,解决了POI并发造成的报错

  • SpringBoot整合EasyExcel的完整过程记录

    目录 为什么要用EasyExcel 1.EasyExcel简介 2.使用EasyExcel实现写 2.1 创建实体类 2.2 测试写Excel 3.使用EasyExcel实现读 3.1 创建读取操作的监听器 3.2 测试读Excel 4.springboot项目实践EasyExcel 4.1 pom中引入相关依赖 4.2 创建数据库表及添加数据 4.3 实体类 4.4 Controller层 4.5 Service层 4.6 创建监听器(核心部分) 4.7 结果展示 总结 为什么要用EasyEx

  • SpringBoot整合EasyExcel进行大数据处理的方法详解

    目录 EasyExcel 需要的Maven 基础读案例 操作的excel 实体类 读取监听器 测试 基础写案例 实体类 测试 Excel模板方式 准备模块 实体类 测试 EasyExcel EasyExcel文档 我用过Poi和EasyPoi这些工具总体来说: POI 优点我觉得自由,但是迎来的就是复杂度,和大数据量时候性能的缺点 EasyPoi基于POI 的二次封装,解决了大部分的常用场景,简化了代码,但是特别复杂表格处理还是不行,而且性能的话和poi差不多,简单来说就是简化了Poi的操作,少

  • SpringBoot集成POI实现Excel导入导出的示例详解

    目录 知识准备 什么是POI POI中基础概念 实现案例 Pom依赖 导出Excel 导入Excel 示例源码 知识准备 需要了解POI工具,以及POI对Excel中的对象的封装对应关系. 什么是POI Apache POI 是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程序对Microsoft Office格式档案读和写的功能.POI为“Poor Obfuscation Implementation”的首字母缩写,意为“简洁版的模糊实现”. A

  • java实现文件导入导出

    文件导入导出必须代码 ExportExcel.java /** * Copyright © 2012-2014 <a href="https://github.com/thinkgem/jeesite">JeeSite</a> All rights reserved. */ package com.thinkgem.jeesite.common.utils.excel; import java.io.FileNotFoundException; import j

  • Laravel 5使用Laravel Excel实现Excel/CSV文件导入导出的功能详解

    1.简介 本文主要给大家介绍了关于Laravel 5用Laravel Excel实现Excel/CSV文件导入导出的相关内容,下面话不多说了,来一起看看详细的介绍吧. Laravel Excel 在 Laravel 5 中集成 PHPOffice 套件中的 PHPExcel ,从而方便我们以优雅的.富有表现力的代码实现Excel/CSV文件的导入和 导出 . 该项目的GitHub地址是: https://github.com/Maatwebsite/Laravel-Excel. 本地下载地址:h

随机推荐