实现Excel文件和其他文件导出为压缩包,并导入

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
简介: 实现Excel文件和其他文件导出为压缩包,并导入

 导出

后端:

@PostMapping("/exportExcelData")
  public void exportExcelData(HttpServletRequest request, HttpServletResponse response, @RequestBody ResData resData) throws IOException {
    List<Long> menuIds = resData.getMenuIds();
    List<Conversion> conversions = new ArrayList<>();
    List<String> ktrFilePaths = new ArrayList<>();
    for (Long menuId : menuIds) {
      Conversion conversion = conversionMapper.selectById(menuId);
      if (conversion != null) {
        conversions.add(conversion);
        String ktrFilePath = fileService.getKtrFilePathById(menuId);
        if (ktrFilePath != null && !ktrFilePaths.contains(ktrFilePath)) {
          ktrFilePaths.add(ktrFilePath);
        }
      }
    }
    // 创建Excel工作簿
    HSSFWorkbook workbook = new HSSFWorkbook();
    // 创建一个工作表
    Sheet sheet = workbook.createSheet("Conversions");
    // 创建单元格样式,并设置为文本格式
    CellStyle textStyle = workbook.createCellStyle();
    DataFormat format = workbook.createDataFormat();
    textStyle.setDataFormat(format.getFormat("@")); // "@" 表示文本格式
    // 创建标题行
    Row titleRow = sheet.createRow(0);
    // 创建单元格样式,并设置为文本格式
    titleRow.createCell(0).setCellValue("主键");
    titleRow.createCell(1).setCellValue("分组id");
    titleRow.createCell(2).setCellValue("名称");
    titleRow.createCell(3).setCellValue("备注");
    titleRow.createCell(4).setCellValue("创建人");
    titleRow.createCell(5).setCellValue("关联状态");
    titleRow.createCell(6).setCellValue("XMl");
    titleRow.createCell(7).setCellValue("创建时间");
    // 应用文本格式到标题行的特定单元格
    titleRow.getCell(0).setCellStyle(textStyle);
    titleRow.getCell(1).setCellStyle(textStyle);
    // 填充数据
    int rowNum = 1;
    for (Conversion conversion : conversions) {
      Row row = sheet.createRow(rowNum++);
      Cell cell = row.createCell(0);
      cell.setCellValue(String.valueOf(conversion.getId()));
      cell.setCellStyle(textStyle);
      cell = row.createCell(1);
      cell.setCellValue(String.valueOf(conversion.getGroupId()));
      cell.setCellStyle(textStyle); // 应用文本格式
      row.createCell(2).setCellValue(conversion.getName());
      row.createCell(3).setCellValue(conversion.getRemark());
      row.createCell(4).setCellValue(conversion.getCreateUserName());
      row.createCell(5).setCellValue(conversion.getState());
      row.createCell(6).setCellValue(conversion.getEditXml());
      row.createCell(7).setCellValue(String.valueOf(conversion.getCreateTime()));
    }
    // 设置响应头
    response.setContentType("application/vnd.ms-excel");
    response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("conversions.xls", "UTF-8"));
    // 设置响应头
    response.setContentType("application/zip");
    response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("conversions.zip", "UTF-8"));
    ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream());
    // 将Excel文件添加到压缩包
    ZipEntry excelEntry = new ZipEntry("conversions.xls");
    zipOut.putNextEntry(excelEntry);
    workbook.write(zipOut);
    zipOut.closeEntry();
    workbook.close();
    // 添加.ktr文件到ktr目录
    for (String filePath : ktrFilePaths) {
      File ktrFile = new File(filePath);
      if (ktrFile.exists()) {
        FileInputStream fis = new FileInputStream(ktrFile);
        // 创建ZipEntry时,需要包含ktr目录
        ZipEntry ktrEntry = new ZipEntry("ktr/" + ktrFile.getName());
        zipOut.putNextEntry(ktrEntry);
        byte[] bytes = new byte[1024];
        int length;
        while ((length = fis.read(bytes)) >= 0) {
          zipOut.write(bytes, 0, length);
        }
        fis.close();
        zipOut.closeEntry();
      }
    }
    // 完成压缩包
    zipOut.finish();
    zipOut.close();
  }

image.gif

导出后的文件组成:

image.gif 编辑

image.gif 编辑

image.gif 编辑

excel文件:

image.gif 编辑

前端:

<template>
  <div class="app-container" style="width:100%;">
    <el-form label-width="80px" label-position="left">
      <el-form-item label="模型树">
        <el-tree
          ref="tree"
          :data="treeData"
          show-checkbox
          :default-expand-all="false"
          node-key="id"
          highlight-current
          :props="defaultProps"
        />
      </el-form-item>
    </el-form>
    <div style="text-align: center;width:100%;">
      <el-button type="primary" @click="onSave">导出</el-button>
      <el-button type="danger" @click="closePage">取消</el-button>
    </div>
  </div>
</template>
<script>
import { getTreeData } from '@/api/dataSchema'
import { exportData,exportExcelData } from '@/api/conversion'
import { Message } from 'element-ui'
export default {
  name: 'Zzjg',
  inject: ['getList'],
  props: {
    proid: {
      type: String,
      required: true
    }
  },
  data() {
    return {
      defaultProps: {
        children: 'children',
        label: 'name'
      },
      treeData: []
    }
  },
  methods: {
    getDetailed() {
      const loading = this.$loading({
        lock: true,
        text: 'Loading',
        spinner: 'el-icon-loading',
        background: 'rgba(0, 0, 0, 0.7)'
      })
      getTreeData().then(response => {
        this.treeData = response.data
        
        loading.close()
      }).catch(function() {
        loading.close()
      })
    },
    onSave() {
      var menuIds = this.$refs.tree.getCheckedKeys()
      if (menuIds.length === 0) {
        Message({
          message: '请选择要导出的模型',
          type: 'error',
          duration: 5 * 1000
        })
        return
      } else {
        const loading = this.$loading({
          lock: true,
          text: 'Loading',
          spinner: 'el-icon-loading',
          background: 'rgba(0, 0, 0, 0.7)'
        })
        
        exportExcelData({ menuIds: menuIds }).then(response => {
          var fileName = 'download.zip'
          const contentDisposition = response.headers['content-disposition']
          if (contentDisposition) {
            fileName = window.decodeURI(response.headers['content-disposition'].split('=')[1], 'UTF-8')
          }
          const blob = new Blob([response.data], {
            type: `application/zip` // word文档为msword,pdf文档为pdf
          })
          const objectUrl = URL.createObjectURL(blob)
          const link = document.createElement('a')
          link.href = objectUrl
          link.setAttribute('download', fileName)
          document.body.appendChild(link)
          link.click()
          // 释放内存
          window.URL.revokeObjectURL(link.href)
          Message({
            message: '导出成功',
            type: 'success',
            duration: 5 * 1000
          })
          loading.close()
          this.$emit('update:visible', false)
          this.getList()
        }).catch(response => {
          loading.close()
        })
      }
    },
    closePage() {
      this.$emit('update:visible', false)
      this.getList()
    }
  }
}
</script>

image.gif

代码拆解:

通过前端传来的menuIds进行遍历,把每一条数据插到excel里面并且通过menuIds找到文件名与之对应的ktr文件放到文件夹中。

for (Long menuId : menuIds) {
      Conversion conversion = conversionMapper.selectById(menuId);
      if (conversion != null) {
        conversions.add(conversion);
        String ktrFilePath = fileService.getKtrFilePathById(menuId);
        if (ktrFilePath != null && !ktrFilePaths.contains(ktrFilePath)) {
          ktrFilePaths.add(ktrFilePath);
        }
      }
    }

image.gif

创建excel导出模板:

// 创建Excel工作簿
    HSSFWorkbook workbook = new HSSFWorkbook();
    // 创建一个工作表
    Sheet sheet = workbook.createSheet("Conversions");
    // 创建单元格样式,并设置为文本格式
    CellStyle textStyle = workbook.createCellStyle();
    DataFormat format = workbook.createDataFormat();
    textStyle.setDataFormat(format.getFormat("@")); // "@" 表示文本格式
    // 创建标题行
    Row titleRow = sheet.createRow(0);
    // 创建单元格样式,并设置为文本格式
    titleRow.createCell(0).setCellValue("主键");
    titleRow.createCell(1).setCellValue("分组id");
    titleRow.createCell(2).setCellValue("名称");
    titleRow.createCell(3).setCellValue("备注");
    titleRow.createCell(4).setCellValue("创建人");
    titleRow.createCell(5).setCellValue("关联状态");
    titleRow.createCell(6).setCellValue("XMl");
    titleRow.createCell(7).setCellValue("创建时间");
    // 应用文本格式到标题行的特定单元格
    titleRow.getCell(0).setCellStyle(textStyle);
    titleRow.getCell(1).setCellStyle(textStyle);
    // 填充数据
    int rowNum = 1;
    for (Conversion conversion : conversions) {
      Row row = sheet.createRow(rowNum++);
      Cell cell = row.createCell(0);
      cell.setCellValue(String.valueOf(conversion.getId()));
      cell.setCellStyle(textStyle);
      cell = row.createCell(1);
      cell.setCellValue(String.valueOf(conversion.getGroupId()));
      cell.setCellStyle(textStyle); // 应用文本格式
      row.createCell(2).setCellValue(conversion.getName());
      row.createCell(3).setCellValue(conversion.getRemark());
      row.createCell(4).setCellValue(conversion.getCreateUserName());
      row.createCell(5).setCellValue(conversion.getState());
      row.createCell(6).setCellValue(conversion.getEditXml());
      row.createCell(7).setCellValue(String.valueOf(conversion.getCreateTime()));
    }

image.gif

我这里的id和groupId位数特别长,所以对这两列做了默认为文本的处理,否则会变成科学计数法,会丢精。

具体如下:

 

// 创建单元格样式,并设置为文本格式
    CellStyle textStyle = workbook.createCellStyle();
    DataFormat format = workbook.createDataFormat();
    textStyle.setDataFormat(format.getFormat("@")); // "@" 表示文本格式
// 应用文本格式到标题行的特定单元格
    titleRow.getCell(0).setCellStyle(textStyle);
    titleRow.getCell(1).setCellStyle(textStyle);
Row row = sheet.createRow(rowNum++);
      Cell cell = row.createCell(0);
      cell.setCellValue(String.valueOf(conversion.getId()));
      cell.setCellStyle(textStyle);
      cell = row.createCell(1);
      cell.setCellValue(String.valueOf(conversion.getGroupId()));
      cell.setCellStyle(textStyle); // 应用文本格式

image.gif

把excel文件添加到压缩包:

// 将Excel文件添加到压缩包
    ZipEntry excelEntry = new ZipEntry("conversions.xls");
    zipOut.putNextEntry(excelEntry);
    workbook.write(zipOut);
    zipOut.closeEntry();
    workbook.close();

image.gif

把ktr文件放到ktr命名的文件夹中,并关闭压缩文件流

// 添加.ktr文件到ktr目录
    for (String filePath : ktrFilePaths) {
      File ktrFile = new File(filePath);
      if (ktrFile.exists()) {
        FileInputStream fis = new FileInputStream(ktrFile);
        // 创建ZipEntry时,需要包含ktr目录
        ZipEntry ktrEntry = new ZipEntry("ktr/" + ktrFile.getName());
        zipOut.putNextEntry(ktrEntry);
        byte[] bytes = new byte[1024];
        int length;
        while ((length = fis.read(bytes)) >= 0) {
          zipOut.write(bytes, 0, length);
        }
        fis.close();
        zipOut.closeEntry();
      }
    }
    // 完成压缩包
    zipOut.finish();
    zipOut.close();

image.gif

导出就完成了。

导入

后端

导入的时候有一个要求,就是把导出时的id作为老的id存到数据库里,并生成新的id把新的id作为对应ktr的文件名存到对应的路径下面

解析数据:

@PostMapping("/insertData")
  public ResultData insertData(@RequestAttribute Long _userId, HttpServletRequest request) {
    MultipartHttpServletRequest req = (MultipartHttpServletRequest) request;
    MultipartFile uploadFile = req.getFile("uploadfile_ant");
    String originalName = uploadFile.getOriginalFilename();
    String docPath = "";
    List<Long> codes = new ArrayList<>(); // 用于存储所有导入的 ID
    try {
      String classpath = ResourceUtils.getURL("classpath:").getPath();
      String path = classpath + File.separator + "static" + File.separator + "file" + File.separator + "yulan";
      docPath = path + File.separator + originalName;
      File dir = new File(path);
      if (!dir.exists()) {
        dir.mkdirs();
      }
      // 保存压缩文件
      File zipFile = new File(docPath);
      FileCopyUtils.copy(uploadFile.getInputStream(), new FileOutputStream(zipFile));
      // 解压压缩文件
      File unzipDir = new File(zipFile.getPath().substring(0, zipFile.getPath().lastIndexOf(".zip")));
      if (!unzipDir.exists()) {
        unzipDir.mkdirs();
      }
      unzipFile(zipFile, unzipDir);
      // 处理解压后的文件
      processUnzippedFiles(unzipDir);
      return ResultData.success("ok", codes); // 返回所有导入的 ID 列表
    } catch (Exception e) {
      e.printStackTrace();
      return ResultData.error("error");
    }
  }

image.gif

解压代码:

private void unzipFile(File zipFile, File unzipDir) throws IOException {
    try (ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFile))) {
      ZipEntry entry = zipIn.getNextEntry();
      while (entry != null) {
        String filePath = unzipDir.getPath() + File.separator + entry.getName();
        if (!entry.isDirectory()) {
          extractFile(zipIn, filePath);
        } else {
          File dir = new File(filePath);
          dir.mkdirs();
        }
        zipIn.closeEntry();
        entry = zipIn.getNextEntry();
      }
    }
  }

image.gif

private void extractFile(ZipInputStream zipIn, String filePath) throws IOException {
    new File(filePath).getParentFile().mkdirs();
    try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath))) {
      byte[] bytesIn = new byte[4096];
      int read = 0;
      while ((read = zipIn.read(bytesIn)) != -1) {
        bos.write(bytesIn, 0, read);
      }
    }
  }

image.gif

根据不同的文件类型去做不同的处理:

private void processUnzippedFiles(File unzipDir) throws Exception {
    // 遍历解压后的目录,处理每个文件
    Files.walk(unzipDir.toPath())
        .forEach(filePath -> {
          try {
            if (Files.isRegularFile(filePath) && filePath.toString().endsWith(".xls")) {
              //如果是excel文件
              processExcelFile(filePath, unzipDir.toPath());
//            } else if (Files.isDirectory(filePath) && "ktr".equals(filePath.getFileName().toString())) {
//              //ktr文件夹
//              processKtrDirectory(filePath);
            }
          } catch (Exception e) {
            e.printStackTrace();
          }
        });
  }

image.gif

处理excel:

@Transactional
  public void processExcelFile(Path filePath, Path zipPath) throws Exception {
    Workbook workbook = null;
    try {
      FileInputStream excelFile = new FileInputStream(filePath.toFile());
      workbook = WorkbookFactory.create(excelFile); // 支持多种格式
      // 假设我们只处理第一个工作表
      Sheet sheet = workbook.getSheetAt(0);
      // 跳过标题行
      int startRowIndex = 1;
      DataFormatter formatter = new DataFormatter();
      for (int i = startRowIndex; i <= sheet.getLastRowNum(); i++) {
        Row row = sheet.getRow(i);
        if (row != null) {
          // 假设Excel文件的列顺序和数据库字段对应
          Cell idCell = row.getCell(0);
          Cell groupIdCell = row.getCell(1);
          Cell NameCell = row.getCell(2);
          Cell remarkCell = row.getCell(3);
          Cell creatorCell = row.getCell(4);
          Cell xmlCell = row.getCell(6);
          // 检查空值和数据转换
          String setOldId = formatter.formatCellValue(row.getCell(0));
          String groupId = formatter.formatCellValue(row.getCell(1));
          String remark = (remarkCell != null) ? remarkCell.getStringCellValue() : null;
          String Name = (NameCell != null) ? NameCell.getStringCellValue() : null;
          String creator = (creatorCell != null) ? creatorCell.getStringCellValue() :null;
          String state = formatter.formatCellValue(row.getCell(5));
          String XML = (xmlCell != null) ? xmlCell.getStringCellValue() : null;
          // 创建一个数据对象,例如DataObject,并填充字段
          Conversion conversion = new Conversion();
          conversion.setId(SnowflakeIdGenerator.getId());
          conversion.setOldId(Long.parseLong(setOldId));
          conversion.setGroupId(Long.parseLong(groupId));
          conversion.setName(Name);
          conversion.setRemark(remark);
          conversion.setCreateUserId(creator);
          conversion.setState(Integer.parseInt(state));
          conversion.setEditXml(XML);
          conversion.setCreateTime(LocalDateTime.now());
          // 保存到数据库
          conversionMapper.insert(conversion);
          //ktr文件夹
          processKtrDirectory(zipPath, conversion.getId(), conversion.getOldId());
        }
      }
    } catch (Exception e) {
      throw new Exception("Error processing Excel file", e);
    } finally {
      if (workbook != null) {
        try {
          workbook.close();
        } catch (IOException e) {
          // Log and handle workbook close exception
        }
      }
    }
  }

image.gif

处理ktr:

private void processKtrDirectory(Path ktrDir, Long newId, Long oldId) throws Exception {
    // 处理ktr文件夹,将文件保存到磁盘路径下的逻辑
    // 例如:
    String targetPath = ktrPath + File.separator + Constant.kettleScriptFileName + File.separator + Constant.ktrFileName + File.separator;
    String newPath = ktrDir.toString()+"/ktr";
    try {
      Files.copy(Paths.get(newPath + File.separator + oldId.toString()), Paths.get(targetPath + newId.toString()));
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

image.gif

用copy(source,target)就可以实现把文件保存到指定路径

fileService.getKtrFilePathById:

/**
 * 根据menuId获取对应的.ktr文件路径。
 * @return 文件路径
 */
@Service
@Transactional
public class FileServiceImpl implements FileService {
    @Value("${ktr.path}")
    private String ktrPath;
    public String getKtrFilePathById(Long menuId) {
        // 假设.ktr文件存储在 "/path/to/ktr/files/" 目录下,文件名为 "menuId.ktr"
        String baseDir = ktrPath + File.separator + Constant.kettleScriptFileName + File.separator + Constant.ktrFileName+File.separator;
        File file = new File(baseDir + menuId);
        if (file.exists()) {
            return file.getAbsolutePath();
        } else {
            return null; // 或者抛出一个异常,表示文件不存在
        }
    }
}

image.gif

前端:

<template>
  <div class="app-container" style="margin: 0 auto;width:100%;">
    <el-form ref="form" label-width="80px" label-position="left">
      <!-- <el-form-item>
        <div slot="label">分组<font color="red">*</font></div>
        <el-select v-model="form.groupId" placeholder="请选择分组" style="width: 100%">
          <el-option v-for="item in fzList" :key="item.id" :label="item.name" :value="item.id" />
        </el-select>
      </el-form-item> -->
      <!-- <el-form-item>
        <div slot="label">模型名称<font color="red">*</font></div>
        <el-input v-model="form.name" style="width:100%;" :autosize="{ minRows: 2, maxRows: 2}" />
      </el-form-item> -->
      <el-form-item>
        <div slot="label">导入模型<font color="red">*</font></div>
        <el-upload
          accept=".zip"
          ref="upload"
          name="uploadfile_ant"
          class="upload-demo"
          :limit="1"
          :action="uploadpath"
          :headers="uoloadheaders"
          :before-upload="beforeAvatarUpload"
          :on-success="handleAvatarSuccess"
          :on-change="handleChange"
          :on-remove="handleRemove"
          :on-exceed="handleExceed"
          :file-list="fileList"
        >
          <el-button size="small" icon="el-icon-upload" type="primary">选择模型文件</el-button>
          <span style="color:red;">  上传文件大小不能超过100MB</span>
        </el-upload>
      </el-form-item>
      <!-- <el-form-item label="备注:">
        <el-input v-model="form.remark" type="textarea" maxlength="200" rows="6" placeholder="备注" />
      </el-form-item> -->
    </el-form>
    <!-- <div style="text-align: center;width:100%;">
      <el-button type="primary" @click="onSave">保存</el-button>
      <el-button type="danger" @click="closePage">取消</el-button>
    </div> -->
  </div>
</template>
<script>
import { getWorkList } from '@/api/dataSchema'
import { updateData } from '@/api/conversion'
import { Message, MessageBox } from 'element-ui'
import tool from '@/utils/tool'
export default {
  name: 'Zzjg',
  inject: ['getList'],
  props: {
    proid: {
      type: String,
      required: true
    }
  },
  data() {
    return {
      uploadpath: '',
      uoloadheaders: {},
      fileData: '', // 文件上传数据(多文件合一)
      fileList: [], // upload多文件数组
      fzList: [],
      form: {},
      code: ''
    }
  },
  methods: {
    getDetailed() {
      getWorkList().then(response => {        
        this.fzList = response.data
        let address = process.env.NODE_ENV == 'development' ? process.env.VUE_APP_URL_RECON : process.env.VUE_APP_BASE_API;
        var path = '/ltcloud/conversion/insertData'
        this.uploadpath = address + path
        
        this.uoloadheaders = {
          'X-TOKEN' : tool.getCookie('X-Token'),
          'client-url':location.href,
          'applicationId':this.applicationId
        }
      })
    },
    handleAvatarSuccess(res, file) {
      if (res.code === 20000) {
        this.code = res.data
        Message({
          message: '上传成功',
          type: 'success',
          duration: 5 * 1000
        })
      } else {
        Message({
          message: res.msg,
          type: 'error',
          duration: 5 * 1000
        })
      }
    },
    // 移除
    handleRemove(file, fileList) {
      this.fileList = fileList
    },
    beforeAvatarUpload(file) {
      const isLt2M = file.size / 1024 / 1024 < 100
      if (!isLt2M) {
        this.$message.error('上传文件大小不能超过100MB!')
      }
      return isLt2M
    },
    // 选取文件超过数量提示
    handleExceed(files, fileList) {
      this.$message.warning(`当前限制选择 1 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`)
    },
    // 监控上传文件列表
    handleChange(file, fileList) {
      const existFile = fileList.slice(0, fileList.length - 1).find(f => f.name === file.name)
      if (existFile) {
        this.$message.error('当前文件已经存在!')
        fileList.pop()
      }
      this.fileList = fileList
    },
    onSave() {
      console.log('分组不能为空')
      if (!this.form.groupId) {
        this.$message.error('分组不能为空')
        return
      } else if (!this.form.name) {
        this.$message.error('模型名称不能为空')
        return
      } else if (this.fileList.length === 0) {
        this.$message.error('导入模型不能为空')
        return
      } else {
        const loading = this.$loading({
          lock: true,
          text: 'Loading',
          spinner: 'el-icon-loading',
          background: 'rgba(0, 0, 0, 0.7)'
        })
        
        this.form.idList = this.code
        updateData(this.form).then(response => {
          Message({
            message: '编辑成功',
            type: 'success',
            duration: 5 * 1000
          })
          loading.close()
          this.$emit('update:visible', false)
          this.getList()
        }).catch(response => {
          loading.close()
          this.getList()
        })
      }
    },
    closePage() {
      this.$emit('update:visible', false)
      this.getList()
    }
  }
}
</script>
<style lang="less">
  /deep/ .el-dialog {
    width: 550px;
    height: 650px;
  }
  .displayCol {
    display: flex;
  }
  .newNum {
    height: 20px;
    width: 20px;
    border: 1px solid #333;
    border-radius: 50%;
    text-align: center;
    margin-top: 3px;
    line-height: 20px;
  }
  /deep/.el-form-item__label {
    text-align: left !important;
    padding: 0 10px;
  }
  .disabled-text {
    pointer-events: none; /* 阻止鼠标事件 */
    cursor: default; /* 将鼠标光标设置为默认样式,表明文本不可点击 */
    opacity: 0.5; /* 降低文本的不透明度以显示出它是不可交互的 */
    user-select: none; /* 禁止文本被选中 */
  }
  .el-upload-list {
    float: left;
    margin: 0;
    padding: 0;
    list-style: none;
  }
  .el-upload {
    margin-left: 0px;
    display: inline-block;
    text-align: center;
    cursor: pointer;
    outline: 0;
  }
  .el-upload__tip {
    font-size: 12px;
    color: #606266;
    margin-top: 7px;
    width: 300px;
    line-height: 45px;
    height: 10px;
  }
</style>

image.gif


目录
相关文章
|
20天前
|
人工智能 自然语言处理 Java
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
FastExcel 是一款基于 Java 的高性能 Excel 处理工具,专注于优化大规模数据处理,提供简洁易用的 API 和流式操作能力,支持从 EasyExcel 无缝迁移。
91 9
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
|
1月前
|
Python
按条件将Excel文件拆分到不同的工作表
使用Python的pandas库,可以轻松将Excel文件按条件拆分到不同的工作表中。本文通过一个示例代码展示了如何生成一个包含总成绩表和三个班级表的Excel文件。代码首先创建了一个包含学生姓名、班级和各科成绩的数据框,然后按班级分组,将每个班级的数据分别写入不同的工作表。最后,生成的Excel文件将包含四个工作表,分别为总成绩表和三个班级的成绩表。
38 6
按条件将Excel文件拆分到不同的工作表
|
23天前
|
存储 Java easyexcel
招行面试:100万级别数据的Excel,如何秒级导入到数据库?
本文由40岁老架构师尼恩撰写,分享了应对招商银行Java后端面试绝命12题的经验。文章详细介绍了如何通过系统化准备,在面试中展示强大的技术实力。针对百万级数据的Excel导入难题,尼恩推荐使用阿里巴巴开源的EasyExcel框架,并结合高性能分片读取、Disruptor队列缓冲和高并发批量写入的架构方案,实现高效的数据处理。此外,文章还提供了完整的代码示例和配置说明,帮助读者快速掌握相关技能。建议读者参考《尼恩Java面试宝典PDF》进行系统化刷题,提升面试竞争力。关注公众号【技术自由圈】可获取更多技术资源和指导。
|
1月前
|
Python
批量将不同的工作簿合并到同一个Excel文件
本文介绍如何使用Python的`pandas`库批量合并不同工作簿至同一Excel文件。通过模拟生成三个班级的成绩数据,分别保存为Excel文件,再将这些文件合并成一个包含所有班级成绩的总成绩单。步骤包括安装必要库、生成数据、保存与合并工作簿。
55 6
|
1月前
|
Python
按条件将Excel文件拆分到不同的工作表
使用Python的pandas库,可以轻松将Excel文件按条件拆分为多个工作表。本文通过一个具体示例,展示了如何根据学生班级将成绩数据拆分到不同的工作表中,并生成一个包含总成绩表和各班级成绩表的Excel文件。代码简洁明了,适合初学者学习和应用。
49 6
|
1月前
|
数据采集 数据可视化 数据挖掘
利用Python自动化处理Excel数据:从基础到进阶####
本文旨在为读者提供一个全面的指南,通过Python编程语言实现Excel数据的自动化处理。无论你是初学者还是有经验的开发者,本文都将帮助你掌握Pandas和openpyxl这两个强大的库,从而提升数据处理的效率和准确性。我们将从环境设置开始,逐步深入到数据读取、清洗、分析和可视化等各个环节,最终实现一个实际的自动化项目案例。 ####
158 10
|
3月前
|
数据采集 存储 JavaScript
自动化数据处理:使用Selenium与Excel打造的数据爬取管道
本文介绍了一种使用Selenium和Excel结合代理IP技术从WIPO品牌数据库(branddb.wipo.int)自动化爬取专利信息的方法。通过Selenium模拟用户操作,处理JavaScript动态加载页面,利用代理IP避免IP封禁,确保数据爬取稳定性和隐私性。爬取的数据将存储在Excel中,便于后续分析。此外,文章还详细介绍了Selenium的基本设置、代理IP配置及使用技巧,并探讨了未来可能采用的更多防反爬策略,以提升爬虫效率和稳定性。
216 4
|
5月前
|
关系型数据库 MySQL Shell
不通过navicat工具怎么把查询数据导出到excel表中
不通过navicat工具怎么把查询数据导出到excel表中
62 0
|
3月前
|
数据处理 Python
Python实用记录(十):获取excel数据并通过列表的形式保存为txt文档、xlsx文档、csv文档
这篇文章介绍了如何使用Python读取Excel文件中的数据,处理后将其保存为txt、xlsx和csv格式的文件。
220 3
Python实用记录(十):获取excel数据并通过列表的形式保存为txt文档、xlsx文档、csv文档
|
3月前
|
easyexcel Java UED
SpringBoot中大量数据导出方案:使用EasyExcel并行导出多个excel文件并压缩zip后下载
在SpringBoot环境中,为了优化大量数据的Excel导出体验,可采用异步方式处理。具体做法是将数据拆分后利用`CompletableFuture`与`ThreadPoolTaskExecutor`并行导出,并使用EasyExcel生成多个Excel文件,最终将其压缩成ZIP文件供下载。此方案提升了导出效率,改善了用户体验。代码示例展示了如何实现这一过程,包括多线程处理、模板导出及资源清理等关键步骤。