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

10 篇文章 0 订阅


前言

之前一篇博客介绍了使用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.弹出层界面

在这里插入图片描述

二、后端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);
    }

}


3.所需工具类

json字符串传为List

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/** 
 * Json转换类
 */
public class JsonUtil {

	// 使用jackson进行json转换  
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();  
    
	public static JavaType getCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {   
		 return OBJECT_MAPPER.getTypeFactory().constructParametricType(collectionClass, elementClasses);   
	}  
	
	
    // 定义jackson对象
    private static final ObjectMapper MAPPER = new ObjectMapper();

    /**
     * 将对象转换成json字符串。
     */
    public static String objectToJson(Object data) {
        try {
            String string = MAPPER.writeValueAsString(data);
            return string;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将json结果集转化为对象
     *
     * @param jsonData json数据
     * @param beanType    对象中的object类型
     */
    public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
        try {
            T t = MAPPER.readValue(jsonData, beanType);
            return t;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将json数据转换成pojo对象list
     */
    public static <T> List<T> jsonToList(String jsonData, Class<T> beanType) {
        JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
        try {
            List<T> list = MAPPER.readValue(jsonData, javaType);
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
    
	public  static String  listToJson(List<Object> list) throws JsonParseException, JsonMappingException, IOException{
		String comment_json = OBJECT_MAPPER.writeValueAsString(list); 
		return comment_json; 
	}
	
	public  static String  mapToJson(Map<String,Object> map) throws JsonParseException, JsonMappingException, IOException{
		String comment_json = OBJECT_MAPPER.writeValueAsString(map); 
		return comment_json; 
	}
	
	public  static Map<String,Object> jsonStringToMap(String jsonString) throws Exception{
		Map<String,Object> map = OBJECT_MAPPER.readValue(jsonString, Map.class);
		return map; 
	}
	
	public  static String  listToJson1(List<Map<String, Object>> targetList) throws JsonParseException, JsonMappingException, IOException{
		String comment_json = OBJECT_MAPPER.writeValueAsString(targetList); 
		return comment_json; 
	}
	
	@SuppressWarnings("unchecked")
	public  static List<Map<String, Object>> jsonStringToList1(String jsonString) throws JsonParseException, JsonMappingException, IOException{
		List<Map<String, Object>> commodityOrderInfoList=new ArrayList<Map<String, Object>>();
		if(!jsonString.equals("")){
			JavaType javaType = getCollectionType(ArrayList.class, Object.class); 
			commodityOrderInfoList =  (List<Map<String, Object>>)OBJECT_MAPPER.readValue(jsonString, javaType);
		}
		return commodityOrderInfoList; 
	}
}

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

Vue+SpringBoot使用POI导出EXCEL


总结

然后我们选中用户名,性别,创建日期这几列来测试一下
在这里插入图片描述
在这里插入图片描述
教程写的很仓促,大家琢磨一下就都懂了,加油陌生人!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值