5.用户手机验证码登录
用户手机验证码登录
一、yapi接口文档
二、代码实现
1.服务提供者
1.1在tanhua-dubbo-db模块创建Mapper接口com/tanhua/dubbo/mappers/UserMapper.java(数据层,查询数据库)
package com.tanhua.dubbo.mappers;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tanhua.model.domain.User;
//对应哪个实体就是查哪张表,这是查User表
public interface UserMapper extends BaseMapper<User> {
}
2.2在tanhua-dubbo-interface模块创建业务层接口com/tanhua/dubbo/api/UserApi.java
package com.tanhua.dubbo.api;
import com.tanhua.model.domain.User;
public interface UserApi {
//根据手机号查找用户
User selectByPhoneNumber(String phoneNumber);
}
3.3在在tanhua-dubbo-db模块创建创建业务层实现类com/tanhua/dubbo/api/UserApiImpl.java(调用mapper)
package com.tanhua.dubbo.api;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tanhua.dubbo.mappers.UserMapper;
import com.tanhua.model.domain.User;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
@DubboService
public class UserApiImpl implements UserApi {
@Autowired
private UserMapper userMapper;
public User selectByPhoneNumber(String phoneNumber) {
//1.构造查询条件
QueryWrapper<User> qw =new QueryWrapper<>();
qw.eq("mobile", phoneNumber);
//2.根据手机号码查询用户
User user = userMapper.selectOne(qw);
return user;
}
}
3.4创建服务启动类(mybatis mapper包扫描)
package com.tanhua.dubbo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.tanhua.mapper")
public class TanHuaDbApplication {
public static void main(String[] args) {
SpringApplication.run(TanHuaDbApplication.class, args);
}
}
3.5配置application.yml
server:
port: 8081
spring:
application:
name: tanhua-dubbo-db #服务名称
datasource: #数据源
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/tanhua?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=false
username: root
password: 1234
cloud:
nacos:
discovery:
server-addr: 192.168.136.160:8848 #nacos地址
dubbo:
cloud:
subscribed-services: 'tanhua-app-server'
protocol:
name: dubbo
port: 20881
registry:
address: spring-cloud://localhost
scan:
base-packages: com.tanhua.dubbo.api
mybatis-plus:
global-config:
db-config:
table-prefix: tb_ #表名前缀
id-type: auto #id生成策略
3.6在tanhua-app-server模块的测试模块创建com/itheima/test/UserApiTest.java测试
package com.itheima.test;
import com.tanhua.dubbo.api.UserApi;
import com.tanhua.model.domain.User;
import com.tanhua.server.AppServerApplication;
import org.apache.dubbo.config.annotation.DubboReference;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = AppServerApplication.class)
public class UserApiTest {
@DubboReference
private UserApi userApi;
@Test
public void testFindByMobile() {
User user = userApi.selectByPhoneNumber("13381313372");
System.out.println(user);
}
}
2.服务消费者
2.1表现层,在tanhua-app-server摸块的LoginController中编写代码
@RestController
@RequestMapping("/user")
public class LoginController {
@Autowired
private UserService userService;
/**
* 用户登录接口
* 1.请求路径:/user/loginVerification
* 2.请求参数:phone(String),verificationCode(String)用map集合封装
* 3.返回结果:token,isNew(封装到map集合返回)
*/
@PostMapping("/loginVerification")
public ResponseEntity loginVerification(@RequestBody Map map){
//1.接收参数
String phone = (String) map.get("phone");
String code = (String) map.get("verificationCode");
//2.调用userServi
//返回结果用map封装
Map result =userService.loginVerification(phone,code);
return ResponseEntity.ok(result);
}
}
2.2业务层UserService步骤分析
- 从Redis缓存中获取验证码
- 判断用户输入的验证码与下发的手机验证码是否一致,不一致则抛出一个异常
- 删除Redis中缓存的验证码
- 用dubbo远程调用UserApi,根据手机号码查询用户
- .如果user为空,证明是新用户,把它存进数据库表
- 生成token(存入id和手机号码)
- 构造返回值
@Service
public class UserService {
@Autowired
private SmsTemplate smsTemplate; //发送手机验证码模板
@Autowired
private RedisTemplate<String ,String> redisTemplate;
@DubboReference
private UserApi userApi;
/**
* 登录的业务层接口业务逻辑
* @param phone
* @param code
* @return
*/
public Map loginVerification(String phone, String code) {
//1.从Redis缓存中获取验证码
String redisCode = redisTemplate.opsForValue().get("CHECK_CODE_" + phone);
//2.判断用户输入的验证码与下发的手机验证码是否一致
//不一致则抛出一个异常
if(StringUtils.isEmpty(code) || ! redisCode.equals(code)){
//验证码无效
throw new RuntimeException("验证码无效");
}
//3.删除Redis中缓存的验证码
redisTemplate.delete("CHECK_CODE_" + phone);
//4.用dubbo远程调用UserApi,根据手机号码查询用户
User user = userApi.selectByPhoneNumber(phone);
boolean isNew = false;
//5.如果user为空,证明是新用户,把它存进数据库表
if(user == null){
user =new User();
user.setMobile(phone);
user.setCreated(new Date());
user.setUpdated(new Date());
user.setPassword(DigestUtils.md5Hex("123456"));
Long userId = userApi.addNewUser(user);
user.setId(userId);
isNew =true;
}
//6.生成token(存入id和手机号码)
Map userToken = new HashMap();
userToken.put("id", user.getId());
userToken.put("phone",phone);
String token = JwtUtils.getToken(userToken);
//7.构造返回值
Map resultMap = new HashMap();
resultMap.put("token", token);
resultMap.put("isNew", isNew);
return resultMap;
}
}
3.代码优化
3.1在tanhua-model抽取BasePojo,com/tanhua/model/domain/BasePojo.java
@Data
public abstract class BasePojo implements Serializable {
@TableField(fill = FieldFill.INSERT) //自动填充
private Date created;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updated;
}
3.2自动填充
对于created和updated字段,每次操作都需要手动设置。为了解决这个问题,mybatis-plus支持自定义处理器的形式实现保存更新的自动填充
package com.tanhua.dubbo.server.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
Object created = getFieldValByName("created", metaObject);
if (null == created) {
//字段为空,可以进行填充
setFieldValByName("created", new Date(), metaObject);
}
Object updated = getFieldValByName("updated", metaObject);
if (null == updated) {
//字段为空,可以进行填充
setFieldValByName("updated", new Date(), metaObject);
}
}
@Override
public void updateFill(MetaObject metaObject) {
//更新数据时,直接更新字段
setFieldValByName("updated", new Date(), metaObject);
}
}