用户手机验证码登录
一、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;@DubboServicepublic class UserApiImpl implements UserApi {@Autowiredprivate 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: 8081spring:application:name: tanhua-dubbo-db #服务名称datasource: #数据源driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/tanhua?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=falseusername: rootpassword: 1234cloud:nacos:discovery:server-addr: 192.168.136.160:8848 #nacos地址dubbo:cloud:subscribed-services: 'tanhua-app-server'protocol:name: dubboport: 20881registry:address: spring-cloud://localhostscan:base-packages: com.tanhua.dubbo.apimybatis-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 {@DubboReferenceprivate UserApi userApi;@Testpublic void testFindByMobile() {User user = userApi.selectByPhoneNumber("13381313372");System.out.println(user);}}
2.服务消费者
2.1表现层,在tanhua-app-server摸块的LoginController中编写代码
@RestController@RequestMapping("/user")public class LoginController {@Autowiredprivate 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和手机号码)构造返回值@Servicepublic class UserService {@Autowiredprivate SmsTemplate smsTemplate; //发送手机验证码模板@Autowiredprivate RedisTemplate<String ,String> redisTemplate;@DubboReferenceprivate 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
@Datapublic 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.ponent;import java.util.Date;@Componentpublic class MyMetaObjectHandler implements MetaObjectHandler {@Overridepublic 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);}}@Overridepublic void updateFill(MetaObject metaObject) {//更新数据时,直接更新字段setFieldValByName("updated", new Date(), metaObject);}}
aObject);
if (null == updated) {
//字段为空,可以进行填充
setFieldValByName(“updated”, new Date(), metaObject);
}
}
@Overridepublic void updateFill(MetaObject metaObject) {//更新数据时,直接更新字段setFieldValByName("updated", new Date(), metaObject);}
}