@ApiOperation(value = "static-pool/download/zip",notes = "批量导出某月的数据")
@RequestMapping(value = "/static-pool/download/zip",method = RequestMethod.GET)
public ResponseCommonType downloadZIP(String month,HttpServletResponse servletResponse) throws ParseException, IOException, WriteException {
ResponseCommonType rs = new ResponseCommonType();
rs.setIsSuccess(true);
//获取开始时间为null,结束日期是月底的报告.按照生成时间降序
List reportfileinfoList = fileService.selectFilesByMonth(month);
//按照产品分组,只导出月底日期的最新那份
Map> map = reportfileinfoList.stream().collect(Collectors.groupingBy(Reportfileinfo::getProductCode));
//把文件名和byte[]封装到fileInfo对象
List files = new ArrayList<>();
//遍历每个产品的n个文件
for (Map.Entry> entry : map.entrySet()) {
List productFiles = entry.getValue();
//只要最新一个,数据库中已经按照生成时间降序排序
Reportfileinfo info = productFiles.get(0);
String reportManageMongoKey = info.getReportManageMongoKey();
//静态逾期
List reportstaticallyoverdueList = new ArrayList<>();
Reportbasicinfo rbi = null;
Reportfileinfo rfi = null;
List mongoByName = mongoService.findByName(reportManageMongoKey);
List reportfileinfoByKey = exportToWordService.getReportfileinfoByKey(reportManageMongoKey);
if (CollectionUtils.isEmpty(mongoByName)) {//MongoDB有数据
rs.setIsSuccess(false);
rs.setResponseMessage("MongoDB没有数据");
}
Manage manage = mongoByName.get(0);
ManagementBodyModel managementBodyModel = JSON.parseObject(manage.getManageValue(), ManagementBodyModel.class);
reportstaticallyoverdueList = managementBodyModel.getReportstaticallyoverdueList();
rbi = managementBodyModel.getReportbasicinfo();
rfi = reportfileinfoByKey.get(0);
//根据字节输出流,创建一个workbook对象
ByteOutputStream byteOutputStream = new ByteOutputStream();
WritableWorkbook wbook = Workbook.createWorkbook(byteOutputStream);
//设置excel数据和格式
setExcelData(wbook, reportstaticallyoverdueList);
wbook.write();
wbook.close();
byte[] bytes = byteOutputStream.getBytes();
byteOutputStream.close();
Calendar c = Calendar.getInstance();
c.setTime(rfi.getGndDate());
int monthV = c.get(Calendar.MONTH) + 1;
String fileName = "【" + c.get(Calendar.YEAR) + "年" + monthV + "月】" + rbi.getTrustProductCode() + rbi.getProductShortName() + "项目静态池数据" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"))+".xls";
FileInfo fileInfo = new FileInfo("", fileName, bytes);
files.add(fileInfo);
if (files == null) {
rs.setIsSuccess(false);
rs.setResponseMessage("没有获取到文件");
return rs;
}
}
String zipFileName = month.split("-")[0] + "年" + month.split("-")[1] + "项目静态池数据" + LocalDate.now().toString().replace("-", "") + ".zip";
toZip_ByteArrayOutputStream(files, zipFileName, servletResponse);
return rs;
}
private void setExcelData(WritableWorkbook wbook,List list) throws WriteException {
// sheet名称
WritableSheet wsheet = wbook.createSheet("静态池数据", 0);
WritableCellFormat format1 = new WritableCellFormat();
// 把水平对齐方式指定为居中
format1.setAlignment(jxl.format.Alignment.CENTRE);
// 把垂直对齐方式指定为居中
format1.setVerticalAlignment(jxl.format.VerticalAlignment.CENTRE);
format1.setBorder(Border.ALL, BorderLineStyle.THIN);
NumberFormat nf = new NumberFormat("0.00");
WritableCellFormat numberFormat = new WritableCellFormat(nf);
// 把水平对齐方式指定为居中
numberFormat.setAlignment(jxl.format.Alignment.CENTRE);
// 把垂直对齐方式指定为居中
numberFormat.setVerticalAlignment(jxl.format.VerticalAlignment.CENTRE);
numberFormat.setBorder(Border.ALL, BorderLineStyle.THIN);
//设置表格头
wsheet.addCell(new Label(0, 0, "静态池", format1));
wsheet.addCell(new Label(1, 0, "报告期末", format1));
wsheet.addCell(new Label(2, 0, "静态池规模", format1));
wsheet.addCell(new Label(3, 0, "静态池笔数", format1));
wsheet.addCell(new Label(4, 0, "期末存续笔数", format1));
wsheet.addCell(new Label(5, 0, "逾期1-30天金额", format1));
wsheet.addCell(new Label(6, 0, "逾期31-60天金额", format1));
wsheet.addCell(new Label(7, 0, "逾期61-90天金额", format1));
wsheet.addCell(new Label(8, 0, "逾期90天+金额", format1));
wsheet.addCell(new Label(9, 0, "M1逾期率", format1));
wsheet.addCell(new Label(10, 0, "M2逾期率", format1));
wsheet.addCell(new Label(11, 0, "M3逾期率", format1));
wsheet.addCell(new Label(12, 0, "M3+逾期率", format1));
//设置每列宽度
wsheet.setColumnView(0, 8);
wsheet.setColumnView(1, 8);
wsheet.setColumnView(2, 15);
wsheet.setColumnView(3, 10);
wsheet.setColumnView(4, 12);
wsheet.setColumnView(5, 15);
wsheet.setColumnView(6, 15);
wsheet.setColumnView(7, 15);
wsheet.setColumnView(8, 15);
wsheet.setColumnView(9, 15);
wsheet.setColumnView(10, 15);
wsheet.setColumnView(11, 15);
wsheet.setColumnView(12, 15);
//高度
wsheet.setRowView(0, 500);
for (int i = 0; i < list.size(); i++) {
Reportstaticallyoverdue info = list.get(i);
wsheet.addCell(new Label(0, 1 + i, info.getStaticPool(), format1));
wsheet.addCell(new Label(1, 1 + i, info.getObservationMonth(), format1));
wsheet.addCell(new Label(2, 1 + i, info.getStaticPoolScale()!=null?info.getStaticPoolScale().toString():"", format1));
wsheet.addCell(new Label(3, 1 + i, info.getStaticPoolNumber() != null ? info.getStaticPoolNumber().toString() : "", format1));
wsheet.addCell(new Label(4, 1 + i, info.getRemainingNum(), format1));
wsheet.addCell(new Label(5, 1 + i, info.getOverdueM1Amount() != null ? info.getOverdueM1Amount().toString() : "", format1));
wsheet.addCell(new Label(6, 1 + i, info.getOverdueM2Amount() != null ? info.getOverdueM2Amount().toString() : "", format1));
wsheet.addCell(new Label(7, 1 + i, info.getOverdueM3Amount() != null ? info.getOverdueM3Amount().toString() : "", format1));
wsheet.addCell(new Label(8, 1 + i, info.getOverdueM4Amount() != null ? info.getOverdueM4Amount().toString() : "", format1));
wsheet.addCell(new Label(9, 1 + i, info.getM1() != null ? info.getM1().toString() : "", format1));
wsheet.addCell(new Label(10, 1 + i, info.getM2() != null ? info.getM2().toString() : "", format1));
wsheet.addCell(new Label(11, 1 + i, info.getM3() != null ? info.getM3().toString() : "", format1));
wsheet.addCell(new Label(12, 1 + i, info.getM4() != null ? info.getM4().toString() : "", format1));
}
}
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ZIPUtil {
/**
* 批量文件流压缩
* @author momo
* @since 2018-8-9
* @param files 被压缩压缩文件名, 被压缩的文件流
* @throws IOException
*/
public static void toZip_ByteArrayOutputStream(List files, String zipFileName, HttpServletResponse response) throws IOException {
if (files == null) {
return;
}
//1.创建字节数组输出流,用于返回压缩后的输出流字节数组
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//2.创建压缩输出流
ZipOutputStream zipOut = new ZipOutputStream(baos);
//3.遍历要批量压缩的集合文件流
ByteArrayInputStream bais = null;
FileInfo fileInfo = null;
String fileName = null;
int temp = 0;
for (int i = 0; i < files.size(); i++) {
fileInfo = files.get(i);
fileName = fileInfo.getFilename();
//3.1将需要压缩的字节输出流,转为字节数组输入流,
bais = new ByteArrayInputStream(fileInfo.getContent());
//3.2设置ZipEntry对象,并对需要压缩的文件命名
zipOut.putNextEntry(new ZipEntry(fileName));
//3.3读取要压缩的字节输出流,进行压缩
temp = 0;
while ((temp = bais.read()) != -1) {
zipOut.write(temp); // 压缩输出
}
// 3.4关闭流
bais.close();
}
zipOut.close();
// 清空response
response.reset();
// 设置response的Header
zipFileName = new String(zipFileName.getBytes("UTF-8"), "ISO-8859-1");
response.addHeader("Content-Disposition", String.format("attachment; filename=\"%s\"", zipFileName));
response.setContentType("application/octet-stream;charset=utf-8");
OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
response.setContentType("application/octet-stream");
toClient.write(baos.toByteArray());
toClient.flush();
toClient.close();
baos.close();// 关闭流
}
}
核心代码:
//根据字节输出流,创建一个workbook对象
ByteOutputStream byteOutputStream = new ByteOutputStream();
WritableWorkbook wbook = Workbook.createWorkbook(byteOutputStream);
//设置excel数据和格式
setExcelData(wbook, reportstaticallyoverdueList);
wbook.write();
wbook.close();
byte[] bytes = byteOutputStream.getBytes();
byteOutputStream.close();
这样得到了一个带excel格式的字节输出流, 能得到其字节数组.
ZIPUtil类里,实现了根据byte[]数组,生成zip流,响应到浏览器端. 核心代码是:
//1.创建字节数组输出流,用于返回压缩后的输出流字节数组
ByteArrayOutputStream baos = new ByteArrayOutputStream();
步骤总结:
1.基于字节输出流ByteOutputStream,创建一个workbook对象
2.wbook.write();实现把wbook对象数据,更新到字节输出流
3.byteOutputStream对象.getBytes();得到字节输出流里的字节数组
4.根据字节数组打包成zip. (可以打包任何格式的文件)
4.1
4.2
PS:这里的FileInfo只是对文件id,文件名,文件内容字节数组的一个简单封装:
private String id; private String filename; private byte[] content;