做過很多的項目,我們通常需要通過一點設計模式來解決一些稍微複雜的問題。比如說讀取一個data,有多行資料檔案。在讀取過程中可能會出現些特殊情況,要求是,假如出現以外情況,需要把已經讀取的資料寫到資料庫裡,而出錯的位置需要記錄在系統中,下次讀取的時候從這個位置往下,這個記錄出錯位置並且下次執行,這些基礎的服務,可能是在架構中做處理,而不需要讓編寫業務程式的程式員知道這些。
設計:
可能我們只需要寫一個IBaseBatchController介面,提供一些開放的介面。供程式員使用,可能是這樣的
public interface IBaseBatchController{
public int execute();
}
外面的程式就是通過這個方法去調用。
比如說IBaseBatchController cc = new AAABatchController():
cc.execute();
我們需要解決的問題是在interface和實作類別中間加一個AbstractBaseCatchController,目標就是在中間做基礎的服務。
public void execute(String[] args){
try {
init(args);
if (getSyntaxCheckFirst()) {
// file first before doing biz processing
boolean validationOK = validateSyntax();
if (validationOK) {
initFileHandler(args);
processSingleFile(args);
} else {
updateTxInfo(IBatchStatusConstant.JOB_STATUS_ABORTED);
}
} else {
processSingleFile(args);
}
} catch (Exception e) {
throw new ECustomsUnChkException(e);
}
}
protected void processSingleFile(String args[]){
try
{
List errList = null;
errList = parseHeader();
if(errList != null && errList.size() != 0)
{
processError(errList);
if(isAbortOnHeaderFail()) {
throw new BatchAbortProcessingException(HEADER_FAIL_MSG);
}
}
int commitCount = 0;
boolean notEndofContent = true;
do
{
if(logger.isInfoEnabled()) {
logger.info("Commit count:" + (commitCount + 1));
}
try
{
parseBatchContent();
}
catch(ECustomsChkException e)
{
if(e.getMessage().equals(BATCH_EOF)) {
notEndofContent = false;
}
else {
throw e;
}
}
commitCount++;
} while(notEndofContent && !fileAbortIndicator);
if(fileAbortIndicator) {
throw new BatchAbortProcessingException(RECORD_FAIL_MSG);
}
errList = parseTrailer();
if(errList != null && errList.size() != 0)
{
processError(errList);
if(isAbortOnTrailerFail()) {
throw new BatchAbortProcessingException(TRAILER_FAIL_MSG);
}
}
updateTxInfo(IBatchStatusConstant.JOB_STATUS_COMPLETED);
}
catch (BatchAbortProcessingException e) {
updateTxInfo(IBatchStatusConstant.JOB_STATUS_ABORTED, e.getMessage());
throw new ECustomsUnChkException(e);
}
catch(Exception e)
{
updateTxInfo(IBatchStatusConstant.JOB_STATUS_ABORTED);
logger.error(this, e);
throw new ECustomsUnChkException(e);
}
public abstract parseBatchContent();//供實作類別實現用。比如決定資料存放在什麼表裡。
public List parseHeader() throws ECustomsChkException, IOException {
debug("parseHeader");
results = readHeader();
List errorList = null;
if (results != null) {
errorList = results.getErrorList();
} else {
ErrorRecInfo errInfo = new ErrorRecInfo();
errInfo.setErrorMessage("Invalid file, file has no content");
errorList = new ArrayList();
errorList.add(errInfo);
}
return errorList;
}
}
需要做的是,在parsecontent方法裡寫處理資料的商務邏輯,解析出來的資料寫到什麼表裡。
題外話,假設是通過Spring來管理bean的話,
假設需要在AbstractBaseCatchController 裡通過注入的方式添加某些bean的話,那麼請在AAABatchController實作類別一併定義。
<bean id="invStatementMgr" parent="txProxyTemplate">
<property name="target">
<bean
class="ecustoms.ics.app.inventory.biz.InventoryStatementMgr">
<property name="dao">---------------是在AbstractBatchController 裡。
<ref local="inventoryStatementDAO" />
</property>
<property name="syntaxCheckCmd">---------------是在AbstractBatchController 裡。
<ref bean="inventorySyntaxCheckCmd" />
</property>
<property name="bizValidationCmd">
<ref local="inventoryBizValidationCmd" />
</property>
<property name="uploadDao">---------------是在AbstractBatchController 裡。
<bean class="ecustoms.ics.app.upload.dao.UploadDAO" />
</property>
<property name="notificationMgr" ref="notificationMgr" />---------------是在AbstractBatchController 裡。
<property name="referenceDao">
<bean class="ecustoms.ics.app.ref.dao.ReferenceDAO" />-------------定義在實作類別InventoryStatementMgr裡。
</property>
<property name="contactMgr" ref="ContactMgr"/>
<property name="userMgr" ref="userMgr"/>
<property name="aaMgr" ref="aaManager"/>
</bean>
</property>
</bean>