入口
/**
* 导出接收人列表
*/
@PostMapping("/export")
@ResponseBody
public AjaxResult export(Wxpusher wxpusher) {
List<Wxpusher> list = wxpusherService.selectWxpusherList(wxpusher);
// 工具的泛型接口,创建专用工具实例
ExcelUtil<Wxpusher> util = new ExcelUtil<Wxpusher>(Wxpusher.class);
// 传入需要打印的 数据集合 和 工作表名称
return util.exportExcel(list, "接收人数据");
}
Excel工具
泛型构造器
public class ExcelUtil<T>{
/**
* 实体对象
*/
public Class<T> clazz;
public ExcelUtil(Class<T> clazz)
{
this.clazz = clazz;
}
}
导出方法
/**
* 对list数据源将其里面的数据导入到excel表单
*
* @param list 导出数据集合
* @param sheetName 工作表的名称
* @return 结果
*/
public AjaxResult exportExcel(List<T> list, String sheetName)
{
return exportExcel(list, sheetName, StringUtils.EMPTY); // 导出 Excel 文件
}
/**
* 对list数据源将其里面的数据导入到excel表单
*
* @param list 导出数据集合
* @param sheetName 工作表的名称
* @param title 标题
* @return 结果
*/
public AjaxResult exportExcel(List<T> list, String sheetName, String title)
{
this.init(list, sheetName, title, Type.EXPORT);
return exportExcel();
}
初始化
private List<T> list; // 数据集合
private String sheetName; // 工作表名
private Type type; // 导出类型
private String title; // 标题
public void init(List<T> list, String sheetName, String title, Type type)
{
if (list == null)
{
list = new ArrayList<T>(); // 防空
}
this.list = list;
this.sheetName = sheetName;
this.type = type;
this.title = title;
createExcelField(); // 创建字段
createWorkbook(); // 创建工作本
createTitle(); // 创建标题
}
反射获取字段
private List<Object[]> fields; // 注解列表
private short maxHeight; // 最大高度
/**
* 得到所有定义字段
*/
private void createExcelField()
{
this.fields = getFields(); // 获取字段
// 根据注解中的sort字段大小进行排序
this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList());
this.maxHeight = getRowHeight(); // 根据注解获取最大行高
}
/**
* 获取字段注解信息
*/
public List<Object[]> getFields()
{
List<Object[]> fields = new ArrayList<Object[]>();
List<Field> tempFields = new ArrayList<>();
tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); // 反射获取超类的字段
tempFields.addAll(Arrays.asList(clazz.getDeclaredFields())); // 反射获取当前类的字段
for (Field field : tempFields)
{
// 单注解
if (field.isAnnotationPresent(Excel.class)) // 有 @Excel 注解的
{
Excel attr = field.getAnnotation(Excel.class);
// 匹配注解中的字段(类型)
if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
{
field.setAccessible(true);
fields.add(new Object[] { field, attr });
}
}
// 多注解
if (field.isAnnotationPresent(Excels.class))
{
Excels attrs = field.getAnnotation(Excels.class);
Excel[] excels = attrs.value();
for (Excel attr : excels)
{
if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
{
field.setAccessible(true);
fields.add(new Object[] { field, attr });
}
}
}
}
return fields;
}
/**
* 根据注解获取最大行高
*/
public short getRowHeight()
{
double maxHeight = 0;
for (Object[] os : this.fields)
{
Excel excel = (Excel) os[1];
// 取注解中的最大行高作为行高
maxHeight = Math.max(maxHeight, excel.height());
}
return (short) (maxHeight * 20);
}
创建工作本
/**
* 创建一个工作簿
*/
public void createWorkbook()
{
this.wb = new SXSSFWorkbook(500); // 创建缓存为500行的工作本
this.sheet = wb.createSheet(); // 为工作本创建工作表
wb.setSheetName(0, sheetName); // 设置表名
this.styles = createStyles(wb); // 创建样式
}
创建行
/**
* 创建写入数据到Sheet
*/
public void writeSheet()
{
// 取出一共有多少个sheet.
int sheetNo = Math.max(1, (int) Math.ceil(list.size() * 1.0 / sheetSize));
for (int index = 0; index < sheetNo; index++)
{
createSheet(sheetNo, index);
// 产生一行
Row row = sheet.createRow(rownum);
int column = 0;
// 写入各个字段的列头名称
for (Object[] os : fields)
{
Excel excel = (Excel) os[1];
this.createCell(excel, row, column++); // 创建单元格
}
if (Type.EXPORT.equals(type))
{
fillExcelData(index, row);
addStatisticsRow();
}
}
}
后续很繁杂就不看了,不难,有兴趣去研究一下
响应回前端
生成的Excel文件已经导出到项目指定的文件目录下,返回前端的是文件名
/**
* 对list数据源将其里面的数据导入到excel表单
*
* @return 结果
*/
public AjaxResult exportExcel()
{
OutputStream out = null;
try
{
writeSheet(); // 写入数据到工作表
String filename = encodingFilename(sheetName); // 拼接生成文件名
out = new FileOutputStream(getAbsoluteFile(filename)); // 创建文件输出流
wb.write(out); // 把文件导出到指定的绝对路径下
return AjaxResult.success(filename); // 返回文件名
}
catch (Exception e)
{
log.error("导出Excel异常{}", e.getMessage());
throw new UtilException("导出Excel失败,请联系网站管理员!");
}
finally
{
IOUtils.closeQuietly(wb);
IOUtils.closeQuietly(out);
}
}
前端拿到文件名,再去跳转到下载接口
// 导出数据
exportExcel: function (formId) {
table.set();
$.modal.confirm("确定导出所有" + table.options.modalName + "吗?", function () {
var currentId = $.common.isEmpty(formId) ? $('form').attr('id') : formId;
var params = $("#" + table.options.id).bootstrapTable('getOptions');
var dataParam = $("#" + currentId).serializeArray();
dataParam.push({"name": "orderByColumn", "value": params.sortName});
dataParam.push({"name": "isAsc", "value": params.sortOrder});
$.modal.loading("正在导出数据,请稍候...");
$.post(table.options.exportUrl, dataParam, function (result) {
if (result.code == web_status.SUCCESS) {
// 跳转到下载链接
window.location.href = ctx + "common/download?fileName=" + encodeURI(result.msg) + "&delete=" + true;
} else if (result.code == web_status.WARNING) {
$.modal.alertWarning(result.msg)
} else {
$.modal.alertError(result.msg);
}
$.modal.closeLoading();
});
});
},
下载接口
/**
* 通用下载请求
*
* @param fileName 文件名称
* @param delete 是否删除
*/
@GetMapping("/download")
public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request)
{
try
{
if (!FileUtils.checkAllowDownload(fileName)) // 检查是否允许下载
{
throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName));
}
// 生成下载文件名
String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
String filePath = RuoYiConfig.getDownloadPath() + fileName; // 文件的绝对路径
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); // 设置响应类型
FileUtils.setAttachmentResponseHeader(response, realFileName); // 下载文件名重新编码
FileUtils.writeBytes(filePath, response.getOutputStream()); // 用 response 对象的输出流写出字节流
if (delete) // 完事儿删除文件
{
FileUtils.deleteFile(filePath);
}
}
catch (Exception e)
{
log.error("下载文件失败", e);
}
}
具体写出方法
/**
* echoo mark 输出指定文件的byte数组
*
* @param filePath 文件路径
* @param os 输出流
* @return
*/
public static void writeBytes(String filePath, OutputStream os) throws IOException
{
FileInputStream fis = null;
try
{
File file = new File(filePath);
if (!file.exists())
{
throw new FileNotFoundException(filePath);
}
fis = new FileInputStream(file); // 读取文件
byte[] b = new byte[1024]; // 缓存字节数组
int length; // 临时变量:读取长度
while ((length = fis.read(b)) > 0) // 没读取完
{
os.write(b, 0, length); // 写出
}
}
catch (IOException e)
{
throw e;
}
finally
{
IOUtils.close(os);
IOUtils.close(fis);
}
}