導出csv格式文件的本質是導出以逗號爲分隔的文本數據 ;
這裏使用List<LinkedHashMap<String, Object>> 而不使用List<List<String, Object>> ,
不用申請獲取那麼多的連續內存!
1. controller:
/**
* 賬單彙總 - 條件導出
*
* @param orderCode 檢索條件
* @param billDtStart 檢索條件
* @param billDtEnd 檢索條件
* @param state 檢索條件
* @param corganCodes 檢索條件
* @param status 檢索條件
* @param flag 檢索條件
* @param userNameLike 檢索條件
* @param capitalSide 資金方
* @param response 相應信息
*/
@GetMapping("/downloadBillExcel")
public void downloadBillExcel(@RequestParam(required = false) String orderCode,
@RequestParam(required = false) String billDtStart,
@RequestParam(required = false) String billDtEnd,
@RequestParam(required = false) String state,
@RequestParam(required = false) String corganCodes,
@RequestParam(required = false) String status,
@RequestParam(required = false) String flag,
@RequestParam(required = false) String userNameLike,
@RequestParam(required = false) String capitalSide, HttpServletResponse response,
HttpServletRequest request) {
UserDto user = UserUtils.getUserByCookie(request);
if (StringUtils.isBlank(orderCode) && StringUtils.isAnyBlank(billDtStart, billDtEnd)) {
try {
response.setContentType("text/html;charset=UTF-8");
response.getWriter().println("請傳入訂單編號或賬單日期開始時間結束時間!");
return;
} catch (Exception e) {
log.error("Exception:{}", e);
ExcelUtil.downloadExceptionExcel(response, e);
}
}
PageMapperDto mapperDto = new PageMapperDto();
mapperDto.setPageStart(null);
mapperDto.setPageSize(null);
mapperDto.setUserName(userNameLike);
mapperDto.setOrderCode(orderCode);
mapperDto.setCorganCodeListByParam(VehicleUtils.stringToList(corganCodes));
mapperDto.setFlagList(VehicleUtils.stringToList(flag));
mapperDto.setStateList(VehicleUtils.stringToList(state));
mapperDto.setStatusList(VehicleUtils.stringToList(status));
mapperDto.setCapitalSideList(VehicleUtils.stringToList(capitalSide));
if (StringUtils.isNotBlank(billDtStart) && StringUtils.isNotBlank(billDtEnd)) {
mapperDto
.setBillDtStart(DateUtils.date2String(DateUtils.parseTimestampToDate(Long.parseLong(billDtStart))));
mapperDto.setBillDtEnd(DateUtils.date2String(DateUtils.parseTimestampToDate(Long.parseLong(billDtEnd))));
}
log.info("條件下載賬單信息mapperDto:{}", JSON.toJSON(mapperDto));
Result<List<String>> organListResult = organService.findOrganCodeListByUserAccount(user, false);
if (organListResult.isSuccess()) {
mapperDto.setCorganCodeListByData(organListResult.getValue());
log.info("數據權限過濾的分公司:{}", mapperDto.getCorganCodeListByData().size());
}
orderBillingDownloadService.downloadBillCsv(response, mapperDto);
}
2. service:
/**
* 賬單信息下載 服務類接口
*
* @author zhangshiwei
* @since 2020年6月18日 下午4:15:37
*/
public interface OrderBillingDownloadService {
/**
* 賬單彙總 - 下載csv
*
* @param response 響應信息
* @param mapperDto 檢索條件
*/
void downloadBillCsv(HttpServletResponse response, PageMapperDto mapperDto);
}
3. serviceImpl:
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.yifenqi.common.DateUtils;
import com.yifenqi.zulin.biz.common.constants.YesNoEnum;
import com.yifenqi.zulin.biz.common.dto.PageMapperDto;
import com.yifenqi.zulin.biz.common.util.CsvUtils;
import com.yifenqi.zulin.biz.order.constants.BillFlagEnum;
import com.yifenqi.zulin.biz.order.constants.BillStateEnum;
import com.yifenqi.zulin.biz.order.constants.BillStatusEnum;
import com.yifenqi.zulin.biz.order.constants.OrderConstant;
import com.yifenqi.zulin.biz.order.dto.OrderBillingPageResponseDto;
import com.yifenqi.zulin.biz.order.service.OrderBillingDownloadService;
import com.yifenqi.zulin.biz.vehicle.constants.VehicleConstants;
import com.yifenqi.zulin.component.mybatis.order.OrderBillingMapper;
import lombok.extern.slf4j.Slf4j;
/**
* 賬單下載 服務實現類
*
* @author zhangshiwei
* @since 2020年6月18日 下午4:16:01
*/
@Slf4j
@Service
public class OrderBillingDownloadServiceImpl implements OrderBillingDownloadService {
@Autowired
private OrderBillingMapper orderBillingMapper;
@Value("${file.upload.temp.path}")
private String fileDir;
@Override
public void downloadBillCsv(HttpServletResponse response, PageMapperDto mapperDto) {
try {
List<OrderBillingPageResponseDto> responseDtoList = orderBillingMapper.findOrderBillingPage(mapperDto);
log.info("downloadBillCsv-賬單:{}", responseDtoList.size());
List<LinkedHashMap<String, Object>> linkedHashMapList = this.dtoListToLinkedHashMapList(responseDtoList);
CsvUtils.createAndDownloadCSVFile(linkedHashMapList, fileDir, "賬單彙總下載", response);
} catch (Exception e) {
log.error("Exception:{}", e);
}
}
private List<LinkedHashMap<String, Object>> dtoListToLinkedHashMapList(List<OrderBillingPageResponseDto> responseDtoList) {
List<LinkedHashMap<String, Object>> exportData = new ArrayList<>(responseDtoList.size());
String[] titleArray = new String[] { "訂單編號", "賬單期數", "賬單日期", "承租人姓名", "申請時間", "分公司", "分期金額", "應還本金", "應還利息",
"逾期違約金", "逾期違約罰息", "代扣結果", "資方業務狀態", "賬單標記", "賬單狀態", "是否已逾期", "實際還款日期", "已還月租", "已還本金", "已還利息", "已還違約金",
"已還罰息", "待還月租", "待還本金", "待還利息", "待還違約金", "待還罰息" };
LinkedHashMap<String, Object> titleData = new LinkedHashMap<>();
for (int i = 0; i < titleArray.length; i++) {
titleData.put(String.valueOf(i + 1), titleArray[i]);
}
exportData.add(titleData);
for (OrderBillingPageResponseDto responseDto : responseDtoList) {
LinkedHashMap<String, Object> rowData = this.dealDataForCsv(responseDto);
exportData.add(rowData);
}
return exportData;
}
private LinkedHashMap<String, Object> dealDataForCsv(OrderBillingPageResponseDto responseDto) {
LinkedHashMap<String, Object> rowData = new LinkedHashMap<>();
rowData.put("1", responseDto.getOrderCode());
rowData.put("2", String.valueOf(responseDto.getBillPeriod()));
rowData.put("3", DateUtils.formatDate(responseDto.getBillDt(), OrderConstant.DATE_FORMAT));
rowData.put("4", String.valueOf(responseDto.getUserName()));
if (null != responseDto.getApplyTime()) {
rowData.put("5", DateUtils.formatDate(responseDto.getApplyTime(), VehicleConstants.TIANYI_TIME_FORMAT));
}
rowData.put("6", responseDto.getOrganName());
rowData.put("7", responseDto.getBillFee());
rowData.put("8", responseDto.getBillCapital());
rowData.put("9", responseDto.getBillInterest());
rowData.put("10", responseDto.getOverdueContractAmt());
rowData.put("11", responseDto.getOverduePenalty());
rowData.put("12", responseDto.getWithholdResult());
BillStateEnum billStateEnum = BillStateEnum.getEnumByCode(responseDto.getState());
if (billStateEnum != null) {
rowData.put("13", billStateEnum.getMsg());
}
BillFlagEnum billFlagEnum = BillFlagEnum.getEnumByCode(responseDto.getFlag());
if (billFlagEnum != null) {
rowData.put("14", billFlagEnum.getMsg());
}
BillStatusEnum billStatusEnum = BillStatusEnum.getEnumByCode(responseDto.getStatus());
if (billStatusEnum != null) {
rowData.put("15", billStatusEnum.getMsg());
}
YesNoEnum yesNoEnum = YesNoEnum.getEnumByCode(responseDto.getIsOverdue());
if (yesNoEnum != null) {
rowData.put("16", yesNoEnum.getMsg());
}
if (null != responseDto.getBillRepayDt()) {
rowData.put("17", DateUtils.formatDate(responseDto.getBillRepayDt(), OrderConstant.DATE_FORMAT));
}
rowData.put("18", responseDto.getPaidFee());
rowData.put("19", responseDto.getBillCapital().subtract(responseDto.getUnpaidCapital()));
rowData.put("20", responseDto.getBillInterest().subtract(responseDto.getUnpaidIntrest()));
rowData.put("21", responseDto.getOverdueContractAmt().subtract(responseDto.getUnpaidContractAmt()));
rowData.put("22", responseDto.getOverduePenalty().subtract(responseDto.getUnpaidPenalty()));
rowData.put("23", responseDto.getUnpaidFee());
rowData.put("24", responseDto.getUnpaidCapital());
rowData.put("25", responseDto.getUnpaidIntrest());
rowData.put("26", responseDto.getUnpaidContractAmt());
rowData.put("27", responseDto.getUnpaidPenalty());
return rowData;
}
}
4. 工具類:
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.FileCopyUtils;
import lombok.extern.slf4j.Slf4j;
/**
* CSV文件工具類
*
* @author zhangshiwei
* @since 2020-06-11 16:11:12
*/
@Slf4j
public class CsvUtils {
/**
* CSV文件生成並下載
*
* @param dataList 數據列表
* @param fileDir 文件目錄
* @param fileName 文件名
* @param response 響應信息
*/
public static void createAndDownloadCSVFile(List<LinkedHashMap<String, Object>> dataList, String fileDir,
String fileName, HttpServletResponse response) {
if (CollectionUtils.isEmpty(dataList) || StringUtils.isAnyBlank(fileDir, fileName) || null == response) {
return;
}
BufferedWriter csvWriter = null;
try {
response.setHeader("Charset", "UTF-8");
response.setHeader("Content-Type", "application/force-download");
response.setHeader("Content-Type", "application/vnd.ms-excel");
response.setHeader("Content-disposition",
"attachment; filename=" + URLEncoder.encode(fileName, "utf8") + ".csv");
response.flushBuffer();
OutputStream outputStream = response.getOutputStream();
File csvFile = new File(fileDir + File.separator + fileName + ".csv");
File parent = csvFile.getParentFile();
if (parent != null && !parent.exists()) {
boolean mkdirsResult = parent.mkdirs();
log.info("mkdirsResult:{}", mkdirsResult);
}
boolean createNewFileResult = csvFile.createNewFile();
log.info("createNewFileResult:{}", createNewFileResult);
// GB2312使正確讀取分隔符","
csvWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(csvFile), "GB2312"), 1024);
// 寫入文件內容
for (LinkedHashMap<String, Object> linkedHashMap : dataList) {
Iterator<Entry<String, Object>> iterator = linkedHashMap.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, Object> entry = iterator.next();
String rowStr = String.format("%s%s%s", "\"", entry.getValue(), "\",");
csvWriter.write(rowStr);
}
csvWriter.newLine();
}
csvWriter.flush();
byte[] buffer = CsvUtils.getFileByteArray(csvFile);
if (null != buffer) {
FileCopyUtils.copy(buffer, outputStream);
}
boolean deleteResult = csvFile.delete();
log.info("deleteResult is{}", deleteResult);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != csvWriter) {
csvWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 獲取文件字節流
*
* @param file 文件信息
* @return 字節流
*/
public static byte[] getFileByteArray(File file) {
if (null == file) {
return null;
}
byte[] buffer = null;
FileInputStream fis;
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
fis = new FileInputStream(file);
byte[] b = new byte[1024];
int n;
while ((n = fis.read(b)) != -1) {
bos.write(b, 0, n);
}
fis.close();
bos.close();
buffer = bos.toByteArray();
if (file.exists()) {
boolean deleteResult = file.delete();
log.info("getFileByteArray deleteResult:{}", deleteResult);
}
} catch (Exception e) {
log.info("getFileByteArray Exception:{}", e);
}
return buffer;
}
}
6. 使用poi包下載excel文件很方便,但是內部數據格式是設置好的,只能按照jar要求的格式來,除非將相關代碼copy一套再修改,否則每次請求都是需要很多的連續內存.