###内容目录(由[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中我们通过 一个 :(冒号)将同一类信息,归属到同一个文件夹下。