SpringBoot @Async 异步处理业务逻辑和发短信逻辑

有个业务场景,业务数据审核通过后需要给用户发短信,发短信过程比较耗时,可能需要几秒甚至十几秒,因此使用异步发短信

使用了注解@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("缺陷上报记录审核拒绝,发送短信给缺陷记录上报人******");
	}
}

至此问题就解决了,写博客标注一下 

原文地址:https://www.cnblogs.com/ph7seven/p/9549824.html

时间: 2024-11-05 22:28:06

SpringBoot @Async 异步处理业务逻辑和发短信逻辑的相关文章

关于定时发短信业务的讨论

关于定时发短信业务的讨论 事情的起因 需求:在每次线下活动的开始的前一天晚上七点给报名参加价值研习社的用户发一条通知短信用户记得准时参加活动. 备注:因为我们的业务并发不是很大,所以很多场景并没有考虑到并发情况下的一些问题,这个需求正好通过crontab执行,并且加上服务器的自动弹性伸缩,所以相当于模拟了一次并发的业务场景. 先简单介绍一下数据库的表结构: 这几个方案都依赖每天晚上七点执行一次corntab. 方案1 根据开讲时间查询活动表是否有满足条件的线下活动,如果有的话,再通过活动id关联

西门子S7200 PLC发短信应用方案

西门子PLC发短信方案概述 为了实现无人值守,在设备发生故障时,通过短信或者拨号的方式,通知值班人员,在PLC控制系统中获得了广泛的应用.传统的实现方式一般采取通过PLC的通讯口外接短信猫的方式,通过PLC的自由通讯协议,控制PLC发出短信.此类方案缺陷在于: 1.程序复杂,需要熟悉PLC自由协议编程,AT指令集,如果需要发出中文短信,还需要UNICODE编码,非常麻烦,因此,使用短信猫的方式,一般只实现简单的报警. 2.可靠性差,普通短信猫很多并非为恶劣的工业环境设计,多采用国产模块或拆机TC

Android 打电话,发短信,调用系统浏览器

打电话: Intent intent = new Intent(Intent.ACTION_DIAL); intent.setData(Uri.parse("tel:10086")); startActivity(intent); 发短信: SmsManager smsManager=SmsManager.getDefault();//取得短信管理器 /**发简单的文本信息 * destinationAddress: 目标地址,发给谁 * scAddress: 来源的地址,谁发的 *

Java通过SMS短信平台实现发短信功能

在项目中使用过发短信的功能,但那个由于公司内部的限制很麻烦,今天在网上找到一个简单的,闲来无事就把它记录如下: 本程序是通过使用中国网建提供的SMS短信平台实现的(该平台目前为注册用户提供5条免费短信,3条免费彩信,这足够用于我们测试用了.在使用前需要注册,注册地址为http://sms.webchinese.cn/reg.shtml),下面是程序源码: /** * @Author dengsilinming * @Date 2012-9-18 * */ package com.dengsili

iOS开发中打电话发短信等功能的实现

在APP开发中,可能会涉及到打电话.发短信.发邮件等功能.比如说,通常一个产品的“关于”页面,会有开发者的联系方式,理想情况下,当用户点击该电话号码时,能够自动的帮用户拨出去,就涉及到了打电话的功能. iOS开发中,有三种方式可以打电话: (1)直接跳到拨号界面,代码如下 1 2 NSURL *url = [NSURL URLWithString:@"tel://10010"];  [[UIApplication sharedApplication] openURL:url]; 缺点:

利用阿里大于接口发短信(Delphi版)

阿里大于是阿里通信旗下产品,融合了三大运营商的通信能力,提供包括短信.语音.流量直充.私密专线.店铺手机号等个性化服务.每条四毛五,价钱还算公道,经老农测试,响应速度非常快,基本上是秒到.官方文档提供了以下语言的 Demo JAVA .NET PHP Python CURL C/C++ NodeJS 唯独没有 Dephi,这不能怪马云,毕竟 Delphi 实在太小众了. 最近用 Delphi 写个 App,注册用户需要用到手机短信验证,于是找到的阿里大于,使用 Delphi 10.1 berli

iOS中打电话、打开网址、发邮件、发短信等

常用小功能 小功能简介 iOS中的很多小功能都是非常简单的,几行代码就搞定了,比如打电话.打开网址.发邮件.发短信等 打电话-方法1 最简单最直接的方式:直接跳到拨号界面 NSURL *url = [NSURL URLWithString:@"tel://10010"]; [[UIApplication sharedApplication] openURL:url]; 缺点 电话打完后,不会自动回到原应用,直接停留在通话记录界面 打电话-方法2 拨号之前会弹框询问用户是否拨号,拨完后能

3-IOS-小功能(打电话、发短信、发邮件)

iOS中的很多小功能都是非常简单的,几行代码就搞定了,比如打电话.打开网址.发邮件.发短信等 一.打电话 1>最简单最直接的方式:直接跳到拨号界面NSURL *url = [NSURL URLWithString:@"tel://10010"];[[UIApplication sharedApplication] openURL:url];缺点:电话打完后,不会自动回到原应用,直接停留在通话记录界面 2>拨号之前会弹框询问用户是否拨号,拨完后能自动回到原应用NSURL *u

调用系统的打电话,发短信,邮件,蓝牙

在开发某些应用时可能希望能够调用iOS系统内置的电话.短信.邮件.浏览器应用,此时你可以直接使用UIApplication的OpenURL:方法指定特定的协议来打开不同的系统应用.常用的协议如下: 打电话:tel:或者tel://.telprompt:或telprompt://(拨打电话前有提示) 发短信:sms:或者sms:// 发送邮件:mailto:或者mailto:// 启动浏览器:http:或者http:// 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16