Vue+SpringBoot导出Excel,自定义要导出的表格的列

Vue+SpringBoot导出Excel,自定义要导出的表格的列

  • 前言
  • 一、Vue弹出层?
    • 1.数据展示
    • 2.导出弹出层
    • 3.弹出层界面
  • 二、后端API
    • 1.控制类
    • 2.实现逻辑
  • 总结


前言

之前一篇博客介绍了使用POI来完成报表的导出,默认都是导出所有数据列,但是我们有时候可能需要导出某些指定的列,搭配我前端使用的Vue和ElementUI,然后便做出来个可以自定义导出列的功能


一、Vue弹出层?

1.数据展示

首先我们来看一下我们要导出的数据,先看一下所有的列

在这里插入图片描述看一下data中的数据,有用户名和日期搜索

// el
ifLoading: false,
exportShow: false,
userDataList: [],
rangeTime: '',
searchData: {
     
  total: 0,
  pageNum: 1,
  pageSize: 5,
  userAccount: '',
},
columnTitle: [],

下面可以看到prop,label这些属性就是我们一会儿需要获取到的数据

<el-table :data="userDataList" border style="width: 100%;" class="el-table01" v-loading="ifLoading" ref="userDataListRef">
  <el-table-column prop="index" :label="$t('serialNo')" align="center"></el-table-column>
  <el-table-column prop="userAccount" :label="$t('account')" align="center"></el-table-column>
  <el-table-column prop="userName" :label="$t('userName')" align="center"></el-table-column>
  <el-table-column prop="userSex" :label="$t('userSex')" align="center">
    <template slot-scope="scope">
      <span v-if="scope.row.userSex == 0">{
     {
     $t('womanText')}}</span>
      <span v-if="scope.row.userSex == 1">{
     {
     $t('manText')}}</span>
    </template>
  </el-table-column>
  <el-table-column prop="userIslogin" :label="$t('isLogin')" align="center">
    <template slot-scope="scope">
      <span v-if="scope.row.userIslogin == 0">{
     {
     $t('offline')}}</span>
      <span v-if="scope.row.userIslogin == 1" style="color: #357ae8;font-weight: bold;">{
     {
     $t('online')}}</span>
    </template>
  </el-table-column>
  <el-table-column prop="userBirthday" :label="$t('birthday')" align="center"></el-table-column>
  <el-table-column prop="userCreateTime" :label="$t('createTime')" align="center"></el-table-column>
</el-table>

2.导出弹出层

在这里我使用了el-popover,弹出层组件都想试一下嘛,其实这个的确没有其他的好用

<div class="btnBox">
  <el-button size="medium" :loading="ifLoading" type="primary" @click="queryMainData()">{
     {
      $t('search') }}</el-button>
  <el-popover
    placement="bottom"
    width="320"
    :offset="-100"
    v-model="exportShow">
    <h2>{
     {
      $t('pleaseSelectEx') }}</h2>
    <div class="excel-title-cls">
      <el-row>
        <el-col v-for="ct in columnTitle" :key="ct.prop" :span="10">
        <span v-if="ct.prop != 'index'">
          <el-checkbox class="btn-check" v-model="ct.checked" border>{
     {
     ct.label}}</el-checkbox>
        </span>
          <span v-else>
          <el-checkbox class="btn-check" v-model="ct.checked" disabled border>{
     {
     ct.label}}</el-checkbox>
        </span>
        </el-col>
      </el-row>
    </div>
    <div style="text-align: right; margin: 0">
      <el-button type="primary"  @click="exportData('check')">{
     {
      $t('exportSome') }}</el-button>
      <el-button class="btn-all"  @click="exportData('all')">{
     {
      $t('exportAll') }}</el-button>
      <el-button type="error" plain @click="exportShow = false">{
     {
      $t('close') }}</el-button>
    </div>
    <el-button slot="reference" size="medium" type="success" @click="exportOpen">{
     {
      $t('export') }}</el-button>
  </el-popover>
</div>

获取所有列方法
我们在打开弹出层时获取所有的列,并循环遍历到弹出层中

exportOpen(){
     
  this.columnTitle = []
  this.$refs.userDataListRef.$children.forEach(obj => {
     
    if (obj.label != undefined){
     
      // 每个列我们自己设置3个属性,label:显示的文本,prop:英文编码,checked:选中状态
      let columnChild = {
     'label':obj.label,'checked':false,'prop':obj.prop}
      // 存到columnTitle数组中
      this.columnTitle.push(columnChild)
    }
  })
},

导出部分和导出全部的方法
根据参数 all 或者 check来判断全导出还是部分导出

exportData(type) {
     
  // 日期搜索框
  this.searchData.startDatetime = ''
  this.searchData.endDatetime = ''
  if (this.rangeTime && this.rangeTime.length) {
     
    this.searchData.startDatetime = this.rangeTime[0]
    this.searchData.endDatetime = this.rangeTime[1]
  }
  let s = this.searchData
  // 遍历所有列数组,将序号去除,如果选中将数据加入新的数组
  let columnTitleNew = []
  this.columnTitle.forEach((item)=>{
     
    if (type === 'all'){
     
      if (item.prop != 'index'){
     
        columnTitleNew.push(item)
      }
    } else if (type === 'check'){
     
      if (item.checked){
     
        columnTitleNew.push(item)
      }
    }
  })
  if (columnTitleNew.length == 0){
     
    this.$message({
     type: 'error',message: '请选择要导出的列'})
    return
  } else {
     
    // 传递新的数组给后端,调用后端导出接口,这里需要对格式进行转换防止URL无法识别部分编码
    this.exportShow = false
    var url = 'http://localhost:8089/api/reportExport/userList'
    var href = url + '?userAccount=' + s.userAccount + '&startDatetime=' + s.startDatetime + '&endDatetime=' + s.endDatetime + '&columnTitle=' + encodeURI(JSON.stringify(columnTitleNew))
    window.open(href)
  }
},

3.弹出层界面

Vue+SpringBoot导出Excel,自定义要导出的表格的列_第1张图片

二、后端API

1.控制类

我们需要传递分页,模糊搜索,导出的列这些参数

@GetMapping("/reportExport/userList")
@ApiOperation(value="用户信息导出" , notes ="用户信息自定义列导出" ,  response = Result.class)
@ApiImplicitParams({
     
        @ApiImplicitParam(name = "userAccount", value = "用户账号", required = true, dataType = "string", paramType = "query"),
        @ApiImplicitParam(name = "startDatetime", value = "开始时间yyyy-MM-dd格式", dataType = "string", paramType = "query"),
        @ApiImplicitParam(name = "endDatetime", value = "结束时间yyyy-MM-dd格式", dataType = "string", paramType = "query"),
        @ApiImplicitParam(name = "pageNum", value = "数据页数量", required = false, dataType = "Integer", paramType = "query"),
        @ApiImplicitParam(name = "pageSize", value = "数据页编号,从1开始", required = false, dataType = "Integer", paramType = "query"),
})
public Object prodTest(HttpServletResponse response,
                       @RequestParam(required = false) String userAccount,
                       @RequestParam(required = false) String startDatetime,
                       @RequestParam(required = false) String endDatetime,
                       @RequestParam(required = false) String columnTitle) throws IOException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
     
    String fileName = DateUtils.format(new Date(),"yyyyMMddHHmmss") +"-USER.xls";
    String headStr = "attachment; filename=" + fileName;
    response.setContentType("APPLICATION/OCTET-STREAM");
    response.setHeader("Content-Disposition", headStr);
    reportService.exportUserList(response.getOutputStream(), userAccount, startDatetime, endDatetime, columnTitle);
    return null;
}

2.实现逻辑

来看一下Impl中的具体实现

@Override
public void exportUserList(OutputStream out, String userAccount, String startDatetime, String endDatetime, String columnTitle) throws IOException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
     
    List<SysUser> list = userMapper.queryUserList(userAccount, startDatetime, endDatetime);
    List<Object[]> dataList = new ArrayList<Object[]>();
    // 把需要展示的列json数据转为List
    List<Map<String, Object>> cols = JsonUtils.jsonStringToList1(columnTitle);
    // 设置Excel列标题
    String[] rowsName = new String[cols.size()+1];
    rowsName[0] = "序号";
    for (int i = 0; i < cols.size(); i++) {
     
        rowsName[i+1] = cols.get(i).get("label").toString();
    }
    // 设置Excel行数据
    for (SysUser p : list) {
     
        Object[] objs = new Object[cols.size()+1];
        objs[0] = "";
        for (int j = 0; j < cols.size(); j++) {
     
            String prop = cols.get(j).get("prop").toString();
            if (prop.equals("userCreateTime")) {
     
                objs[j + 1] = new DateTime(invokeGetMethod(SysUser.class, prop, p)).toString(DateUtils.DATE_PATTERN[3]);
            } else if (prop.equals("userBirthday")){
     
                objs[j + 1] = new DateTime(invokeGetMethod(SysUser.class, prop, p)).toString(DateUtils.DATE_PATTERN[5]);
            } else if (prop.equals("userSex")) {
     
                String userSex = invokeGetMethod(SysUser.class, prop, p).toString();
                if (userSex.equals("0")) {
     
                    objs[j + 1] = "女";
                } else if (userSex.equals("1")) {
     
                    objs[j + 1] = "男";
                } else {
     
                    objs[j + 1] = "未知";
                }
            } else if (prop.equals("userIslogin")) {
     
                String userLogin = invokeGetMethod(SysUser.class, prop, p).toString();
                if (userLogin.equals("1")) {
     
                    objs[j + 1] = "在线";
                } else {
     
                    objs[j + 1] = "离线";
                }
            } else {
     
                objs[j + 1] = invokeGetMethod(SysUser.class, prop, p);
            }
        }
        dataList.add(objs);
    }
    String title = "用户信息报表";
    ExportExcel ex = new ExportExcel(title, rowsName, dataList);
    try {
     
        ex.export(out);
    } catch (Exception e) {
     
        e.printStackTrace();
    }
    out.flush();
    out.close();
}

以上我们需要调用自定义的反射辅助类,根据实体类属性来调用实体类get方法

package cn.liu783.vueappjava.util;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectUtils {
     


    /**
     *  拼接属性,调用目标Class的get方法
     *
     * @param c 属性所属实体类
     * @param filedName 需要调用的属性名
     * @param obj 实体类实例
     * @return 返回get方法结果
     */
    public static Object invokeGetMethod(Class<?> c, String filedName, Object obj) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
     
        String methodName = "get" + filedName.substring(0, 1).toUpperCase() + filedName.substring(1);
        Class<?>[] nullClasses = null;
        Method method = c.getMethod(methodName, nullClasses);
        Object[] nullObjects = null;
        return method.invoke(obj, nullObjects);
    }

}

导出的工具类大家可以我的这篇文章

Vue+SpringBoot使用POI导出EXCEL


总结

然后我们选中用户名,性别,创建日期这几列来测试一下
Vue+SpringBoot导出Excel,自定义要导出的表格的列_第2张图片
Vue+SpringBoot导出Excel,自定义要导出的表格的列_第3张图片
教程写的很仓促,大家琢磨一下就都懂了,加油陌生人!

你可能感兴趣的:(Java,VUE,excel,poi,vue)