【java小程式實戰】redis快取session的實現
阿新 • • 發佈:2018-12-21
###內容目錄(由[TOC]自動生成)
文章目錄
一、有狀態session
當用戶訪問web網站的時候,會產生一個session,維護這使用者和系統的關係
二、無狀態session
當app端的使用者訪問網站的時候,沒有session這個會話,無法維護使用者和系統的關係。
三、redis-session
1、使用者資訊儲存到redis中,形成無狀態會話。
2、便於擴充套件,當單體應用擴充套件成叢集會相當方便。
3、便於許可權驗證。
四、redis應用
先去官網下載redis版本,並安裝,關於安裝的教程,大家可以自行百度。
1、pom依賴
<!-- 引入 redis 依賴 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.8.7.RELEASE</version> </dependency>
2、application.properties redis的配置
############################################################ # # redis 配置 # ############################################################ # Redis 資料庫索引(預設為0) spring.redis.database=1 # Redis伺服器地址 spring.redis.host=localhost # Redis伺服器埠號 spring.redis.port=6379 #Redis 伺服器連線密碼(預設為空) spring.redis.password= # 連線池最大連線數(使用負值表示沒有限制) spring.redis.pool.max-active=1000 #連線池最大阻塞等待時間(使用負值表示沒有限制) spring.redis.pool.max-wait=-1 # 連線池中最大空閒連線 spring.redis.pool.max-idle=10 # 連線池中的最小空閒連線 spring.redis.pool.min-idle=2 # 連線超時時間(毫秒) spring.redis.timeout=0
3、redis的一個工具類
package com.imooc.utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* 使用redisTemplate 的操作實現類
*/
@Component
public class RedisOperator {
@Autowired
private StringRedisTemplate stringRedisTemplate;
// Key (鍵),簡單的 key-value操作
/**
* 實現命令:TTL key, 以秒為單位,返回給定的key的剩餘時間)(ttl,time to live)
* @param key
* @return
*/
public long ttl(String key){
return stringRedisTemplate.getExpire(key);
}
/**
* 實現命令: expire ,設定過期時間,單位秒
* @param key
* @param timeout
*/
public void expire(String key, long timeout) {
stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS);
}
/**
* 實現命令: incr key ,增加key 一次
* @param key
* @param delta
* @return
*/
public long incr(String key, long delta){
return stringRedisTemplate.opsForValue().increment(key,delta);
}
/**
* 實現命令:KEYS pattern, 查詢所有符合給定模式 pattern 的key
* @param pattern
* @return
*/
public Set<String> keys(String pattern){
return stringRedisTemplate.keys(pattern);
}
/**
* 實現命令:DEL key ,刪除一個key
* @param key
*/
public void del(String key){
stringRedisTemplate.delete(key);
}
/**
* 實現命令: SET key value,設定一個key-value(將字串值value 關聯到key)
* @param key
* @param value
*/
public void set(String key, String value){
stringRedisTemplate.opsForValue().set(key, value);
}
/**
* 實現命令:SET key value time,設定一個key-value 過期時間。
* @param key
* @param value
* @param time
*/
public void set(String key, String value, long time){
stringRedisTemplate.opsForValue().set(key, value, time);
}
/**
* 實現命令: GET key,返回key所關聯的字串值
* @param key
* @return
*/
public String get(String key){
return (String)stringRedisTemplate.opsForValue().get(key);
}
// Hash (雜湊表)
/**
* 實現命令: HSET key field value ,將雜湊表key 中的域 field 的值設為value
* @param key
* @param field
* @param value
*/
public void hset(String key, String field, Object value){
stringRedisTemplate.opsForHash().put(key, field, value);
}
/**
* 實現命令:HGET key field,返回雜湊表 key中給定域field的值
* @param key
* @param field
* @return
*/
public String hget(String key, String field){
return (String) stringRedisTemplate.opsForHash().get(key, field);
}
/**
* 實現命令: HDEL key field[field...],刪除雜湊表 key 中的一個或多個指定域,不存在的域將被忽略。
* @param key
* @param fields
*/
public void hdel(String key, Object... fields){
stringRedisTemplate.opsForHash().delete(key, fields);
}
/**
* 實現命令: HGETALL key,返回雜湊表 key中,所有的域和值
* @param key
* @return
*/
public Map<Object, Object> hgetall(String key){
return stringRedisTemplate.opsForHash().entries(key);
}
//List (列表)
/**
* 實現命令: LPUSH key value,將一個值value 插入到列表 key 的表頭
* @param key
* @param value
* @return
*/
public long lpush(String key, String value){
return stringRedisTemplate.opsForList().leftPush(key, value);
}
/**
* 實現命令:LPOP key,移出並返回列表 key的頭元素。
* @param key
* @return
*/
public String lpop(String key) {
return (String)stringRedisTemplate.opsForList().leftPop(key);
}
/**
* 實現命令:RPUSH key value ,將一個值value 插入到列表 key 的表尾
* @param key
* @param value
* @return
*/
public long rpush(String key, String value){
return stringRedisTemplate.opsForList().rightPush(key, value);
}
}
4、在api模組,新建一個vo包,建立UsersVo物件,添加了一個userToken屬性。
package com.imooc.pojo.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import javax.persistence.Column;
import javax.persistence.Id;
@ApiModel(value = "使用者物件" ,description = "這是使用者物件")
public class UsersVo {
@ApiModelProperty(hidden = true)
private String id;
@ApiModelProperty(hidden = true)
private String userToken;
/**
* 使用者名稱
*/
@ApiModelProperty(value = "使用者名稱" , name = "username" , example = "csdnuser" ,required = true)
private String username;
/**
* 密碼
*/
@ApiModelProperty(value = "密碼" , name = "password" , example = "123456" ,required = true)
private String password;
/**
* 我的頭像,如果沒有預設給一張
*/
@ApiModelProperty(hidden = true)
private String faceImage;
/**
* 暱稱
*/
private String nickname;
/**
* 我的粉絲數量
*/
@ApiModelProperty(hidden = true)
private Integer fansCounts;
/**
* 我關注的人總數
*/
@ApiModelProperty(hidden = true)
private Integer followCounts;
/**
* 我接受到的讚美/收藏 的數量
*/
@ApiModelProperty(hidden = true)
private Integer receiveLikeCounts;
/**
* @return id
*/
public String getId() {
return id;
}
/**
* @param id
*/
public void setId(String id) {
this.id = id;
}
/**
* 獲取使用者名稱
*
* @return username - 使用者名稱
*/
public String getUsername() {
return username;
}
/**
* 設定使用者名稱
*
* @param username 使用者名稱
*/
public void setUsername(String username) {
this.username = username;
}
/**
* 獲取密碼
*
* @return password - 密碼
*/
public String getPassword() {
return password;
}
/**
* 設定密碼
*
* @param password 密碼
*/
public void setPassword(String password) {
this.password = password;
}
/**
* 獲取我的頭像,如果沒有預設給一張
*
* @return face_image - 我的頭像,如果沒有預設給一張
*/
public String getFaceImage() {
return faceImage;
}
/**
* 設定我的頭像,如果沒有預設給一張
*
* @param faceImage 我的頭像,如果沒有預設給一張
*/
public void setFaceImage(String faceImage) {
this.faceImage = faceImage;
}
/**
* 獲取暱稱
*
* @return nickname - 暱稱
*/
public String getNickname() {
return nickname;
}
/**
* 設定暱稱
*
* @param nickname 暱稱
*/
public void setNickname(String nickname) {
this.nickname = nickname;
}
/**
* 獲取我的粉絲數量
*
* @return fans_counts - 我的粉絲數量
*/
public Integer getFansCounts() {
return fansCounts;
}
/**
* 設定我的粉絲數量
*
* @param fansCounts 我的粉絲數量
*/
public void setFansCounts(Integer fansCounts) {
this.fansCounts = fansCounts;
}
/**
* 獲取我關注的人總數
*
* @return follow_counts - 我關注的人總數
*/
public Integer getFollowCounts() {
return followCounts;
}
/**
* 設定我關注的人總數
*
* @param followCounts 我關注的人總數
*/
public void setFollowCounts(Integer followCounts) {
this.followCounts = followCounts;
}
/**
* 獲取我接受到的讚美/收藏 的數量
*
* @return receive_like_counts - 我接受到的讚美/收藏 的數量
*/
public Integer getReceiveLikeCounts() {
return receiveLikeCounts;
}
/**
* 設定我接受到的讚美/收藏 的數量
*
* @param receiveLikeCounts 我接受到的讚美/收藏 的數量
*/
public void setReceiveLikeCounts(Integer receiveLikeCounts) {
this.receiveLikeCounts = receiveLikeCounts;
}
public String getUserToken() {
return userToken;
}
public void setUserToken(String userToken) {
this.userToken = userToken;
}
}
5、建立一個BasicController
package com.imooc.controller;
import com.imooc.utils.RedisOperator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class BasicController {
@Autowired
public RedisOperator redis;
public static final String USER_REDIS_SESSION = "user-redis-session";
}
5、對RegistLoginController進行修改
package com.imooc.controller;
import com.imooc.imoocvideosdevservice.com.imooc.service.UserService;
import com.imooc.pojo.Users;
import com.imooc.pojo.vo.UsersVo;
import com.imooc.utils.IMoocJSONResult;
import com.imooc.utils.MD5Utils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;
//返回格式為json格式
@RestController
@Api(value = "使用者註冊登陸的介面" , tags = {"註冊和登陸的controller"})
public class RegistLoginController extends BasicController {
@Autowired
private UserService userService;
@ApiOperation(value = "使用者註冊", notes = "使用者註冊的介面")
@PostMapping("/regist")
public IMoocJSONResult regist(@RequestBody Users user) throws Exception {
System.out.println("username:"+user.getUsername()+"password:"+user.getPassword());
//1、判斷使用者名稱和密碼是否為空
if(StringUtils.isBlank(user.getUsername()) || StringUtils.isBlank(user.getPassword())){
return IMoocJSONResult.errorMsg("使用者名稱和密碼不能為空");
}
//2、判斷使用者名稱是否存在
boolean usernameIsExist = userService.queryUsernameIsExist(user.getUsername());
//3、儲存使用者,註冊資訊
if(!usernameIsExist){
user.setNickname(user.getUsername());
user.setPassword(MD5Utils.getMD5Str(user.getPassword()));
user.setReceiveLikeCounts(0);
user.setFansCounts(0);
user.setFollowCounts(0);
userService.saveUser(user);
}else{
return IMoocJSONResult.errorMsg("使用者名稱已經存在");
}
//在註冊完畢,將使用者資料返回給前端之前,為了安全,將密碼設為null
user.setPassword("");
//使用uuid,設定使用者的value
// String uniqueToken = UUID.randomUUID().toString();
// redis.set(USER_REDIS_SESSION + ":" + user.getId(), uniqueToken, 1000 * 60 * 30);
// UsersVo usersVo = new UsersVo();
// BeanUtils.copyProperties(user, usersVo);
// usersVo.setUserToken(uniqueToken);
// 繫結使用者資訊到redis
UsersVo usersVo = setUserRedisSessionToken(user);
return IMoocJSONResult.ok(usersVo);
}
@ApiOperation(value= "使用者登陸" , notes = "使用者登陸介面")
@PostMapping("/login")
public IMoocJSONResult login(@RequestBody Users users) throws NoSuchAlgorithmException, InterruptedException {
Thread.sleep(3000);
String username = users.getUsername();
String password = users.getPassword();
//1、判斷使用者名稱和密碼不能為空
if (StringUtils.isBlank(username) || StringUtils.isBlank(password)){
return IMoocJSONResult.errorMsg("使用者名稱和密碼不能為空");
}
// 2、判斷使用者是否存在
Users userResult = userService.queryUserForLogin(username,MD5Utils.getMD5Str(password));
//3、返回
if (userResult !=null ){
//密碼設定為null,返回給前端
userResult.setPassword("");
//將使用者資訊進行redis設定
UsersVo usersVo = setUserRedisSessionToken(userResult);
return IMoocJSONResult.ok(usersVo);
} else {
return IMoocJSONResult.errorMsg("使用者名稱或密碼不正確,請重試...");
}
}
/**
* 將使用者資訊進行redis設定
* @param userModel
* @return
*/
public UsersVo setUserRedisSessionToken(Users userModel){
//使用uuid,設定使用者的value
String uniqueToken = UUID.randomUUID().toString();
redis.set(USER_REDIS_SESSION + ":" + userModel.getId(), uniqueToken, 1000 * 60 * 30);
UsersVo usersVo = new UsersVo();
BeanUtils.copyProperties(userModel, usersVo);
usersVo.setUserToken(uniqueToken);
return usersVo;
}
}
現在我們就可以重啟後端程式碼,通過小程式訪問。之後可以在Redis-Desktop Manager工具中檢視,快取的使用者資訊。
備註: 在controller中我們通過 一個 :(冒號)將同一類資訊,歸屬到同一個資料夾下。