Vue+easyexcel实现excel导入导出

1.引入easyexcel依赖

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.0.5</version>
        </dependency>

2.导出实体

@Data
@EqualsAndHashCode(callSuper = false)
@ApiModel(value="Account对象", description="")
public class Account implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "id")
    @TableId(value = "id", type = IdType.AUTO)
    @ExcelIgnore
    private Integer id;

    @ApiModelProperty(value = "昵称")
    @ExcelProperty("用户名")
    private String username;

    @ApiModelProperty(value = "用户密码")
    @ExcelIgnore
    private String password;

    @ApiModelProperty(value = "真实姓名")
    @ExcelProperty("真实姓名")
    private String pname;

    @ApiModelProperty(value = "性别")
    @ExcelProperty("性别")
    private String sex;

    @ApiModelProperty(value = "手机号码")
    @ExcelProperty("性别")
    private String phone;

    @ApiModelProperty(value = "头像")
    @ExcelIgnore
    private String touxiang;

    @ApiModelProperty(value = "会员")
    @ExcelProperty(value = "等级")
    private Integer member;

    @ApiModelProperty(value = "地址")
    @ExcelProperty(value = "地址")
    private String address;

    @ApiModelProperty(value = "生日")
    @ExcelProperty(value = "生日")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private LocalDate birthday;

    @ApiModelProperty(value = "注册日期")
    @ExcelProperty(value = "注册日期")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;

    @ApiModelProperty(value = "存在状态")
    @ExcelProperty(value = "账户状态")
    private Integer estate;

    @ApiModelProperty(value = "身份证号码")
    @ExcelProperty(value = "身份证号码")
    private String idCard;


}

3.导出时设置转化器

因为我用的是localdate和localdatetime

1.定义转化器,如下

import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

/**
 * @Author: ChenTaoTao
 * @Date: 2022/3/28 10:07
 * @Describe:
 */
public class LocalDateConverter implements Converter<LocalDate> {
 
    @Override
    public Class<LocalDate> supportJavaTypeKey() {
        return LocalDate.class;
    }

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


    @Override
    public LocalDate convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
        return LocalDate.parse(cellData.getStringValue(), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }

    @Override
    public WriteCellData<String> convertToExcelData(LocalDate value, ExcelContentProperty contentProperty,
                                                    GlobalConfiguration globalConfiguration) {
        return new WriteCellData<>(value.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
    }
 
}
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * @Author: ChenTaoTao
 * @Date: 2022/3/28 10:07
 * @Describe:
 */
public class LocalDateTimeConverter  implements Converter<LocalDateTime> {
    @Override
    public Class<LocalDateTime> supportJavaTypeKey() {
        return LocalDateTime.class;
    }

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


    @Override
    public LocalDateTime convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
        return LocalDateTime.parse(cellData.getStringValue(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }

    @Override
    public WriteCellData<String> convertToExcelData(LocalDateTime value, ExcelContentProperty contentProperty,
                                                    GlobalConfiguration globalConfiguration) {
        return new WriteCellData<>(value.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
    }

}

2.导出工具类

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

/**
 * @Author: ChenTaoTao
 * @Date: 2022/3/19 16:51
 * @Describe: 文件导出
 */
@Slf4j
public class EasyExcelUtil {
    public static <T> void writeExcel(HttpServletRequest request,HttpServletResponse response, List<T> data, Class tClass, String name){
        try {
            String dateStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
            name = name+dateStr;
            //防止下载时中文乱码
            name = new String(name.getBytes("UTF-8"), "ISO-8859-1");
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            //添加这个是防止前端拿不到Content-disposition
            response.setHeader("Content-Disposition", "attachment;filename=" + name+".xlsx");
            response.setHeader("Access-Control-Expose-Headers","Content-disposition");
            // 这里需要设置不关闭流
            EasyExcel.write(response.getOutputStream(), tClass).autoCloseStream(Boolean.FALSE).sheet(name).registerConverter(new LocalDateConverter()).registerConverter(new LocalDateTimeConverter())
                    .doWrite(data);
        } catch (Exception e) {
            log.error("文件导出失败,错误信息{}",e);
            // 重置response
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            R r = R.err("文件下载失败");
            try {
                response.getWriter().println(JSON.toJSONString(r));
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
        }
    }
}

4.controller使用

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author chentaotao
 * @since 2022-03-23
 */
@RestController
@RequestMapping("/mall/account")
@Api
public class AccountController {

    @Autowired
    private IAccountService iAccountService;
    
    @GetMapping("/export")
    @ApiOperation(value = "文件导出")
    public void export(HttpServletResponse response){
        List<Account> accountList = iAccountService.list();
        EasyExcelUtil.writeExcel(accountList,Account.class,"账户");
    }

}

5.自定义vue 导出请求

此处使用axios

import axios from 'axios'
//此处忽略了部分非必要的导入

// create an axios instance
const service = axios.create({
//baseUrl请修改为你自己的url
  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
  // withCredentials: true, // send cookies when cross-domain requests
  timeout: 5000 // request timeout
})
// response interceptor
service.interceptors.response.use(
  /**
   * If you want to get http information such as headers or status
   * Please return  response => response
   */

  /**
   * Determine the request status by custom code
   * Here is just an example
   * You can also judge the status by HTTP Status Code
   */
  response => {
      let disposition = response.headers['content-disposition'];
      //以下部分有需要优化,如后端返回时没有携带文件后缀名,没有.时会有问题等等
      let filename = disposition?disposition.substring(disposition.indexOf('=')+1,disposition.indexOf('.')):"下载文件";
      let newName = decodeURI(escape(filename))
      let extName =disposition.substring(disposition.indexOf('.')+1)
      let blob = new Blob([response.data],{type: 'application/vnd.ms-excel'});
      let link = document.createElement("a");
      let evt = document.createEvent("HTMLEvents");
      evt.initEvent("click", false, false);
      link.href = URL.createObjectURL(blob);
      link.download = newName+"."+extName;
      link.style.display = "none";
      document.body.appendChild(link);
      link.click();
      window.URL.revokeObjectURL(link.href);
  },
  error => {
    console.log('err' + error) // for debug
    Message({
      message: error.message,
      type: 'error',
      duration: 5 * 1000
    })
    return Promise.reject(error)
  }
)

export default service

6.vue中的导出使用

//exportExcel 则是刚刚5.自定义导出请求的代码
import exportExcel from '@/utils/export'

export function exportExcels(data) {
  return exportExcel({
    url: '/mall/account/export',
    method: 'get',
    responseType: 'blob'
    // params: { id: params }
  })
}

vue中的使用

<template>
  <div class="app-container">

      <el-card style="width: 98%;margin: 0 auto">
        <el-form :inline="true" :model="query" style="padding-left: 3%" class="demo-form-inline" >
          <el-form-item label="用户名" >
            <el-input v-model="query.userName" placeholder="用户名" />
          </el-form-item>
          <el-form-item label="真实姓名">
            <el-input v-model="query.realName" placeholder="真实姓名" />
          </el-form-item>
          <el-form-item label="状态">
            <el-select v-model="query.state" placeholder="状态">
              <el-option label="全部" value="" />
              <el-option label="启用" value="1" />
              <el-option label="禁用" value="0" />
            </el-select>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="getList">查询</el-button>
          </el-form-item>

          <el-button style="float: right" @click="open">新增用户</el-button>
        </el-form>

        <el-button @click="exportExcel">导出</el-button>
      </el-card>



      <Dialog ref="dialog" :config="config" @fresh ="getList" :before-close="beforeClose" @close="resetForm" />

      <el-card style="margin-top: 20px;width: 98%;margin: 0 auto;padding-left: 2%">
        <!--数据列表-->
        <el-table
          v-loading="listLoading"
          :data="list"
          element-loading-text="载入中"
          border
          fit
          stripe
          highlight-current-row
          :height="tableHeight"
        >
          <el-table-column label="id" width="120px" align="center">
            <template slot-scope="scope">
              <span>{{ scope.row.id }}</span>
            </template>
          </el-table-column>
          <el-table-column label="用户名" width="120px" align="center">
            <template slot-scope="scope">
              <span>{{ scope.row.userName }}</span>
            </template>
          </el-table-column>
          <el-table-column label="用户姓名" width="300px" align="center">
            <template slot-scope="scope">
              <span>{{ scope.row.realName }}</span>
            </template>
          </el-table-column>
          <el-table-column label="状态" width="120px" align="center">
            <template slot-scope="scope">
              <span>{{ scope.row.state=='1'?'启用':'禁用' }}</span>
            </template>
          </el-table-column>
          <el-table-column label="创建时间" width="180px" align="center">
            <template slot-scope="scope">
              <i class="el-icon-time" />
              <span style="margin-left: 10px">{{ scope.row.createTime }}</span>
            </template>
          </el-table-column>
          <el-table-column label="更新时间" width="180px" align="center">
            <template slot-scope="scope">
              <i class="el-icon-time" />
              <span style="margin-left: 10px">{{ scope.row.updateTime }}</span>
            </template>
          </el-table-column>
          <el-table-column label="操作">
            <template slot-scope="scope">
              <el-button
                size="mini"
                @click="handleEdit(scope.$index, scope.row)"
              >编辑</el-button>
              <el-button
                size="mini"
                type="danger"
                @click="handleDelete(scope.$index, scope.row)"
              >删除</el-button>
            </template>
          </el-table-column>
        </el-table>
        <el-pagination
          :current-page="query.pageNo"
          :page-sizes="[1, 20, 50, 100]"
          :page-size="query.pageSize"
          layout="total, sizes, prev, pager, next, jumper"
          :total="total"
          @size-change="pageSizeChange"
          @current-change="pageCurrentChange"
        />

      </el-card>
    </div>



</template>
<script>
import { getPage, deleteBatch} from '@/api/user'
import Dialog from '@/pages/user/dialog/UserDialog'
import {exportExcels} from "@/api/exportExcel";
export default {
  components: {
    Dialog
  },
  data() {
    return {
      listLoading: true,
      tableHeight: window.innerHeight - 300,
      query: {
        pageNo: 1,
        pageSize: 10,
        userName: '',
        state: ''
      },
      list: [],
      deleteIds: {
        ids: []
      },
      total: 1,
      count: 1,
      config: {
        id: '',
        top: '20vh',
        width: '500px',
        title: '温馨提示',
        center: true,
        btnTxt: ['取消', '提交']
      }
    }
  },
  created() {
    this.getList()
  },
  methods: {
    getList() {
      this.listLoading = true;
      const data = getPage(this.query).then(res => {
        this.list = res.data.records
        this.total = res.data.total
      })
      this.listLoading = false
    },
    pageSizeChange(val) {
      console.log(val)
      this.query.pageSize = val
      this.getList()
    },
    pageCurrentChange(val) {
      console.log(val)
      this.query.pageNo = val
      this.getList()
    },
    handleEdit(index, row) {
      // console.log(row)
      this.config.id = row.id
      this.open()
    },
    handleDelete(index, row) {
      this.deleteIds.ids.push(row.id)
      deleteBatch(this.deleteIds).then(res => {
        this.getList()
      }).catch(err => {
        console.log(err)
      })
    },
    open() {
      this.$refs.dialog.open(cancel => {
        // cancel();

      })
      // .then(() => {console.log(this.$refs.span)});   //这里就充分利用了open方法中返回的nextTick
    },
    beforeClose() {

    },
    resetForm() {
      // 这里可以写重置表单的实现
    },
    exportExcel(){
    //此处就是导出
      exportExcels().then()
    }
  }
}
</script>

效果如下:

在这里插入图片描述
点击导出后
在这里插入图片描述
当然这里的账户状态可以自定义convert做转化

7.导入

本质就是文件上传

1.定义数据处理类

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author: ChenTaoTao
 * @Date: 2022/3/28 12:25
 * @Describe:
 */
@Slf4j
public class AccountImportListener extends AnalysisEventListener<Account> {

    private static final int BATCH_COUNT = 1000;

    List<Account> data = new ArrayList<>();

    IAccountService accountService;

    public AccountImportListener(IAccountService accountService){
        this.accountService = accountService;
    }

    /**
     *  读数据的过程中要做什么,如设置默认值等等
     */
    @Override
    public void invoke(Account account, AnalysisContext analysisContext) {
        log.info("被添加的数据为i{}",account);
        data.add(account);
        if(data.size()==BATCH_COUNT){
           accountService.saveBatch(data);
           data.clear();
        }
    }

    /**
     * 所有数据读完以后要做什么
     * @param analysisContext
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {

        if(!CollectionUtils.isEmpty(data)){
            accountService.saveBatch(data);
            data.clear();
        }
        log.info("恭喜,数据已经导入成功啦!");
    }
}

2.controller中使用:

    @PostMapping("import")
    @ApiOperation(value = "导入")
    public R importData(@RequestPart("file")MultipartFile file) throws IOException {
        EasyExcel.read(file.getInputStream(),Account.class,new AccountImportListener(iAccountService)).sheet().registerConverter(new LocalDateTimeConverter())
        .registerConverter(new LocalDateConverter()).doRead();
        return R.ok();
    }
  • 7
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
实现上传excel文件并将数据传输到数据库的步骤如下: 1. 前端实现文件上传功能:使用Vue.js开发前端页面,使用element-ui组件库实现文件上传组件。具体实现可以参考element-ui的文档和示例代码。 2. 后端实现文件上传功能:使用Spring Boot框架开发后端接口,使用Apache POI或者EasyExcel解析Excel文件并将数据存入数据库。具体实现可以参考Spring Boot官方文档和EasyExcel的官方文档。 3. 前后端交互:前端页面通过Ajax请求后端接口上传文件,并将文件数据以form-data格式传输到后端。后端接口接收到请求后,解析Excel文件并将数据存入数据库,最后返回上传结果给前端。 下面是一个简单的示例代码,仅供参考: 前端代码: ```vue <template> <el-upload class="upload-demo" drag action="/api/upload" :before-upload="beforeUpload" :on-success="onSuccess" :on-error="onError" > <i class="el-icon-upload"></i> <div class="el-upload__text">将 Excel 文件拖到此处,或点击上传</div> <div class="el-upload__tip" slot="tip">仅支持 .xls 和 .xlsx 格式的 Excel 文件</div> </el-upload> </template> <script> export default { methods: { beforeUpload(file) { const isExcel = file.type === 'application/vnd.ms-excel' || file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; if (!isExcel) { this.$message.error('只能上传 .xls 或 .xlsx 格式的 Excel 文件'); } return isExcel; }, onSuccess(response) { if (response.code === 0) { this.$message.success('上传成功'); } else { this.$message.error(`上传失败: ${response.msg}`); } }, onError(error) { this.$message.error(`上传失败: ${error.message}`); }, }, }; </script> ``` 后端代码: ```java @RestController @RequestMapping("/api") public class UploadController { @PostMapping("/upload") public Result<?> upload(@RequestParam("file") MultipartFile file) throws IOException { if (file.isEmpty()) { return Result.error("上传失败: 文件为空"); } String filename = file.getOriginalFilename(); String ext = FilenameUtils.getExtension(filename); if (!"xls".equals(ext) && !"xlsx".equals(ext)) { return Result.error("上传失败: 仅支持 .xls 或 .xlsx 格式的 Excel 文件"); } List<User> userList = new ArrayList<>(); Workbook workbook = WorkbookFactory.create(file.getInputStream()); Sheet sheet = workbook.getSheetAt(0); for (int i = 1; i <= sheet.getLastRowNum(); i++) { Row row = sheet.getRow(i); if (row == null) { continue; } User user = new User(); user.setName(row.getCell(0).getStringCellValue()); user.setAge((int) row.getCell(1).getNumericCellValue()); user.setGender(row.getCell(2).getStringCellValue()); userList.add(user); } userService.saveAll(userList); return Result.ok(); } } ``` 上述代码中,`UploadController`是一个Spring MVC的控制器类,用于处理上传文件的请求。`upload`方法接收一个`MultipartFile`类型的参数,即前端上传的文件数据。在方法中,我们首先判断文件是否为空,然后根据文件的扩展名判断是否为Excel文件。如果不是Excel文件,则返回上传失败的结果。否则,我们使用Apache POI库解析Excel文件,将数据转换成`User`对象并存入数据库。最后,返回上传成功的结果。 需要注意的是,上述代码中的`User`对象是一个自定义的Java类,用于存储Excel中的数据。在实际开发中,需要根据实际情况定义相应的Java类来存储数据。同时,还需要在Spring Boot的配置文件中配置数据库连接信息、数据源等相关信息。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

SinceThenLater

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

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

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

打赏作者

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

抵扣说明:

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

余额充值