本练习场景
- 用户输入手机号,申请验证码
- 后台生成验证码,存入redis,设置5分钟自动过期,返回给用户
- 用户提交手机号和验证码给后台验证
- 后台验证登录信息,验证通过后
- 先查询redis是否保存有该用户信息,没有则查数据库
- 数据库如无记录,说明为新用户,自动注册
- 将用户信息存入redis,返回handler
- controller将用户信息存入session,返回
handler代码
@Controller
@RequestMapping("login")
public class LoginHandler {
@Resource
private LoginService loginService;
@GetMapping("valCode")
public ResponseEntity getValidateCode(String phone) {
String valCode = loginService.getValCode(phone);
return ResponseEntity.ok(new ResponseBean(StatusEnum.OPE_SUC, valCode));
}
@PostMapping("doLogin")
public ResponseEntity doLogin(String phone, String valCode, HttpSession session) {
Myuser myuser = loginService.doLogin(phone, valCode);
if (myuser == null) {
throw new MyExceptin(StatusEnum.OPE_ERR);
}
session.setAttribute("LOGIN_USER", myuser);
myuser.setUpass("");
return ResponseEntity.ok(new ResponseBean(StatusEnum.LOGIN_SUC, myuser));
}
}
serviceImpl代码
@Service
public class LoginServiceImpl implements LoginService {
private Logger logger = LoggerFactory.getLogger(LoginServiceImpl.class);
@Resource
private ShardedJedisPool jedisPool;
@Resource
private LoginMapper loginMapper;
@Override
public String getValCode(String phone) {
if (phone == null) {
throw new MyExceptin(StatusEnum.PHONE_EMPTY);
}
String valCode = StringRandom.getValCode();
logger.info("获取到了验证码,验证码为:" + valCode);
ShardedJedis resource = jedisPool.getResource();
resource.setex(RedisHeadInfo.CODE_HEAD + phone, 5 * 60, valCode);
resource.close();
return valCode;
}
@Override
public Myuser doLogin(String phone, String valCode) {
if (phone == null) {
throw new MyExceptin(StatusEnum.PHONE_EMPTY);
}
boolean checked = checkValidateCode(phone, valCode);
if (!checked) {
throw new MyExceptin(StatusEnum.OPE_ERR);
}
return getMyuserByPhone(phone);
}
private boolean checkValidateCode(String phone, String valCode) {
ShardedJedis resource = jedisPool.getResource();
String code = resource.get(RedisHeadInfo.CODE_HEAD + phone);
if (code == null || valCode == null || !code.equals(valCode.trim())) {
logger.info("验证码为空或验证码输入错误,操作账户为:" + phone + ",正确验证码为:" + code + ",用户输入的验证码为:" + valCode);
resource.close();
return false;
}
resource.close();
return true;
}
private Myuser getMyuserByPhone(String phone) {
ShardedJedis resource = jedisPool.getResource();
String userStr = resource.hget(RedisHeadInfo.LOGIN_KEY, phone);
if (userStr != null) {
logger.info("缓存中存有该用户信息");
resource.close();
return JSON.parseObject(userStr, Myuser.class);
}
Myuser myuser = loginMapper.selectByPhone(phone);
if (myuser == null) {
logger.info("数据库无此用户信息,自动注册");
myuser = new Myuser();
myuser.setUname("游客");
myuser.setUpass("1234");
myuser.setUphone(phone);
loginMapper.insertMyuser(myuser);
myuser.setNewuser("yes");
}
resource.hset(RedisHeadInfo.LOGIN_KEY, phone, JSON.toJSONString(myuser));
logger.info("将用户的登录信息存入了redis");
resource.close();
return myuser;
}
}
RedisHeadInfo字段头
public interface RedisHeadInfo {
String CODE_HEAD = "code:";
String LOGIN_KEY = "loginUser";
}
总结
- jedisPool总是需要关闭,可以引入redis的工具类,对每个方法做了简单封装,避免了繁琐的获取resource、关闭的操作;
- 验证通过后的登录账户信息先查redis,练习时忘记了这一步;
- 验证码暂存redis时候,value存为string类型,key为XXX:手机号,此格式会将验证码信息整理在XXX的文件夹下,便于统一管理;
- 用户信息存redis时,value存为map类型,统一管理,同时取值可以根据key值取。