阿里云短信服务
-
当用户点击套餐详情页面时,点击立即预约按钮
-
此时会跳转一个页面,需要添加用户的个人信息
-
判断用户输入的手机号是否正确
//发送验证码
sendValidateCode() {
//获取用户输入的手机号
let telephone = this.orderInfo.telephone;
//判断手机是否正确
if (!checkTelephone(telephone)) {
//如果不正确给出提示
this.$message.error("请输入正确的手机号");
return false;
}
//在按钮上显示30秒倒计时效果
validateCodeButton = $("#validateCodeButton")[0];//锁定dom对象
clock = window.setInterval(doLoop, 1000);//实现指定时间调用指定的方法
axios.post("/validateCode/send4Order.do?telephone=" + telephone).then(res => {
if (!res.data.flag) {
this.$message.error("验证码发送失败,请检查手机号输入是否正确");
}
})
- 当用户填写信息时需要发送短信,当点击发送验证码时回想服务端发起请求
- 此时后台接受到请求之后掉用阿里云发送短信的工具类给用户手机发送验证码
- 然后将生成的验证码为value手机号+唯一标识为key存到redis里面一分钟
jedisPool.getResource().setex(telephone + RedisConstant.SENDTYPE_ORDER, 300, validateCode.toString());
阿里云短信工具类
/**
* 短信发送工具类
*/
@SuppressWarnings("all")
public class SMSUtils {
public static final String VALIDATE_CODE = "SMS_205462377";//发送短信验证码
public static final String ORDER_NOTICE = "SMS_159771588";//体检预约成功通知
/**
* 通过阿里云短信服务发送短信到指定的手机号上
* @param templateCode -- 短信模板的编号
* @param phoneNumbers -- 指定发送短信的手机号码
* @param param -- 验证码
* @throws ClientException
*/
public static void sendShortMessage(String templateCode,String phoneNumbers,String param) throws ClientException{
// 设置超时时间-可自行调整
System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
System.setProperty("sun.net.client.defaultReadTimeout", "10000");
// 初始化ascClient需要的几个参数
final String product = "Dysmsapi";// 短信API产品名称(短信产品名固定,无需修改)
final String domain = "dysmsapi.aliyuncs.com";// 短信API产品域名(接口地址固定,无需修改)
// 替换成你的AK
final String accessKeyId = "你的accessKeyId,参考本文档步骤2";
final String accessKeySecret = "你的accessKeySecret,参考本文档步骤2";
// 初始化ascClient,暂时不支持多region(请勿修改)
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
IAcsClient acsClient = new DefaultAcsClient(profile);
// 组装请求对象
SendSmsRequest request = new SendSmsRequest();
// 使用post提交
request.setMethod(MethodType.POST);
// 必填:待发送手机号。支持以逗号分隔的形式进行批量调用,批量上限为1000个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式
request.setPhoneNumbers(phoneNumbers);
// 必填:短信签名-可在短信控制台中找到
request.setSignName("阿里云签名");
// 必填:短信模板-可在短信控制台中找到
request.setTemplateCode(templateCode);
// 可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
// 友情提示:如果JSON中需要带换行符,请参照标准的JSON协议对换行符的要求,比如短信内容中包含\r\n的情况在JSON中需要表示成\\r\\n,否则会导致JSON在服务端解析失败
request.setTemplateParam("{\"code\":\""+param+"\"}");
// 可选-上行短信扩展码(扩展码字段控制在7位或以下,无特殊需求用户请忽略此字段)
// request.setSmsUpExtendCode("90997");
// 可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
// request.setOutId("yourOutId");
// 请求失败这里会抛ClientException异常
SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
if (sendSmsResponse.getCode() != null && sendSmsResponse.getCode().equals("OK")) {
// 请求成功
System.out.println("请求成功");
}
}
}
提交预约
- 当用户点击提交预约的时候会校验身份证和日期是否正确
- 检验成功之后将用户填写的数据携带发送异步请求
//提交预约
submitOrder() {
//对用户输入的身份证进行校验
let idCard = this.orderInfo.idCard;
if (!checkIdCard(idCard)) {
//如果身份证不合法就给出错误的提示
this.$message.error("身份证输入错误,请重新输入");
return false;
}
//对用户输入的日期进行校验
let data = this.orderInfo.orderDate;
if (data == null && data === undefined) {
this.$message.error("请填写日期");
return false
}
//如果身份证检验成功就发送ajax请求,提交表单数据到后台进行业务处理
axios.post("/order/submit.do", this.orderInfo).then(res => {
if (res.data.flag) {
//预约成功,跳转到成功页面
window.location.href = "orderSuccess.html?orderId=" + res.data.data;
} else {
//预约失败,给出提示
this.$message.error(res.data.message);
}
体检预约控制层
- 获取用户填写的验证码和redis存储的验证码判断是否一致
- 如果填写正确设置用户的预约类型
- 通过dubbo远程调用服务在线预约业务处理
- 如果添加错误就像错误信息响应给用户
@PostMapping("/submit")
public Result submit(@RequestBody Map map) {
//获取前台传递过来的电话号码:18290481045
String telephone = (String) map.get("telephone");
//从Redis中获取保存的验证码:5895
String validateCodeInRedis = jedisPool.getResource().get(telephone + RedisConstant.SENDTYPE_ORDER);
//获取用户输入的验证码
String validateCode = (String) map.get("validateCode");
//将用户输入的验证码和Redis中保存的验证码进行比对
if (validateCodeInRedis != null && validateCode != null && validateCode.equals(validateCodeInRedis)) {
//如果比对成功,调用服务完成预约业务处理
//设置预约类型,分为微信预约、电话预约
map.put("orderType", Order.ORDERTYPE_WEIXIN);
Result result = null;
try {
//通过Dubbo远程调用服务实现在线预约业务处理
result = orderService.order(map);
} catch (Exception e) {
e.printStackTrace();
return result;
}
return result;
} else {
//如果比对不成功,返回结果给页面
return Result.failed(MessageConstant.VALIDATECODE_ERROR);
}
}
业务层在线预约处理
用户进行预约需要判断是否重乎预约以及当日是否有体检的安排
- 检查用户所选择的预约日期是否进行预约设置,如果没有设置预约就无法预约
- 判断设置的当日的可预约人数是否已满,如果已满则无法预约
- 查询用户是否在重复预约(查询用户是否是会员)
- 如果是会员就直接预约,如果不是会员就进行自动注册添加到会员列表里面在进行预约
- 如果预约成功需要将当日的已预约人数进行重新设置+1
public Result order(Map map) throws Exception {
//检查用户所选择预约的日期是否进行预约设置,如果没有设置就无法进行预约
//获取用户预约的日期
String orderDate = (String) map.get("orderDate");
//根据用户传递的日期查询当日日期的设置
OrderSetting orderSetting = orderSettingDao.findByOrderDate(DateUtils.parseString2Date(orderDate));
if (orderSetting == null) {
//指定日期没有进行预约设置,无法完成预约
return Result.failed(MessageConstant.SELECTED_DATE_CANNOT_ORDER);
}
//获取当日设置的可预约人数
int number = orderSetting.getNumber();
//获取当日已预约的人数
int reservations = orderSetting.getReservations();
//如果可预约人数小于已预约人数就不能进行预约
if (reservations >= number) {
//指定日期没有进行预约设置,无法完成体检预约
return Result.failed(MessageConstant.SELECTED_DATE_CANNOT_ORDER);
}
//检查用户是否重复预约
//获取用户填写的电话号码
String telephone = (String) map.get("telephone");
//根据用户的电话号码查询用户的信息
Member member = memberDao.findByTelephone(telephone);
//如果用户的信息不为空,说明今天已经预约过
if (member != null) {
//判断是否在重复预约
//获取会员的id
Integer memberId = member.getId();
//获取预约日期
Date date = DateUtils.parseString2Date(orderDate);
//获取套餐的id
String setmealId = (String) map.get("setmealId");
//封装到订单对象(会员的id,预约的日期,套餐的id)
Order order = new Order(memberId, date, Integer.parseInt(setmealId));
//根据条件查询
List<Order> list = orderDao.findByCondition(order);
if (list != null && list.size() > 0) {
//如果能够查询出来信息说明已经预约过
return Result.failed(MessageConstant.HAS_ORDERED);
}
} else {
//检查当前用户是否是会员,如果是会员就直接预约,如果不是会员,就完成自动注册在预约
member = new Member();
//名字
member.setName((String) map.get("name"));
//电话
member.setPhoneNumber(telephone);
//身份证
member.setIdCard((String) map.get("idCard"));
//性别
member.setSex((String) map.get("sex"));
//日期
member.setRegTime(new Date());
//注册会员
memberDao.add(member);
}
//5.预约成功,更新当日的已预约人数
Order order = new Order();
//设置会员Id
order.setMemberId(member.getId());
//预约日期
order.setOrderDate(DateUtils.parseString2Date(orderDate));
//预约类型
order.setOrderType((String) map.get("orderType"));
//到诊状态
order.setOrderStatus(Order.ORDERSTATUS_NO);
//套餐id
order.setSetmealId(Integer.parseInt((String)map.get("setmealId")));
orderDao.add(order);
//设置已预约的人数+1
orderSetting.setReservations(orderSetting.getReservations() + 1);
orderSettingDao.editReservationsByOrderDate(orderSetting);
return Result.success(MessageConstant.ORDER_SUCCESS,order.getId());
}
中途出现的问题
- 前台异步get请求,后台不能用post接受,否则报405错误
- git回退版本会创建一个临时分支,再次切换有可能消失 注意安全
- 回此预约记得设置预约人数+1 否则数据库参数不变
- 订单设置参数完毕之后没有添加到数据库里面返回前台接收不到id就不能回显用户的数据
因为id是每添加一次利用mybatis高级特性自动生成主键id - 每次使用完redis连接池记得关闭,否则消耗过大。