1. 程式人生 > >SpringBoot @Async 異步處理業務邏輯和發短信邏輯

SpringBoot @Async 異步處理業務邏輯和發短信邏輯

場景 ems agg tor ctf sele attr cati nag

有個業務場景,業務數據審核通過後需要給用戶發短信,發短信過程比較耗時,可能需要幾秒甚至十幾秒,因此使用異步發短信

使用了註解@Async來實現:

1.SpringApplication啟用註解@EnableAsync

@SpringBootApplication
@ImportResource(locations = { "classpath:/spring/spring-*.xml" })
@EnableTransactionManagement(proxyTargetClass=true)
@EnableScheduling
@EnableAutoConfiguration(exclude = { FreeMarkerAutoConfiguration.class })
@EnableSwagger2
@ServletComponentScan(basePackages="com.xx")
@EnableMongoRepositories(basePackages = "com.xx.xx.xx.xx")
@EnableAsync
public class IemsApplication {

	public static void main(String[] args) {
		SpringApplication.run(IemsApplication.class, args);
	}
    ...

2.在業務層(@Service)具體的審核方法上添加註釋@Async

@Async
public void cancelAudit(DefectForm defectForm) {
	Map<String,Object> params = new HashMap<>();
	params.put("defectId", defectForm.getDefectId()); //缺陷記錄ID
	params.put("defectStatus", 3); //更新缺陷記錄狀態審核拒絕
	params.put("reason", defectForm.getReason()); //拒絕理由
	defectRecordDao.updateByPrimaryKeySelective(params);
	
     //上面是業務處理,下面是發短信
//審核拒絕發送短信,短信發送給缺陷上報人,缺陷內容,審核拒絕理由 Account account = accountDao.findAccountById(xxx); if(account != null && StringUtils.isNotBlank(account.getMobile())){ String mobile = account.getMobile(); String defectContent = defectForm.getDefectContent(); String reason = defectForm.getReason(); Map<String,String> templateData = new HashMap<>(); templateData.put("defectContent", defectContent); templateData.put("reason", reason); smsService.sendSms(null, mobile, SmsConstant.DEFECT_REFUSRD_CODE, templateData,false); logger.debug("缺陷上報記錄審核拒絕,發送短信給缺陷記錄上報人******"); } }

3.前端邏輯:

/**
 * 審核拒絕,確定
 * @returns
 */
function makeRefuse(){
	var reason = $("#refuse_reason").val();
	if (reason==null || reason.trim()==""){
		AppUtils.showTooltip("請填寫拒絕理由!",false);
		return;
	}
	var curDefect = recordsJson[xxx];
	$.ajax({
		url: path + ‘/xxx/xxx/qqq/cancelAudit‘,
		type: ‘post‘,
		dataType: ‘json‘,
		data:curDefect,
		success: function(data){
			if(data=="ok"){
				AppUtils.showTooltip("審核拒絕成功!",true);
				$("#topForm").attr("action",path + ‘/xxx/xxx/xxx‘);
				$("#topForm").submit();
			}
		}
	});
}

4.Controller層

@RequestMapping("/xxx/xxx/cancelAudit")
@ResponseBody
public String cancelAudit(DefectForm defectForm){
	defectRecordService.cancelAudit(defectForm);
	return "ok";
}

  

經測試,可以異步更新、發送短信

但是,發現一個嚴重的問題:前臺頁面點擊取消審核後頁面狀態偶爾能刷新過來,偶爾還是之前的狀態,重新查詢一次後,頁面顯示正常

分析代碼:Controller層代碼寫的有問題,Controller層調用Service層(defectRecordService.cancelAudit(defectForm);),Service層cancelAudit(DefectForm defectForm)方法整個是@Async,

主線程會直接返回,而新啟的線程處理Service層的邏輯。這樣ajax返回前臺,前臺再去刷新數據的時候,可能新啟線程Service的更新邏輯還沒處理完,這樣就導致了頁面刷新狀態錯誤的問題

其實:我們期望的是,業務邏輯(更新操作)執行完成後再返回;整個業務邏輯(更新操作完成,返回)與發短信異步

修改後的代碼:

1.Controller層

@RequestMapping("/xxx/xxx/cancelAudit")
	@ResponseBody
	public String cancelAudit(DefectForm defectForm){
		defectRecordService.cancelAudit(defectForm); //更新操作,成功後往下走,sendCancelAuditMsg會新啟一個線程處理,主線程繼續往下走,走到return "ok";返回 
//審核拒絕:業務操作完成後發短信 defectRecordService.sendCancelAuditMsg(defectForm); return "ok"; }

2.Service層

//這裏我們就不需要添加異步註解了
public void cancelAudit(DefectForm defectForm) {
		Map<String,Object> params = new HashMap<>();
		params.put("defectId", defectForm.getDefectId()); //缺陷記錄ID
		params.put("defectStatus", 3); //更新缺陷記錄狀態審核拒絕
		params.put("reason", defectForm.getReason()); //拒絕理由
		defectRecordDao.updateByPrimaryKeySelective(params);
	}

  

//把發短信的邏輯抽出來,單獨一個方法,使用異步註解
@Async
public void sendCancelAuditMsg(DefectForm defectForm){
	//審核拒絕發送短信,短信發送給缺陷上報人,缺陷內容,審核拒絕理由
	Account account = accountDao.findAccountById(defectForm.getCreatorUserid());
	if(account != null && StringUtils.isNotBlank(account.getMobile())){
		String mobile = account.getMobile();
		String defectContent = defectForm.getDefectContent();
		String reason = defectForm.getReason();
		Map<String,String> templateData = new HashMap<>();
		templateData.put("defectContent", defectContent);
		templateData.put("reason", reason);
		smsService.sendSms(null, mobile, SmsConstant.DEFECT_REFUSRD_CODE, templateData,false);
		logger.debug("缺陷上報記錄審核拒絕,發送短信給缺陷記錄上報人******");
	}
}

至此問題就解決了,寫博客標註一下 

SpringBoot @Async 異步處理業務邏輯和發短信邏輯