【java小程序实战】redis缓存session的实现

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

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/taojin12/article/details/84853420