模板方法樣例

模板方法設計模式

一、實現

package com.jd.fms.proxyinvoice.project.workerengine;

import com.jd.cwbase.worker.domain.WorkerException;
import com.jd.cwbase.worker.domain.WorkerResult;
import com.jd.cwbase.worker.workUtil.CycleWorkerEngine;
import com.jd.fms.proxyinvoice.project.custenum.domainTypeEnum.WorkerEnum;
import com.jd.fms.proxyinvoice.project.service.worker.EleInvRedResultWorkerService;

import javax.annotation.Resource;

/**
 * 查詢航信結果信息輪訓任務紅票
 * @author chengchunguang
 * @date   2019/04/09
 */
public class EleInvoiceRedResultCycWorker extends CycleWorkerEngine {

	@Resource
    private EleInvRedResultWorkerService eleInvRedResultWorkerService;

    @Override
    protected WorkerResult executeWorker(Integer orderNo) throws WorkerException {

        WorkerResult wr = new WorkerResult(false, "失敗");
        try {
            //紅衝Service調用的所以會調用EleInvLevyCycWorkerService
        	eleInvRedResultWorkerService.doSolve();
            wr.setSuccess(true);
            wr.setMsg("成功");
        } catch (Exception e) {
        	logger.error("EleInvoiceResultCycWorker.executeWorker.Exception:查詢航信結果信息紅票輪訓任務處理失敗", e);
            wr.setMsg(e.getMessage());
        }
        return wr;
    }

    @Override
    public String getWorkerTypeCode() {
        return WorkerEnum.ELE_INVOICE_RESULT_RED_CYC.value();
    }
}


package com.jd.fms.proxyinvoice.project.service.worker;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.jd.fms.proxyinvoice.common.util.CheckUtil;
import com.jd.fms.proxyinvoice.common.util.ResponseMsgSubtringUtil;
import com.jd.fms.proxyinvoice.common.util.StringUtil;
import com.jd.fms.proxyinvoice.project.custenum.constant.CycTaskResultEnum;
import com.jd.fms.proxyinvoice.project.custenum.domainTypeEnum.TaskStatus;
import com.jd.fms.proxyinvoice.project.dao.EleInvoiceCycMapper;
import com.jd.fms.proxyinvoice.project.server.domain.CycTaskResult;
import com.jd.fms.proxyinvoice.project.server.domain.EleInvoiceCycDto;
import com.jd.fms.proxyinvoice.project.server.domain.EleWorkerResult;

import java.util.List;

/**
 * 循環任務處理基類
 * 
 * @author chengchunguang
 * @date 2018/11/02
 */
public abstract class AbstractEleInvCycTaskService {

	/**
	 * 稅局接口返回信息截取長度
	 */
	private static final int MAX_LEN_DBCLUM_REP_MSG = 250;
	
	private static final int TASK_DEFAULT_DELAY_DAYS = 0;
	
	/**
	 * 一次查詢鎖定數量
	 */
	private static final int TASK_DEFAULT_LOCK_NUM = 200;

	protected Logger logger = LoggerFactory.getLogger(getClass());

	@Autowired
	protected EleInvoiceCycMapper eleInvoiceCycMapper;
	
	public void setEleInvoiceCycMapper(EleInvoiceCycMapper eleInvoiceCycMapper) {
		this.eleInvoiceCycMapper = eleInvoiceCycMapper;
	}

	public final EleWorkerResult doSolve() {
		EleWorkerResult result = new EleWorkerResult(true, "任務完成");
		
		
		List<EleInvoiceCycDto> taskList = eleInvoiceCycMapper.queryCycTasksDelayday(getCycType(), TaskStatus.UNTREATED.value(), getDelayDays(), getLockNum());
		
		if (CheckUtil.isEmpty(taskList)) {
			result.setSuccess(true);
			result.setMessage("沒有未處理的【" + getCycTaskDesc() + "】");
			return result;
		}
		for (EleInvoiceCycDto task : taskList) {
			try {
				doSingleTask(task);
			} catch (Exception e) {
				logger.error("循環處理【{}】出現異常:{}", getCycTaskDesc(), e);
				result.setSuccess(false);
				result.setMessage("循環處理【" + getCycTaskDesc() + "】出現異常");
			}
		}
		return result;
	}

	/**
	 * 循環任務類型編碼
	 * @return 
	 */
	protected abstract String getCycType();

	/**
	 * 循環任務描述
	 * @return 
	 */
	protected abstract String getCycTaskDesc();

	private final void doSingleTask(EleInvoiceCycDto task) {

		// 記錄當前任務狀態,出現未知異常將狀態改爲未處理,以便於下次循環繼續處理
		Integer currentStatus = null;
		try {
			// 任務狀態改爲處理中
			if (eleInvoiceCycMapper.updateStatusById(task.getId(), TaskStatus.PROCESSING.value(),
					TaskStatus.UNTREATED.value(), null) != 1) {
				logger.warn("更新任務{}狀態[未處理]-->[處理中]影響行數不爲1,不處理此任務", task.getId());
				return;
			}
			currentStatus = TaskStatus.PROCESSING.value();
			String refId = task.getRefId();
			if(StringUtil.isBlank(refId)) {
				logger.error("【{}】:{}", getCycTaskDesc(), "refId爲空");
				currentStatus = updateTaskStatus(task.getId(), TaskStatus.FAILED.value(), "refId爲空");
				return;
			} 
			CycTaskResult ret = execTask(refId);
			if(ret == null) {
				logger.error("【{}】:關聯單號【{}】:{}", new String[] { getCycTaskDesc(), refId, "任務執行結果爲空" });
				currentStatus = updateTaskStatus(task.getId(), TaskStatus.FAILED.value(), "任務執行結果爲空");
				return;
			}
			if (CycTaskResultEnum.SUCCEED.equals(ret.getCode())) {
				logger.info("【{}】:關聯單號【{}】:{}", new String[] { getCycTaskDesc(), refId, "成功" });
				currentStatus = updateTaskStatus(task.getId(), TaskStatus.SUCCEED.value(), "成功");
			} else if(CycTaskResultEnum.RETRY.equals(ret.getCode())) {
				logger.info("【{}】:關聯單號【{}】:{}", new String[] { getCycTaskDesc(), refId, "下次任務重試" });
				currentStatus = updateTaskStatus(task.getId(), TaskStatus.UNTREATED.value(),
						ResponseMsgSubtringUtil.formartErrorMsg(ret.getMessage(), MAX_LEN_DBCLUM_REP_MSG));
			} else {
				logger.error("【{}】:關聯單號【{}】:{}", new String[] { getCycTaskDesc(), refId, "任務失敗" });
				currentStatus = updateTaskStatus(task.getId(), TaskStatus.FAILED.value(),
						ResponseMsgSubtringUtil.formartErrorMsg(ret.getMessage(), MAX_LEN_DBCLUM_REP_MSG));
			}
			
		} catch (Exception e) {
			logger.error(getCycTaskDesc(), e);
			if (TaskStatus.PROCESSING.value().equals(currentStatus)) {
				currentStatus = updateTaskStatus(task.getId(), TaskStatus.FAILED.value(),
						ResponseMsgSubtringUtil.formartErrorMsg(e.getMessage(), MAX_LEN_DBCLUM_REP_MSG));
			}
		} finally {
			if (TaskStatus.PROCESSING.value().equals(currentStatus)) {
				// 出現未知異常,任務狀態改爲未處理
				logger.error("【{}】:finally, change TaskStatus PROCESSING-->UNTREATED", getCycTaskDesc());
				updateTaskStatus(task.getId(), TaskStatus.UNTREATED.value(), "出現未知異常");
			}
		}
	}

	private Integer updateTaskStatus(Long taskId, Integer status, String message) {
		eleInvoiceCycMapper.updateStatusByIdAddExecNum(taskId, status, TaskStatus.PROCESSING.value(), message);
		return status;
	}
	
	/**
	 * 任務延遲執行
	 * @return Integer 天
	 */
	protected Integer getDelayDays() {
		return TASK_DEFAULT_DELAY_DAYS;
	}
	
	/**
	 * 一次抓取鎖定數量
	 * @return
	 */
	protected Integer getLockNum() {
		return TASK_DEFAULT_LOCK_NUM;
	}
	
	/**
	 * 執行任務
	 * @param refId 任務id orderNo
	 */
	protected abstract CycTaskResult execTask(String refId);

}


package com.jd.fms.proxyinvoice.project.service.worker;

import org.springframework.stereotype.Service;

import com.jd.fms.proxyinvoice.common.exception.BusinessException;
import com.jd.fms.proxyinvoice.project.custenum.constant.Constants;
import com.jd.fms.proxyinvoice.project.custenum.constant.CycTaskResultEnum;
import com.jd.fms.proxyinvoice.project.custenum.domainTypeEnum.EleInvoiceApplyStatusEnum;
import com.jd.fms.proxyinvoice.project.custenum.domainTypeEnum.WorkerEnum;
import com.jd.fms.proxyinvoice.project.server.domain.CycTaskResult;
import com.jd.fms.proxyinvoice.project.server.domain.ServerException;
import com.jd.fms.proxyinvoice.project.service.EleInvApplyWorkService;
import com.jd.fms.proxyinvoice.project.service.taxbureau.LevyResult;
import com.jd.fms.proxyinvoice.project.service.taxbureau.LevyResultDto;
import com.jd.fms.proxyinvoice.project.service.taxbureau.SendToTaxBureauService;
import com.jd.fms.proxyinvoice.project.service.taxbureau.TaxBureauResponseCode;
import com.jd.fms.proxyinvoice.project.service.taxbureau.TaxInvoiceQuery;
import com.jd.ump.profiler.CallerInfo;
import com.jd.ump.profiler.proxy.Profiler;

import javax.annotation.Resource;

/**
 * 發票徵收結果輪詢任務
 * @author chengchunguang
 * @date   2018/11/02
 */
@Service
public class EleInvLevyCycWorkerService extends AbstractEleInvCycTaskService{

	@Resource
	private SendToTaxBureauService sendToTaxBureauService;
	
	@Resource
	private EleInvApplyWorkService eleInvApplyWorkService;

	/**
	 * 獲取執行任務
	 * @return
	 */
	@Override
	protected Integer getDelayDays() {
		return 1;
	}

	@Override
	protected CycTaskResult execTask(String refId) {
		CallerInfo info = Profiler.registerInfo("project.service.worker.eleInvLevyCycWorkerService.execTask", Constants.APP_NAME,
                false, true);
		CycTaskResult result = new CycTaskResult(CycTaskResultEnum.FAILED, "失敗");
		try {
			TaxInvoiceQuery query = buildTaxInvoiceQuery(refId);
			LevyResult response = sendToTaxBureauService.queryOrderInfoData(query);

			// 接口返回爲空,任務狀態改爲未處理,下次任務循環繼續查詢
			if (response == null) {
				/**
				 * 返回爲空的情況: 1,響應編碼不爲200 2,稅局服務端連接超時 3,系統對象-xml轉換異常
				 */
				logger.error("調用稅局查詢徵收信息返回爲空, orderNo:{}", refId);
				result.setMessage("調用稅局查詢徵收信息返回爲空");
				result.setCode(CycTaskResultEnum.RETRY);
				return result;
			}
			if (TaxBureauResponseCode.MQ99.value().equals(response.getCode())
					|| TaxBureauResponseCode.E99E.value().equals(response.getCode())) {
				logger.error("查詢徵收信息接口返回系統異常 , code:{}, msg:{}, orderNo:{}",
						new String[] { response.getCode(), response.getMessage(), refId });
				throw new BusinessException("", "查詢徵收信息接口返回系統異常," + response.getCode() + ":" + response.getMessage());
			}
			
			if (TaxBureauResponseCode.NOT_OPEN_TICKET.value().equals(response.getCode()) ||
				TaxBureauResponseCode.INCORRECT_ORDERNO.value().equals(response.getCode())) {
				/**
				 *  E99	系統編碼或tranid有誤
					E92	無法查詢到徵收信息
					E91	該訂單號是無效的
					E90	該訂單還未開票
					00	查詢成功
				 */
				// E90該會員還未做登記, 任務狀態改爲未處理,下次任務循環繼續查詢
				logger.info("該訂單還未開票 , 任務狀態改爲未處理,下次任務循環繼續查詢, orderNo:{}", refId);
				result.setMessage("該訂單還未開票");
				result.setCode(CycTaskResultEnum.RETRY);
				return result;
			} else if (TaxBureauResponseCode.SUCCESS.value().equals(response.getCode())) {
				LevyResultDto data = response.getData();
				if (!refId.equals(data.getYdh())) {
					logger.error("益世系統訂單號【{}】,稅局返回訂單號【{}】不一致", refId, data.getYdh());
					throw new ServerException("訂單號不一致,refId:" + refId + ",ydh:" + data.getYdh());
				}
				// 查詢成功保存徵收信息
				eleInvApplyWorkService.saveLevyInfo(refId, data);
				result.setMessage("成功");
				result.setCode(CycTaskResultEnum.SUCCEED);
				return result;
			} else if (TaxBureauResponseCode.INCORRECT_TRANID.value().equals(response.getCode()) ||
					TaxBureauResponseCode.UNVALID_ORDERNO.value().equals(response.getCode())) {
				logger.error("查詢徵收信息接口返回錯誤 , code:{}, msg:{}, orderNo:{}",
						new String[] { response.getCode(), response.getMessage(), refId });
				eleInvApplyWorkService.updateInvApplyOrderStatus(refId, EleInvoiceApplyStatusEnum.APPLYING, EleInvoiceApplyStatusEnum.APPLY_FAILED);
				result.setMessage("查詢徵收信息接口返回錯誤," + response.getCode() + ":" + response.getMessage());
				result.setCode(CycTaskResultEnum.FAILED);
				return result;
			} else {
				// 其他錯誤,報警,任務重試
				logger.error("查詢徵收信息接口返回未知錯誤 , code:{}, msg:{}, orderNo:{}",
						new String[] { response.getCode(), response.getMessage(), refId });
				throw new BusinessException("", "查詢徵收信息接口返回未知錯誤," + response.getCode() + ":" + response.getMessage());
			}
		} catch (ServerException e) {
			Profiler.functionError(info);
			logger.error("查詢徵收信息任務出現異常,任務失敗", e);
			result.setMessage(e.getMessage());
			result.setCode(CycTaskResultEnum.FAILED);
		} catch (Exception e) {
			Profiler.functionError(info);
			//出現未知異常,任務狀態改爲未處理, 下次任務循環繼續查詢
			logger.error("查詢徵收信息任務出現未知異常,任務重試", e);
			result.setMessage("查詢徵收信息任務出現未知異常,任務重試");
			result.setCode(CycTaskResultEnum.RETRY);
		} finally {
            Profiler.registerInfoEnd(info);
        }
		return result;
	}


	@Override
	protected String getCycType() {
		return WorkerEnum.ELE_INVOICE_LEVY_CYC.value();
	}

	@Override
	protected String getCycTaskDesc() {
		return WorkerEnum.ELE_INVOICE_LEVY_CYC.getTitle();
	}
	
	/**
	 * 一次抓取鎖定數量
	 * @return
	 */
	@Override
	protected Integer getLockNum() {
		return 50;
	}

	private TaxInvoiceQuery buildTaxInvoiceQuery(String refId) {
		TaxInvoiceQuery query = new TaxInvoiceQuery();
		query.setOrderNo(refId);
		return query;
	}

}


protected String getCycTaskDesc() {
		return WorkerEnum.ELE_INVOICE_LEVY_CYC.getTitle();
	}
	
	/**
	 * 一次抓取鎖定數量
	 * @return
	 */
	@Override
	protected Integer getLockNum() {
		return 50;
	}

	private TaxInvoiceQuery buildTaxInvoiceQuery(String refId) {
		TaxInvoiceQuery query = new TaxInvoiceQuery();
		query.setOrderNo(refId);
		return query;
	}

}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章