想將多個查詢及產生檔案之程式碼(每組程式均有不同的運作邏輯),
以下是我規劃的架構(由spring4 + struts2 + hibernate5):

相關程式碼架構示意如下:
一、設定檔
1.struts.xml
...
<action name="DTDayReport_*" class="com.xxx.action.DTDayReportAction" method="{1}">
<result name="success">/ajax/DTDayReport.jsp</result>
<result name="{1}" type="json">
<param name="root">dataMap</param>
</result>
</action>
...
2.(enum) DayReport.java
public enum DayReport {
SNP("SNP", "檔案一", "com.xxx.bean.DTRptXXX1"),
SNT("SNT", "檔案二", "com.xxx.bean.DTRptXXX2"),
SNT("SNT", "檔案三", "com.xxx.bean.DTRptXXX3");
protected String id;
protected String desc;
protected String className;
private DayReport(String id, String desc, String className) {
this.id = id;
this.desc = desc;
this.className = className;
}
public String getId() {
return id;
}
public String getDesc() {
return desc;
}
public String getClassName() {
return className;
}
}
3.DTReportCol.java
public class DTReportCol {
private String colId;
private String colDesc;
private String colType; //String, double , int, Date
private int digit; //顯示小數位數
private String dateFmt; //Ex.yyyy-mm-dd
private String codeType;
public DTReportCol(String colId, String colDesc, String colType, int digit, String dateFmt) {
this(colId, colDesc, colType, digit, dateFmt, "");
}
public DTReportCol(String colId, String colDesc, String colType, int digit, String dateFmt, String codeType) {
super();
this.colId = colId;
this.colDesc = colDesc;
this.colType = colType;
this.digit = digit;
this.dateFmt = dateFmt;
this.codeType = codeType;
}
public String getColId() {
return colId;
}
public void setColId(String colId) {
this.colId = colId;
}
public String getColDesc() {
return colDesc;
}
public void setColDesc(String colDesc) {
this.colDesc = colDesc;
}
public String getColType() {
return colType;
}
public void setColType(String colType) {
this.colType = colType;
}
public int getDigit() {
return digit;
}
public void setDigit(int digit) {
this.digit = digit;
}
public String getDateFmt() {
return dateFmt;
}
public void setDateFmt(String dateFmt) {
this.dateFmt = dateFmt;
}
public String getCodeType() {
return codeType;
}
public void setCodeType(String codeType) {
this.codeType = codeType;
}
@Override
public String toString() {
return "DTReportCol [colId=" + colId + ", colDesc=" + colDesc + ", colType=" + colType + ", digit=" + digit
+ ", dateFmt=" + dateFmt + ", codeType=" + codeType + "]";
}
}
4.(interface) DTRptInterface.java
import java.util.LinkedList;
import com.xxx.entity.DTReportCol;
public interface DTRptInterface {
public abstract String retriveFileName();
public abstract LinkedList retriveCols();
public abstract boolean rerunByDate(String applyDate_in, String errorMsg, String modifyEmp);
public abstract boolean removeByDate(String applyDate_in, String errorMsg, String modifyEmp);
}
二、bean檔
1.DTRptDayPK.java
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Embeddable;
@Embeddable
public class DTRptDayPK implements Serializable {
@Column(name = "applyDate")
private Date applyDate;
@Column(name = "rowIdx")
private int rowIdx;
public DTRptDayPK() {
}
public DTRptDayPK(Date applyDate, int rowIdx) {
super();
this.applyDate = applyDate;
this.rowIdx = rowIdx;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((applyDate == null) ? 0 : applyDate.hashCode());
result = prime * result + rowIdx;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DTRptDayPK other = (DTRptDayPK) obj;
if (applyDate == null) {
if (other.applyDate != null)
return false;
} else if (!applyDate.equals(other.applyDate))
return false;
if (rowIdx != other.rowIdx)
return false;
return true;
}
public Date getApplyDate() {
return applyDate;
}
public void setApplyDate(Date applyDate) {
this.applyDate = applyDate;
}
public int getRowIdx() {
return rowIdx;
}
public void setRowIdx(int rowIdx) {
this.rowIdx = rowIdx;
}
@Override
public String toString() {
return "DTRptDayPK [applyDate=" + applyDate + ", rowIdx=" + rowIdx + "]";
}
}
2.DTRptXXX1.java – 與DayReport.java配合設定,可n個
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
...
@Entity
@Table(name = "DTRptXXX1")
public class DTRptXXX1 implements Serializable, DTRptInterface {
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(
name = "applyDate",
column = @Column(name = "applyDate")),
@AttributeOverride(
name = "rowIdx",
column = @Column(name = "rowIdx"))
})
protected DTRptXXX1PK dtRptDayPK;
//請新增相關欄位
...
@Column(name = "modifyTime")
private Date modifyTime;
@Column(name = "modifyEmp")
private String modifyEmp;
public DTRptXXX1() {
}
public DTRptXXX1(DTRptDayPK dtRptDayPK, ... , Date modifyTime, String modifyEmp) {
super();
//請新增相關欄位
...
this.modifyTime = modifyTime;
this.modifyEmp = modifyEmp;
}
public DTRptDayPK getDtRptDayPK() {
return dtRptDayPK;
}
public void setDtRptDayPK(DTRptDayPK dtRptDayPK) {
this.dtRptDayPK = dtRptDayPK;
}
public String getApplyComp() {
return applyComp;
}
//請新增相關欄位之set及get function
...
public Date getModifyTime() {
return modifyTime;
}
public void setModifyTime(Date modifyTime) {
this.modifyTime = modifyTime;
}
public String getModifyEmp() {
return modifyEmp;
}
public void setModifyEmp(String modifyEmp) {
this.modifyEmp = modifyEmp;
}
@Override
public String toString() {
return "DTRptSNP [dtRptDayPK=" + dtRptDayPK +
...
", modifyTime=" + modifyTime + ", modifyEmp=" + modifyEmp + "]";
}
@Override
public String retriveFileName() {
return "DTRptXXX1.txt";
}
@Override
public LinkedList retriveCols() {
LinkedList dtReportColList = new LinkedList<>();
//請新增相關欄位
...
dtReportColList.add(new DTReportCol("modifyTime", "修改時間", "Date", 0, "yyyy-mm-dd HH:mm:ss"));
dtReportColList.add(new DTReportCol("modifyEmp", "修改人員", "String", 0, null));
return dtReportColList;
}
@Override
public boolean rerunByDate(String applyDate_in, String errorMsg, String modifyEmp) {
DTServiceEntry dtServiceEntry = new DTServiceEntry();
//1.條件判斷
...
//2.清除舊資料
boolean bRemoveOK = removeByDate(applyDate_in, errorMsg, modifyEmp);
if (bRemoveOK == false) {
errorMsg = "清除舊資料失敗" + errorMsg + ".";
return false;
}
//3.取得資料
...
//4.寫入資料庫
...
//5.寫入檔案
...
return bOK_modify;
}
@Override
public boolean removeByDate(String applyDate_in, String errorMsg, String modifyEmp) {
DTServiceEntry dtServiceEntry = new DTServiceEntry();
Logger logger = LogManager.getLogger(this.getClass().getName());
//1.清除舊資料
...
//2.清除舊檔案
...
return true;
}
}
三、(View) DTDayReport.jsp
javascript呼叫後端action的主要程式碼示意如下
//footable
var myfootable = {
first : true,
rerun : function() {
var kindVal = $('#s2_kind').find(':selected').val();
var settleDateVal = $('#settleDate').val();
if (kindVal.length <= 0 || settleDateVal.length <= 0) {
if (myfootable.first == false) {
$('#modal-body-msg').text("請輸入種類及日期.");
$('#messageModal').modal('show');
}
myfootable.first = false;
return;
}
myfootable.first = false;
var formData = {kind : kindVal, settleDate : settleDateVal};
$.ajax({
url : 'DTDayReport_getJsonRerun.action',
type: "POST",
data : formData,
dataType : 'json',
success : myfootable.ajax_loaddata,
error : function(xhr, statusText, error) {
alert("錯誤! 無法取得資料.");
}
});
},
query : function () {
var kindVal = $('#s2_kind').find(':selected').val();
var settleDateVal = $('#settleDate').val();
if (kindVal.length <= 0 || settleDateVal.length <= 0) {
if (myfootable.first == false) {
$('#modal-body-msg').text("請輸入種類及日期.");
$('#messageModal').modal('show');
}
myfootable.first = false;
return;
}
myfootable.first = false;
var formData = {kind : kindVal, settleDate : settleDateVal};
$.ajax({
url : 'DTDayReport_getJson.action',
type: "POST",
data : formData,
dataType : 'json',
success : myfootable.ajax_loaddata,
error : function(xhr, statusText, error) {
alert("錯誤! 無法取得資料.");
}
});
},
ajax_loaddata : function(data) {
$("#footable tbody tr").each(function(index, elem) {
$(elem).remove();
});
$.each(data, function(index, item) {
if (index == "result") {
if (item.show == true || (item.success == false && myfootable.first == false)) {
$('#modal-body-msg').text(item.message);
$('#messageModal').modal('show');
}
} else if (index == 'TRANDATE') {
$('.date-picker').datepicker('change', {dateFormat: 'yy-mm-dd', maxDate: item});
} else if (index == 'dtRpt' && item != null) {
$.each(item, function(index2, item2) {
var row = myfootable.create_table_row(item2);
$('#footable tbody').append(row);
});
} else if (index == 'settleT2Date') {
$('#settleT2Date').val(item);
}
});
myfootable.first = false;
$('#footable').trigger('footable_initialize');
},
create_table_row : function (item) {
var row = '<tr>';
$.each(reportColList, function(index_col, item_col) {
var colId = ((item_col.colId == 'applyDate' || item_col.colId == 'rowIdx')
? ('dtRptDayPK.' + item_col.colId) : item_col.colId);
var sVal = eval('item.' + colId);
//1.日期
if (item_col.colType == 'Date') {
sVal = sVal.replace('T',' ');
if (item_col.dateFmt == 'yyyy-mm-dd')
sVal = sVal.substring(0, 10);
}
//2.代碼mapping
if (item_col.codeType != null && item_col.codeType.length > 0) {
var mapObj = codeMap[item_col.codeType];
if (mapObj !== undefined) {
if (mapObj[sVal] !== undefined)
sVal = sVal + '-' + mapObj[sVal];
}
}
row += '<td data-value="' + sVal + '">' + sVal + '</td>';
});
row += '</tr>';
return row;
},
downloadFile : function(e) {
e.preventDefault();
var kindVal = $('#s2_kind').find(':selected').val();
var settleDateVal = $('#settleDate').val();
if (kindVal.length <= 0 || settleDateVal.length <= 0) {
if (myfootable.first == false) {
$('#modal-body-msg').text("請輸入種類及日期.");
$('#messageModal').modal('show');
}
return;
}
var url = 'DTDayReport.action?kind=' + kindVal + '&type=Download&settleDate=' + settleDateVal;
window.open(url, "_blank").focus();
}
}
四、(Action) DTDayReportAction.java
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
...
public class DTDayReportAction extends BaseAction {
private static String rootPath = "DownloadPath_Ftp";
//將被Struts2序列化為JSON字符串的對象
private Map<String, Object> dataMap = new LinkedHashMap<String, Object>();
//Query
private String kind;
private String type; //Download=下載檔案
private String settleDate;
public DTDayReportAction() {
super();
myPlatFormList.add(new UserPrivItem(PlatForm.DERIVTRADE.toString(), "DTDaySettle"));
}
/**
* Struts2序列化指定?性?,必?有??性的getter方法,??上,如果?有?性,而只有getter方法也是可以的
* @return
*/
public Map<String, Object> getDataMap() {
return dataMap;
}
public void setDataMap(Map<String, Object> dataMap) {
this.dataMap = dataMap;
}
//Query
public String getKind() {
return kind;
}
public void setKind(String kind) {
this.kind = kind;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getSettleDate() {
return settleDate;
}
public void setSettleDate(String settleDate) {
this.settleDate = settleDate;
}
public String getJson() {
boolean bSuccess = true;
String message = "";
dataMap.clear();
//1.回覆結果
Map<String, Object> dataMessage = new LinkedHashMap<String, Object>();
dataMessage.put("success", bSuccess);
dataMessage.put("message", message);
dataMessage.put("show", false);
dataMap.put("result", dataMessage);
//2.取得目前交易及前一結帳日
String tranDate = ...
request.setAttribute("TRANDATE", tranDate);
//3.取得資料
retriveData();
return "getJson";
}
public String getJsonRerun() {
boolean bSuccess = false;
String message = "";
dataMap.clear();
//1.取得欄位
for (DayReport dayReport : DayReport.values()) {
if (dayReport.getId().compareTo(kind) != 0)
continue;
final String className = dayReport.getClassName();
Thread thread = new Thread(new Runnable() {
public void run() {
try {
UserItem userItem = (UserItem) session.getAttribute("UserItem");
Class<?> dayReportClass = Class.forName(className);
Constructor<?> constructor = dayReportClass.getDeclaredConstructor();
DTRptInterface obj = (DTRptInterface) constructor.newInstance();
Method method = dayReportClass.getMethod("rerunByDate",
new Class[] {String.class, String.class, String.class});
String errorMsg = "";
boolean bRerunOK = (boolean) method.invoke(obj, settleDate, errorMsg, userItem.getUsername());
logger.info("bRerunOK: " + bRerunOK + ", errorMsg: " + errorMsg);
} catch (ClassNotFoundException e1) {
logger.error("kind=" + kind + " : ClassNotFoundException - " + e1.getMessage());
} catch (NoSuchMethodException e2) {
logger.error("kind=" + kind + " : : NoSuchMethodException - " + e2.getMessage());
} catch (IllegalAccessException e3) {
logger.error("kind=" + kind + " : IllegalAccessException - " + e3.getMessage());
} catch (InvocationTargetException e4) {
logger.error("kind=" + kind + " : InvocationTargetException - " + e4.getMessage());
e4.printStackTrace();
} catch (InstantiationException e5) {
logger.error("kind=" + kind + " : InstantiationException - " + e5.getMessage());
}
}
});
thread.start();
try {
thread.join(300 * 1000);
} catch (InterruptedException e) {
logger.error(e.getMessage());
}
bSuccess = true;
break;
}
message = (bSuccess == true) ? "重新產出資料中,請確認." : "重新產出資料失敗,請確認.";
//2.回傳結果
Map<String, Object> dataMessage = new LinkedHashMap<String, Object>();
dataMessage.put("success", bSuccess);
dataMessage.put("message", message);
dataMessage.put("show", true);
dataMap.put("result", dataMessage);
//3.取得目前交易及前一日期
String tranDate = ...
request.setAttribute("TRANDATE", tranDate);
//4.取得資料
retriveData();
return "getJsonRerun";
}
//取得清單
private boolean retriveData() {
if (kind.compareToIgnoreCase(DayReport.DTRptXXX1.getId()) == 0) {
List dtRptXXX1List = ...
dataMap.put("dtRpt", dtRptXXX1List);
} else if (kind.compareToIgnoreCase(DayReport.DTRptXXX2.getId()) == 0) {
...
} else
return false;
return true;
}
@Override
public String execute() throws Exception {
//下載檔案
if (type != null && type.compareToIgnoreCase("Download") == 0) {
String fileName = retriveFileName();
if (fileName == null || fileName.trim().length() <= 0) { response.getWriter().println("Get File error"); return NONE; } String filePath = SysConfigUtil.getValue(application, rootPath) + File.separator + settleDate.replace("-", "") + File.separator + fileName; logger.info("download filePath= " + filePath); FileInputStream fis = null; try { //1.開檔 fis = new FileInputStream(filePath); //2.顯示檔案 byte[] buffer = new byte[1024]; int len = 0; String docFileName = java.net.URLEncoder.encode(fileName, "UTF-8"); response.setHeader("Content-Disposition", "attachment;filename=".concat(docFileName)); String extension = DataUtil.getExtension(fileName); response.setContentType(getContentType(extension)); OutputStream out = response.getOutputStream(); while ((len = fis.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
out.close();
} catch (IOException e) {
logger.error(e.getMessage());
response.getWriter().println("Get Image error");
} finally {
if (fis != null)
fis.close();
}
return NONE;
}
//1.取得目前交易及前一結帳日
String tranDate = ...
request.setAttribute("TRANDATE", tranDate);
//2.取得欄位
for (DayReport dayReport : DayReport.values()) {
if (dayReport.getId().compareTo(kind) == 0) {
try {
Class<?> dayReportClass = Class.forName(dayReport.getClassName());
Constructor<?> constructor = dayReportClass.getDeclaredConstructor();
DTRptInterface obj = (DTRptInterface) constructor.newInstance();
Method method = dayReportClass.getMethod("retriveCols", new Class[] {});
LinkedList dtReportColList = (LinkedList) method.invoke(obj);
logger.info(dtReportColList);
request.setAttribute("dtReportColList", dtReportColList);
} catch (ClassNotFoundException e1) {
logger.error("kind=" + kind + " : ClassNotFoundException - " + e1.getMessage());
} catch (NoSuchMethodException e2) {
logger.error("kind=" + kind + " : : NoSuchMethodException - " + e2.getMessage());
} catch (IllegalAccessException e3) {
logger.error("kind=" + kind + " : IllegalAccessException - " + e3.getMessage());
} catch (InvocationTargetException e4) {
logger.error("kind=" + kind + " : InvocationTargetException - " + e4.getMessage());
} catch (InstantiationException e5) {
logger.error("kind=" + kind + " : InstantiationException - " + e5.getMessage());
}
break;
}
}
return super.execute();
}
/**
* 取得檔案名稱
* @return
*/
private String retriveFileName() {
String fileName = null;
for (DayReport dayReport : DayReport.values()) {
if (dayReport.getId().compareTo(kind) != 0)
continue;
String className = dayReport.getClassName();
try {
Class<?> dayReportClass = Class.forName(className);
Constructor<?> constructor = dayReportClass.getDeclaredConstructor();
DTRptInterface obj = (DTRptInterface) constructor.newInstance();
Method method = dayReportClass.getMethod("retriveFileName", new Class[] {});
fileName = (String) method.invoke(obj);
logger.info("fileName: " + fileName);
} catch (ClassNotFoundException e1) {
logger.error("kind=" + kind + " : ClassNotFoundException - " + e1.getStackTrace());
} catch (NoSuchMethodException e2) {
logger.error("kind=" + kind + " : : NoSuchMethodException - " + e2.getStackTrace());
} catch (IllegalAccessException e3) {
logger.error("kind=" + kind + " : IllegalAccessException - " + e3.getStackTrace());
} catch (InvocationTargetException e4) {
logger.error("kind=" + kind + " : InvocationTargetException - " + e4.getStackTrace());
} catch (InstantiationException e5) {
logger.error("kind=" + kind + " : InstantiationException - " + e5.getStackTrace());
}
break;
}
return fileName;
}
}
五、執行結果 : 每個查詢報表畫面類似如下
