从零开始搭建日志系统(3)-用户登录注册逻辑完成

git 项目地址

git项目地址

https://github.com/MrITzhongzi/blog-system.git

逻辑梳理
  1. 用户注册需要提供手机号,密码等信息,后台会自动把密码加密存入数据库
  2. 同一个手机号只能注册一个
  3. 登录的时候会验证手机号密码
  4. 登录成功后台会根据用户信息生成JWT密钥token,后续api都需要这个token
遇到的坑

1.mybatis插入数据返回自增主键问题

 	/**
     * 插入用户
     * @param user
     * @return
     */
    @Insert("insert into lhw_user(user_ip, user_name, user_password, user_nickname, user_telephone_number) values (#{userIp}, #{userName},#{userPassword},#{userNickname}, #{userTelephoneNumber});")
    @Options(useGeneratedKeys = true, keyProperty = "userId", keyColumn = "user_id", useCache = false)
    int insert(LhwUser user);

看这一段代码,你一定以为insert返回的是一个int类型的,我们插入的数据的主键id。其实这是错的,这个 int类型的返回值是 我们插入数据的条数(一般为1)

为什么使用了useGeneratedKeys = true, keyProperty = “userId”, keyColumn = “user_id” 还是返回行数 而不是主键ID

因为Mybatis把返回的主键ID存入 user对象里了,在我们调用 insert方法的时候我们一定是这样的:

LhwUser user = new LhwUser();
// 赋值操作
int row = xxxx.insert(user);
// row是受影响的行数,主键ID存入 user对象里了
//插入成功后,我们再输出一下 user对象

 system.out.print(user);

当我们再输出user的时候,发现user中userId字段已经有值了,就是我们插入数据库的主键ID值。

  1. mybatis返回单个对象的问题(数据库数据无法映射到相应对象里)

    @Select("SELECT * FROM lhw_user WHERE user_telephone_number = #{phone};")
    LhwUser queryUserByPhone(String phone);

看这段代码,我刚开始以为会返回一个LhwUser对象,事实上他一直是 null。

然后我就用下面这段代码测试:

 @Select("SELECT * FROM lhw_user WHERE user_telephone_number = #{phone};")
    Object queryUserByPhone(String phone);

我看一下Object的值是 查询到数据的主键 ID,是一个long类型数字。

原因:
数据库的字段无法映射到LhwUser类中的字段,需要在配置文件中把数据库字段映射成驼峰命名的LhsUser的字段。
加入如下配置:

 # mybatis 下划线转驼峰配置,两者都可以
#mybatis.configuration.mapUnderscoreToCamelCase=true
# 开启此配置是为了 在查询单个对象时,可以直接把数据库中的字段映射到返回的对象里
mybatis:
  configuration:
    map-underscore-to-camel-case: true

这样就可以使用mybatis 直接返回我们需要的对象了。

注册登录核心代码
package com.lhw.blog.controller;

import com.lhw.blog.config.CommonParam;
import com.lhw.blog.domain.LhwUser;
import com.lhw.blog.service.UserService;
import com.lhw.blog.tool.IpUtil;
import com.lhw.blog.tool.JWTUtils;
import com.lhw.blog.tool.JsonBuilder;
import com.lhw.blog.tool.SecretUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @description:  用户模块
 * @author: linger
 * @time: 2020/4/8 1:42 下午
 */
@RestController
@RequestMapping("/api/user")
public class UserController {

    @Resource
    private UserService userService;

    /**
     * 用户注册 api
     * @param username
     * @param password
     * @param phone
     * @param nickname
     * @param request
     * @return
     */
    @RequestMapping(path = "register", method = RequestMethod.POST)
    public JsonBuilder userRegister(@RequestParam(value = "username") String username,
                                    @RequestParam(value = "password") String password,
                                    @RequestParam(value = "phone") String phone,
                                    @RequestParam(value = "nickname") String nickname,
                                    HttpServletRequest request){

        // 从数据库查询有没有此用户,有的话返回错误,没有继续

        LhwUser tempUser = userService.queryUserByPhone(phone);
        if(tempUser != null) {
            return JsonBuilder.buildError("该手机号已经注册");
        }
        // 校验 各个字段是否符合要求
        if(username.trim().isEmpty()
                || password.trim().isEmpty()
                || phone.trim().isEmpty()
                || nickname.trim().isEmpty()) {
            return JsonBuilder.buildError("输入的信息有误");
        } else if (username.contains(CommonParam.NULLSTRING)
                || password.contains(CommonParam.NULLSTRING)
                || phone.contains(CommonParam.NULLSTRING)
                || nickname.contains(CommonParam.NULLSTRING)) {
            return JsonBuilder.buildError("输入的信息不能包含空格");
        }

        // 密码加密,存入数据库
        String newPwd = SecretUtils.generatePwd(password);
        if(newPwd == null) {
            return JsonBuilder.buildError("密码加密失败,请稍后再试。");
        }

        //获取 ip
        String requestIp = IpUtil.getIpAddr(request);

        LhwUser user = new LhwUser();
        user.setUserPassword(newPwd);
        user.setUserTelephoneNumber(phone);
        user.setUserNickname(nickname);
        user.setUserName(username);
        user.setUserIp(requestIp);
        // 返回主键id  0 为异常
        Integer row = userService.insert(user);
        if(row != 0) {
            Map<String,String> map = new HashMap<>();
            map.put("nickname", nickname);
            map.put("phone", phone);
            return JsonBuilder.buildSuccess("成功", map);
        }

        return JsonBuilder.buildError("失败,请稍后重试");
    }


    @RequestMapping(path = "login", method = RequestMethod.POST)
    public JsonBuilder userRegister(@RequestParam(value="phone") String phone,
                                    @RequestParam(value = "password") String password){


        LhwUser user = userService.queryUserByPhone(phone);
        if(user == null) {
            return JsonBuilder.buildError("用户不存在。");
        }

        String generatePwd = SecretUtils.generatePwd(password);
        if(phone.equals(user.getUserTelephoneNumber()) && generatePwd.equals(user.getUserPassword())) {
            String token = JWTUtils.generateToken(user);
            Map<String, String> map = new HashMap<>();
            map.put("username", user.getUserName());
            map.put("nickname", user.getUserNickname());
            map.put("phone", user.getUserTelephoneNumber());
            map.put("token", token);
            return JsonBuilder.buildSuccess(map);
        }


        return JsonBuilder.buildError("用户名或密码不正确");
    }
}

JWTUtils代码
package com.lhw.blog.tool;

import com.lhw.blog.domain.LhwUser;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;

import java.util.Date;

/**
 * @description: 用于生成和解析JWT
 * @author: lihongwei
 * @time: 2020/4/8 4:01 下午
 */
public class JWTUtils {

    /**
     * 密钥
     */
    private static String secret = "itzhongzi";

    /**
     * 过期时间
     */
    private static long expire = 1000 * 60 * 60 * 24 * 7;

    /**
     * 发行者
     */
    private static String subject = "lihongwei";

    /**
     *  使用 ID 和 pwssword 生成JWTtoken
     * @param user
     * @return
     */
    public static String generateToken(LhwUser user){
        if(user == null || user.getUserId() == null
                || user.getUserNickname().isEmpty()
                || user.getUserTelephoneNumber().isEmpty()
                || user.getUserPassword().isEmpty() ) {
            return null;
        }

        String jwtToken = Jwts.builder().setSubject(subject)
                .claim("id", user.getUserId())
                .claim("password", user.getUserPassword())
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + expire))
                .signWith(SignatureAlgorithm.HS256, secret)
                .compact();


        return  jwtToken;
    }

    /**
     * 检验 token
     * @param token
     * @return
     */
    public static Claims checkJWT(String token) {
        try {
            Claims body = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
            return body;
        } catch (Exception e) { }

        return null;
    }

}

接口测试
  1. 注册
  • localhost:8088/api/user/register?username=lihongwei&password=123456&phone=17862806858&nickname=以勒
	{
		    "code": 0,
		    "description": "成功",
		    "data": {
		        "phone": "17862806858",
		        "nickname": "以勒"
		    }
		}
  1. 登录
  • localhost:8088/api/user/login?phone=17862806857&password=123456
{
    "code": 0,
    "description": "success",
    "data": {
        "phone": "17862806857",
        "nickname": "以勒",
        "username": "lihongwei",
        "token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJsaWhvbmd3ZWkiLCJpZCI6NTYsInBhc3N3b3JkIjoiLTRuMzVvNGQxaWlxZjVqZGE4MDg2bDd2N2R0ODJmdTduIiwiaWF0IjoxNTg2NDg0MzI2LCJleHAiOjE1ODcwODkxMjZ9.acdQjApX99loBTPJdfpRYxdZDnFe0WRhp0KZlUAk75w"
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章