git 项目地址
git项目地址
https://github.com/MrITzhongzi/blog-system.git
逻辑梳理
- 用户注册需要提供手机号,密码等信息,后台会自动把密码加密存入数据库
- 同一个手机号只能注册一个
- 登录的时候会验证手机号密码
- 登录成功后台会根据用户信息生成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值。
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;
}
}
接口测试
- 注册
- localhost:8088/api/user/register?username=lihongwei&password=123456&phone=17862806858&nickname=以勒
{
"code": 0,
"description": "成功",
"data": {
"phone": "17862806858",
"nickname": "以勒"
}
}
- 登录
- localhost:8088/api/user/login?phone=17862806857&password=123456
{
"code": 0,
"description": "success",
"data": {
"phone": "17862806857",
"nickname": "以勒",
"username": "lihongwei",
"token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJsaWhvbmd3ZWkiLCJpZCI6NTYsInBhc3N3b3JkIjoiLTRuMzVvNGQxaWlxZjVqZGE4MDg2bDd2N2R0ODJmdTduIiwiaWF0IjoxNTg2NDg0MzI2LCJleHAiOjE1ODcwODkxMjZ9.acdQjApX99loBTPJdfpRYxdZDnFe0WRhp0KZlUAk75w"
}
}