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"
}
}