Redis Basic Application Demo

Posted by sosha on Thu, 25 Jun 2020 09:51:27 +0200

Article catalog

1, Redis common command operations

1. String type

Assignment command: set key value

Value command: get key

Increasing number: incr key

Number decrement: incr key

Increase the specified integer: increment key increment

Reduce the specified integer: decrby key increment

E:\Redis>redis-cli.exe
127.0.0.1:6379> set test:name zhangsan
OK
127.0.0.1:6379> get test:name
"zhangsan"
127.0.0.1:6379> incr num  -- Automatic initialization num,And return the result after adding 1
(integer) 1
127.0.0.1:6379> decr num  -- Returns the result after subtracting 1
(integer) 0
127.0.0.1:6379> incrby num 5 -- Return the result after adding 5
(integer) 5
127.0.0.1:6379> decrby num 4 -- Return the result after subtracting 5
(integer) 1
127.0.0.1:6379>

2. Hash type

Assignment command: hset key field value returns 1 to indicate that the new Field has been set to a new value, 0 to indicate that the Field already exists, and overwrites the original value with the new value

Value instruction: hget key field

Delete instruction: hdel key field

127.0.0.1:6379> hset test:teacher username zhangsan -- value yes hash Types include key-value
(integer) 1
127.0.0.1:6379> hget test:teacher username
"zhangsan"
127.0.0.1:6379> hset test:person id 1
(integer) 1
127.0.0.1:6379> hget test:person id
"1"
127.0.0.1:6379> hset test:person id 2
(integer) 0
127.0.0.1:6379> hdel test:person id
(integer) 1

3. List type list

list can be made into stack and queue. If it is left in, right out, stack, left in, left out, queue

Add an element to the list header: lpush key value [value ]Number of elements in the list after inserting successfully

Add an element to the end of the list: rpushkey value [value ]Number of elements in the list after inserting successfully

Element stack from the left: the first step of lpop key is to remove the element on the left of the list, and the second step is to return the removed element value

The first step is to remove the elements on the right side of the list, and the second step is to return the removed element values

Get the number of elements in the list: len key

Get the element value of the specified index: lindex key index this command will return the element of the specified location (index) in the linked list. The index is 0-based

Get list: lrange key start stop returns the list of elements in the specified range.

127.0.0.1:6379> lpush list 1 2 3 4 5
(integer) 5
127.0.0.1:6379> lpop list
"5"
127.0.0.1:6379> llen list
(integer) 4
127.0.0.1:6379> lindex list 2
"2"
127.0.0.1:6379> rpop list
"1"

4. Unordered set

Add element: sadd key memer returns the number of elements actually inserted into the collection

Get the number of elements in the collection: scar key

Pop an element from the collection: pop key returns the removed member (arbitrary)

Determine whether the element is in the collection: sismer key member returns 1 to indicate that it already exists, 0 to indicate that it does not exist

127.0.0.1:6379> sadd myset 1
(integer) 1
127.0.0.1:6379> sadd myset 2 3 4
(integer) 3
127.0.0.1:6379> scard myset
(integer) 4
127.0.0.1:6379> spop myset
"2"
127.0.0.1:6379> sismember myset 3
(integer) 1
127.0.0.1:6379>

5. Ordered sort

Add element: zadd key score member [score] [member] add successfully returns the number of members actually inserted

Get the number of elements in the collection: zcard key

Get the number of elements in the specified score range: zcount key min max this command is used to get the number of members whose score is between min and Max

Get score of element: zscore key member

Increase the score of an element: zincrby key increment member

Get the ranking of elements: zrank key member

127.0.0.1:6379> zadd myzset 1 a 2 b 3 c
(integer) 3
127.0.0.1:6379> zcard myzset
(integer) 3
127.0.0.1:6379> zcount myzset 1 3
(integer) 3
127.0.0.1:6379> zscore myzset a
"1"
127.0.0.1:6379> zscore myzset c
"3"
127.0.0.1:6379> zincrby myzset 2 a
"3"
127.0.0.1:6379> zscore myzset a
"3"
127.0.0.1:6379> zrank myzset a
(integer) 1
127.0.0.1:6379> zrank myzset c
(integer) 2
127.0.0.1:6379>

2, Distributed shared session

Implementation ideas:
(1) The login page submits the user name and password.
(2) Generate token after login. Token is equivalent to the original sessionid, string, and uuid can be used.
(3) Save the user information to redis. Key is token and value is userId.
(4) Set the expiration time of the key. Simulate the expiration time of the Session. Generally one hour.
(5) Interceptor intercept request verification sessionId

1. LoginReqVO login user to submit user name and password

@Data
public class LoginReqVO {
    @ApiModelProperty(value = "user name")
    private String username;

    @ApiModelProperty(value = "password")
    private String password;
}

2. LoginRespVO responds user information and token to browser

@Data
public class LoginRespVO {
    @ApiModelProperty(value = "User authentication certificate")
    private String token;

    @ApiModelProperty(value = "user id")
    private String userId;
}

3,UserServiceImpl

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private RedisTemplate redisTemplate;
    @Override
    public LoginRespVO login(LoginReqVO vo) {
        //Find the user in the database summary according to the submitted user name
        SysUser sysUser = sysUserMapper.selectByUsername(vo.getUsername());

        //If the user does not exist
        if(sysUser==null){
            throw new BusinessException(4001005,"The user does not exist, please register first");
        }

        //If the user status is disabled
        if(sysUser.getStatus()==2){
            throw new BusinessException(4001006,"This account has been disabled. Please contact the system administrator");
        }

        //If the user password is incorrect (encrypt the plaintext and compare it with the password in the database)
 if(!PasswordUtils.matches(sysUser.getSalt(),vo.getPassword(),sysUser.getPassword())){
            throw new BusinessException(4001007,"User name and password do not match");
        }

        //Login succeeded, generate token
        String token= UUID.randomUUID().toString();

        //Respond token and user information to browser
        LoginRespVO respVO=new LoginRespVO();
        respVO.setUserId(sysUser.getId());
        respVO.setToken(token);

        //Put the user information in the redis cache. The key is the token and the value is the user information. At the same time, set the token expiration time to 60s
        redisTemplate.opsForValue().set(token,sysUser.getId(),60, TimeUnit.MINUTES);
        return respVO;
    }
}

4,UserController

@RestController
@RequestMapping("/api")
@Api(tags = "User module")
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping("/user/login")
    @ApiOperation(value = "User login interface")
    public LoginRespVO login(@RequestBody LoginReqVO vo){
        return userService.login(vo);
    }
}

5. Configure interception path: login registration request cannot be intercepted and needs to be released

@Configuration
public class WebAppConfig implements WebMvcConfigurer {
    @Bean
    public TokenInterceptor tokenInterceptor(){
        return new TokenInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(tokenInterceptor())
.addPathPatterns("/api/**").excludePathPatterns("/api/user/login","/api/user/register","/api/user/code/*");
    }
}

6. TokenInterceptor configuration Interceptor: for other requests except login registration, interceptors are required to determine whether the user is in login status.

public class TokenInterceptor implements HandlerInterceptor {
    @Autowired
    private RedisService redisService;

    private RedisTemplate redisTemplate;

    //Intercept the login request and verify whether the user is in login state before executing the Controller layer method
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //Get token from request header
        String token=request.getHeader("token");
        //Judge whether the token is empty
        if(StringUtils.isEmpty(token)){
            throw new BusinessException(4001002,"User certificate cannot be empty, please login again");
        }else {
            //If the token is not empty, you need to determine whether the token is valid
            if(!redisTemplate.hasKey(token)){
                throw new BusinessException(4001002,"User credentials are invalid, please login again");
            }
        }
        return true;
    }
}

3, Remote login reminder offline

Recently, I received a request from the product that an account can only be logged in at one place at the same time. If it is logged in at other places, it will prompt that it has been logged in elsewhere. At the same time, the same browser can only log in to one user at the same time.

Implementation ideas:

(1) The login page submits the user name and password.

(2) Generate token after login.

(3) Save the user information to redis. Key is token and value is userId.

(4) Set the expiration time of the key.

(5) Store the token in redis, key is userid, and value is the token

(6) Interceptor intercepts request verification token.

(7) After obtaining the userId, compare whether the token carried by the header is consistent with the token marked by redis. In case of inconsistency, the user will be prompted that he has logged in from another place.

1, LoginReqVO

@Data
public class LoginReqVO {
    @ApiModelProperty(value = "user name")
    private String username;

    @ApiModelProperty(value = "password")
    private String password;
}

2,LoginRespVO

@Data
public class LoginRespVO {
    @ApiModelProperty(value = "User authentication certificate")
    private String token;

    @ApiModelProperty(value = "user id")
    private String userId;
}

3. UserServiceImpl: after the user logs in successfully, generate a token and respond to the browser

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private RedisTemplate redisTemplate;
    
    @Override
    public LoginRespVO login(LoginReqVO vo) {
        //Find the user in the database summary according to the submitted user name
        SysUser sysUser = sysUserMapper.selectByUsername(vo.getUsername());

        //If the user does not exist
        if(sysUser==null){
            throw new BusinessException(4001005,"The user does not exist, please register first");
        }

        //If the user status is disabled
        if(sysUser.getStatus()==2){
            throw new BusinessException(4001006,"This account has been disabled. Please contact the system administrator");
        }

        //If the user password is incorrect
        if(!PasswordUtils.matches(sysUser.getSalt(),vo.getPassword(),sysUser.getPassword())){
            throw new BusinessException(4001007,"User name and password do not match");
        }

        //Login succeeded, generate token
        String token= UUID.randomUUID().toString();

        //Respond token and user information to browser
        LoginRespVO respVO=new LoginRespVO();
        respVO.setUserId(sysUser.getId());
        respVO.setToken(token);

        //Put the user information in the redis cache. The key is the token, and the value is the user information. The expiration time is 60 minutes
        redisTemplate.opsForValue().set(token,sysUser.getId(),60, TimeUnit.MINUTES);

        //Mark token, store token into redis cache, key is userId, value is token, expiration time is 60 minutes
        redisTemplate.opsForValue().set(sysUser.getId(),token,60,TimeUnit.MINUTES);
        return respVO;
    }
}

4,UserController:

@RestController
@RequestMapping("/api")
@Api(tags = "User module")
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping("/user/login")
    @ApiOperation(value = "User login interface")
    public LoginRespVO login(@RequestBody LoginReqVO vo){
        return userService.login(vo);
    }
}

5. Configure interceptor interception path: release login

@Configuration
public class WebAppConfig implements WebMvcConfigurer {
    @Bean
    public TokenInterceptor tokenInterceptor(){
        return new TokenInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(tokenInterceptor())
                .addPathPatterns("/api/**").excludePathPatterns("/api/user/login","/api/user/register","/api/user/code/*");
    }
}

6. Configure Interceptor: judge whether the token of the front end passing through the class is consistent with the token of the redis cache

public class TokenInterceptor implements HandlerInterceptor {
    @Autowired
    private RedisService redisService;

    private RedisTemplate redisTemplate;

    //Intercept the login request and verify whether the user is in login state before executing the Controller layer method
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //Get token from request header
        String token=request.getHeader("token");
        //Judge whether the token is empty
        if(StringUtils.isEmpty(token)){
            throw new BusinessException(4001002,"User certificate cannot be empty, please login again");
        }else {
            //Determine whether the token in the cache expires
            if(!redisTemplate.hasKey(token)){
                throw new BusinessException(4001002,"User credentials are invalid, please login again");
            }

            //Get the value userId according to the key token
            String userId= (String) redisTemplate.opsForValue().get(token);

            //If there is no userId in redis or the token passed from the browser does not match the token in redis cache
if(redisTemplate.hasKey(userId)&&!token.equals(redisTemplate.opsForValue().get(userId)){
                throw new BusinessException(4001002,"Your account has been logged in from another place, please log in again");
            }
        }
        return true;
    }
}

4, Register SMS verification code

SMS verification code is one of the essential basic functional modules of all projects. If one day suddenly you are assigned a requirement by your leader. Check the mobile number when the user registers.

The requirements are as follows:
(1) Check mobile number when registering
(2) Each mobile phone number can send up to five registered SMS verification codes every day
(3) The verification code is valid for 5 minutes.

Ideas:
(1) Verify that the phone number meets the requirements before sending.
(2) Generate SMS verification code.
(3) Send the verification code to the phone.
(4) Store the verification code in redis
(5) Mark mobile number
(6) Check whether the mobile number and verification code are correct when registering

1,RegisterReqVO

@Data
public class RegisterReqVO {
    @ApiModelProperty(value = "account number")
    private String username;
    @ApiModelProperty(value = "cell-phone number")
    private String phone;
    @ApiModelProperty(value = "password")
    private String password;
    @ApiModelProperty(value = "Verification Code")
    private String code;
}

2. Contact: key to build redis

 */
public class Contant {

    /**
     * Judge whether it reaches the online key
     */
    public final static String REGISTER_CODE_COUNT_KEY="register-code-count-key_";

    /**
     * Validation code validity key
     */
    public final static String REGISTER_CODE_COUNT_VALIDITY_KEY="register-code-count-validity-key_";
}

3,UserServiceImpl

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private RedisTemplate redisTemplate;
    
    /**
     * Get verification code
     */
    @Override
    public String getCode(String phone) {
        //Verify the phone number is legal
        Pattern pattern = Pattern.compile("^1(3|4|5|7|8)\\d{9}$");
        Matcher matcher = pattern.matcher(phone);
        if(!matcher.matches()) {
            throw  new BusinessException(4001004,"Mobile number format error");
        }
        //Add 1 to the number of times for each access to the verification code to determine whether the access to the verification code exceeds the limit
        long count = redisTemplate.opsForValue().increment(Contant.REGISTER_CODE_COUNT_KEY+phone,1);
        if(count>5){
            throw new BusinessException(4001004,"The delivery limit of the day has been reached");
        }

        //Generate 6-bit random number as verification code
        String code=generateCode();
      
        //Store the generated verification code in redis with an expiration time of 5 minutes
        redisService.set(Contant.REGISTER_CODE_COUNT_VALIDITY_KEY+phone,code,5,TimeUnit.MINUTES;
        //Send SMS here with output simulation
        System.out.println(code);
        return code;
    }

    /**
     * Generate six digit verification code
     */
    private String generateCode(){
        Random random = new Random();
        int x = random.nextInt(899999);
        String code = String.valueOf(x + 100000);
        return code;
    }

    /**
     * User registration
     */
    @Override
    public String register(RegisterReqVO vo) {

        //Judge whether the verification code is valid
        if(!redisTemplate.hasKey(Contant.REGISTER_CODE_COUNT_VALIDITY_KEY+vo.getPhone()){
            throw new BusinessException(4001008,"The verification code is invalid. Please get it again");
        }
        //Check whether the verification code is correct (whether the verification code passed from the front end is consistent with that in the redis cache)
        if(!vo.getCode().equals(redisTemplate.opsForValue().get(Contant.REGISTER_CODE_COUNT_VALIDITY_KEY+vo.getPhone()))){
         throw new BusinessException(4001009,"Please enter the correct verification code");
        }

        SysUser sysUser = sysUserMapper.selectByUsername(vo.getUsername());
        if(sysUser!=null){
            throw new BusinessException(4001010,"The user name is already registered");
        }

        //Constructing user information to store in database
        SysUser user=new SysUser();
        //Property copy
        BeanUtils.copyProperties(vo,user);
        user.setId(UUID.randomUUID().toString());
        user.setCreateTime(new Date());
        String salt=PasswordUtils.getSalt();
        String ecdPwd=PasswordUtils.encode(vo.getPassword(),salt);
        user.setSalt(salt);
        user.setPassword(ecdPwd);
        int i = sysUserMapper.insertSelective(user);

        if(i!=1){
            throw new BusinessException(4001011,"operation failed");
        }

        //Clear redis cache when registration is successful
        redisTemplate.delete(Contant.REGISTER_CODE_COUNT_VALIDITY_KEY+vo.getPhone());
        redisTemplate.delete(Contant.REGISTER_CODE_COUNT_KEY+vo.getPhone());

        return "login was successful";
    }
}

4,UserController

@RestController
@RequestMapping("/api")
@Api(tags = "User module")
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping("/user/register")
    @ApiOperation(value = "User registration interface")
    public String register(@RequestBody RegisterReqVO vo){
        return userService.register(vo);
    }
    
    @GetMapping("/user/code/{phone}")
    public String getCode(@PathVariable("phone") String phone){
        return userService.getCode(phone);
    }
}

Topics: Redis Mobile Database Session