亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

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

設計簽到功能對應的數(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>

配置文件

# 應用服務 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;
    }
    /**
     * 構建API信息
     * 本函數(shù)用于創(chuàng)建并返回一個ApiInfo對象,該對象包含了API文檔的標題、描述、版本以及聯(lián)系方式等信息。
     * @return 返回構建好的ApiInfo對象
     */
    private ApiInfo webApiInfo(){
        // 使用ApiInfoBuilder構建API信息
        return new ApiInfoBuilder()
        .title("Student message API文檔") // 設置文檔標題
        .description("本文檔描述了Swagger2測試接口定義") // 設置文檔描述
        .version("1.0") // 設置文檔版本號
        .contact(new Contact("nullpointer", "http://blog.nullpointer.love", "nullpointer2024@gmail.com")) // 設置聯(lián)系人信息
        .build(); // 構建并返回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 = "簽到相關接口")
@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"));
        //設置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進行與計算得到二進制的末尾 當末尾為1 說明簽到 為0 說明沒有簽到
        int result = 0;
        while ((num & 1) == 1) {
            result++;
            num = num >>>1;
        }
        //返回簽到結果
        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, "服務異常"),
    DATA_ERROR(204, "數(shù)據(jù)異常"),
    ILLEGAL_REQUEST(205, "非法請求"),
    REPEAT_SUBMIT(206, "重復提交"),
    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, "無訪問權限"),
    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 = "簽到結果")
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);
    }
}

測試結果

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

相關文章

  • Redis緩存鍵清理問題解決

    Redis緩存鍵清理問題解決

    對于使用redis作為緩存服務器的開發(fā)者而言,定期清除redis中的緩存數(shù)據(jù)是非常必要的,本文主要介紹了Redis緩存鍵清理問題解決,具有一定的參考價值,感興趣的可以了解一下
    2024-06-06
  • 淺談一下如何保證Redis緩存與數(shù)據(jù)庫的一致性

    淺談一下如何保證Redis緩存與數(shù)據(jù)庫的一致性

    這篇文章主要介紹了一下如何保證Redis緩存與數(shù)據(jù)庫的一致性,今天這篇文章就帶你詳細了解一下四種同步策略,需要的朋友可以參考下
    2023-03-03
  • Redis集群水平擴展、集群中添加以及刪除節(jié)點的操作

    Redis集群水平擴展、集群中添加以及刪除節(jié)點的操作

    這篇文章主要介紹了Redis集群水平擴展、集群中添加以及刪除節(jié)點的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-03-03
  • Redis如何一鍵部署腳本

    Redis如何一鍵部署腳本

    這篇文章主要介紹了Redis如何一鍵部署腳本,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-04-04
  • 詳解redis在微服務領域的貢獻

    詳解redis在微服務領域的貢獻

    本文以dubbo為例看下redis是如何利用自身特性來完成注冊中心的功能,對redis微服務相關知識感興趣的朋友一起看看吧
    2021-10-10
  • Redis+IDEA實現(xiàn)單機鎖和分布式鎖的過程

    Redis+IDEA實現(xiàn)單機鎖和分布式鎖的過程

    這篇文章主要介紹了Redis+IDEA實現(xiàn)單機鎖和分布式鎖的過程,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-07-07
  • 基于 Redis 的 JWT令牌失效處理方案(實現(xiàn)步驟)

    基于 Redis 的 JWT令牌失效處理方案(實現(xiàn)步驟)

    當用戶登錄狀態(tài)到登出狀態(tài)時,對應的JWT的令牌需要設置為失效狀態(tài),這時可以使用基于Redis 的黑名單方案來實現(xiàn)JWT令牌失效,本文給大家分享基于 Redis 的 JWT令牌失效處理方案,感興趣的朋友一起看看吧
    2024-03-03
  • Redis 對比 Memcached 并在 CentOS 下進行安裝配置詳解

    Redis 對比 Memcached 并在 CentOS 下進行安裝配置詳解

    Redis 是一個開源、支持網(wǎng)絡、基于內存、鍵值對的 Key-Value 數(shù)據(jù)庫,本篇文章主要介紹了Redis 對比 Memcached 并在 CentOS 下進行安裝配置詳解,有興趣的可以了解一下。
    2016-11-11
  • Spring+Redis+RabbitMQ開發(fā)限流和秒殺項目功能

    Spring+Redis+RabbitMQ開發(fā)限流和秒殺項目功能

    本項目將通過整合Springboot和Redis以及Lua腳本來實現(xiàn)限流和秒殺的效果,將通過RabbitMQ消息隊列來實現(xiàn)異步保存秒殺結果的效果,對Spring?Redis?RabbitMQ限流秒殺功能實現(xiàn)感興趣的朋友一起看看吧
    2022-02-02
  • 基于Redis 實現(xiàn)網(wǎng)站PV/UV數(shù)據(jù)統(tǒng)計

    基于Redis 實現(xiàn)網(wǎng)站PV/UV數(shù)據(jù)統(tǒng)計

    PV和UV是兩個重要的指標,本文主要介紹了基于Redis 實現(xiàn)網(wǎng)站PV/UV數(shù)據(jù)統(tǒng)計,具有一定的參考價值,感興趣的可以了解一下
    2025-04-04

最新評論