前端使用xlsx插件读取excel文件数据(保姆级教程)

Posted ADMIN_WKP

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端使用xlsx插件读取excel文件数据(保姆级教程)相关的知识,希望对你有一定的参考价值。

本人属于一个实习菜鸟,大神请谨慎阅读............

      在开发过程中,难免会碰到用前端来处理excel文件的需求,我们需要解析出excel文件的内容然后在以对象的形式展示或者与后端对接

功能的实现思路:

     文件选择   =>  FileReader对象得到二进制数据  =>  XLSX处理二进制数据 => 得到数据

1.导入按钮的样式与事件(element ui)

        首先我们需要的是一个导入的按钮但是我们导入按钮并不好处理触发选择文件(file)的change事件所以我们可以用定位来解决这个问题,原理就是:选择文件按钮(file)覆盖在正常按钮上面然后在把选择文件按钮(file)透明的变为0即可

<el-button size="mini" type="success" style="margin-top: 10px" :disabled="disabled" 
class="el-dialog-position">
    <span v-if="importStatus === false">
        导入<i class="el-icon-upload el-icon--right" />
        <input ref="files" type="file" v-if="!disabled" class="excelFile" @change="excelFileMethod" />
    </span>
    <span v-if="importStatus === true">
        导入中<i class="el-icon-loading el-icon--right" />
    </span>
</el-button>

        接下来就是chnage事件了,当用户更改 input、select 和textarea元素的值时,change 事件在这些元素上触发。和 input 事件不同的是,并不是每次元素的 value 改变时都会触发 change 事件。我们选择文件并确认以后得到了下面着一些大堆数据

这一大堆的数据我们不用管,我们只关注target对象里面的files对象就可以了因为等一下我们需要用到,但是注意这里的只是文件的信息并不是数据更不是二进制文件!!!!!!

2.对得到的文件信息进行处理(fileReader的使用)

        先对fileReader做个介绍,FileReader 对象允许 Web 应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。(官网原文)这里给你们个地址自己去看属性和方法的使用我就不做过多的介绍了.........先看代码:

// change事件
excelFileMethod(e) 
    var _this = this
	//  excel文件信息
	const files = e.target.files
	console.log(files);
	// 构建fileReader对象
	const fileReader = new FileReader()
	// 读取操作完成时
	fileReader.onload = function(e) 
		try 
			// 二进制数据
			console.log(e.target.result)
			
		 catch (e) 
			console.log('文件类型不正确')
			return
		
	
	// 读取指定文件内容
	fileReader.readAsBinaryString(files[0])
  • 第一步我们需要构建一个新的FileReader对象
  • 第二步使用FileReader.readAsBinaryString()读取指定的Blob中的内容。一旦完成,result属性中将包含所读取文件的原始二进制数据。
  • 第三步就是FileReader.onLoad该事件在读取操作完成时触发。

3.对得到的二进制数据进行处理(XLSX插件的使用)

        XLSX插件的使用,使用前我们需要下载并CND使用也可以是npm安装看个人需求,我这里是vue项目所以就是npm安装了然后还需要我们引入XLSX,方法如下:

import XLSX from 'xlsx'

通过上面的代码我们已经得到了二进制数据了,我们就开始对二进制数据进行解析吧!使用XLSX.read(data, type: type)方法来实现,type主要取值如下:

  • base64:以base64方式读取
  • binary:BinaryString格式( byte n is data.charCodeAt(n) )
  • string:UTF8编码的字符串
  • buffer:nodejs Buffer
  • array:Uint8Array,8位无符号数组
  • file:文件的路径(仅nodejs下支持)

这个方法返回一个workBook对象,对象的内容如下:

可以看到workBook对象,sheetNames里面保存了所有的sheet名字,然后Sheets则保存了每个sheet的具体内容(我们称之为Sheet Object)。每一个sheet是通过类似A1这样的键值保存每个单元格的内容,我们称之为单元格对象(Cell Object)

解析workBook对象的方法

  • XLSX.utils.sheet_to_csv:生成CSV格式
  • XLSX.utils.sheet_to_txt:生成纯文本格式
  • XLSX.utils.sheet_to_html:生成html格式
  • XLSX.utils.sheet_to_json:输出JSON格式

这里用到的是XLSX.utils.sheet_to_json所以我着重介绍,XLSX.utils.sheet_to_json(data, type)有两个参数,第一个是我们wordBook对象里面Sheets对象对应的数据,第二个参数配置如下:

  • raw: 使用原始值 (true) 或格式化字符串 (false)  (默认值:true
  • dateNF: 在字符串输出中使用指定的日期格式(默认值:FMT 14
  • defval: 使用指定值代替 null 或 undefined ()
  • blankrows: 在输出中包含空行**(默认值:** )
  • range: 

            (number)使用工作表范围,但将起始行设置为值

            (String)使用指定范围(A1 样式的有界范围字符串

            (default)使用工作表范围 ( worksheet[‘!ref’])

  • header:

            1: 生成数组数组(“二维数组”)

            "A".行对象键是文字列标签

            array of strings: 使用指定的字符串作为行对象中的键

            (default): 将第一行作为键读取并消除歧义

下面就是整个导入excel文件并读取数据的代码流程了,我们可以对得到的数据作为参数与后端接口进行对接就可以了!

// 处理excel文件
excelFileMethod(e) 
    // 导入状态和文件信息
    var _this = this
    _this.importStatus = true
    const excelFile = e.target.files
    // 构建fileReader对象
    const fileReader = new FileReader()
    // 该事件为读取完成时触发
    fileReader.onload = function (ev) 
      try 
        const data = ev.target.result
        const workbook = XLSX.read(data, type: 'binary')
        const list = ''
        const listNew = list.concat(XLSX.utils.sheet_to_json(workbook.Sheets['sheets1'], header: 1))
        _this.excelData.list = listNew.slice(6).split(',')
        // 得到的数据发送axios请求
        importExcel(_this.excelData).then(res => 
          console.log(res)
          _this.importStatus = false
          if (res.code === 200) 
            _this.$alert(res.data.msg, '导入成功', 
              confirmButtonText: '确定',
              callback: () => 
                // 确认后做什么
              
            )
           else 
            _this.$alert(res.data.msg, '导入失败', 
              confirmButtonText: '确定',
              callback: () => 
                // 确认后做什么
              
            )
          
        )
       catch (e) 
        _this.$message(message: '文件类型不正确', type: 'warning')
      
    
    // 读取数据
    fileReader.readAsBinaryString(excelFile[0])

后续还会持续更新技术问题感兴趣的小伙伴可以点关注或者是私信我哦!!!

保姆级Java后端查询数据库结果导出xlsx文件+打印xlsx表格

目录

前言

最近在弄一个需求,需求如下:
需求一:Vue前端点击导出按钮,就可以将从数据库查出的数据导出成xlsx,即Excel表格形式
需求二点击打印按钮,要将生成的xlsx文件启动进程,调用打印接口,实现打印,这是为了生成客户订单表,可以让机器直接打印

PS:想吐槽网上很多都复制粘贴的技术文章,找半天一点卵用都没用,这里记录一下自己解决方案,若转发请注明出处,原创不易,有问题可评论区留言

需求一效果预览

需求二效果预览

一、需求1:数据库查询的数据导出成Excel表格

1.1 Vue前端实现导出按钮+点击事件

<el-button type="success" round icon="el-icon-download" @click="exportByEasyPoi">导出</el-button>

对应按钮点击触发的exportByEasyPoi方法,这里我用的是EasyPoi操作Excel,也挺多公司用的
注:前端是Vue2

<script>
import userApi from '@/api/userManage'
export default 
	methods: 
		exportByEasyPoi() 
      		userApi.exportByEasyPoi().then(response => 
        		this.$message.success('导出成功')
      		)
    	
	

</script>

这里我调用了src/api/userManage.js,这是自己创建的js脚本,调用后端接口的

import request from '@/utils/request'

export default 
	exportByEasyPoi() 
    return request(
      url: `/user/exportep`,
      method: 'get',
      timeout: '10000'
    )
  

需求一前端就这么多了,接下来就是后端

1.2 后端根据数据库查询结果生成xlsx文件

首先导入EasyPoi相关依赖

<!--easypoi-->
<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-spring-boot-starter</artifactId>
    <version>4.3.0</version>
</dependency>
<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-base</artifactId>
    <version>4.3.0</version>
</dependency>
<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-web</artifactId>
    <version>4.3.0</version>
</dependency>
<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-annotation</artifactId>
    <version>4.3.0</version>
</dependency>
<!-- lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.20</version>
</dependency>

下面先给出后端核心逻辑代码,后面会具体讲解,这里就不加篇幅,直接把逻辑代码写在Controller层,原本应该写在Service层,即xxxServiceImpl实现类中,这里为了方便,直接这么写下。

@Autowired
private IUserService userService;

@GetMapping("/exportep")
public Result<?> exportByEasyPoi(HttpServletResponse response) throws IOException 
	// mybatisplus实现的list(),拿到用户信息列表
    List<User> users = userService.list();
    List<ExcelUserVo> excelUserVos = BeanCopyUtils.copyBeanList(users, ExcelUserVo.class);
    // easypoi导出
    ExportParams params = new ExportParams();
    params.setTitle("测试");
    // 表格左下角的sheet名称
    params.setSheetName("用户信息");
    Workbook workbook = ExcelExportUtil.exportExcel(params, ExcelUserVo.class, excelUserVos);
    // 判断文件路径是否存在,并将信息写入文件
    try
        // 文件夹是否存在,若没有对应文件夹直接根据路径生成文件会报错
        File folder = new File(Constants.XLSX_DIR);
        if (!folder.exists() && !folder.isDirectory()) 
            folder.mkdirs();
        
        // 文件是否存在
        File file = new File(Constants.XLSX_DIR + "\\\\" + Constants.XLSX_NAME);
        if (!file.exists())
            file.createNewFile();
        
        // 输出流写入
        FileOutputStream outputStream = new FileOutputStream(Constants.XLSX_DIR + "\\\\" + Constants.XLSX_NAME);
        workbook.write(outputStream);
        // 关闭写,不然用户点击生成的文件会显示只读
        outputStream.close();
        workbook.close();
    catch (IOException e)
        e.printStackTrace();
    
    return Result.success("导出成功");

ExcelUserVo.java是自己需要显示在表格中的列,就是我们查询用户表,大部分时候不需要展示所有的属性到前端,挑需要显示的,所以封装成xxxVo,比如密码、创建时间、备注可以不显示在前端,不用打印就不要。

import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.annotation.ExcelTarget;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@NoArgsConstructor
@AllArgsConstructor
@ExcelTarget("sys_user")
public class ExcelUserVo implements Serializable 

    @Excel(name = "用户id", width = 10)
//    @ExcelIgnore // 表示忽略, 不在表格生成
    private Integer id;

    @Excel(name = "用户名", width = 20)
    private String username;

    @Excel(name = "邮箱", width = 30)
    private String email;

    @Excel(name = "电话", width = 30)
    private String phone;

    @Excel(name = "状态(1:正常,0:禁用)", width = 10)
    private Integer status;

BeanCopyUtils.java是常用工具类,可以实现对象的拷贝,将两个对象中相同属性字段值拷贝,这里就是将User中相同属性值拷贝到ExportUserVo类中。

import java.util.List;
import java.util.stream.Collectors;

public class BeanCopyUtils 
    private BeanCopyUtils() 
    

    /** 单个对象*/
    public static <V> V copyBean(Object source, Class<V> clazz) 
        /** 创建目标对象 实现属性拷贝*/
        V result = null;
        try 
            result = clazz.newInstance();
            /** 拷贝*/
            BeanUtils.copyProperties(source, result);
         catch (Exception e) 
            e.printStackTrace();
        
        return result;
    
    
    /** 集合*/
    public static <O, V> List<V> copyBeanList(List<O> list, Class<V> clazz) 
        /** 创建目标对象 实现属性拷贝*/
        return list.stream()
                .map(o -> copyBean(o, clazz))
                .collect(Collectors.toList());
    

自定义常量Constants.java,这里主要是定义输出路径

public class Constants 

    // excel表
    public static final String XLSX_DIR = "D:\\\\study\\\\excel";

    public static final String XLSX_NAME = "easypoi.xlsx";
    

数据库sys_user表结构

DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL,
  `password` varchar(100) DEFAULT NULL,
  `email` varchar(50) DEFAULT NULL,
  `phone` varchar(20) DEFAULT NULL,
  `status` int(1) DEFAULT NULL,
  `avatar` varchar(200) DEFAULT NULL,
  `deleted` int(1) DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

二、需求2:对生成的xlsx文件调用打印机打印

2.1 Vue前端实现按钮+事件

<el-button type="warning" round icon="el-icon-printer" @click="printExcel">打印</el-button>
methods: 
	printExcel() 
      userApi.printTable().then(response => 
        this.$message.success('请求打印成功')
      )
	

userManage.js中再写一个调用后端接口的

export default 
	printTable() 
	    return request(
	      url: `/user/print`,
	      method: 'get',
	      timeout: '100000'
	    )
	

2.2 后端实现打印

这里也干脆实现逻辑不写在Service层了,省点字,实际开发中还是要遵循规范哈

@GetMapping("/print")
public Result<?> printInfo()
    try 
    	String filepath = Constants.XLSX_DIR + "\\\\" + Constants.XLSX_NAME;
        PrintUtil.print(filepath);
     catch (Exception e) 
        e.printStackTrace();
    
    return Result.success();

核心打印工具PrintUtil.java,这个java文件稍微有点长

import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.ComThread;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;

import javax.imageio.ImageIO;
import javax.print.*;
import javax.print.attribute.DocAttributeSet;
import javax.print.attribute.HashDocAttributeSet;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.standard.OrientationRequested;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

public class PrintUtil 

    /**
     * 竖屏模式
     */
    public static OrientationRequested PORTRAIT = OrientationRequested.PORTRAIT;

    /**
     * 横屏模式
     */
    public static OrientationRequested LANDSCAPE = OrientationRequested.LANDSCAPE;



    /**
     * 获取全部打印设备信息
     * @return 返回全部能用的打印服务的List
     */
    public static List<PrintService> getDeviceList() 
        // 构建打印请求属性集
        HashPrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
        // 设置打印格式,因为未确定类型,所以选择autosense
        DocFlavor flavor = DocFlavor.BYTE_ARRAY.AUTOSENSE;
        // 查找所有的可用的打印服务
        PrintService printService[] = PrintServiceLookup.lookupPrintServices(flavor, pras);
        List<PrintService> list = Arrays.asList(printService);
        return list;
    


    /**
     * 根据文件类型不同调用不同代码去打印
     * @param filePath 文件路径
     */
    public static void print(String filePath) throws Exception 
        PrintService printService = PrintServiceLookup.lookupDefaultPrintService();
        String defaultDeviceName = printService.getName();
        print(filePath, defaultDeviceName);
    

    /**
     * 额外传入一个 AfterPrint,会在打印完成后调用 afterPrint.run()
     * @param filePath
     * @param afterPrint
     * @throws Exception
     */
    public static void print(String filePath, AfterPrint afterPrint) throws Exception 
        print(filePath);
        afterPrint.run();
    

    /**
     * 根据文件类型不同调用不同代码去打印
     * @param filePath 文件路径
     * @param deviceName 设备名称,传入哪个设备的名称,就让哪个设备去打印
     */
    public static void print(String filePath, String deviceName) throws Exception
        List<PrintService> list = getDeviceList();
        PrintService printService = null;
        for (PrintService p : list) 
            if(p.getName().equals(deviceName)) 
                printService = p;
                break;
            
        
        if(printService == null) 
            throw new Exception("Device not found");
        
        String type = filePath.replaceAll(".*\\\\.","");
        if("jpg".equalsIgnoreCase(type)) 
            normalPrint(new File(filePath), DocFlavor.INPUT_STREAM.JPEG, printService以上是关于前端使用xlsx插件读取excel文件数据(保姆级教程)的主要内容,如果未能解决你的问题,请参考以下文章

前端 XLSX 插件包 读取excel文件转成json数据给接口

React读取Excel——js-xlsx 插件的使用

前端vue获取excell中的数据

在vue中,实现纯前端读取和展示excel文件

使用js-xlsx库,前端读取Excel报表文件

JS-XLS/X读取和解析Excel表格文件(xls/xlsx)的JavaScript插件