SpringBoot + Ant Design Vue实现数据导出功能
一、需求
- 以xlsx格式导出所选表格中的内容
- 要求进行分级
- 设置表头颜色。
二、前端代码实现
2.1 显示实现
首先我们需要添加一个用于到导出的按钮上去,像这样的:
<a-button @click="exportBatchlistVerify">批量导出</a-button>
至于它放哪里,是什么样式可以根据自己的需求决定。
2.2 代码逻辑
按钮有了,下来我们开始实现这个按钮的功能。
- 导出数据确定。
表格设置: 表头添加以下代码
<s-table
:row-key="(record) => record.id"
:row-selection="options.rowSelection"
>
Vue代码 :获取选中的目标ID数组
import listApi from '@/api/listApi'
let selectedRowKeys = ref([])
const options = {
alert: {
show: false,
clear: () => {
selectedRowKeys = ref([])
}
},
rowSelection: {
onChange: (selectedRowKey, selectedRows) => {
selectedRowKeys.value = selectedRowKey
},
//这里是设置复选框的宽度,可以删掉
columnWidth : 6
}
}
按钮功能实现:
const exportBatchlistVerify = () => {
if (selectedRowKeys.value.length < 1) {
message.warning('请输入查询条件或勾选要导出的信息')
}
if (selectedRowKeys.value.length > 0) {
const params = {
checklistIds: selectedRowKeys.value
.map((m) => {
return m
})
.join()
}
exportBatchChecklist(params)
return
}
exportBatchList(params)
}
const exportBatchList= (params) => {
listApi.listExport(params).then((res) => {
downloadUtil.resultDownload(res)
table.value.clearSelected()
})
}
listApi: 导入部分和 baseRequest 请参考 Vue封装axios实现
import { baseRequest } from '@/utils/request'
const request = (url, ...arg) => baseRequest(`/list/` + url, ...arg)
listExport(data) {
return request('export', data, 'get', {
responseType: 'blob'
})
},
三、后端代码实现
3.1 实体类
我们首先建一个简单的实体,展示将要导出的数据内容:
import com.baomidou.mybatisplus.annotation.TableName;
import com.fhs.core.trans.vo.TransPojo;
import lombok.Data;
/**
* Auth lhd
* Date 2023/6/21 9:42
* Annotate 导出功能测试类
*/
@Data
@TableName("userTest")
public class UserTest implements TransPojo {
private String id;
private String name;
private String tel;
private String password;
private String address;
}
3.2 接收参数和打印模板
有了实体类后,我们将开始进行具体的逻辑编写,但在这之前我们需要定义接收前端传参的类,和定义我们的打印模板。
接收参数:
import lombok.Data;
/**
* Auth lhd
* Date 2023/6/21 9:46
* Annotate
*/
@Data
public class UserTestExportParam {
private String listIds;
}
这部分很简单,我们只需要即将打印的内容ID即可。
打印模板:
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.HeadStyle;
import com.alibaba.excel.enums.poi.FillPatternTypeEnum;
import lombok.Data;
/**
* Auth lhd
* Date 2023/6/21 10:10
* Annotate
*/
@Data
public class UserTestResult {
@HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 40)
@ExcelProperty({"人物名称"})
private String name;
@HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29)
@ExcelProperty({"基本信息","联系方式 "})
private String tel;
@HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 31)
@ExcelProperty({"基本信息","地址 "})
private String address;
@HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 26)
@ExcelProperty({"基本信息","不能外露","账号密码 "})
private String password;
}
打印模板定义了我们们即将打印的表格的表头结构和列名、表头颜色。
备注:通过修改打印模板类的注解,可以实现自定义的表头和表头颜色
3.3 正式的逻辑
映射接口和XML:
- 接口 UserTestMapper
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.modular.userTest.entity.UserTest;
/**
* Auth lhd
* Date 2023/6/21 10:02
* Annotate
*/
public interface UserTestMapper extends BaseMapper<UserTest> {
}
- XML UserTestMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.modular.userTest.mapper.UserTestMapper">
</ma
核心逻辑接口和实现:
- 逻辑接口 UserTestService
import com.baomidou.mybatisplus.extension.service.IService;
import com.modular.userTest.entity.UserTest;
import com.modular.userTest.param.UserTestExportParam;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Auth lhd
* Date 2023/6/21 9:44
* Annotate
*/
public interface UserTestService extends IService<UserTest> {
void exportUserTestList(UserTestExportParam listExportParam, HttpServletResponse response) throws IOException;
}
- 接口实现 UserTestServiceImpl
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.alibaba.excel.write.style.row.AbstractRowHeightStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fhs.trans.service.impl.TransService;
import org.apache.poi.ss.usermodel.*;
import org.springframework.stereotype.Service;
import com.modular.userTest.entity.UserTest;
import com.modular.userTest.mapper.UserTestMapper;
import com.modular.userTest.param.UserTestExportParam;
import com.modular.userTest.result.UserTestResult;
import com.modular.userTest.service.UserTestService;
import com.common.excel.CommonExcelCustomMergeStrategy;
import com.common.exception.CommonException;
import com.common.util.CommonDownloadUtil;
import com.common.util.CommonResponseUtil;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
/**
* Auth lhd
* Date 2023/6/21 10:01
* Annotate
*/
@Service
public class UserTestServiceImpl extends ServiceImpl<UserTestMapper, UserTest> implements UserTestService {
@Resource
private TransService transService;
@Override
public void exportUserTestList(UserTestExportParam listExportParam, HttpServletResponse response) throws IOException {
File tempFile = null;
try {
QueryWrapper<UserTest> queryWrapper = new QueryWrapper<>();
if(ObjectUtil.isNotEmpty(listExportParam.getListIds())) {
queryWrapper.lambda().in(UserTest::getId, StrUtil.split(listExportParam.getListIds(), StrUtil.COMMA));
}
String fileName = "人物信息表.xlsx";
List<UserTest> userlists = this.list(queryWrapper);
if(ObjectUtil.isEmpty(userlists)) {
throw new CommonException("无数据可导出");
}
transService.transBatch(userlists);
List<UserTestResult> listResults = userlists.stream()
.map(userlist -> {
UserTestResult listExportResult = new UserTestResult();
BeanUtil.copyProperties(userlist, listExportResult);
listExportResult.setName(ObjectUtil.isNotEmpty(listExportResult.getName())?
listExportResult.getName():"无检查地址");
return listExportResult;
}).collect(Collectors.toList());
// 创建临时文件
tempFile = FileUtil.file(FileUtil.getTmpDir() + FileUtil.FILE_SEPARATOR + fileName);
// 头的策略
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
WriteFont headWriteFont = new WriteFont();
headWriteFont.setFontHeightInPoints((short) 14);
headWriteCellStyle.setWriteFont(headWriteFont);
// 水平垂直居中
headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
headWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// 内容的策略
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
// 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定
contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
// 内容背景白色
contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
WriteFont contentWriteFont = new WriteFont();
// 内容字体大小
contentWriteFont.setFontHeightInPoints((short) 12);
contentWriteCellStyle.setWriteFont(contentWriteFont);
//设置边框样式,细实线
contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
// 水平垂直居中
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle,
contentWriteCellStyle);
// 写excel
EasyExcel.write(tempFile.getPath(), UserTestResult.class)
// 自定义样式
.registerWriteHandler(horizontalCellStyleStrategy)
// 自动列宽
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
// 机构分组合并单元格
.registerWriteHandler(new CommonExcelCustomMergeStrategy(listResults.stream().map(UserTestResult::getName)
.collect(Collectors.toList()), 0))
// 设置第一行字体
.registerWriteHandler(new CellWriteHandler() {
@Override
public void afterCellDispose(CellWriteHandlerContext context) {
WriteCellData<?> cellData = context.getFirstCellData();
WriteCellStyle writeCellStyle = cellData.getOrCreateStyle();
Integer rowIndex = context.getRowIndex();
if(rowIndex == 0) {
WriteFont headWriteFont = new WriteFont();
headWriteFont.setFontName("宋体");
headWriteFont.setBold(true);
headWriteFont.setFontHeightInPoints((short) 16);
writeCellStyle.setWriteFont(headWriteFont);
}
}
})
// 设置表头行高
.registerWriteHandler(new AbstractRowHeightStyleStrategy() {
@Override
protected void setHeadColumnHeight(Row row, int relativeRowIndex) {
if(relativeRowIndex == 0) {
// 表头第一行
row.setHeightInPoints(34);
} else {
// 表头其他行
row.setHeightInPoints(30);
}
}
@Override
protected void setContentColumnHeight(Row row, int relativeRowIndex) {
// 内容行
row.setHeightInPoints(20);
}
})
.sheet("人物信息表信息")
.doWrite(listResults);
CommonDownloadUtil.download(tempFile, response);
} catch (Exception e) {
log.error(">>> 人物信息表导出异常:", e);
CommonResponseUtil.renderError(response, "导出失败");
} finally {
FileUtil.del(tempFile);
}
}
}
这里只展示具体逻辑,common开头的公共类和工具类感兴趣的伙伴可以私信我获取~
3.4 Contorller
最后写一个简单的controller类即可:
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.modular.userTest.param.UserTestExportParam;
import com.modular.userTest.service.UserTestService;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Auth lhd
* Date 2023/6/21 10:17
* Annotate
*/
@RestController
public class UserTestController {
@Resource
private UserTestService userTestService;
@GetMapping(value="/list/export",produces=MediaType.APPLICATION_OCTET_STREAM_VALUE)
public void exportUser(UserTestExportParam listExportParam, HttpServletResponse response) throws IOException {
userTestService.exportUserTestList(listExportParam, response);
}
}
我们看看打印效果: