diff --git a/postdischarge-admin/src/main/resources/application.yml b/postdischarge-admin/src/main/resources/application.yml index 6e907cdc..600d7108 100644 --- a/postdischarge-admin/src/main/resources/application.yml +++ b/postdischarge-admin/src/main/resources/application.yml @@ -9,7 +9,7 @@ xinelu: # 实例演示开关 demoEnabled: true # 文件路径 示例( Windows配置D:/postdischarge/uploadPath,Linux配置 /home/postdischarge/uploadPath) - profile: D:/postdischarge/uploadPath + profile: E:/postdischarge/uploadPath # 签约知情书上传 sign-informed-file-url: /signInformed # 素材库封面上传 @@ -223,4 +223,24 @@ wechat-official-account-config: # 微信公众号事件回调消息加密密钥 official-account-encoding-aes-key: Awcn7nvDU4bcfBwAZmiRbB3lFgXAm2RIg45utdb5Zt3 # 测试模板id - test-template-id: WUCYtSbH-QFRV_fMcfmn86QLsz1zo881QW7fQNTWOjc \ No newline at end of file + test-template-id: WUCYtSbH-QFRV_fMcfmn86QLsz1zo881QW7fQNTWOjc + +# 阿里云参数配置 +aliyun-sms: + # AccessKey ID + accessKeyId: LTAIo6vpMk2441nc + # AccessKey Secret + accessKeySecret: JxPKD3Vx404QsZ3SvYSai1wuOlyRtR + # 产品名称:云通信短信API产品,开发者无需替换 + product: Dysmsapi + # 产品域名,开发者无需替换 + domain: dysmsapi.aliyuncs.com + # 地域ID + regionId: cn-qingdao + # 阿里云登录确认验证模板-短信签名 + signName: 新医路 + # 阿里云登录确认验证模板-模板CODE + templateCode: SMS_152466667 + # 阿里云登录确认验证模板-模板内容 + templateContent: 验证码${code},您正在登录,若非本人操作,请勿泄露。 + diff --git a/postdischarge-common/src/main/java/com/xinelu/common/config/AliYunSmsConfig.java b/postdischarge-common/src/main/java/com/xinelu/common/config/AliYunSmsConfig.java new file mode 100644 index 00000000..472d6288 --- /dev/null +++ b/postdischarge-common/src/main/java/com/xinelu/common/config/AliYunSmsConfig.java @@ -0,0 +1,53 @@ +package com.xinelu.common.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * @program: PostDischargePatientManage + * @description: 阿里云参数配置 + * @author: yxl + * @create: 2024-07-02 20:48 + **/ +@Data +@Component +@ConfigurationProperties(prefix = "aliyun-sms") +public class AliYunSmsConfig { + + /** + * AccessKey ID + */ + private String accessKeyId; + + /** + * AccessKey Secret + */ + private String accessKeySecret; + + /** + * 产品名称:云通信短信API产品,开发者无需替换 + */ + private String product; + + /** + * 产品域名,开发者无需替换 + */ + private String domain; + + /** + * 地域ID + */ + private String regionId; + + /** + * 阿里云登录确认验证模板-模板签名 + */ + private String signName; + + /** + * 阿里云登录确认验证模板-模板CODE + */ + private String templateCode; + +} diff --git a/postdischarge-common/src/main/java/com/xinelu/common/constant/Constants.java b/postdischarge-common/src/main/java/com/xinelu/common/constant/Constants.java index 15c42a4a..bcea6215 100644 --- a/postdischarge-common/src/main/java/com/xinelu/common/constant/Constants.java +++ b/postdischarge-common/src/main/java/com/xinelu/common/constant/Constants.java @@ -368,4 +368,22 @@ public class Constants { * 常用术语最小层数 */ public static final Long TERM_MIN_LEVEL = 1L; + + /** + * 登录发送短信验证冷却键前缀 + */ + public static final String SMS_COOL_DOWN ="SMS_COOL_DOWN_"; + + /** + * 登录发送短信验证冷却键对应的值 + */ + public static final String SMS_COOL_DOWN_VALUE ="COOL_DOWN"; + + + /** + * 登录发送短信验证前缀 + */ + public static final String SMS_CODE ="SMS_CODE_"; + + } diff --git a/postdischarge-common/src/main/java/com/xinelu/common/enums/SmsErrorCodeEnum.java b/postdischarge-common/src/main/java/com/xinelu/common/enums/SmsErrorCodeEnum.java new file mode 100644 index 00000000..a2008480 --- /dev/null +++ b/postdischarge-common/src/main/java/com/xinelu/common/enums/SmsErrorCodeEnum.java @@ -0,0 +1,236 @@ +package com.xinelu.common.enums; + +import lombok.Getter; + +/** + * 短信发送失败错误码枚举 + */ +@Getter +public enum SmsErrorCodeEnum { + + /** + * RAM权限不足 + */ + RAM_PERMISSION_DENY("isp.RAM_PERMISSION_DENY", "RAM权限不足"), + + /** + * 业务停机 + */ + OUT_OF_SERVICE("isv.OUT_OF_SERVICE", "业务停机"), + + /** + * 未开通云通信产品的阿里云客户 + */ + PRODUCT_UN_SUBSCRIPT("isv.PRODUCT_UN_SUBSCRIPT", "未开通云通信产品的阿里云客户"), + + /** + * 产品未开通 + */ + PRODUCT_UNSUBSCRIBE("isv.PRODUCT_UNSUBSCRIBE", "产品未开通"), + + /** + * 账户不存在 + */ + ACCOUNT_NOT_EXISTS("isv.ACCOUNT_NOT_EXISTS", "账户不存在"), + + /** + * 账户异常 + */ + ACCOUNT_ABNORMAL("isv.ACCOUNT_ABNORMAL", "账户异常"), + + /** + * 该账号下找不到对应模板 + */ + SMS_TEMPLATE_ILLEGAL("isv.SMS_TEMPLATE_ILLEGAL", "该账号下找不到对应模板"), + + /** + * 测试模板和签名限制 + */ + SMS_TEST_SIGN_TEMPLATE_LIMIT("isv.SMS_TEST_SIGN_TEMPLATE_LIMIT", "测试模板和签名限制"), + + /** + * 签名和模板类型不一致 + */ + SMS_SIGNATURE_SCENE_ILLEGAL("isv.SMS_SIGNATURE_SCENE_ILLEGAL", "签名和模板类型不一致"), + + /** + * 签名禁止使用 + */ + SMS_SIGN_ILLEGAL("isv.SMS_SIGN_ILLEGAL", "签名禁止使用"), + + /** + * 该账号下找不到对应签名 + */ + SMS_SIGNATURE_ILLEGAL("isv.SMS_SIGNATURE_ILLEGAL", "该账号下找不到对应签名"), + + /** + * 系统出现错误,请重新调用 + */ + SYSTEM_ERROR("isp.SYSTEM_ERROR", "系统出现错误,请重新调用"), + + /** + * 手机号码格式错误 + */ + MOBILE_NUMBER_ILLEGAL("isv.MOBILE_NUMBER_ILLEGAL", "手机号码格式错误"), + + /** + * 手机号码数量超过限制,最多支持1000条 + */ + MOBILE_COUNT_OVER_LIMIT("isv.MOBILE_COUNT_OVER_LIMIT", "手机号码数量超过限制,最多支持1000条"), + + /** + * 模板变量中存在未赋值变量 + */ + TEMPLATE_MISSING_PARAMETERS("isv.TEMPLATE_MISSING_PARAMETERS", "模板变量中存在未赋值变量"), + + /** + * 传入的变量内容和实际申请模板时变量所选择的属性类型不配 + */ + TEMPLATE_PARAMS_ILLEGAL("isv.TEMPLATE_PARAMS_ILLEGAL", "传入的变量内容和实际申请模板时变量所选择的属性类型不配"), + + /** + * 超过单自然日模板申请数量上限 + */ + TEMPLATE_COUNT_OVER_LIMIT("isv.TEMPLATE_COUNT_OVER_LIMIT", "超过单自然日模板申请数量上限"), + + /** + * 模板字符数量超过限制 + */ + TEMPLATE_OVER_LIMIT("isv.TEMPLATE_OVER_LIMIT", "模板字符数量超过限制"), + + /** + * 触发云通信流控限制 + */ + BUSINESS_LIMIT_CONTROL("isv.BUSINESS_LIMIT_CONTROL", "触发云通信流控限制"), + + /** + * 参数格式错误,请修改为字符串值 + */ + INVALID_JSON_PARAM("isv.INVALID_JSON_PARAM", "参数格式错误,请修改为字符串值"), + + /** + * 参数格式不正确 + */ + INVALID_PARAMETERS("isv.INVALID_PARAMETERS", "参数格式不正确"), + + /** + * 变量中传入疑似违规信息 + */ + BLACK_KEY_CONTROL_LIMIT("isv.BLACK_KEY_CONTROL_LIMIT", "变量中传入疑似违规信息"), + + /** + * 参数超过长度限制 + */ + PARAM_LENGTH_LIMIT("isv.PARAM_LENGTH_LIMIT", "参数超过长度限制"), + + /** + * 变量不支持传入URL + */ + PARAM_NOT_SUPPORT_URL("isv.PARAM_NOT_SUPPORT_URL", "变量不支持传入URL"), + + /** + * 账户余额不足 + */ + AMOUNT_NOT_ENOUGH("isv.AMOUNT_NOT_ENOUGH", "账户余额不足"), + + /** + * 关键字拦截 + */ + FILTER("FILTER", "关键字拦截"), + + /** + * 重复过滤 + */ + VALVE_MC("VALVE:M_MC", "重复过滤"), + + /** + * 单个号码日或月发送上限,流控超限,频繁发送超限 + */ + MOBILE_SEND_LIMIT("MOBILE_SEND_LIMIT", "单个号码日或月发送上限,流控超限,频繁发送超限"), + + /** + * 手机号在黑名单(平台或运营商) + */ + MOBILE_IN_BLACK("MOBILE_IN_BLACK", "手机号在黑名单(平台或运营商)"), + + /** + * 手机终端问题、内存满、SIM卡满、非法设备等 + */ + MOBILE_TERMINAL_ERROR("MOBILE_TERMINAL_ERROR", "手机终端问题、内存满、SIM卡满、非法设备等"), + + /** + * 未开通国际短信 + */ + SP_NOT_BY_INTER_SMS("SP_NOT_BY_INTER_SMS", "未开通国际短信"), + + /** + * 用户手机退订此业务、产品未开通 + */ + USER_REJECT("USER_REJECT", "用户手机退订此业务、产品未开通"), + + /** + * 运营商未知错误 + */ + SP_UNKNOWN_ERROR("SP_UNKNOWN_ERROR", "运营商未知错误"), + + /** + * 用户账户异常、携号转网、欠费等 + */ + MOBILE_ACCOUNT_ABNORMAL("MOBILE_ACCOUNT_ABNORMAL", "用户账户异常、携号转网、欠费等"), + + /** + * 消息发送成功 + */ + DELIVERED("DELIVERED", "消息发送成功"), + + /** + * 内容关键字拦截 + */ + CONTENT_KEYWORD("CONTENT_KEYWORD", "内容关键字拦截"), + + /** + * 签名黑名单 + */ + SIGNATURE_BLACKLIST("SIGNATURE_BLACKLIST", "签名黑名单"), + + /** + * 号码不合法 + */ + INVALID_NUMBER("INVALID_NUMBER", "号码不合法"), + + /** + * 无路由器 + */ + NO_ROUTE("NO_ROUTE", "无路由器"), + + /** + * 模板内容无退订 + */ + CONTENT_ERROR("CONTENT_ERROR", "模板内容无退订"), + + /** + * 未知错误 + */ + UNKNOWN_ERROR("UNKNOWN_ERROR", "未知错误"); + + private final String code; + private final String message; + + SmsErrorCodeEnum(String code, String message) { + this.code = code; + this.message = message; + } + + public String getMessage() { + return message; + } + + public static SmsErrorCodeEnum getMsgByCode(String code) { + for (SmsErrorCodeEnum errorCode : SmsErrorCodeEnum.values()) { + if (errorCode.code.equals(code)) { + return errorCode; + } + } + return UNKNOWN_ERROR; + } +} diff --git a/postdischarge-common/src/main/java/com/xinelu/common/utils/uuid/IdUtils.java b/postdischarge-common/src/main/java/com/xinelu/common/utils/uuid/IdUtils.java index 959a8203..07bc5e2a 100644 --- a/postdischarge-common/src/main/java/com/xinelu/common/utils/uuid/IdUtils.java +++ b/postdischarge-common/src/main/java/com/xinelu/common/utils/uuid/IdUtils.java @@ -1,5 +1,7 @@ package com.xinelu.common.utils.uuid; +import java.security.SecureRandom; + /** * ID生成器工具类 * @@ -41,4 +43,14 @@ public class IdUtils { public static String fastSimpleUUID() { return UUID.fastUUID().toString(true); } + + /** + * SecureRandom生成六位随机数 + * @return 六位随机数 + */ + public static int generateSixDigitNumber() { + SecureRandom random = new SecureRandom(); + // // 100000 (inclusive) to 999999 (inclusive) + return 100000 + random.nextInt(900000); + } } diff --git a/postdischarge-manage/src/main/java/com/xinelu/manage/mapper/residentinfo/ResidentInfoMapper.java b/postdischarge-manage/src/main/java/com/xinelu/manage/mapper/residentinfo/ResidentInfoMapper.java index daeb251c..cceea607 100644 --- a/postdischarge-manage/src/main/java/com/xinelu/manage/mapper/residentinfo/ResidentInfoMapper.java +++ b/postdischarge-manage/src/main/java/com/xinelu/manage/mapper/residentinfo/ResidentInfoMapper.java @@ -69,4 +69,7 @@ public interface ResidentInfoMapper { * @return 被护理人基本信息 */ ResidentInfo getResidentInfoByPhoneAndOpenId(@Param("phone") String phone, @Param("openId") String openId); + + + List getResidentInfoByPhoneAndName(@Param("phone") String phone, @Param("patientName") String patientName); } diff --git a/postdischarge-manage/src/main/resources/mapper/manage/residentinfo/ResidentInfoMapper.xml b/postdischarge-manage/src/main/resources/mapper/manage/residentinfo/ResidentInfoMapper.xml index 366b49e2..e3d682b6 100644 --- a/postdischarge-manage/src/main/resources/mapper/manage/residentinfo/ResidentInfoMapper.xml +++ b/postdischarge-manage/src/main/resources/mapper/manage/residentinfo/ResidentInfoMapper.xml @@ -197,4 +197,17 @@ + + \ No newline at end of file diff --git a/postdischarge-mobile/pom.xml b/postdischarge-mobile/pom.xml index 0ac748c5..8105eba4 100644 --- a/postdischarge-mobile/pom.xml +++ b/postdischarge-mobile/pom.xml @@ -39,5 +39,12 @@ org.simpleframework simple-xml + + + + com.alibaba.cloud + spring-cloud-alicloud-sms + 2.2.0.RELEASE + \ No newline at end of file diff --git a/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/MobileTestController.java b/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/MobileTestController.java index 8c4fd0e1..a7c878e8 100644 --- a/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/MobileTestController.java +++ b/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/MobileTestController.java @@ -1,5 +1,12 @@ package com.xinelu.mobile.controller; +import com.alibaba.fastjson2.JSONObject; +import com.aliyuncs.exceptions.ClientException; +import com.xinelu.common.config.AliYunSmsConfig; +import com.xinelu.common.core.domain.AjaxResult; +import com.xinelu.common.utils.uuid.IdUtils; +import com.xinelu.mobile.dto.smssend.SmsInfoDTO; +import com.xinelu.mobile.utils.SmsSendUtils; import com.xinelu.mobile.utils.WeChatAppletUtils; import com.xinelu.mobile.utils.WeChatOfficialAccountUtils; import com.xinelu.mobile.vo.wechatofficialaccountcallback.PatientVO; @@ -22,6 +29,10 @@ public class MobileTestController { private WeChatAppletUtils weChatAppletUtils; @Resource private WeChatOfficialAccountUtils weChatOfficialAccountUtils; + @Resource + private SmsSendUtils smsSendUtils; + @Resource + private AliYunSmsConfig aliYunSmsConfig; /** * 测试获取微信小程序accessToken @@ -54,4 +65,25 @@ public class MobileTestController { public void sendAppletTemplate(PatientVO patientVO) { weChatOfficialAccountUtils.sendAppletTemplateMessage(patientVO); } + + /** + *发送短信验证 + */ + @GetMapping("/sendSms") + public AjaxResult sendAppletTemplate(String phoneNum) throws ClientException { + SmsInfoDTO smsInfoDTO = new SmsInfoDTO(); + smsInfoDTO.setPhoneNumbers(phoneNum); + smsInfoDTO.setSignName(aliYunSmsConfig.getSignName()); + smsInfoDTO.setTemplateCode(aliYunSmsConfig.getTemplateCode()); + // 生成六位数验证码 + String code = String.valueOf(IdUtils.generateSixDigitNumber()); + JSONObject obj = new JSONObject(); + obj.put("code", code); + smsInfoDTO.setTemplateParam(obj); + Boolean b = smsSendUtils.sendSms(smsInfoDTO); + if (!b) { + return AjaxResult.error("短信发送失败"); + } + return AjaxResult.success("短信发送成功"); + } } diff --git a/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/appletpersoncenter/AppletPersonCenterController.java b/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/appletpersoncenter/AppletPersonCenterController.java index 2ea19c97..19b67cb9 100644 --- a/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/appletpersoncenter/AppletPersonCenterController.java +++ b/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/appletpersoncenter/AppletPersonCenterController.java @@ -4,12 +4,11 @@ import com.xinelu.common.core.controller.BaseController; import com.xinelu.common.core.domain.AjaxResult; import com.xinelu.common.core.page.TableDataInfo; import com.xinelu.mobile.dto.appletpersoncenter.HealthRecordDTO; +import com.xinelu.mobile.dto.verifysmscode.VerifySmsCodeDTO; import com.xinelu.mobile.service.appletpersoncenter.AppletPersonCenterService; +import io.swagger.annotations.ApiOperation; import org.apache.commons.lang3.StringUtils; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.util.List; @@ -80,4 +79,40 @@ public class AppletPersonCenterController extends BaseController { return AjaxResult.success(appletPersonCenterService.getHealthRecordInfoById(id)); } + @ApiOperation("院后微信小程序登录接口") + @GetMapping("/appletLoginV1") + public AjaxResult appletLoginV1(@RequestParam("loginCode") String loginCode) { + if (StringUtils.isBlank(loginCode)) { + return AjaxResult.error("登录凭证编码不能为空!"); + } + return appletPersonCenterService.appletLoginV1(loginCode); + } + + @ApiOperation("小程序登录发送短信验证码") + @GetMapping("/sendSms") + public AjaxResult sendSms(String phoneNum) { + if (StringUtils.isBlank(phoneNum)) { + return AjaxResult.error("手机号码不能为空!"); + } + return appletPersonCenterService.sendSms(phoneNum); + } + + @ApiOperation("小程序登录验证短信验证码") + @PostMapping("/verifySmsCode") + public AjaxResult verifySmsCode(@RequestBody VerifySmsCodeDTO verifySmsCodeDTO) { + if (StringUtils.isBlank(verifySmsCodeDTO.getOpenId())) { + return AjaxResult.error("微信小程序openid不能为空!"); + } + if (StringUtils.isBlank(verifySmsCodeDTO.getPhoneNum())) { + return AjaxResult.error("手机号不能为空!"); + } + if (StringUtils.isBlank(verifySmsCodeDTO.getPatientName())) { + return AjaxResult.error("姓名不能为空"); + } + if (StringUtils.isBlank(verifySmsCodeDTO.getSmsCode())) { + return AjaxResult.error("短信验证码不能为空!"); + } + return appletPersonCenterService.verifySmsCode(verifySmsCodeDTO); + } + } diff --git a/postdischarge-mobile/src/main/java/com/xinelu/mobile/dto/smssend/SmsInfoDTO.java b/postdischarge-mobile/src/main/java/com/xinelu/mobile/dto/smssend/SmsInfoDTO.java new file mode 100644 index 00000000..a26afc75 --- /dev/null +++ b/postdischarge-mobile/src/main/java/com/xinelu/mobile/dto/smssend/SmsInfoDTO.java @@ -0,0 +1,34 @@ +package com.xinelu.mobile.dto.smssend; + +import com.alibaba.fastjson2.JSONObject; +import lombok.Data; + +/** + * @program: PostDischargePatientManage + * @description: 短信发送参数DTO + * @author: yxl + * @create: 2024-07-02 21:05 + **/ +@Data +public class SmsInfoDTO { + + /** + * :短信签名 + */ + private String signName; + + /** + * 待发送手机号,多个用逗号隔开 + */ + private String phoneNumbers; + + /** + * 短信模板Code + */ + private String templateCode; + + /** + * 模板中的变量替换JSON串 + */ + private JSONObject templateParam; +} diff --git a/postdischarge-mobile/src/main/java/com/xinelu/mobile/dto/verifysmscode/VerifySmsCodeDTO.java b/postdischarge-mobile/src/main/java/com/xinelu/mobile/dto/verifysmscode/VerifySmsCodeDTO.java new file mode 100644 index 00000000..5a262881 --- /dev/null +++ b/postdischarge-mobile/src/main/java/com/xinelu/mobile/dto/verifysmscode/VerifySmsCodeDTO.java @@ -0,0 +1,27 @@ +package com.xinelu.mobile.dto.verifysmscode; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @program: PostDischargePatientManage + * @description: 验证短信验证码DTO + * @author: yxl + * @create: 2024-07-03 14:58 + **/ +@Data +public class VerifySmsCodeDTO { + + + @ApiModelProperty(value = "微信小程序openid") + private String openId; + + @ApiModelProperty(value = "手机号") + private String phoneNum; + + @ApiModelProperty(value = "姓名") + private String patientName; + + @ApiModelProperty(value = "短信验证码") + private String smsCode; +} diff --git a/postdischarge-mobile/src/main/java/com/xinelu/mobile/service/appletpersoncenter/AppletPersonCenterService.java b/postdischarge-mobile/src/main/java/com/xinelu/mobile/service/appletpersoncenter/AppletPersonCenterService.java index d66bdd47..a19a72a3 100644 --- a/postdischarge-mobile/src/main/java/com/xinelu/mobile/service/appletpersoncenter/AppletPersonCenterService.java +++ b/postdischarge-mobile/src/main/java/com/xinelu/mobile/service/appletpersoncenter/AppletPersonCenterService.java @@ -3,6 +3,7 @@ package com.xinelu.mobile.service.appletpersoncenter; import com.xinelu.common.core.domain.AjaxResult; import com.xinelu.mobile.dto.appletpersoncenter.HealthRecordDTO; import com.xinelu.mobile.dto.appletpersoncenter.HealthRecordInfoDTO; +import com.xinelu.mobile.dto.verifysmscode.VerifySmsCodeDTO; import java.util.List; @@ -48,4 +49,25 @@ public interface AppletPersonCenterService { */ HealthRecordInfoDTO getHealthRecordInfoById(Long id); + + /** + * 院后微信小程序登录接口 + * @param loginCode 登录凭证 + * @return 微信小程序用户登录信息 + */ + AjaxResult appletLoginV1(String loginCode); + + /** + * 小程序登录发送验证码 + * @param phoneNum 手机号码 + * @return 发送短信验证码信息 + */ + AjaxResult sendSms(String phoneNum); + + /** + * 小程序登录验证短信验证码 + * @param verifySmsCodeDTO 验证短信验证码DTO + * @return 验证短信验证码信息 + */ + AjaxResult verifySmsCode(VerifySmsCodeDTO verifySmsCodeDTO); } diff --git a/postdischarge-mobile/src/main/java/com/xinelu/mobile/service/appletpersoncenter/Impl/AppletPersonCenterServiceImpl.java b/postdischarge-mobile/src/main/java/com/xinelu/mobile/service/appletpersoncenter/Impl/AppletPersonCenterServiceImpl.java index 91a10c3e..bad9c76b 100644 --- a/postdischarge-mobile/src/main/java/com/xinelu/mobile/service/appletpersoncenter/Impl/AppletPersonCenterServiceImpl.java +++ b/postdischarge-mobile/src/main/java/com/xinelu/mobile/service/appletpersoncenter/Impl/AppletPersonCenterServiceImpl.java @@ -1,26 +1,36 @@ package com.xinelu.mobile.service.appletpersoncenter.Impl; +import com.alibaba.fastjson2.JSONObject; +import com.aliyuncs.exceptions.ClientException; +import com.xinelu.common.config.AliYunSmsConfig; import com.xinelu.common.config.WeChatAppletChatConfig; import com.xinelu.common.constant.Constants; import com.xinelu.common.core.domain.AjaxResult; +import com.xinelu.common.utils.uuid.IdUtils; import com.xinelu.manage.domain.residentinfo.ResidentInfo; import com.xinelu.manage.mapper.residentinfo.ResidentInfoMapper; import com.xinelu.mobile.dto.appletpersoncenter.HealthRecordDTO; import com.xinelu.mobile.dto.appletpersoncenter.HealthRecordInfoDTO; +import com.xinelu.mobile.dto.smssend.SmsInfoDTO; +import com.xinelu.mobile.dto.verifysmscode.VerifySmsCodeDTO; import com.xinelu.mobile.mapper.appletpersoncenter.AppletPersonCenterMapper; import com.xinelu.mobile.service.appletpersoncenter.AppletPersonCenterService; +import com.xinelu.mobile.utils.SmsSendUtils; import com.xinelu.mobile.utils.WeChatAppletUtils; import com.xinelu.mobile.vo.appletpersoncenter.PostDischargeAppletPhoneVO; import com.xinelu.mobile.vo.appletpersoncenter.PostDischargeAppletVO; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.time.LocalDateTime; import java.util.List; import java.util.Objects; +import java.util.concurrent.TimeUnit; /** * @Description 院后小程序个人中心业务层实现类 @@ -37,12 +47,17 @@ public class AppletPersonCenterServiceImpl implements AppletPersonCenterService @Resource private WeChatAppletChatConfig weChatAppletChatConfig; @Resource - private RedisTemplate redisTemplate; + private RedisTemplate redisTemplate; @Resource private ResidentInfoMapper residentInfoMapper; @Resource private AppletPersonCenterMapper appletPersonCenterMapper; + @Resource + private SmsSendUtils smsSendUtils; + @Resource + private AliYunSmsConfig aliYunSmsConfig; + /** * 院后微信小程序一键登录接口 * @@ -156,4 +171,116 @@ public class AppletPersonCenterServiceImpl implements AppletPersonCenterService } return healthRecordInfoDTO; } + + /** + * 院后微信小程序登录接口 + * + * @param loginCode 登录凭证 + * @return 微信小程序用户登录信息 + */ + @Override + public AjaxResult appletLoginV1(String loginCode) { + //根据code获取用户的微信unionId以及openId等信息 + PostDischargeAppletVO appletLoginInfo = weChatAppletUtils.getPostDischargeAppletLogin(weChatAppletChatConfig.getAppletId(), weChatAppletChatConfig.getSecret(), loginCode, weChatAppletChatConfig.getGrantType()); + if (Objects.isNull(appletLoginInfo)) { + return AjaxResult.error("获取院后微信小程序用户信息失败"); + } + if (Objects.nonNull(appletLoginInfo.getErrcode()) && appletLoginInfo.getErrcode() != Constants.SUCCESS_CODE) { + return AjaxResult.error("获取院后微信小程序用户信息失败,失败信息为:" + appletLoginInfo.getErrmsg()); + } + String openId = StringUtils.isBlank(appletLoginInfo.getOpenid()) ? "" : appletLoginInfo.getOpenid(); + ResidentInfo residentInfo = residentInfoMapper.getResidentInfoByPhoneAndOpenId(null, openId); + if (ObjectUtils.isEmpty(residentInfo)) { + return AjaxResult.success("未注册", openId); + } + return AjaxResult.success("已注册", residentInfo); + } + + /** + * 小程序登录发送验证码 + * + * @param phoneNum 手机号码 + * @return 发送短信验证码信息 + */ + @Override + public AjaxResult sendSms(String phoneNum) { + try { + String coolDownKey = Constants.SMS_COOL_DOWN + phoneNum; + String cacheKey = Constants.SMS_CODE + phoneNum; + ValueOperations valueOperations = redisTemplate.opsForValue(); + + // 检查是否处于冷却期 + if (valueOperations.get(coolDownKey) != null) { + return AjaxResult.error("请等待60秒后再尝试发送验证码"); + } + + // 生成并发送新的验证码 + SmsInfoDTO smsInfoDTO = new SmsInfoDTO(); + smsInfoDTO.setPhoneNumbers(phoneNum); + smsInfoDTO.setSignName(aliYunSmsConfig.getSignName()); + smsInfoDTO.setTemplateCode(aliYunSmsConfig.getTemplateCode()); + String code = String.valueOf(IdUtils.generateSixDigitNumber()); + JSONObject obj = new JSONObject(); + obj.put("code", code); + smsInfoDTO.setTemplateParam(obj); + Boolean b = smsSendUtils.sendSms(smsInfoDTO); + if (!b) { + log.error("短信发送失败,手机号:{}", phoneNum); + return AjaxResult.error("短信发送失败"); + } + + // 更新验证码和冷却键 + valueOperations.set(cacheKey, code, 5, TimeUnit.MINUTES); + valueOperations.set(coolDownKey, Constants.SMS_COOL_DOWN_VALUE, 60, TimeUnit.SECONDS); + log.info("手机号为{}的验证码已经生成", phoneNum); + return AjaxResult.success("短信发送成功"); + } catch (ClientException e) { + log.error("短信发送失败,手机号:{},错误原因:{}", phoneNum, e.getMessage(), e); + return AjaxResult.error("短信发送失败"); + } + } + + /** + * 小程序登录验证短信验证码 + * + * @param verifySmsCodeDTO 验证短信验证码DTO + * @return 验证短信验证码信息 + */ + @Override + public AjaxResult verifySmsCode(VerifySmsCodeDTO verifySmsCodeDTO) { + try { + String openId = verifySmsCodeDTO.getOpenId(); + String smsCode = verifySmsCodeDTO.getSmsCode(); + String cacheKey = Constants.SMS_CODE + verifySmsCodeDTO.getPhoneNum(); + ValueOperations valueOperations = redisTemplate.opsForValue(); + String storedCode = valueOperations.get(cacheKey); + + if (storedCode == null) { + log.info("验证码已过期,手机号:{}", verifySmsCodeDTO.getPhoneNum()); + return AjaxResult.error("验证码已过期,请重新获取!"); + } + + if (!storedCode.equals(smsCode)) { + log.info("验证码验证失败,手机号:{},输入的验证码:{},获取的验证码:{}", verifySmsCodeDTO.getPhoneNum(), smsCode, storedCode); + return AjaxResult.error("验证码错误,请重新输入!"); + } + + log.info("验证码验证成功,手机号:{}", verifySmsCodeDTO.getPhoneNum()); + List residentInfos = residentInfoMapper.getResidentInfoByPhoneAndName(verifySmsCodeDTO.getPhoneNum(), verifySmsCodeDTO.getPatientName()); + + if (residentInfos == null || residentInfos.isEmpty()) { + return AjaxResult.error("您的用户信息尚未录入系统,无法执行注册操作!"); + } else if (residentInfos.size() > 1) { + // 存在姓名和手机号重复的情况 + return AjaxResult.error("您的信息存在重复记录,请联系管理员进行操作!"); + } + ResidentInfo residentInfo = residentInfos.get(0); + residentInfo.setOpenId(openId); + residentInfoMapper.updateResidentInfo(residentInfo); + return AjaxResult.success("注册成功!", residentInfo); + } catch (Exception e) { + log.error("验证验证码时发生异常,手机号:{},异常信息:{}", verifySmsCodeDTO.getPhoneNum(), e.getMessage(), e); + return AjaxResult.error("短信验证码验证失败!"); + } + } } diff --git a/postdischarge-mobile/src/main/java/com/xinelu/mobile/utils/SmsSendUtils.java b/postdischarge-mobile/src/main/java/com/xinelu/mobile/utils/SmsSendUtils.java new file mode 100644 index 00000000..6f950f95 --- /dev/null +++ b/postdischarge-mobile/src/main/java/com/xinelu/mobile/utils/SmsSendUtils.java @@ -0,0 +1,86 @@ +package com.xinelu.mobile.utils; + +import com.aliyuncs.DefaultAcsClient; +import com.aliyuncs.IAcsClient; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; +import com.aliyuncs.exceptions.ClientException; +import com.aliyuncs.profile.DefaultProfile; +import com.aliyuncs.profile.IClientProfile; +import com.xinelu.common.config.AliYunSmsConfig; +import com.xinelu.common.enums.SmsErrorCodeEnum; +import com.xinelu.common.exception.ServiceException; +import com.xinelu.mobile.dto.smssend.SmsInfoDTO; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * @program: PostDischargePatientManage + * @description: 短信发送工具类 + * @author: yxl + * @create: 2024-07-02 20:50 + **/ +@Component +@Slf4j +public class SmsSendUtils { + + private static final String SUCCESS = "OK"; + + @Resource + private AliYunSmsConfig aliyunSmsConfig; + + /** + * 发送短信 + */ + public Boolean sendSms(SmsInfoDTO smsInfoDTO) throws ClientException, ServiceException { + try { + // 短信发送参数非空性判断 + if (ObjectUtils.isEmpty(smsInfoDTO)) { + throw new ServiceException("短信发送参数不能为空!"); + } + if (StringUtils.isBlank(smsInfoDTO.getPhoneNumbers())) { + throw new ServiceException("待发送手机号不能为空!"); + } + if (StringUtils.isBlank(smsInfoDTO.getSignName())) { + throw new ServiceException("短信签名不能为空!"); + } + if (StringUtils.isBlank(smsInfoDTO.getTemplateCode())) { + throw new ServiceException("短信模板Code不能为空!"); + } + + // 设置系统的默认连接超时时间和读取超时时间 + System.setProperty("sun.net.client.defaultConnectTimeout", "10000"); + System.setProperty("sun.net.client.defaultReadTimeout", "10000"); + + // 初始化acsClient,暂不支持region化 + IClientProfile profile = DefaultProfile.getProfile(aliyunSmsConfig.getRegionId(), aliyunSmsConfig.getAccessKeyId(), aliyunSmsConfig.getAccessKeySecret()); + DefaultProfile.addEndpoint(aliyunSmsConfig.getRegionId(), aliyunSmsConfig.getProduct(), aliyunSmsConfig.getDomain()); + IAcsClient acsClient = new DefaultAcsClient(profile); + + // 组装请求对象 + SendSmsRequest request = new SendSmsRequest(); + request.setPhoneNumbers(smsInfoDTO.getPhoneNumbers()); + request.setSignName(smsInfoDTO.getSignName()); + request.setTemplateCode(smsInfoDTO.getTemplateCode()); + request.setTemplateParam(smsInfoDTO.getTemplateParam().toJSONString()); + + SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); + // 判断响应的结果 + if (!SUCCESS.equals(sendSmsResponse.getCode())) { + SmsErrorCodeEnum errorCode = SmsErrorCodeEnum.getMsgByCode(sendSmsResponse.getCode()); + log.error("短信发送失败,错误码:{},错误信息:{}", sendSmsResponse.getCode(), errorCode.getMessage()); + return false; + } + log.info("短信发送成功:code:{}", sendSmsResponse.getCode()); + return true; + } catch (ClientException e) { + log.error("发送短信出现异常,异常信息:{}", e.getMessage()); + throw e; + } + } +} +