用户注册
需求分析
注册账号,用手机号注册,填写后发送短信验证码,填写短信验证码正确方可注册成功。
实现思路
(1)发送短信验证码逻辑:用户服务将要发送的短信验证码发送给rabbitmq和redis ,
短信服务将消息从rabbitmq中取出并调用阿里云通信发送短信。阿里云通信整合了三大
运营商的短信网关,最终把验证码发送到用户的手机上。rabbitmq采用直接模式,用户
服务为消息生产者,短信服务为消息消费者。
(2)注册逻辑:注册时从redis中提取短信验证码与用户填写的验证码进行比对,如果一
致则可以注册,否则拦截请求。
后端代码
发送短信验证码到MQ
实现思路: 在用户服务编写API ,生成手机验证码,存入Redis并发送到RabbitMQ
1.添加配置文件applicationContext-rabbitmq-producer.xml
<beans …/>
<!‐‐连接工厂‐‐>
<rabbit:connection‐factory id=“connectionFactory” host=“127.0.0.1” port=“5672” username=“guest” password=“guest” />
<rabbit:admin connection‐factory=“connectionFactory”></rabbit:admin>
<!‐‐创建队列‐‐>
<rabbit:queue name=“queue.sms” />
<rabbit:template id=“rabbitTemplate” connection‐factory=“connectionFactory” />
2.在UserService中新增方法定义
/**
- 发送短信验证码
- @param mobile
*/
public void sendSms(String phone);
3.UserServiceImpl方法实现
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private RabbitTemplate rabbitTemplate;
/**
- 发送短信验证码
- @param phone
*/
public void sendSms(String phone){
//1.得到六位短信验证码
int max=999999;
int min=100000;
Random random = new Random();
int code = random.nextInt(max);
if(code<min){
code=code+min;
}
System.out.println(“短信验证码:”+code);
//2.保存到redis里
redisTemplate.boundValueOps(“code_”+phone).set(code+"");
redisTemplate.boundValueOps(“code_”+phone).expire(5,TimeUnit.MINUTES);//5分钟失效
//3.发送给RabbitMQ
Map<String,String> map=new HashMap();
map.put(“phone”, phone);
map.put(“code”, code+"");
//因为不能发送Map形式的数据,需要转为字符串
rabbitTemplate.convertAndSend("",“queue.sms”,JSON.toJSONString(map)); //直接模式,使用默认的交换器 RouteKey就是队列的名称
}
4.新增UserController
@RestController
@RequestMapping("/user")
public class UserController {
@Reference
private UserService userService;
/**
- 发送短信验证码
- @param phone
*/
@GetMapping(value="/sendSms")
public Result sendSms(String phone){
userService.sendSms(phone);
return new Result();
}
}
短信服务接收消息
短信发送是由单独的短信服务提供的功能,所有的短信都是先发送到消息队列,短信服务从消息队列中提取手机号和验证码,调用短信发送接口进行发送短信。
添加监听实现类SmsMessageConsumer
public class SmsMessageConsumer implements MessageListener {
public void onMessage(Message message) {
String jsonString = new String(message.getBody());
Map<String,String> map = JSON.parseObject(jsonString, Map.class);
String phone = map.get(“phone”);
String code=map.get(“code”);
System.out.println(“手机号:”+phone+“验证码:”+code);
}
}
添加配置文件applicationContext-rabbitmq-consumer.xml
<!‐‐连接工厂‐‐>
<rabbit:connection‐factory id=“connectionFactory” host=“127.0.0.1”
port=“5672” username=“guest” password=“guest” />
<!‐‐创建队列‐‐>
<rabbit:queue name=“queue.sms” />
<!‐‐消费者监听类‐‐>
<!‐‐设置监听容器‐‐>
<rabbit:listener‐container connection‐factory=“connectionFactory” >
<rabbit:listener queue‐names=“queue.sms” ref=“messageConsumer”/>
</rabbit:listener‐container>
用户注册 (用户收到验证码后,输入验证码点击注册)
(1)UserService增加方法定义
/**
- 增加
- @param user
- @param smsCode
*/
public void add(User user,String smsCode); //参数为用户信息和短信验证码
(2)UserServiceImpl实现方法
/**
- 增加
- @param user
- @param smsCode
*/
public void add(User user,String smsCode) {
//比较短信验证码
//从Redis中获取系统短信验证码(系统生成的)
String sysCode= (String) redisTemplate.boundValueOps(“code_”+user.getPhone()).get();
if(sysCode==null){
throw new RuntimeException(“验证码未发送或已过期”);
}
if(!smsCode.equals(sysCode)){
throw new RuntimeException(“验证码不正确”);
}
if(user.getUsername()==null){
user.setUsername(user.getPhone());
}
User searchUser=new User();
searchUser.setUsername(user.getUsername());
//应该可以直接根据手机号去搜索数据库中的手机号字段看是否存在该手机号,因为用户可能会在系统中修改用户名,根据用户名去判断就没意义了,除非设置用户名不能修改
if(userMapper.selectCount(searchUser)>0) { //查询是否存在相同记录 selectCount是根据条件查询满足条件的记录数
throw new RuntimeException(“该手机号已注册”);
}
user.setCreated(new Date());
user.setUpdated(new Date());
user.setPoints(0);//积分初始值为0
user.setStatus(“1”);//状态1
user.setIsEmailCheck(“0”);//邮箱认证,还未认证
user.setIsMobileCheck(“1”);//手机认证,已认证
userMapper.insert(user); //将用户信息存入数据库
}
(3)UserController增加方法
@PostMapping("/save")
public Result save(@RequestBody User user , String smsCode ){
//密码加密
BCryptPasswordEncoder encoder=new BCryptPasswordEncoder();
String newpassword = encoder.encode(user.getPassword());
user.setPassword(newpassword);
userService.add(user,smsCode);
return new Result();
}