Spring Boot REST请求含邮件、短信双操作时应如何做异常处理
解决方案
一、先修复现有Service的逻辑错误
你当前Service代码存在严重逻辑问题:无论邮件是否发送成功,最终都会执行smsService.sendSMS(act, "Email Success"),如果邮件发送失败,会连续发送「邮件失败」「邮件成功」两条错误短信,完全不符合业务预期。
二、具体改造步骤
1. 定义业务结果DTO
用来封装邮件、短信的发送状态,方便传递给客户端
// 先定义状态枚举,也可以直接用布尔值简化 public enum SendStatus { SUCCESS, FAILED } @Data public class AlertSendResult { private SendStatus emailStatus; private String emailErrorMsg; private SendStatus smsStatus; private String smsErrorMsg; }
2. 重构Service层逻辑
调整发送流程,捕获每个环节的异常,记录状态,不再向上抛无意义的通用异常
@Override public AlertSendResult createAlert(Action act) { AlertSendResult result = new AlertSendResult(); // 处理邮件发送逻辑 try { emailService.sendEmail(act); result.setEmailStatus(SendStatus.SUCCESS); // 邮件发送成功,发送对应通知短信 try { smsService.sendSMS(act, "Email Success"); result.setSmsStatus(SendStatus.SUCCESS); } catch (Exception smsEx) { log.error("Send success notice sms failed", smsEx); result.setSmsStatus(SendStatus.FAILED); result.setSmsErrorMsg(smsEx.getMessage()); } } catch (Exception emailEx) { log.error("Send email failed", emailEx); result.setEmailStatus(SendStatus.FAILED); result.setEmailErrorMsg(emailEx.getMessage()); // 邮件发送失败,发送对应通知短信 try { smsService.sendSMS(act, "Email Failed"); result.setSmsStatus(SendStatus.SUCCESS); } catch (Exception smsEx) { log.error("Send fail notice sms failed", smsEx); result.setSmsStatus(SendStatus.FAILED); result.setSmsErrorMsg(smsEx.getMessage()); } } return result; }
3. 改造Controller层返回结果
把Service返回的详细状态直接返回给客户端,客户端可以通过返回体的字段明确判断每个环节的执行结果
@Override public ResponseEntity<AlertSendResult> sendAction(Action act) { try { AlertSendResult result = actionService.createAlert(act); // 可根据业务需求调整HTTP状态码,比如只要不是系统级异常都返回200,业务状态从返回体读取 return new ResponseEntity<>(result, HttpStatus.OK); }catch (Exception e) { log.error("Exception occured while generating alerts. " , e); AlertSendResult errorResult = new AlertSendResult(); errorResult.setEmailStatus(SendStatus.FAILED); errorResult.setSmsStatus(SendStatus.FAILED); errorResult.setEmailErrorMsg("System internal error"); errorResult.setSmsErrorMsg("System internal error"); return new ResponseEntity<>(errorResult, HttpStatus.INTERNAL_SERVER_ERROR); } }
三、可选优化点
- 发送邮件、短信属于IO密集型操作,可以放到异步线程池执行,避免阻塞接口响应,异步场景下需单独处理结果记录逻辑
- 可以把每一次的发送结果持久化到数据库,方便后续对账、故障排查
- 针对发送失败的场景,可以增加有限次数的重试机制,避免临时网络波动导致的发送失败
内容的提问来源于stack exchange,提问作者Thinker
相关产品推荐
相关产品推荐

