最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Redis bitmap 實現(xiàn)簽到案例(最新推薦)

 更新時間:2024年07月06日 10:41:18   作者:一橘Java小菜鳥  
這篇文章主要介紹了Redis bitmap 實現(xiàn)簽到案例,通過設(shè)計簽到功能對應(yīng)的數(shù)據(jù)庫表,結(jié)合sql語句給大家講解的非常詳細,具體示例代碼跟隨小編一起看看吧

數(shù)據(jù)庫實現(xiàn)

設(shè)計簽到功能對應(yīng)的數(shù)據(jù)庫表

 CREATE TABLE `sign_record` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `user_id` bigint NOT NULL COMMENT '用戶id',
  `year` year NOT NULL COMMENT '簽到年份',
  `month` tinyint NOT NULL COMMENT '簽到月份',
  `date` date NOT NULL COMMENT '簽到日期',
  `is_backup` bit(1) NOT NULL COMMENT '是否補簽',
  PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='簽到記錄表';

這張表中的一條記錄是一個用戶一次的簽到記錄。假如一個用戶1年簽到100次,而網(wǎng)站有100萬用戶,就會產(chǎn)生1億條記錄。隨著用戶量增多、時間的推移,這張表中的數(shù)據(jù)只會越來越多,占用的空間也會越來越大。

redis bitmap 實現(xiàn)

一個用戶簽到的情況無非就兩種,要么簽了,要么沒。 可以用 0 或者1如果我們按月來統(tǒng)計用戶簽到信息,簽到記錄為1,未簽到則記錄為0,就可以用一個長度為31位的二級制數(shù)來表示一個用戶一個月的簽到情況。最終效果如下

java代碼

引入依賴

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.orchids</groupId>
  <artifactId>signinbybitmap</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>signinbybitmap</name>
  <description>signinbybitmap</description>
  <properties>
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <spring-boot.version>2.6.13</spring-boot.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.github.xiaoymin</groupId>
      <artifactId>knife4j-spring-boot-starter</artifactId>
      <version>3.0.3</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
  </dependencies>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>${spring-boot.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
          <encoding>UTF-8</encoding>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>${spring-boot.version}</version>
        <configuration>
          <mainClass>com.orchids.signinbybitmap.SignByBitmapApplication</mainClass>
          <skip>true</skip>
        </configuration>
        <executions>
          <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

配置文件

# 應(yīng)用服務(wù) WEB 訪問端口
server:
  port: 8080
spring:
  redis:
    host: localhost
    port: 6379
    password: 6379
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher

knife4j配置類

package com.orchids.signinbybitmap.web.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
//import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
 * @ Author qwh
 * @ Date 2024/7/5 13:08
 */
@Configuration
//@EnableSwagger2
public class knife4jConfiguration {
    @Bean
    public Docket webApiConfig(){
        // 創(chuàng)建Docket實例
        Docket webApi = new Docket(DocumentationType.SWAGGER_2)
        .groupName("StudentApi")
        .apiInfo(webApiInfo())
        .select()
        // 選擇需要文檔化的API,只顯示指定包下的頁面
        .apis(RequestHandlerSelectors.basePackage("com.orchids.signinbybitmap"))
        // 指定路徑匹配規(guī)則,只對/student開頭的路徑進行文檔化
        .paths(PathSelectors.regex("/User/.*"))
        .build();
        return webApi;
    }
    /**
     * 構(gòu)建API信息
     * 本函數(shù)用于創(chuàng)建并返回一個ApiInfo對象,該對象包含了API文檔的標題、描述、版本以及聯(lián)系方式等信息。
     * @return 返回構(gòu)建好的ApiInfo對象
     */
    private ApiInfo webApiInfo(){
        // 使用ApiInfoBuilder構(gòu)建API信息
        return new ApiInfoBuilder()
        .title("Student message API文檔") // 設(shè)置文檔標題
        .description("本文檔描述了Swagger2測試接口定義") // 設(shè)置文檔描述
        .version("1.0") // 設(shè)置文檔版本號
        .contact(new Contact("nullpointer", "http://blog.nullpointer.love", "nullpointer2024@gmail.com")) // 設(shè)置聯(lián)系人信息
        .build(); // 構(gòu)建并返回ApiInfo對象
    }
}

controller

package com.orchids.signinbybitmap.web.controller;
import com.orchids.signinbybitmap.web.domain.result.Result;
import com.orchids.signinbybitmap.web.domain.vo.SignResultVO;
import com.orchids.signinbybitmap.web.service.SignService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
/**
 * @ Author qwh
 * @ Date 2024/7/5 13:01
 */
@Api(tags = "簽到相關(guān)接口")
@RestController
@RequestMapping("/User")
@RequiredArgsConstructor
public class SignController {
    private final SignService signService;
    @ApiOperation("簽到")
    @GetMapping("Sign")
    public Result<SignResultVO> AddSignRecords() {
        return signService.AddSignRecords();
    }
}

service

package com.orchids.signinbybitmap.web.service;
import com.orchids.signinbybitmap.web.domain.result.Result;
import com.orchids.signinbybitmap.web.domain.vo.SignResultVO;
/**
 * @ Author qwh
 * @ Date 2024/7/5 13:35
 */
public interface SignService {
    Result<SignResultVO> AddSignRecords();
}

可以擴展其他功能

package com.orchids.signinbybitmap.web.service.impl;
import com.orchids.signinbybitmap.web.domain.result.Result;
import com.orchids.signinbybitmap.web.domain.vo.SignResultVO;
import com.orchids.signinbybitmap.web.exception.SignException;
import com.orchids.signinbybitmap.web.service.SignService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.LinkedList;
import java.util.List;
/**
 * @ Author qwh
 * @ Date 2024/7/5 13:35
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SignServiceImpl implements SignService {
    private final String SIGN_UID= "sign:uid:";
    private final StringRedisTemplate redisTemplate;
    @Override
    public Result<SignResultVO> AddSignRecords() {
        SignResultVO vo = new SignResultVO();
        //獲取簽到用戶
        Long userId = 1388888L;
        //獲取簽到日期
        LocalDateTime now = LocalDateTime.now();
        String format = now.format(DateTimeFormatter.ofPattern(":yyyy-MM-dd"));
        //設(shè)置redisKey   sign:uid:1388888:2024-07-05 5 1
        String key = SIGN_UID + userId.toString() + format;
        //計算簽到偏移量
        int offset = now.getDayOfMonth() - 1;
        //添加簽到記錄到redis
        Boolean sign = redisTemplate.opsForValue().setBit(key, offset, true);
        if (sign){
            throw new SignException("親!您今天已經(jīng)登錄過喲 (?′?`?)",520);
        }
        //計算連續(xù)簽到天數(shù)
        int day = now.getDayOfMonth();
        int continueDays = countSignDays(key,day);
        int rewardPoints = 0;
        switch (continueDays){
            case 2:
                rewardPoints = 10;
                break;
            case 4:
                rewardPoints=20;
                break;
            case 6:
                rewardPoints = 40;
                break;
        }
        //獲取簽到詳情信息
        List<Integer> signDayRecord = SignRecords(userId,key,day);
        vo.setUserId(userId.intValue());
        vo.setSignDays(continueDays);
        vo.setRewardPoints(rewardPoints);
        vo.setSignRecords(signDayRecord);
        return Result.ok(vo);
    }
    /**
     * 獲取連續(xù)簽到天數(shù)
     * @param key
     * @param days
     * @return
     */
    private int countSignDays(String key, int days) {
        //從redis讀取簽到記錄
        List<Long> nums = redisTemplate.opsForValue().bitField(key, BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(days)).valueAt(0));
        //計算簽到次數(shù)
        int num = nums.get(0).intValue();
        //num與1進行與計算得到二進制的末尾 當(dāng)末尾為1 說明簽到 為0 說明沒有簽到
        int result = 0;
        while ((num & 1) == 1) {
            result++;
            num = num >>>1;
        }
        //返回簽到結(jié)果
        return result;
    }
    /**
     * 獲取簽到詳情
     * @param userId
     * @param key
     * @param day
     * @return
     */
    private List<Integer> SignRecords(Long userId, String key, int day) {
        //獲取從redis中獲取登錄信息
        List<Long> sign = redisTemplate.opsForValue().bitField(key, BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(day)).valueAt(0));
        int num = sign.get(0).intValue();
        LinkedList<Integer> result = new LinkedList<>();
        while (day > 0) {
            result.addFirst(num & 1);
            num = num >>> 1;
            day--;
        }
        return result;
    }
}

其他類

package com.orchids.signinbybitmap.web.domain.result;
import lombok.Data;
/**
 * @ Author qwh
 * @ Date 2024/7/5 16:52
 */
@Data
public class Result<T> {
    //返回碼
    private Integer code;
    //返回消息
    private String message;
    //返回數(shù)據(jù)
    private T data;
    public Result() {
    }
    private static <T> Result<T> build(T data) {
        Result<T> result = new Result<>();
        if (data != null)
            result.setData(data);
        return result;
    }
    public static <T> Result<T> build(T body, ResultCode resultCode) {
        Result<T> result = build(body);
        result.setCode(resultCode.getCode());
        result.setMessage(resultCode.getMessage());
        return result;
    }
    public static <T> Result<T> ok(T data) {
        return build(data, ResultCode.SUCCESS);
    }
    public static <T> Result<T> ok() {
        return Result.ok(null);
    }
    public static <T> Result<T> fail(Integer code, String message) {
        Result<T> result = build(null);
        result.setCode(code);
        result.setMessage(message);
        return result;
    }
    public static <T> Result<T> fail() {
        return build(null, ResultCode.FAIL);
    }
}
package com.orchids.signinbybitmap.web.domain.result;
import lombok.Getter;
/**
 * @ Author qwh
 * @ Date 2024/7/5 16:54
 */
@Getter
public enum ResultCode {
    SUCCESS(200, "成功"),
    FAIL(201, "失敗"),
    PARAM_ERROR(202, "參數(shù)不正確"),
    SERVICE_ERROR(203, "服務(wù)異常"),
    DATA_ERROR(204, "數(shù)據(jù)異常"),
    ILLEGAL_REQUEST(205, "非法請求"),
    REPEAT_SUBMIT(206, "重復(fù)提交"),
    DELETE_ERROR(207, "請先刪除子集"),
    ADMIN_ACCOUNT_EXIST_ERROR(301, "賬號已存在"),
    ADMIN_CAPTCHA_CODE_ERROR(302, "驗證碼錯誤"),
    ADMIN_CAPTCHA_CODE_EXPIRED(303, "驗證碼已過期"),
    ADMIN_CAPTCHA_CODE_NOT_FOUND(304, "未輸入驗證碼"),
    ADMIN_ACCOUNT_NOT_EXIST(330,"用戶不存在"),
    ADMIN_LOGIN_AUTH(305, "未登陸"),
    ADMIN_ACCOUNT_NOT_EXIST_ERROR(306, "賬號不存在"),
    ADMIN_ACCOUNT_ERROR(307, "用戶名或密碼錯誤"),
    ADMIN_ACCOUNT_DISABLED_ERROR(308, "該用戶已被禁用"),
    ADMIN_ACCESS_FORBIDDEN(309, "無訪問權(quán)限"),
    APP_LOGIN_AUTH(501, "未登陸"),
    APP_LOGIN_PHONE_EMPTY(502, "手機號碼為空"),
    APP_LOGIN_CODE_EMPTY(503, "驗證碼為空"),
    APP_SEND_SMS_TOO_OFTEN(504, "驗證法發(fā)送過于頻繁"),
    APP_LOGIN_CODE_EXPIRED(505, "驗證碼已過期"),
    APP_LOGIN_CODE_ERROR(506, "驗證碼錯誤"),
    APP_ACCOUNT_DISABLED_ERROR(507, "該用戶已被禁用"),
    TOKEN_EXPIRED(601, "token過期"),
    TOKEN_INVALID(602, "token非法");
    private final Integer code;
    private final String message;
    ResultCode(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}
package com.orchids.signinbybitmap.web.domain.vo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.models.auth.In;
import lombok.Data;
import java.util.List;
/**
 * @ Author qwh
 * @ Date 2024/7/5 13:36
 */
@Data
@ApiModel(description = "簽到結(jié)果")
public class SignResultVO {
    @ApiModelProperty("簽到人")
    private Integer UserId;
    @ApiModelProperty("簽到得分")
    private Integer signPoints = 1;
    @ApiModelProperty("連續(xù)簽到天數(shù)")
    private Integer signDays;
    @ApiModelProperty("連續(xù)簽到獎勵積分,連續(xù)簽到超過7天以上才有獎勵")
    private Integer rewardPoints;
    @ApiModelProperty("簽到詳細信息")
    private List<Integer> signRecords;
}
package com.orchids.signinbybitmap.web.exception;
import com.orchids.signinbybitmap.web.domain.result.Result;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
 * @ Author qwh
 * @ Date 2024/7/5 16:51
 */
@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Result error(Exception e){
        e.printStackTrace();
        return Result.fail();
    }
    @ExceptionHandler(SignException.class)
    @ResponseBody
    public Result error(SignException e){
        e.printStackTrace();
        return Result.fail(e.getCode(), e.getMessage());
    }
}
package com.orchids.signinbybitmap.web.exception;
import lombok.Data;
/**
 * @ Author qwh
 * @ Date 2024/7/5 16:47
 */
@Data
public class SignException extends RuntimeException{
    //異常狀態(tài)碼
    private Integer code;
    /**
     * 通過狀態(tài)碼和錯誤消息創(chuàng)建異常對象
     * @param message
     * @param code
     */
    public SignException(String message, Integer code) {
        super(message);
        this.code = code;
    }
    @Override
    public String toString() {
        return "SignException{" +
                "code=" + code +
                ", message=" + this.getMessage() +
                '}';
    }
}
package com.orchids.signinbybitmap;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SignByBitmapApplication {
    public static void main(String[] args) {
        SpringApplication.run(SignByBitmapApplication.class, args);
    }
}

測試結(jié)果

到此這篇關(guān)于Redis bitmap 實現(xiàn)簽到案例的文章就介紹到這了,更多相關(guān)Redis bitmap 簽到內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Redis cluster集群模式的原理解析

    Redis cluster集群模式的原理解析

    這篇文章主要介紹了Redis cluster集群模式的原理解析,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • Redis 哨兵高模式搭建及Java代碼配置

    Redis 哨兵高模式搭建及Java代碼配置

    這篇文章主要介紹了Redis 哨兵高模式搭建及Java代碼配置,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Redisson 加鎖解鎖的實現(xiàn)

    Redisson 加鎖解鎖的實現(xiàn)

    本文主要介紹了Redisson 加鎖解鎖的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • Redis分布式緩存的安裝

    Redis分布式緩存的安裝

    這篇文章主要介紹了Redis分布式緩存的安裝,Redis?是一個開源(BSD許可)的,內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)存儲系統(tǒng),它可以用作數(shù)據(jù)庫、緩存和消息中間件,需要的朋友可以參考下
    2023-05-05
  • Redis秒殺實現(xiàn)方案講解

    Redis秒殺實現(xiàn)方案講解

    這篇文章主要介紹了Redis秒殺實現(xiàn)方案,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-12-12
  • redis緩存與數(shù)據(jù)庫一致性的問題及解決

    redis緩存與數(shù)據(jù)庫一致性的問題及解決

    這篇文章主要介紹了redis緩存與數(shù)據(jù)庫一致性的問題及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • Redis利用互斥鎖解決緩存擊穿問題

    Redis利用互斥鎖解決緩存擊穿問題

    使用互斥鎖可以有效防止緩存擊穿的情況發(fā)生,它能夠保證在緩存失效時,只有一個線程或者進程能夠去加載數(shù)據(jù),其余的請求都會等待這個加載過程完成,雖然這種方式會犧牲一部分性能,但它大大提高了系統(tǒng)的穩(wěn)定性和可用性
    2024-08-08
  • 在redisCluster中模糊獲取key方式

    在redisCluster中模糊獲取key方式

    這篇文章主要介紹了在redisCluster中模糊獲取key方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • 淺談redis在項目中的應(yīng)用

    淺談redis在項目中的應(yīng)用

    下面小編就為大家?guī)硪黄獪\談redis在項目中的應(yīng)用。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-12-12
  • 深入理解Redis 內(nèi)存管理

    深入理解Redis 內(nèi)存管理

    本文主要介紹了深入理解Redis 內(nèi)存管理,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-02-02

最新評論

昌黎县| 安义县| 鄯善县| 西青区| 逊克县| 孝昌县| 上高县| 嘉义县| 广昌县| 南川市| 麟游县| 芦溪县| 清新县| 岳普湖县| 陇南市| 冷水江市| 马边| 册亨县| 皋兰县| 敦煌市| 开江县| 渭南市| 昆明市| 武定县| 金沙县| 滨州市| 西峡县| 安仁县| 仙桃市| 郧西县| 汽车| 安国市| 景宁| 大英县| 雷波县| 黔江区| 颍上县| 班戈县| 瑞安市| 长顺县| 伽师县|