SpringCloud把xml報文匯出Excel(csv格式)文件
阿新 • • 發佈:2018-11-01
匯出excel報表之類,相信有過1~2年開發經驗的至少都做過了。但是大多應該都是傳統的SSH或SSM架構,相對於在最近流行的SpringCloud分散式架構上做類似匯出,可能經歷不是那麼多。
鄙人做過的匯出excel報表,有2種方案:
- Poi原生的,jar類庫
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.9</version> </dependency>
HSSFWorkbook、HSSFSheet、HSSFCellStyle等一系列,poi包中類庫。優勢:可以根據業務需要最大限度的格式化excel報表(合併單元格/居中/字型顏色等);此種方案見另一篇資料: poi格式匯出excel
poi方法參考另一篇博文:poi方法匯出excel文件 - apache系列的commons-csv類庫:CSVPrinter
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-csv</artifactId> <version>1.4</version> </dependency>
由於本人專案中,之前統一了匯出方案由:CSVPrinter格式,也妥協於api-zuul閘道器的輸入輸出流格式的限制,最終選用此種。優勢:可與查詢介面合併,查詢資料供前端頁面呼叫,匯出直接輸出excel文件。
今天跟大家分享一下,在SpringCloud架構下,匯出excel報表的經驗。同時又錯誤或遺漏之處歡迎指正建議,感激。
xml報文內容格式:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Root> <SttlCntNb>2</SttlCntNb> <DebitCntAmt>CNY0.00</DebitCntAmt> <CreditCntAmt>CNY4700.00</CreditCntAmt> <SttlList> <SttlInf> <SttlReptFlg>2018052500170139</SttlReptFlg> <SttlDCFlg>2</SttlDCFlg> <SttlAmt>CNY100.00</SttlAmt> <BatchList> <BatchInf> <BatchId>B201805230015</BatchId> <BatchDCFlg>2</BatchDCFlg> <BatchNetAmt>CNY100.00</BatchNetAmt> <SubItemList> <SubItemInf>0113|C3228644000018|04|CNY0.00|0|CNY5.00|1|</SubItemInf> <SubItemInf>0120|C3228640000020|05|CNY50.00|1|CNY0.00|0|</SubItemInf> <SubItemInf>0114|C3228640000029|07|CNY0.00|0|CNY5.00|1|</SubItemInf> <SubItemInf>0115|C3228640000019|06|CNY0.00|0|CNY5.00|1|</SubItemInf> <SubItemInf>0111|C3228640000016|03|CNY0.00|0|CNY10.00|1|</SubItemInf> <SubItemInf>0110|C3228644000016|01|CNY0.00|0|CNY110.00|1|</SubItemInf> <SubItemInf>0112|C3228644000017|99|CNY0.00|0|CNY5.00|1|</SubItemInf> <SubItemInf>0110|C3228644000016|02|CNY0.00|0|CNY10.00|1|</SubItemInf> </SubItemList> </BatchInf> </BatchList> </SttlInf> <SttlInf> <SttlReptFlg>2018052500170138</SttlReptFlg> <SttlDCFlg>2</SttlDCFlg> <SttlAmt>CNY4600.00</SttlAmt> <BatchList> <BatchInf> <BatchId>B201805240001</BatchId> <BatchDCFlg>2</BatchDCFlg> <BatchNetAmt>CNY400.00</BatchNetAmt> <SubItemList> <SubItemInf>0126|C1010511003703|00|CNY0.00|4|CNY0.00|0|</SubItemInf> <SubItemInf>0125|C1010211000012|01|CNY0.00|8|CNY0.00|0|</SubItemInf> <SubItemInf>0126|C1010211000012|01|CNY0.00|8|CNY0.00|0|</SubItemInf> <SubItemInf>0124|C1010211000012|01|CNY0.00|8|CNY0.00|0|</SubItemInf> <SubItemInf>0123|C1010211000012|01|CNY0.00|4|CNY0.00|0|</SubItemInf> <SubItemInf>0110|C1010211000012|01|CNY0.00|0|CNY400.00|2|</SubItemInf> </SubItemList> </BatchInf> <BatchInf> <BatchId>B201805240002</BatchId> <BatchDCFlg>2</BatchDCFlg> <BatchNetAmt>CNY400.00</BatchNetAmt> <SubItemList> <SubItemInf>0125|C1010211000012|00|CNY400.00|4|CNY0.00|0|</SubItemInf> <SubItemInf>0110|C1010211000012|00|CNY0.00|0|CNY800.00|2|</SubItemInf> </SubItemList> </BatchInf> <BatchInf> <BatchId>B201805240003</BatchId> <BatchDCFlg>1</BatchDCFlg> <BatchNetAmt>CNY0.00</BatchNetAmt> <SubItemList> <SubItemInf>0120|C1010211000012|00|CNY0.00|4|CNY0.00|0|</SubItemInf> </SubItemList> </BatchInf> <BatchInf> <BatchId>B201805240004</BatchId> <BatchDCFlg>2</BatchDCFlg> <BatchNetAmt>CNY1200.00</BatchNetAmt> <SubItemList> <SubItemInf>0112|C1010211000012|01|CNY0.00|0|CNY1200.00|2|</SubItemInf> </SubItemList> </BatchInf> <BatchInf> <BatchId>B201805240005</BatchId> <BatchDCFlg>2</BatchDCFlg> <BatchNetAmt>CNY400.00</BatchNetAmt> <SubItemList> <SubItemInf>0113|C1010211000012|00|CNY0.00|0|CNY400.00|4|</SubItemInf> </SubItemList> </BatchInf> <BatchInf> <BatchId>B201805240006</BatchId> <BatchDCFlg>2</BatchDCFlg> <BatchNetAmt>CNY400.00</BatchNetAmt> <SubItemList> <SubItemInf>0114|C1010211000012|00|CNY0.00|0|CNY400.00|4|</SubItemInf> </SubItemList> </BatchInf> <BatchInf> <BatchId>B201805240007</BatchId> <BatchDCFlg>2</BatchDCFlg> <BatchNetAmt>CNY200.00</BatchNetAmt> <SubItemList> <SubItemInf>0115|C1010211000012|01|CNY0.00|0|CNY200.00|2|</SubItemInf> </SubItemList> </BatchInf> <BatchInf> <BatchId>B201805240008</BatchId> <BatchDCFlg>2</BatchDCFlg> <BatchNetAmt>CNY600.00</BatchNetAmt> <SubItemList> <SubItemInf>0115|C1010211000012|01|CNY0.00|0|CNY600.00|2|</SubItemInf> </SubItemList> </BatchInf> <BatchInf> <BatchId>B201805240009</BatchId> <BatchDCFlg>2</BatchDCFlg> <BatchNetAmt>CNY400.00</BatchNetAmt> <SubItemList> <SubItemInf>0110|C1010511003703|00|CNY0.00|0|CNY400.00|2|</SubItemInf> </SubItemList> </BatchInf> <BatchInf> <BatchId>B201805240010</BatchId> <BatchDCFlg>2</BatchDCFlg> <BatchNetAmt>CNY1200.00</BatchNetAmt> <SubItemList> <SubItemInf>0111|C1010211000012|01|CNY0.00|0|CNY1200.00|4|</SubItemInf> </SubItemList> </BatchInf> <BatchInf> <BatchId>B201805240012</BatchId> <BatchDCFlg>1</BatchDCFlg> <BatchNetAmt>CNY1200.00</BatchNetAmt> <SubItemList> <SubItemInf>0116|C1010511003703|00|CNY1200.00|4|CNY0.00|0|</SubItemInf> </SubItemList> </BatchInf> </BatchList> </SttlInf> </SttlList> </Root>
可以看到嵌套了好幾層:SttlList—>SttlInf—>BatchList—>BatchInf—>SubItemList—>SubItemInf
其中,要先把xml報文解析成obj物件,根據xml報文拆分後封裝的obj物件,對於xml報文解析可檢視另一篇:
核心類庫是:
1、org.apache.commons.csv 類庫中的CSVPrinter進行列印輸出。
2、藉助java.io的輸入輸出流等
-
HttpServletRequest
-
HttpServletResponse
-
OutputStream/OutputStreamWriter
3、org.apache.commons.io關閉CSVPrinter列印輸出流。
上程式碼:介面Controller控制入口類:
@RequestMapping(value = "/export")
@Logable(businessTag = "accountInfoExport")
@Exceptionable
@Validatable
@ApiOperation(value = "對賬檔案匯出", notes = "對賬檔案匯出", httpMethod = "GET")
@ApiImplicitParams({
@ApiImplicitParam(name = "accountDate", value = "對賬日期(yyyy-MM-dd)", required = true, dataType = "String", length = 100, paramType = "query"),
@ApiImplicitParam(name = "download", value = "是否下載:true/false", required = true, dataType = "boolean", length = 100, paramType = "query"),
@ApiImplicitParam(name = "fileName", value = "例:AccountInfo", required = true, dataType = "String", length = 100, paramType = "query"),
@ApiImplicitParam(name = "type", value = "格式:csv", required = true, dataType = "String", length = 100, paramType = "query")})
public PageResult<SettInfoExportDto> exportAccountInfo(@RequestParam String accountDate,
@RequestParam(value = "download", required = true) boolean download,
@RequestParam(value = "fileName", required = true) String fileName,
@RequestParam(value = "type", required = true) String type,
HttpServletRequest request, HttpServletResponse response) {
PageResult<SettInfoExportDto> pageResult = new PageResult<SettInfoExportDto>();
AccountInfoEntityResp accountInfoEntityResp = accountInfoService.getLocalAccountInf(accountDate);
//1.結算場次列表
List<String> settListTitles = new ArrayList<>();
settListTitles.add("報文標識號");
settListTitles.add("場次借貸標識");
settListTitles.add("場次金額");
//2.批次列表
List<String> batchInfListTitles = new ArrayList<>();
batchInfListTitles.add("報文標識號");
batchInfListTitles.add("批次號");
batchInfListTitles.add("批次借貸標識");
batchInfListTitles.add("批次金額");
//3.分項列表
List<String> sttlInfListTitles = new ArrayList<>();
sttlInfListTitles.add("批次號");
sttlInfListTitles.add("業務型別");
sttlInfListTitles.add("銀行金額機構標識");
sttlInfListTitles.add("賬戶型別");
sttlInfListTitles.add("分項借方發生額");
sttlInfListTitles.add("分項借方發生筆數");
sttlInfListTitles.add("分項貸方發生額");
sttlInfListTitles.add("分項貸方發生筆數");
//4.賬務日期...
Map<String, String> statisticsData = new HashMap<>();
String settCount = accountInfoEntityResp.getSttlCntNb().toString();
String debitAmount = accountInfoEntityResp.getDebitCntAmt().toString();
String creditAmount = accountInfoEntityResp.getCreditCntAmt().toString();
statisticsData.put("財務日期:", accountDate.replace("//-","///"));
statisticsData.put("結算總筆數", settCount);
statisticsData.put("借方金額", debitAmount);
statisticsData.put("貸方金額", creditAmount);
//5.結算場次列表資料list
List<SettInfoExportDto> settInfoExportDtoList = new ArrayList<SettInfoExportDto>();
//6.批次列表資料list
List<BatchInfExportDto> batchInfExportDtoList = new ArrayList<BatchInfExportDto>();
//7.分項列表資料list
List<SubItemInfoExportDto> subItemInfoExportDtoList = new ArrayList<SubItemInfoExportDto>();
if(accountInfoEntityResp.getSttlList() != null){
//結算場次列表資料
for(int i=0; i<accountInfoEntityResp.getSttlList().size(); i++){
SettInfoExportDto settInfoExportDto = new SettInfoExportDto();
settInfoExportDto.setSttlAmt(accountInfoEntityResp.getSttlList().get(i).getSttlAmt());
settInfoExportDto.setSttlDCFlg(accountInfoServiceImpl.DCFlag(accountInfoEntityResp.getSttlList().get(i).getSttlDCFlg()));
settInfoExportDto.setSttlReptFlg(accountInfoEntityResp.getSttlList().get(i).getSttlReptFlg());
settInfoExportDtoList.add(settInfoExportDto);
//批次列表資料
if(accountInfoEntityResp.getSttlList().get(i).getBatchList() != null){
for(int j= 0; j<accountInfoEntityResp.getSttlList().get(i).getBatchList().size(); j++) {
BatchInfExportDto batchInfExportDto = new BatchInfExportDto();
batchInfExportDto.setSttlReptFlg(accountInfoEntityResp.getSttlList().get(i).getSttlReptFlg());
batchInfExportDto.setBatchDCFlg(accountInfoEntityResp.getSttlList().get(i).getBatchList().get(j).getBatchDCFlg());
batchInfExportDto.setBatchId(accountInfoEntityResp.getSttlList().get(i).getBatchList().get(j).getBatchId());
batchInfExportDto.setBatchNetAmt(accountInfoEntityResp.getSttlList().get(i).getBatchList().get(j).getBatchNetAmt());
batchInfExportDtoList.add(batchInfExportDto);
//分項列表資料
if(accountInfoEntityResp.getSttlList().get(i).getBatchList().get(j).getSubItemList() != null){
for(int f=0; f< accountInfoEntityResp.getSttlList().get(i).getBatchList().get(j).getSubItemList().size(); f++){
SubItemInfoExportDto subItemInfoExportDto = new SubItemInfoExportDto();
subItemInfoExportDto.setBatchId(accountInfoEntityResp.getSttlList().get(i).getBatchList().get(j).getBatchId());
String subStr = accountInfoEntityResp.getSttlList().get(i).getBatchList().get(j).getSubItemList().get(f).getSubItemInf();
subStr = subStr.replace("CNY","");
String[] subArray = {};
subArray = subStr.split("\\|");
subItemInfoExportDto.setBusinessType(accountInfoServiceImpl.busiType(subArray[0]));
subItemInfoExportDto.setBankOrgFlag(subArray[1]);
subItemInfoExportDto.setAccountType(accountInfoServiceImpl.accountType(subArray[2]));
subItemInfoExportDto.setDebitSplitAmount(subArray[3]);
subItemInfoExportDto.setDebitSplitCount(Integer.valueOf(subArray[4]));
subItemInfoExportDto.setCreditSplitAmount(subArray[5]);
subItemInfoExportDto.setCreditSplitCount(Integer.valueOf(subArray[6]));
subItemInfoExportDtoList.add(subItemInfoExportDto);
}
}
}
}
}
}
settListTitles.addAll(batchInfListTitles);
settListTitles.addAll(sttlInfListTitles);
CSVPrinter csvPrinter = accountInfoService.downloadCsv(request, response, settListTitles);
pageResult.setTitles(settListTitles);
pageResult.setResult(Constants.detailReturnCode.RETURN_SUCCESS.code);
pageResult.setRows(settInfoExportDtoList);
accountInfoService.printlnCsv(csvPrinter,statisticsData,settInfoExportDtoList,batchInfExportDtoList,
subItemInfoExportDtoList,settListTitles,batchInfListTitles,sttlInfListTitles);
IOUtils.closeQuietly(csvPrinter);
return null;
}
輸入輸出流,封裝CSVPrinter物件:
public CSVPrinter downloadCsv(HttpServletRequest request, HttpServletResponse response, List<String> titles) {
try {
// 獲取資料
String fileName = request.getParameter("fileName");
// 設定檔名, 用於下載
response.setContentType("application/csv;charset=UTF-8");
response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(fileName, "utf-8"));
// 新增UTF-8的BOM頭,避免Excel開啟檔案時使用系統預設編碼產生亂碼
byte[] byteBOM = new byte[] { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF };
OutputStream outputStream = response.getOutputStream();
outputStream.write(byteBOM);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, "utf-8");
CSVPrinter printer = CSVFormat.DEFAULT.withHeader(titles.toArray(new String[titles.size()])).print(outputStreamWriter);
return printer;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
csv匯出記錄:
public void printlnCsv(CSVPrinter printer, Map<String, String> statisticsData,List<SettInfoExportDto> settInfoExportDtoList,
List<BatchInfExportDto> batchInfExportDtoList,List<SubItemInfoExportDto> subItemInfoExportDtoList,
List<String> settListTitles,List<String> batchInfListTitles,List<String> sttlInfListTitles){
if(subItemInfoExportDtoList.size() > 0){
try{
//報文標識號
String sttlReptFlg = null;
//結算列表資料
for(SettInfoExportDto row:settInfoExportDtoList){
Field[] declaredFields = row.getClass().getDeclaredFields();
for (Field declaredField : declaredFields) {
declaredField.setAccessible(true);
FieldAnnotation annotation = declaredField.getAnnotation(FieldAnnotation.class);
if (annotation == null) {
// 只有註解了 FieldAnnotation 的欄位,才會輸出
continue;
}
Object value = declaredField.get(row);
if (StringUtils.equals(annotation.fieldName(), "報文標識號")) {
sttlReptFlg = (String) value;
}
printer.print(value + "\t");
}
// 換行
printer.println();
//列印批次列表資料
printBacthRecord(printer,sttlReptFlg, batchInfExportDtoList, subItemInfoExportDtoList, settListTitles
,batchInfListTitles, sttlInfListTitles);
}
// 換行
printer.println();
//手續費行
if (statisticsData != null && !statisticsData.isEmpty()) {
Iterator<String> iterator = statisticsData.keySet().iterator();
while (iterator.hasNext()) {
String key = (String) iterator.next();
printer.print(key);
printer.print(statisticsData.get(key));
// 換行
printer.println();
}
byte[] nulls = new byte[] { (byte) 00, (byte) 00, (byte) 00 };
printer.print(new String(nulls));
}
printer.flush();
}catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 列印批次列表資料
*/
public void printBacthRecord(CSVPrinter printer,String sttlReptFlg,List<BatchInfExportDto> batchInfExportDtoList,
List<SubItemInfoExportDto> subItemInfoExportDtoList,List<String> settListTitles ,
List<String> batchInfListTitles,List<String> sttlInfListTitles) throws IOException {
int i = settListTitles.size() - batchInfListTitles.size() - sttlInfListTitles.size();
//取出該報文標識號的批次列表
List<BatchInfExportDto> printBatchInfoList = new ArrayList<BatchInfExportDto>();
if(batchInfExportDtoList != null && batchInfExportDtoList.size()>0){
for(BatchInfExportDto record:batchInfExportDtoList){
if(record.getSttlReptFlg().equals(sttlReptFlg)){
printBatchInfoList.add(record);
}
}
}
if (printBatchInfoList != null && !printBatchInfoList.isEmpty()) {
String batchId = null;
for (BatchInfExportDto bacthInfo : printBatchInfoList) {
byte[] nulls = new byte[i];
for (byte b : nulls) {
printer.print(new String(nulls));
}
printer.print(sttlReptFlg);
printer.print(bacthInfo.getBatchId());
printer.print(bacthInfo.getBatchDCFlg());
printer.print(bacthInfo.getBatchNetAmt());
batchId = bacthInfo.getBatchId();
// 換行
printer.println();
//列印分項列表資料
printSubItemRecord(printer,batchId,subItemInfoExportDtoList,settListTitles,sttlInfListTitles);
}
}
}
/**
* 列印分項列表資料
*/
public void printSubItemRecord(CSVPrinter printer,String batchId,List<SubItemInfoExportDto> subItemInfoExportDtoList,
List<String> settListTitles ,List<String> sttlInfListTitles ) throws IOException {
int i = settListTitles.size() - sttlInfListTitles.size();
//取出該批次號的分項列表
List<SubItemInfoExportDto> subItemPrintRecordList = new ArrayList<SubItemInfoExportDto>();
if(subItemInfoExportDtoList != null && subItemInfoExportDtoList.size()>0){
for(SubItemInfoExportDto record : subItemInfoExportDtoList){
if(record.getBatchId().equals(batchId)){
subItemPrintRecordList.add(record);
}
}
}
if (subItemPrintRecordList != null && !subItemPrintRecordList.isEmpty()) {
for (SubItemInfoExportDto subItemInfo : subItemPrintRecordList) {
byte[] nulls = new byte[i];
for (byte b : nulls) {
printer.print(new String(nulls));
}
printer.print(batchId);
printer.print(subItemInfo.getBusinessType());
printer.print(subItemInfo.getBankOrgFlag());
printer.print(subItemInfo.getAccountType());
printer.print(subItemInfo.getDebitSplitAmount());
printer.print(subItemInfo.getDebitSplitCount());
printer.print(subItemInfo.getCreditSplitAmount());
printer.print(subItemInfo.getDebitSplitCount());
// 換行
printer.println();
}
}
}
主要核心程式碼以上。
最終匯出效果如下: