使用靜態代理模式實現公用的報表匯出功能
阿新 • • 發佈:2020-12-11
先聊一下什麼是代理模式?
代理模式 給某個物件提供一個代理物件,並由代理獨享控制對原物件的引用。什麼意思呢?代理模式就有點像我們生活中常見的中介。
舉個例子,我想買輛二手車,第一種方式是自己去找車源,但是像質量檢測等一系列的車輛過戶流程都需要自己去辦,我覺得這樣太浪費精力和時間了。於是我想到了第二種方式,就是找一箇中介公司,他們代替我辦理過戶流程,我只需要負責選擇自己喜歡的汽車,然後付錢就行了,這就簡單很多了。
畫個UML圖如下。
前面提到了我們選擇中介是為了省事,其實在程式碼中使用代理模式也可以省事,因為不只有我這個物件會去找這個中介,其他需要買二手車的人也需要去找這個中介,那這個中介的作用就做到了重用了。
下面說在程式中為什麼要使用代理模式
- 中介隔離:在某些情況下,一個客戶不想或不能直接引用委託物件。
- 開閉原則,增加功能:當代碼需要增加業務功能時,我們只需要修改代理類就行,符合開閉原則。
代理模式分為靜態代理和動態代理。我們今天著重講靜態代理
下面進入獵殺時刻!!!!
使用靜態代理模式實現公用的匯出功能
先來一張設計圖
先看代理介面
public interface ReportWithExcelTempAble<T> { /** * 獲得報表資料 * @param searchParam * @return */ default List<List<?>> getMultipleSheetData(T searchParam) { ArrayList<List<?>> result = Lists.newArrayList(); result.add(getSingleSheetData(searchParam)); return result; } default List<?> getSingleSheetData(T searchParam) { throw new RuntimeException("Not support method."); } Class<T> getSearchParamType(); /** * 需要匯出的檔名 * @return */ default String getReportFileName(String tempName) { return tempName; } }
getMultipleSheetData
、getReportFileName
都有預設的實現方法,因為大部分都是一個sheet的報表。
再看看代理類,代理主要是代理了報表在匯出中的一系列操作,比如獲取匯出模板,設定匯出名稱等等。
package com.sf.esg.occp.core.common.support.report; import com.alibaba.fastjson.JSONObject; import com.sf.erui.context.SpringContextUtil; import com.sf.erui.util.StringUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; public class ReportProxy implements ReportWithExcelTempAble<JSONObject> { private static Logger LOG = LoggerFactory.getLogger(ReportProxy.class); /** * 模板名稱 */ private String tempName; /** * 報表名稱 */ private String reportFileName; private ReportWithExcelTempAble delegateInstance; private ReportProxy() { } public String getReportFileName() { return reportFileName; } public static <T> ReportProxy of(String delegateName) { ReportProxy director = new ReportProxy(); director.tempName = delegateName; director.delegateInstance = SpringContextUtil.getBean( StringUtil.toLowerCaseFirstOne(director.tempName) , ReportWithExcelTempAble.class); director.reportFileName = director.delegateInstance.getReportFileName(director.tempName); return director; } @Override public List<List<?>> getMultipleSheetData(JSONObject searchParam) { long start = System.currentTimeMillis(); Object searchObj = JSONObject.toJavaObject(searchParam, delegateInstance.getSearchParamType()); LOG.debug("組裝資料費時:{}", System.currentTimeMillis() - start); return delegateInstance.getMultipleSheetData(searchObj); } @Override public Class getSearchParamType() { return delegateInstance.getSearchParamType(); } }
再來看看委託類:
public class BankTransactionExport implements ReportWithExcelTempAble<QueryBankTransactionVO> {
@Autowired
private BankTransactionService bankTransactionService;
@Override
public List<List<?>> getMultipleSheetData(QueryBankTransactionVO searchParam) {
List<List<?>> lists = bankTransactionService.exportMultipleSheet(searchParam);
return lists;
}
@Override
public Class<QueryBankTransactionVO> getSearchParamType() {
return QueryBankTransactionVO.class;
}
@Override
public String getReportFileName(String tempName) {
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
String dateStr = format.format(new Date());
return "SF銀行流水認領明細" + dateStr;
}
}
Controller層:
@RestController
@RequestMapping("/report/excel")
public class ReportController {
public static final String FILE_SUFFIX = ".xlsx";
public static final String TEMP_BASE_PATH = "temp/";
public static final String PAGE_SIZE = "pageSize";
public static final String CURRENT_PAGE = "currentPage";
public static final int PAGE_SIZE_VALUE = 1000;
private static Logger LOG = LoggerFactory.getLogger(ReportController.class);
@GetMapping(params = {"Action=exportExcelByTemp"})
public Response exportExcelByTemp(@RequestParam Map<String, Object> searchParam, HttpServletResponse resp) {
LOG.info("Export report by temp:{}", searchParam);
String tempName = (String) searchParam.get("tempName");
try {
ReportProxy reportDirector = ReportProxy.of(tempName);
String tempPath = TEMP_BASE_PATH + tempName + FILE_SUFFIX;
String fileName = URLEncoder.encode(reportDirector.getReportFileName(), "UTF-8");
resp.setHeader("Content-Disposition", "filename=" + fileName + FILE_SUFFIX);
resp.setContentType("APPLICATION/OCTET-STREAM");
try (InputStream ins = new ClassPathResource(tempPath).getInputStream()) {
ExcelWriterBuilder writeBuilder = EasyExcel.write(resp.getOutputStream()).withTemplate(ins);
ExcelWriter writer = writeBuilder.autoCloseStream(false).
registerConverter(new LocalDateTimeConverter()).build();
JSONObject jsonObject = new JSONObject(searchParam);
List<List<?>> data = reportDirector.getMultipleSheetData(jsonObject);
ExcelUtils.pageExportByTemp(writer, data, tempPath);
writer.finish();
} catch (IOException e) {
LOG.error("Excel Export Err : ", e);
}
return ResponseHelper.buildOk();
} catch (IOException e) {
LOG.error("Response get output stream err:{}", e);
return ResponseHelper.buildFail("請聯絡管理員");
}
}
}
在前端使用get請求呼叫:/report/excel?Action=exportExcelByTemp&tempName="a.xmls"
最後別忘了,新增a.xmls在專案的 temp/
目錄下,我用的Spring boot,對應程式碼中的目錄如下