启动服务时,将字典表数据加载到redis中

一、使用工具

  1. 后端开发工具:IntelliJ IDEA 2020.3
  2. 前端开发工具:Microsoft VS Code 1.50.1
  3. 数据库工具:Navicat Premium 15.0.20
  4. Redis可视化工具:RDM

二、创建Maven项目

由于项目包含用户、账户、字典等多个部分,每部分分别建立module,因此字典的外层命名为basic-dictionary,其中分为dictionary-api和dictionary-biz两个module。
——api中放字典表实体bean和vo;
——biz中放启动加载数据至redis方法和字典表增删改查并对redis进行操作的后端代码。
下图是已建立完成的目录结构,启动类DictionaryBizApplication
在这里插入图片描述

三、配置nacos

在dictionary-biz的resources中建立bootstrap.yml文件配置nacos的ip端口和命名空间id

spring:
  profiles:
    active: dev
  application:
    name: uip-dictionary-biz
  cloud:
    nacos:
      config:
        server-addr: ip地址:默认8848
        file-extension: yaml
        namespace: 命名空间id
        group: 组名

涂抹部分为命名空间id
在这里插入图片描述
在命名空间下创建字典相关配置yaml
Data Id:uip-dictionary-biz-dev.yaml
Group:与配置文件中的组名相同
配置内容:

##端口号
server:
  port: 7707
##Nacos安全隐患问题修正
nacos:
  core:
    auth:
      enable:
        userAgentAuthWhite: false

spring:
  cloud:
    nacos:
      discovery:
        server-addr: ${spring.cloud.nacos.config.server-addr}
        namespace: ${spring.cloud.nacos.config.namespace}
        group: ${spring.cloud.nacos.config.group}
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://数据库ip:3306/库名?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&useSSL=false
    username: 用户名
    password: 密码
  redis:
    database: 0   ##分配在redis的db0中(db0-db15)
    host: redis服务器ip
    port: 6379
    password: 密码
mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      logic-delete-field: DELETED  # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 'Y' # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 'N' # 逻辑未删除值(默认为 0)

四、创建实体

1、创建表实体

已有数据库表uip-dictionary如下所示
在这里插入图片描述
在dictionary-api的entity文件夹中创建表实体

@Data
@EqualsAndHashCode(callSuper = true)
@TableName("uip_dictionary")
@Accessors(chain = true)
public class UipDictionary extends BaseEntity<UipDictionary> {
    private static final long serialVersionUID = 1L;

    @TableField("name")
    @ApiModelProperty(value = "字典名称")
    private String name;

    @TableField("sort_code")
    @ApiModelProperty(value = "同级排序代码")
    private String sortCode;

    @TableField("value")
    @ApiModelProperty(value = "字典值")
    private String value;

    @TableField("type_code")
    @ApiModelProperty(value = "字典类型代码")
    private String typeCode;

    @TableField("status")
    @ApiModelProperty(value = "字典状态 0-已启用,1-已禁用")
    private String status;

    @TableField("defaulted")
    @ApiModelProperty(value = "默认标志 Y-已默认,N-未默认")
    private String defaulted;

    @TableField("remark")
    @ApiModelProperty(value = "菜单描述")
    private String remark;

}

继承的BaseEntity中将id、乐观锁等全部表共同字典提取出来。

@Data
@EqualsAndHashCode(callSuper=true)
@ApiModel
public abstract class BaseEntity<T extends Model<?>> extends Model<T> implements Serializable    {
    private static final long serialVersionUID = 1L;

    @JsonSerialize(using= ToStringSerializer.class)
    @TableId(value = "id", type = IdType.ASSIGN_ID)
    @ApiModelProperty(value = "唯一标识")
    public Long id;

    @Version
    @ApiModelProperty(value = "乐观锁")
    private Long revision;

    @TableField(value = "created_by", fill = FieldFill.INSERT)
    @ApiModelProperty(value = "创建人")
    private String createdBy;
    
    @TableField(value = "created_time", fill = FieldFill.INSERT)
    @ApiModelProperty(value = "创建时间")
    private LocalDateTime createdTime;
    
    @TableField(value = "updated_by", fill = FieldFill.INSERT_UPDATE)
    @ApiModelProperty(value = "更新人")
    private String updatedBy;
    
    @TableField(value = "updated_time", fill = FieldFill.INSERT_UPDATE)
    @ApiModelProperty(value = "更新时间")
    private LocalDateTime updatedTime;
}

※注意:由于id字段使用的分布式id类型IdType.ASSIGN_ID,保存数据时自动生成19位纯数字,数据库字段是bigint类型,在前端获取时由于精度不同会导致最后3位数据全部是000,因此在所有id相关字段加上此注解@JsonSerialize(using= ToStringSerializer.class)

2、创建vo

在dictionary-api的vo文件夹中创建RedisDictionariesVO,此文件只用于前台查询redis数据使用

@Data
@NoArgsConstructor
public class RedisDictionariesVO implements Serializable {
    //实现Serializable 否则Application启动时redis加载数据会报错,此VO无法序列化

    @ApiModelProperty(value = "字典名称")
    private String name;

    @ApiModelProperty(value = "字典值")
    private String value;
}

关于实现Serializable的问题,我在开发的过程中,如果没加这个实现会导致启动服务时报错,而其他同事开发别的redis服务时没有添加也可启动。

五、创建启动

在dictionary-biz中的component文件夹中创建InitDictionariesCacheRunner

@Component
@AllArgsConstructor
@Slf4j
public class InitDictionariesCacheRunner implements CommandLineRunner {

    private final RedisTemplate redisTemplate;
    private final DictionaryBizService dictionaryBizService;

    @Override
    public void run(String... args) throws Exception {

        redisTemplate.delete(BasicConstants.DICTIONARIES_KEY);

        //查询所有字典数据
        List<UipDictionary> uipDictionaries = dictionaryBizService.list();
        //定义字典type数组
        List<String> typeCodeList = uipDictionaries.stream().map(UipDictionary::getTypeCode).collect(Collectors.toList());
        //遍历type_code数组
        typeCodeList.forEach(str->{
            //根据type_code查询对应的name和value
            List<RedisDictionariesVO> listmap = dictionaryBizService.queryByTypeCode(str);
            Map<String, List<RedisDictionariesVO>> dictionariesMap = new TreeMap<>();

            Optional.ofNullable(listmap).orElse(new ArrayList<>()).forEach(uipDictionary -> {
                dictionariesMap.put(str, listmap);
            });

            redisTemplate.opsForHash().putAll(BasicConstants.DICTIONARIES_KEY, dictionariesMap);
        });

    }
}

BasicConstants.DICTIONARIES_KEY是自定义的内容

/**
     * Redis缓存字典规则Key(Key-Value)
     */
    String DICTIONARIES_KEY = "basic:dictionaries";

至此,启动Application后即可在RDM中查看是否将字典表中已有数据加载。
key:字典类型,表字段type_code
value:字典code和value的list集合。
在这里插入图片描述


内容仅供参考,一切请与实际开发为准。


版权声明:本文为zhaopai012原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。