vue+SpringBoot的easyExcel导入导出

vue+SpringBoot的easyExcel导入导出

导入依赖:

<dependency>
  <groupId>org.apache.poi</groupId>
  <artifactId>poi-ooxml</artifactId>
  <version>4.0.1</version>
</dependency>
<dependency>
  <groupId>org.apache.poi</groupId>
  <artifactId>poi</artifactId>
   <version>4.0.1</version>
</dependency>
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>easyexcel</artifactId>
  <version>2.1.6</version>
</dependency>

实体类及注解:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class MonitorNoise {
    @ExcelIgnore
    private String id;

    @ExcelProperty(value = "设备名称",index = 0)
    private String name;

    @ExcelProperty(value = "时间",index = 1)
    private String time;

    @ExcelProperty(value = "设备位置",index = 2)
    private String place;
}

1.导入

controller层:

@RestController
@RequestMapping(value = "/import")
public class ImportController {

    @Autowired
    ImportNoiseListener noiseListener;
    
    //噪声监测数据导入
    @RequestMapping("/importNoise")
    public void importNoise(@RequestParam(name = "file",required = true) MultipartFile excl)
    {
        try {
            InputStream inputStream=excl.getInputStream();
            EasyExcel.read(inputStream, noiseListener)
                    // 设置sheet,默认读取第一个
                    .sheet()
                    .head(MonitorNoise.class)
                    // 设置标题所在行数
                    .headRowNumber(1)
                    .doReadSync();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

监听器及调用service:

@Component
public class ImportNoiseListener extends AnalysisEventListener<MonitorNoise> {
    /**
     * 每隔5120条存储数据库,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 128;
    private List<String> errMessage;

    List<MonitorNoise> noises = new ArrayList<>();
    private ImportService importService;

    public ImportNoiseListener(ImportService importService) {
        this.importService = importService;
        errMessage = new ArrayList<>();
    }

    @Override
    public void invoke(MonitorNoise monitorNoise, AnalysisContext context) {
        noises.add(monitorNoise);
        // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
        if (noises.size() >= BATCH_COUNT) {
            errMessage.addAll(saveData());
            // 存储完成清理 list
            noises.clear();
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        errMessage.addAll(saveData());
        noises.clear();
    }
    /**
     * 加上存储数据库
     */
    private List<String> saveData() {
        return importService.saveNoises(noises);
    }

    public List<String> getErrMessage() {
        return errMessage;
    }

    public void setErrMessage(List<String> errMessage) {
        this.errMessage = errMessage;
    }

}

service层接口:

@Service
public interface ImportService {
    List<String> saveNoises(List<MonitorNoise> list);
}

service层实现类:

@Service
public class ImportServiceImpl implements ImportService {

    @Autowired
    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

    @Override
    public List<String> saveNoises(List<MonitorNoise> noises) {
        ArrayList<String> errMessage = new ArrayList<>();
        MonitorNoise noise = new MonitorNoise();
        Map<String,Object> params = new HashMap<>();
        StringBuilder sql = new StringBuilder("INSERT INTO xxx (name, time, place) VALUES ( :name, :time, :place)");
        params.put("name", noise.getName());
        params.put("time", noise.getTime());
        params.put("place", noise.getPlace());
        SqlParameterSource[] paramss = SqlParameterSourceUtils.createBatch(noises.toArray());

        namedParameterJdbcTemplate.batchUpdate(sql.toString(), paramss);
        return errMessage;
    }
}

导出

controller层:

@RestController
@RequestMapping("/export")
public class ExportController {

    @Autowired
    ExportService exportService;

    @RequestMapping("/exportNoise")
    public void a(HttpServletResponse response){
        try{
            exportService.exportNoise(response);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

service层接口:

@Service
public interface ExportService {
    void exportNoise(HttpServletResponse response);
}

service层实现类:

@Service
public class ExportServiceImpl implements ExportService {

    @Autowired
    NamedParameterJdbcTemplate jdbcTemplate;

    @Override
    public void exportNoise(HttpServletResponse response) {
        try {
            List<MonitorNoise> list = new ArrayList<MonitorNoise>();
            String name = "噪声监测数据导入模板.xlsx";
            // 导出时候会出现中文无法识别问题,需要转码
            String fileName = new String(name.getBytes("gb2312"),"ISO8859-1");
            response.setContentType("application/vnd.ms-excel;chartset=utf-8");
            response.setHeader("Content-Disposition","attachment;filename=" + fileName);
            //调用工具类
            ExcelWriter writer = EasyExcel.write(response.getOutputStream()).registerWriteHandler(new CustomCellWriteHandler()).build();
            WriteSheet sheet = EasyExcel.writerSheet(0,"sheet").head(MonitorNoise.class).build();
            writer.write(list,sheet);
            writer.finish(); // 使用完毕之后关闭
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

涉及工具类:
导出excel自动列宽工具类:

/**
 * Excel 导出列宽度自适应
 */
public class CustomCellWriteHandler extends AbstractColumnWidthStyleStrategy {

    private Map<Integer, Map<Integer, Integer>> CACHE = new HashMap<>();

    @Override
    protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> cellDataList, Cell cell, Head head, Integer integer, Boolean isHead) {
        boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList);
        if (needSetWidth) {
            Map<Integer, Integer> maxColumnWidthMap = CACHE.get(writeSheetHolder.getSheetNo());
            if (maxColumnWidthMap == null) {
                maxColumnWidthMap = new HashMap<>();
                CACHE.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap);
            }

            Integer columnWidth = this.dataLength(cellDataList, cell, isHead);
            if (columnWidth >= 0) {
                if (columnWidth > 255) {
                    columnWidth = 255;
                }

                Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex());
                if (maxColumnWidth == null || columnWidth > maxColumnWidth) {
                    maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth);
                    writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), columnWidth * 256);
                }

            }
        }
    }

    private Integer dataLength(List<CellData> cellDataList, Cell cell, Boolean isHead) {
        if (isHead) {
            return cell.getStringCellValue().getBytes().length;
        } else {
            CellData cellData = cellDataList.get(0);
            CellDataTypeEnum type = cellData.getType();
            if (type == null) {
                return -1;
            } else {
                switch (type) {
                    case STRING:
                        return cellData.getStringValue().getBytes().length;
                    case BOOLEAN:
                        return cellData.getBooleanValue().toString().getBytes().length;
                    case NUMBER:
                        return cellData.getNumberValue().toString().getBytes().length;
                    default:
                        return -1;
                }
            }
        }
    }
}

vue前端导入时:

html代码:

	<el-dialog
      :title="title"
      :visible.sync="this.dialogVisibleNoise"
      width="600px"
      top="8vh"
      :before-close="colseDialog"
      :close-on-click-modal="false"
    >
      <el-row class="import-dialog-row">
        <el-col :span="12">
          <el-upload
            class="uploadFile"
            ref="upload"
            :action=""
            accept=".xls,.xlsx"
            async="false"
            :limit="1"
            :on-success="handleSuccess"
            :file-list="fileList"
            :before-upload="beforeUpload"
            :auto-upload="false"
            :on-remove="handleRemove"
            :on-progress="onProgress"
            element-loading-text="数据导入中,请稍等..."
            v-loading.fullscreen="loading"
          >
            <el-button slot="trigger" size="small" type="primary"
              >选择文件</el-button
            >
            <el-tooltip placement="right-start" style="padding-left: 20px">
              <div slot="content">单次导入,文件数据条数不能超过10000条</div>
              <i class="el-icon-warning"></i>
            </el-tooltip>
          </el-upload>
        </el-col>
      </el-row>
      <el-row style="line-height: 35px">
        <el-col :span="12">
          <div v-show="showInf">
            <span style="color: red">导入失败</span>
          </div>
        </el-col>
        <el-col :span="12"> </el-col>
      </el-row>
      <span slot="footer" class="dialog-footer">
        <el-button size="small" @click="handleClose">{{
          $t("base.button.cancel")
        }}</el-button>
        <el-button size="small" type="primary" @click="handleSave()"
          >导入</el-button
        >
      </span>
    </el-dialog>

js func代码:

	//取消按钮
    handleClose() {
      this.$refs.upload.clearFiles();
      this.isShow = true;
      this.showInf = false;
      this.dialogVisibleNoise = false;
      this.initNoiseData();
    },
    //导入按钮
    handleSave() {
      // debugger;
      let formFile = new FormData();
      formFile.append("file", this.$refs.upload.uploadFiles);
      // this.fileList = this.$refs.upload.uploadFiles;
      for (const key in this.fileList[0]) {
        // debugger;
        if (this.fileList[0].hasOwnProperty(key)) {
          if (this.fileList[0][key]) {
            formFile.append(key, this.fileList[0][key]);
          }
        }
      }
      this.$refs.upload.submit(formFile);
      this.isShow = false;
    },
    //上传成功事件
    handleSuccess(response) {
      var _this = this;
      _this.loading = false;
      console.log(response);
      _this.information = response;
      if (response.code === 500) {
        _this.showInf = true;
        _this.$message.error(response.message || "文件导入失败!");
        return;
      } else {
        _this.$message.success("文件导入成功!");
        _this.handleClose();
      }
    },
    colseDialog() {
      this.$refs.upload.clearFiles();
      this.isShow = true;
      this.showInf = false;
      this.dialogVisibleNoise = false;
    },
    //上传文件前,判断文件类型
    beforeUpload(file) {
      if (file.name.indexOf(".xls") == -1) {
        this.$message.error("只允许上传xls格式文件!");
        return false;
      }
      return true;
    },
    //文件移除事件
    handleRemove() {
      this.isShow = true;
      this.showInf = false;
    },
    onProgress() {
      this.loading = true;
    },

vue前端导出时:

html代码:

	<el-col :span="4">
          <el-button type="primary" size="small" @click="downloadTemplate">下载模板</el-button>
    </el-col>

js func代码:

//下载导入模板
    downloadTemplate(){
      var that = this;
      this.axios[""]
        .request({
          url: "",
          method: "get",
          responseType: "blob"
        })
        .then(function (response) {
          console.log(response)
          console.log(new Blob([response]));
          var blob = new Blob([response], { type: "application/x-xls" }); //创建一个blob对象
          var a = document.createElement("a"); //创建一个<a></a>标签
          a.href = URL.createObjectURL(blob); // response is a blob
          a.download = "000.xlsx"; //文件名称
          a.style.display = "none";
          document.body.appendChild(a);
          a.click();
          a.remove();
          that.dialogVisibleNoise = false
        })
        .catch(function (err) {
          console.log(err);
        });
    },

完毕

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值