项目设计之用户注册与登录
目录
项目设计之用户注册与登录
流程
表设计
create table if not exists kanyuServer.user_db
(
id bigint unsigned auto_increment comment '主键'
primary key,
phone varchar(11) not null comment '手机号码',
password varchar(128) default '' null comment '密码,加密存储',
user_name varchar(32) default '' null comment '昵称,默认是用户id',
create_time timestamp default CURRENT_TIMESTAMP not null comment '创建时间',
update_time timestamp default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
constraint uniqe_key_phone
unique (phone)
);
功能设计
用户注册功能
用户注册的流程如下
1,用户输入手机号和名称
2,后端校验是否注册过
3,数据库插入数据
代码
用户实体类
package com.kanyuServer.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("user_db")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 手机号码
*/
private String phone;
/**
* 密码,需加密存储
*/
private String password;
/**
* 昵称,默认是随机字符
*/
private String userName;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 更新时间
*/
private LocalDateTime updateTime;
}
注册控制器
package com.kanyuServer.controller;
import cn.hutool.json.JSON;
import com.kanyuServer.common.Result;
import com.kanyuServer.dto.RegisterForm;
import com.kanyuServer.entity.User;
import com.kanyuServer.service.LoginService;
import com.kanyuServer.service.RegisterService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
/**
* 登录控制器
*/
@Slf4j
@RestController
@RequestMapping("/register")
public class RegisterController {
@Resource
RegisterService registerService;
@PostMapping("user")
public Result sendCode(@RequestBody RegisterForm registerForm, HttpSession session) {
//打印日志
log.info("用户注册信息"+ registerForm.toString());
Result result = registerService.register(registerForm,session);
return result;
}
}
mapper
package com.kanyuServer.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.kanyuServer.entity.User;
public interface UserMapper extends BaseMapper<User> {
}
service
package com.kanyuServer.service.impl;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kanyuServer.common.Result;
import com.kanyuServer.dto.RegisterForm;
import com.kanyuServer.entity.User;
import com.kanyuServer.mapper.UserMapper;
import com.kanyuServer.service.LoginService;
import com.kanyuServer.service.RegisterService;
import com.kanyuServer.utils.Validate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import com.kanyuServer.utils.PasswordUtil;
import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static com.kanyuServer.constant.RedisConstants.LOGIN_CODE_KEY;
import static com.kanyuServer.constant.RedisConstants.LOGIN_CODE_TTL;
import static com.kanyuServer.constant.ResponseConstant.*;
@Slf4j
@Service
public class RegistererviceImpl extends ServiceImpl<UserMapper, User> implements RegisterService {
//引入redis工具类
@Resource
private StringRedisTemplate stringRedisTemplate;
@Override
public Result register(RegisterForm registerForm, HttpSession session) {
// 1.校验手机号
String phone = registerForm.getPhone();
if (Validate.isPhoneInvalid(phone)) {
// 2.如果不符合,返回错误信息
return Result.fail("手机号格式错误!",400);
}
User user_query = query().eq("phone", phone).one();
if (user_query!=null){
return Result.fail("用户已注册过,请登录",400);
}
registerForm.setPassword(PasswordUtil.hashPassword(registerForm.getPassword()));
User user = new User();
user.setPassword(registerForm.getPassword());
user.setUserName(registerForm.getUserName());
user.setPhone(registerForm.getPhone());
save(user);
return Result.ok();
}
}
用户登录功能
密码登录
@Override
public Result loginWithPassward(LoginForm loginForm, HttpSession session) {
// 1.校验手机号
String phone = loginForm.getPhone();
if (Validate.isPhoneInvalid(phone)) {
// 2.如果不符合,返回错误信息
return Result.fail("手机号格式错误!",400);
}
User user = query().eq("phone", loginForm.getPhone()).one();
if (user==null){
//返回用户不存在 这里预期进入注册网页
return Result.fail(USER_NOT_FOUND,USER_NOT_FOUNT_CODE);
}
//校验密码是否正确 这里直接对比原始的密码与加密的密码是否相同
boolean flag = PasswordUtil.checkPassword(loginForm.getPassword(),user.getPassword());
//不正确
if (!flag){
return Result.fail(USER_PASSWORD_NOT_CORRECT,USER_PASSWORD_NOT_CORRECT_CODE);
}
// 保存用户信息到 redis中
// 随机生成token,作为登录令牌
String token = UUID.randomUUID().toString(true);
// 将User对象转为HashMap存储
LoginForm loginForm1 = BeanUtil.copyProperties(user, LoginForm.class);
System.out.println(loginForm1);
log.info(loginForm1.toString());
loginForm1.setCode("");
Map<String, Object> userMap = BeanUtil.beanToMap(loginForm1, new HashMap<>(),
CopyOptions.create().setIgnoreNullValue(true)
.setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
// 存储
String tokenKey = LOGIN_USER_KEY + token;
stringRedisTemplate.opsForHash().putAll(tokenKey, userMap);
// 设置token有效期
stringRedisTemplate.expire(tokenKey, LOGIN_USER_TTL, TimeUnit.MINUTES);
Map<String,Object> result = new HashMap<>();
result.put("token",token);
result.put("user",user);
//返回token
return Result.ok(result);
}
验证码登录
@Override
public Result loginWithCode(LoginForm loginForm, HttpSession session) {
//校验手机号
String phone = loginForm.getPhone();
if (Validate.isPhoneInvalid(phone)) {
// 如果不符合,返回错误信息
return Result.fail("手机号格式错误!",400);
}
//获取验证码
String code = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + loginForm.getPhone());
String code_user = loginForm.getCode();
//redis拿不到相关验证码,说明过期或者手机号不存在
if (code==null){
return Result.fail(USER_NOT_FOUND,USER_NOT_FOUNT_CODE);
}
//redis保存的验证码与输入的验证码不匹配
if (!code.equals(code_user)){
return Result.fail(CODE_NOT_MATCH,CODE_NOT_MATCH_OCDE);
}
User user = query().eq("phone", loginForm.getPhone()).one();
log.info("user");
log.info(user.toString());
if (user==null){
//返回用户不存在 这里预期进入注册网页
return Result.fail(USER_NOT_FOUND,USER_NOT_FOUNT_CODE);
}
// 保存用户信息到 redis中
// 随机生成token,作为登录令牌
String token = UUID.randomUUID().toString(true);
// 将User对象转为HashMap存储
LoginForm loginForm1 = BeanUtil.copyProperties(user, LoginForm.class);
log.info("loginForm1");
log.info(loginForm1.toString());
loginForm1.setCode("");//把null置为""空字符串类型
Map<String, Object> userMap = BeanUtil.beanToMap(loginForm1, new HashMap<>(),
CopyOptions.create()
.setIgnoreNullValue(true)
.setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
// 存储
String tokenKey = LOGIN_USER_KEY + token;
log.info(userMap.toString());
stringRedisTemplate.opsForHash().putAll(tokenKey, userMap);
//设置token有效期
stringRedisTemplate.expire(tokenKey, LOGIN_USER_TTL, TimeUnit.MINUTES);
//返回token
return Result.ok(token);
}
验证码的详细redis实现可以参考我之前的这边文章
接口
注册
入参
{
"userName":"t",
"phone":13689663339,
"password":3
}
密码登录
入参
{
"phone":13610137901,
"password":3
}
发送验证码
路径参数phone
验证码登录
入参
{
"phone":13610137901,
"password":3
}
已开源 可下载
可以帮点个star呗,感谢