Nacos引入

1.拉取nacos镜像

docker pull nacos/nacos-server:v2.2.3

2.配置MySQL数据库

为什么要外置MySQL数据库
数据持久性:使⽤MySQL作为外置数据库可以确保数据被持久化存储,这对于确保服务的稳定性和数据的可靠性⾄关重要。
⾼可⽤性:Nacos⽀持集群部署,⽽使⽤MySQL作为共享的数据存储可以确保集群中各个节点之间的数据⼀致性。此外,MySQL⾃⾝也⽀持⾼可⽤性和故障转移,如使⽤主从复制或集群解决⽅案,从⽽进⼀步提⾼系统的可⽤性。
性能优化:使⽤nacos内置的数据库虽然能够简化部署,但是性能受到限制,外置的MySQL可以根据需要进⾏优化和扩展,满⾜更⾼的性能要求。
易于管理和维护:现在让 Nacos也连接外置的 MySQL 数据库(且和系统用的是同一种 MySQL),这样做能让技术栈更统一,从而简化数据库相关的管理、维护工作,减少运维成本。
独立的数据库 能数据备份 对权限进行控制 安全性搞 而且容易迁移数据 

3.创建表sql

/******************************************/
/* 库名称 = bitoj_nacos_local */
/******************************************/
create database bitoj_nacos_local;
use bitoj_nacos_local;
/******************************************/
/* 表名称 = config_info */
/******************************************/
CREATE TABLE `config_info` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) DEFAULT NULL COMMENT 'group_id',
`content` longtext NOT NULL COMMENT 'content',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`tenant_id` varchar(128) DEFAULT '' COMMENT '租⼾字段',
`c_desc` varchar(256) DEFAULT NULL COMMENT 'configuration description',
`c_use` varchar(64) DEFAULT NULL COMMENT 'configuration usage',
`effect` varchar(64) DEFAULT NULL COMMENT '配置⽣效的描述',
`type` varchar(64) DEFAULT NULL COMMENT '配置的类型',
`c_schema` text COMMENT '配置的模式',
`encrypted_data_key` text NOT NULL COMMENT '密钥',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info';

/******************************************/
/* 表名称 = config_info_aggr */
/******************************************/
CREATE TABLE `config_info_aggr` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`datum_id` varchar(255) NOT NULL COMMENT 'datum_id',
`content` longtext NOT NULL COMMENT '内容',
`gmt_modified` datetime NOT NULL COMMENT '修改时间',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`tenant_id` varchar(128) DEFAULT '' COMMENT '租⼾字段',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfoaggr_datagrouptenantdatum` (`data_id`,`group_id`,`tenant_id`,`datum_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='增加租⼾字段';


/******************************************/
/* 表名称 = config_info_beta */
/******************************************/
CREATE TABLE `config_info_beta` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`content` longtext NOT NULL COMMENT 'content',
`beta_ips` varchar(1024) DEFAULT NULL COMMENT 'betaIps',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
`tenant_id` varchar(128) DEFAULT '' COMMENT '租⼾字段',
`encrypted_data_key` text NOT NULL COMMENT '密钥',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfobeta_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_beta';

/******************************************/
/* 表名称 = config_info_tag */
/******************************************/
CREATE TABLE `config_info_tag` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
`tag_id` varchar(128) NOT NULL COMMENT 'tag_id',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`content` longtext NOT NULL COMMENT 'content',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfotag_datagrouptenanttag` (`data_id`,`group_id`,`tenant_id`,`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_tag';

/******************************************/
/* 表名称 = config_tags_relation */
/******************************************/
CREATE TABLE `config_tags_relation` (
`id` bigint(20) NOT NULL COMMENT 'id',
`tag_name` varchar(128) NOT NULL COMMENT 'tag_name',
`tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
`nid` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'nid, ⾃增⻓标识',
PRIMARY KEY (`nid`),
UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation';

/******************************************/
/* 表名称 = group_capacity */
/******************************************/
CREATE TABLE `group_capacity` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表⽰整个集 群',
`quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表⽰使⽤默认值',
`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使⽤量',
`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置⼤⼩上限,单位 为字节,0表⽰使⽤默认值',
`max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合⼦配置最⼤ 个数,,0表⽰使⽤默认值',
`max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的⼦ 配置⼤⼩上限,单位为字节,0表⽰使⽤默认值',
`max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最⼤变更历史 数量',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_group_id` (`group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量 信息表';

/******************************************/
/* 表名称 = his_config_info */
/******************************************/
CREATE TABLE `his_config_info` (
`id` bigint(20) unsigned NOT NULL COMMENT 'id',
`nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'nid, ⾃增标识',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`content` longtext NOT NULL COMMENT 'content',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
`op_type` char(10) DEFAULT NULL COMMENT 'operation type',
`tenant_id` varchar(128) DEFAULT '' COMMENT '租⼾字段',
`encrypted_data_key` text NOT NULL COMMENT '密钥',
PRIMARY KEY (`nid`),
KEY `idx_gmt_create` (`gmt_create`),
KEY `idx_gmt_modified` (`gmt_modified`),
KEY `idx_did` (`data_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租⼾改造';


/******************************************/
/* 表名称 = tenant_capacity */
/******************************************/
CREATE TABLE `tenant_capacity` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID',
`quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表⽰使⽤默认值',
`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使⽤量',
`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置⼤⼩上限,单位 为字节,0表⽰使⽤默认值',
`max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合⼦配置最⼤ 个数',
`max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的⼦ 配置⼤⼩上限,单位为字节,0表⽰使⽤默认值',
`max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最⼤变更历史 数量',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租⼾容量信息表';


CREATE TABLE `tenant_info` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`kp` varchar(128) NOT NULL COMMENT 'kp',
`tenant_id` varchar(128) default '' COMMENT 'tenant_id',
`tenant_name` varchar(128) default '' COMMENT 'tenant_name',
`tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc',
`create_source` varchar(32) DEFAULT NULL COMMENT 'create_source',
`gmt_create` bigint(20) NOT NULL COMMENT '创建时间',
`gmt_modified` bigint(20) NOT NULL COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';

CREATE TABLE `users` (
`username` varchar(50) NOT NULL PRIMARY KEY COMMENT 'username',
`password` varchar(500) NOT NULL COMMENT 'password',
`enabled` boolean NOT NULL COMMENT 'enabled'
);

CREATE TABLE `roles` (
`username` varchar(50) NOT NULL COMMENT 'username',
`role` varchar(50) NOT NULL COMMENT 'role',
UNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE
);

CREATE TABLE `permissions` (
`role` varchar(50) NOT NULL COMMENT 'role',
`resource` varchar(128) NOT NULL COMMENT 'resource',
`action` varchar(8) NOT NULL COMMENT 'action',
UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE
);

INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE);

INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');

赋予ojtest用户管理这个数据库的权力

GRANT ALL PRIVILEGES ON bitoj_nacos_local.* TO 'ojtest'@'%';

4.启动nacos容器

docker run -d -p 8848:8848 -p 9848:9848 --name oj-nacos -e MODE=standalone -e 
JVM_XMS=256m -e JVM_XMX=256m -e SPRING_DATASOURCE_PLATFORM=mysql -e 
MYSQL_SERVICE_HOST=${mysql_ip} -e MYSQL_SERVICE_PORT=${mysql_port} -e 
MYSQL_SERVICE_DB_NAME=${nacos_db_name} -e MYSQL_SERVICE_USER=${mysql_user} -e 
MYSQL_SERVICE_PASSWORD=${mysql_password} nacos/nacos-server:v2.2.3
  • docker run:启动一个 Docker 容器。
  • -d:让容器在后台(守护进程模式)运行,不会占用当前终端
  • -p 8848:8848 -p 9848:9848:端口映射,将容器内的 8848(Nacos 主要访问端口)和 9848(Nacos 相关通信端口)映射到宿主机的同名端口,这样外部可以通过宿的 8848 和 9848 端口访问 Nacos。
  • --name oj-nacos:给启动的容器命名为 oj-nacos,方便后续通过名称管理容器(比如停止、删除容器)
  • 以 -e 开头的部分:都是设置环境变量,用于配置 Nacos 的运行参数:

mysql_ip

docker inspect oj-mysql;

mysql_port: 3306 

db_name : bitoj_nacos_local

mysql_user : ojtest

mysql_password:123456

5.项⽬中引⼊

引⼊依赖
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
nacos配置设置:

修改bootstrap.yml
spring:
  application:
    # 应用名称
    name: oj-system
  profiles:
    # 环境配置
    active: local
  cloud:
    nacos:
      discovery:
        namespace: 78015f37-f9d0-4c31-8970-cc017a0923ff
        server-addr: http://localhost:8848
      config:
        namespace: 78015f37-f9d0-4c31-8970-cc017a0923ff
        server-addr: http://localhost:8848
        file-extension: yaml

API⽹关---Gateway

⽹关的核⼼作⽤:

权限控制: 作为微服务的⼊⼝, 对⽤⼾进⾏权限校验, 如果校验失败则进⾏拦截
动态路由: ⼀切请求先经过⽹关, 但⽹关不处理业务, ⽽是根据某种规则, 把请求转发到某个微服务
负载均衡: 当路由的⽬标服务有多个时, 还需要做负载均衡
限流: 请求流量过⾼时, 按照⽹关中配置微服务能够接受的流量进⾏放⾏, 避免服务压⼒过⼤.
我们将使⽤springcloud gateway作为我们项⽬的api⽹关。

引⼊⽹关

1.创建服务

2.引入依赖
<dependencies>
    <!-- SpringCloud Gateway -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>

    <!-- SpringCloud Loadbalancer -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    </dependency>

    <!-- SpringCloud Alibaba Nacos Discovery -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>

    <!-- SpringCloud Alibaba Nacos Config -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>

</dependencies>
3.配置Nacos

bootstrap.yml

# Spring
spring:
  application:
    # 应用名称
    name: oj-gateway
  profiles:
    # 环境配置
    active: local
  cloud:
    nacos:
      discovery:
        namespace: 78015f37-f9d0-4c31-8970-cc017a0923ff
        server-addr: http://localhost:8848
      config:
        namespace: 78015f37-f9d0-4c31-8970-cc017a0923ff
        server-addr: http://localhost:8848
        file-extension: yaml
4.启动类
@SpringBootApplication

public class OjGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(OjGatewayApplication.class, args);
    }
}

⾝份认证

⾝份认证⽅式

我们将使⽤JWT认证机制,完成⽤⼾⾝份的认证。

Jwt(JSON Web Token

JWT组成:
它由三部分组成:头部(header)、载荷(payload)和签名(signature)。

头部(header):包含令牌的类型和使⽤的算法。
使⽤base64编码
载荷(payload):包含⽤⼾信息和其他元数据。(使⽤base64编码)
使⽤base64编码
签名(signature):⽤于验证令牌的完整性和真实性。

⾝份认证流程:
客⼾端使⽤户名跟密码请求登录 。
服务端收到请求,去验证⽤⼾名与密码 。
验证成功后,服务端会签发⼀个Token,再把这个Token发送给客⼾端 。(token上述的jwt串)
客⼾端收到Token以后可以把它存储起来,⽐如放在Cookie⾥或者Local Storage⾥ 。
客⼾端每次向服务端请求资源的时候需要带着服务端签发的Token 。
服务端收到请求,然后去验证客⼾端请求⾥⾯带着的Token,如果验证成功,就向客⼾端返回请求的数据 。
为什么选择JWT
简单⽅便:JWT认证机制不需要像传统的Session认证那样在服务器端存储任何会话信息,所有的认证和授权信息都包含在JWT中。这种⽅式简化了认证流程,减少了服务器的负担。
安全可靠:JWT使⽤数字签名来验证其完整性和真实性,确保数据在传输过程中不被篡改。
⽀持跨域JWT认证机制中在客⼾端与服务器进⾏通信时,客⼾端会将JWT作为请求的⼀部分发送 给服务器,不依赖于浏览器的cookie或session,因此不会受到同源策略的限制。
问题分析
提出问题:⾝份认证仅仅使⽤jwt机制就可以吗?
jwt中payload中存储⽤⼾相关信息,采⽤base64编码,没有加密因此jwt中不能存储敏感数据。
但是我们的⼀些业务逻辑中需要获取当前登录⽤⼾⼀些敏感信息参与到业务逻辑中
jwt是⽆状态的,因此如果想要修改⾥⾯的内容就必须重新签发⼀次新的jwt
⽤⼾修改⾃⼰个⼈信息之后就需要重新登录
⽆法延⻓jwt的过期时间
⽤⼾正在操作突然⾝份认证失败
问题处理思路:
1.payload中不能存放敏感信息。
  • payload中仅仅存储⽤⼾唯⼀标识信息。
  •  需要第三⽅存储机制,作为辅助存储⽤于⽤⼾⾝份认证的信息。存储需要保证安全、可靠。
  •  不需要⻓期存储,仅在⽤⼾处于登录状态时使⽤。
2.想办法⽤⼾修改了个⼈信息之后,jwt不变。
  • payload中仅仅存储⽤⼾唯⼀标识信息,那么修改⽤⼾信息就不会引起jwt改变。
3.能够控制jwt的过期时间
  •  jwt的过期时间,不通过jwt机制提供的⽅法设置
  •  通过第三⽅组件设置并记录jwt的过期时间。
具体处理⽅案:
我们将使⽤redis + jwt的结构完成⾝份认证。jwt中仅存储⽤⼾的唯⼀标识信息,使⽤redis作为第三⽅存储机制,存储⽤于⽤⼾⾝份认证的信息,并通过redis控制jwt的过期时间。

Redis引入

安装redis
docker pull redis
启动redis容器
docker run --name oj-redis -d -p 6379:6379 redis --requirepass "123456"
创建oj-common-redis⼯程

引⼊redis依赖
    <dependencies>
        <!-- SpringBoot Boot Redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <!-- Alibaba Fastjson -->
        <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
            <version>${fastjson2.version}</version>
        </dependency>
    </dependencies>

提供redis配置

序列化:让存入Redis的数据是JSON类型,取出来的时候是你所需类型

package com.bite.common.redis.config;
import com.alibaba.fastjson2.JSON;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import java.nio.charset.Charset;

public class JsonRedisSerializer<T> implements RedisSerializer<T> {
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
    private Class<T> clazz;

    public JsonRedisSerializer(Class<T> clazz) {
        super();
        this.clazz = clazz;
    }

    @Override
    public byte[] serialize(T t) throws SerializationException {
        if (t == null) {
            return new byte[0];
        }
        return JSON.toJSONString(t).getBytes(DEFAULT_CHARSET);
    }

    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        if (bytes == null || bytes.length <= 0) {
            return null;
        }
        String str = new String(bytes, DEFAULT_CHARSET);
        return JSON.parseObject(str, clazz);
    }
}

修改Redis存入方式

利用创建Bean的方式,来序列化和反序列化存入redis的value值(这里需要用到上面写的那个类帮助)

package com.bite.common.redis.config;

import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig extends CachingConfigurerSupport {

    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);

        JsonRedisSerializer serializer = new JsonRedisSerializer(Object.class);

        // 序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());
        //因为value里面可能会存放一些对象
        template.setValueSerializer(serializer);

        // Hash的key和value序列化方式
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(serializer);

        template.afterPropertiesSet();
        return template;
    }
}
封装service

为什么封装service:

抽象与解耦:

言语简化:你封装Service后如果你的其他服务和你对应的接口改变了的时候,你只用修改你的Service层即可,而不用修改大量代码(类似于门面模式)

统⼀接⼝:

言语简化:如果有好多个第三方工具,但是他们的方法不同(前提:类似),你只需要进行封装,把他们变成一个统一的接口样式即可,而不用理解底层代码

扩展性

代码可读性与维护性

import com.alibaba.fastjson2.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
public class RedisService {

    @Autowired
    public RedisTemplate redisTemplate;

    // 操作key
    public Boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    public boolean expire(final String key, final long timeout) {
        return expire(key, timeout, TimeUnit.SECONDS);
    }

    public boolean expire(final String key, final long timeout, final TimeUnit unit) {
        return redisTemplate.expire(key, timeout, unit);
    }

    public boolean deleteObject(final String key) {
        return redisTemplate.delete(key);
    }

    // 操作String类型
    public <T> void setCacheObject(final String key, final T value) {
        redisTemplate.opsForValue().set(key, value);
    }

    public <T> void setCacheObject(final String key, final T value, final Long timeout, final TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
    }

    public <T> T getCacheObject(final String key, Class<T> clazz) {
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        T t = operation.get(key);
        if (t instanceof String) {
            return t;
        }
        return JSON.parseObject(String.valueOf(t), clazz);
    }

    // 操作list结构
    public Long getListSize(final String key) {
        return redisTemplate.opsForList().size(key);
    }

    public <T> List<T> getCacheListByRange(final String key, long start, long end, Class<T> clazz) {
        List range = redisTemplate.opsForList().range(key, start, end);
        if (CollectionUtils.isEmpty(range)) {
            return null;
        }
        return JSON.parseArray(JSON.toJSONString(range), clazz);
    }

    public <T> Long rightPushAll(final String key, Collection<T> list) {
        return redisTemplate.opsForList().rightPushAll(key, list);
    }

    public <T> Long leftPushForList(final String key, T value) {
        return redisTemplate.opsForList().leftPush(key, value);
    }

    public <T> Long removeForList(final String key, T value) {
        return redisTemplate.opsForList().remove(key, 1L, value);
    }

    // 操作Hash类型
    public <T> T getCacheMapValue(final String key, final String hKey, Class<T> clazz) {
        Object cacheMapValue = redisTemplate.opsForHash().get(key, hKey);
        if (cacheMapValue != null) {
            return JSON.parseObject(String.valueOf(cacheMapValue), clazz);
        }
        return null;
    }

    public <T> List<T> getMultiCacheMapValue(final String key, final Collection<String> hKeys, Class<T> clazz) {
        List list = redisTemplate.opsForHash().multiGet(key, hKeys);
        List<T> result = new ArrayList<>();
        for (Object item : list) {
            result.add(JSON.parseObject(JSON.toJSONString(item), clazz));
        }
        return result;
    }

    public <T> void setCacheMapValue(final String key, final String hKey, final T value) {
        redisTemplate.opsForHash().put(key, hKey, value);
    }

    public <K, T> void setCacheMap(final String key, final Map<K, T> dataMap) {
        if (dataMap != null) {
            redisTemplate.opsForHash().putAll(key, dataMap);
        }
    }

    public Long deleteCacheMapValue(final String key, final String hKey) {
        return redisTemplate.opsForHash().delete(key, hKey);
    }
}
创建org.springframework.boot.autoconfigure.AutoConfiguration.imports⽂件

配置redis主机地址和密码

具体服务引入依赖
 <dependency>
        <groupId>com.bite</groupId>
        <artifactId>oj-common-redis</artifactId>
        <version>${oj-common-redis.version}</version>
        <scope>compile</scope>
    </dependency>

代码测试
 @RequestMapping("/redisadd")
    public String RedisAddGet(){
        SysUser sysUser=new SysUser();
        sysUser.setUserAccount("redisadd");
        redisService.setCacheObject("u",sysUser);
        SysUser ans=redisService.getCacheObject("u",SysUser.class);
        return ans.toString();
    }

更多推荐