目录

项目设计之用户注册与登录

项目设计之用户注册与登录

流程

https://i-blog.csdnimg.cn/direct/20e7258a89bd4b06aee5850ce2032fde.png

表设计

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呗,感谢