一 登录系统流程:
异步化登录流程:
代码实现:
先定义实体类:
package com.ruyuan.little.project.rocketmq.api.login.dto;
/**
* @author <a href="mailto:little@163.com">little</a>
* version: 1.0
* Description:登录请求的dto
**/
public class LoginRequestDTO {
/**
* 用户id
*/
private Integer userId;
/**
* 用户名称
*/
private String nickName;
/**
* 手机号
*/
private String phoneNumber;
/**
* token
*/
private String token;
/**
* 小程序id
*/
private Integer beid;
第二步 核心Service类LoginServiceImpl
成员变量
/**
* 日志组件
*/
private static final Logger LOGGER = LoggerFactory.getLogger(LoginServiceImpl.class);
//当一个接口有多个实现类时,在注入时除了使用Autowired,还要使用Qualifier
@Autowired
@Qualifier(value = "loginMqProducer")
private DefaultMQProducer loginMqProducer;
@Value("${rocketmq.login.topic}")
private String loginTopic;
/**
* mysql dubbo api接口
*/
@Reference(version = "1.0.0",
interfaceClass = MysqlApi.class,
cluster = "failfast")
private MysqlApi mysqlApi;
/**
* redis dubbo服务
*/
@Reference(version = "1.0.0",
interfaceClass = RedisApi.class,
cluster = "failfast")
private RedisApi redisApi;
@Override
public void firstLoginDistributeCoupon(LoginRequestDTO loginRequestDTO) {
if (!isFirstLogin(loginRequestDTO)) {
// 不是第一次登陆 返回
LOGGER.info("userId:{} not first login", loginRequestDTO.getUserId());
return;
}
// 更新第一次登陆的标识位
this.updateFirstLoginStatus(loginRequestDTO.getPhoneNumber(), FirstLoginStatusEnum.NO);
// 发送第一次登陆成功的消息
this.sendFirstLoginMessage(loginRequestDTO);
}
方法:
1 直接和controller对接的方法 firstLoginDistributeCoupon
public void firstLoginDistributeCoupon(LoginRequestDTO loginRequestDTO) {
if (!isFirstLogin(loginRequestDTO)) {
// 不是第一次登陆 返回
LOGGER.info("userId:{} not first login", loginRequestDTO.getUserId());
return;
}
// 更新第一次登陆的标识位
this.updateFirstLoginStatus(loginRequestDTO.getPhoneNumber(), FirstLoginStatusEnum.NO);
// 发送第一次登陆成功的消息
this.sendFirstLoginMessage(loginRequestDTO);
}
首先判断是不是第一次登录。方法细节: isFirstLogin(loginRequestDTO)
,去mysql查询是不是第一次登录,
private boolean isFirstLogin(LoginRequestDTO loginRequestDTO) {
MysqlRequestDTO mysqlRequestDTO = new MysqlRequestDTO();
mysqlRequestDTO.setSql("select first_login_status from t_member where id = ? ");
ArrayList<Object> params = new ArrayList<>();
params.add(loginRequestDTO.getUserId());
mysqlRequestDTO.setParams(params);
mysqlRequestDTO.setPhoneNumber(loginRequestDTO.getPhoneNumber());
mysqlRequestDTO.setProjectTypeEnum(LittleProjectTypeEnum.ROCKETMQ);
LOGGER.info("start query first login status param:{}", JSON.toJSONString(mysqlRequestDTO));
CommonResponse<List<Map<String, Object>>> response = mysqlApi.query(mysqlRequestDTO);
LOGGER.info("end query first login status param:{}, response:{}", JSON.toJSONString(mysqlRequestDTO), JSON.toJSONString(response));
//注意这里要首先判断响应码是不是正确再去判断数据库中的值是不是第一次登录。
if (Objects.equals(response.getCode(), ErrorCodeEnum.SUCCESS.getCode())
&& !CollectionUtils.isEmpty(response.getData())) {
Map<String, Object> map = response.getData().get(0);
return Objects.equals(Integer.valueOf(String.valueOf(map.get("first_login_status"))),
FirstLoginStatusEnum.YES.getStatus());
}
return false;
}
如果不是第一次登录,就执行两个操作,第一,去数据库里修改值。updateFirstLoginStatus
private void updateFirstLoginStatus(String phoneNumber, FirstLoginStatusEnum firstLoginStatusEnum) {
MysqlRequestDTO mysqlRequestDTO = new MysqlRequestDTO();
mysqlRequestDTO.setSql("update t_member set first_login_status = ? WHERE beid = 1563 and mobile = ?");
ArrayList<Object> params = new ArrayList<>();
params.add(firstLoginStatusEnum.getStatus());
params.add(phoneNumber);
mysqlRequestDTO.setParams(params);
mysqlRequestDTO.setPhoneNumber(phoneNumber);
mysqlRequestDTO.setProjectTypeEnum(LittleProjectTypeEnum.ROCKETMQ);
LOGGER.info("start query first login status param:{}", JSON.toJSONString(mysqlRequestDTO));
CommonResponse<Integer> response = mysqlApi.update(mysqlRequestDTO);
LOGGER.info("end query first login status param:{}, response:{}", JSON.toJSONString(mysqlRequestDTO), JSON.toJSONString(response));
}
第二,利用mq发送消息 sendFirstLoginMessage
private void sendFirstLoginMessage(LoginRequestDTO loginRequestDTO) {
// 场景一:性能提升 异步发送一个登录成功的消息到mq中
Message message = new Message();
message.setTopic(loginTopic);
// 消息内容用户id
//message发json字符串
message.setBody(JSON.toJSONString(loginRequestDTO).getBytes(StandardCharsets.UTF_8));
try {
LOGGER.info("start send login success notify message");
SendResult sendResult = loginMqProducer.send(message);
LOGGER.info("end send login success notify message, sendResult:{}", JSON.toJSONString(sendResult));
} catch (Exception e) {
LOGGER.error("send login success notify message fail, error message:{}", e);
}
}
这里注意利用loginMqProducer发送消息,所以要提前@bean把这个producer注入到spring容器,利用LoginProducerConfiguration
类注入producer
@Configuration
public class LoginProducerConfiguration {
@Value("${rocketmq.namesrv.address}")
private String namesrvAddress;
@Value("${rocketmq.login.producer.group}")
private String loginProducerGroup;
/**
* 登录生产者
*
* @return 登录消息rocketmq的生产者对象
*/
@Bean(value = "loginMqProducer")
public DefaultMQProducer loginMqProducer() throws MQClientException {
DefaultMQProducer producer = new DefaultMQProducer(loginProducerGroup);
//设置rocketmq的服务器地址
producer.setNamesrvAddr(namesrvAddress);
producer.start();
return producer;
}
}
scp到服务器 scp target/little-project-rocketmq.jar root@47.100.190.149:/home/admin/little-project-rocketmq/target,用脚本部署,查看日志测试成功。(也可以用postman测试)
2021-06-25 10:27:24.666 INFO 1949 — [nio-8088-exec-3]
c.r.l.p.r.a.l.c.LoginController : login success user info:{“beid”:1563,“nickName”:“夏”,“phoneNumber”:“13132181205”,“token”:“322eb718e6a327b3263f35bdf0e00b06”,“userId”:14937}