SpringBoot中集成Redis

news2024/10/5 14:14:10

目标

在原有SpringBoot项目中,集成Redis,并实现Dao层,Service层,Controller层。

pom.xml

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

使用Spring Boot的Redis依赖。

application-dev.yaml

spring:
  redis:
    host: ${REDIS_HOST:localhost}
    port: ${REDIS_PORT:6379}
    database: 0
    password: ${REDIS_PASSWORD}

RedisConfig.java



import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @author zyl
 */
@Configuration
public class RedisConfig {

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory();
    }
    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory());
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.activateDefaultTyping(om.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用jackson的序列化方式
        template.setHashKeySerializer(jackson2JsonRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

这里配置使用redis的链接池,以及key,hash key和数据存储使用的序列化方式。

Domain层

City.java

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * @author zyl
 */
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class City implements Serializable {
    private Long id;

    private String name;

    private String state;

    private String country;
}

注意:这里要实现Serializable接口,只有这样,我们这里使用的Redis依赖库才能够正常使用。

Dao层

CityDao.java

/**
 * @author zyl
 */
public interface CityDao {
    void save(City city);
    City findById(Long id);

    void delete(Long id);
}

上面是Dao的定义层,下面来看看Dao的实现层:

CityDaoImpl.java

import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * @author zyl
 */
@Repository
public class CityDaoImpl implements CityDao {
    private static final String HASH_REFERENCE = "City";

    @Resource
    private RedisTemplate<String, City> redisTemplate;

    @Override
    public void save(City city) {
        Long id = city.getId();
        String key = HASH_REFERENCE + "_" + id;
        BoundHashOperations<String, Long, City> boundHashOperations = redisTemplate.boundHashOps(key);
        boundHashOperations.putIfAbsent(id, city);
        boundHashOperations.expire(60, TimeUnit.SECONDS);
    }

    @Override
    public City findById(Long id) {
        String key = HASH_REFERENCE + "_" +id;
        BoundHashOperations<String, Long, City> boundHashOperations = redisTemplate.boundHashOps(key);
        return boundHashOperations.get(id);
    }

    @Override
    public void delete(Long id) {
        String key = HASH_REFERENCE + "_" +id;
        BoundHashOperations<String, Long, City> boundHashOperations = redisTemplate.boundHashOps(key);
        boundHashOperations.delete(id);
    }
}

注意这里重点是通过BoundHashOperations类来实现Redis相关对象的操作。BoundHashOperations类是操作Redis的重点类。如果使用通过HashOperations类让redis里面的数据过期处理,有点麻烦,故这里使用BoundHashOperations类处理。

VO层

ApiRes.java

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.http.HttpStatus;

/**
 * 通用响应类
 * @author zyl
 */
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
public class ApiRes<T> {
    private int status = HttpStatus.OK.value();
    private String message;
    private T data;

    public static final String SUCCESS_MSG = "操作成功";
    public static final String ERROR_MSG = "操作成功";

    /**
     * 返回成功数据
     * @author zyl
     * @return 成功消息
     */
    public static <T> ApiRes<T> success(T data)
    {
        return ApiRes.success(SUCCESS_MSG, data);
    }

    /**
     * 返回成功消息
     * @author zyl
     * @param msg 返回内容
     * @return 成功消息
     */
    public static <T> ApiRes<T> success(String msg)
    {
        return ApiRes.success(msg, null);
    }

    /**
     * 返回成功消息
     * @author zyl
     * @param msg 返回内容
     * @param data 数据对象
     * @return 成功消息
     */
    public static <T> ApiRes<T> success(String msg, T data)
    {
        return new ApiRes<>(HttpStatus.OK.value(), msg, data);
    }

    /**
     * 返回错误消息
     * @author zyl
     */
    public static <T> ApiRes<T> error()
    {
        return ApiRes.error(ERROR_MSG);
    }

    /**
     * 返回错误消息
     * @author zyl
     * @param msg 返回内容
     * @return 警告消息
     */
    public static <T> ApiRes<T> error(String msg)
    {
        return ApiRes.error(msg, null);
    }

    /**
     * 返回错误消息
     * @author zyl
     * @param msg 返回内容
     * @param data 数据对象
     * @return 警告消息
     */
    public static <T> ApiRes<T> error(String msg, T data)
    {
        return new ApiRes<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), msg, data);
    }

    /**
     * 返回错误消息
     * @author zyl
     * @param msg 返回内容
     * @param code 响应编码
     * @return 警告消息
     */
    public static <T> ApiRes<T> error(int code, String msg)
    {
        return new ApiRes<>(code, msg, null);
    }
}

这里定义实现了统一响应VO,下面继续实现定义City的响应VO:

CityRes.java

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author zyl
 */
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class CityRes {
    private Long id;

    private String name;

    private String state;

    private String country;
}

City响应VO定义实现。

Service层

CityService.java

/**
 * 测试city模板
 * @author zyl
 */
public interface CityService {

    ApiRes<CityRes> findByState(String state);

    ApiRes<CityRes> findById(Long id);

    void delete(Long id);
}

CityServiceImpl.java

import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @author zyl
 */
@Service
public class CityServiceImpl implements CityService {

    @Resource
    private CityMapper cityMapper;

    @Resource
    private CityDao cityDao;
    @Override
    public ApiRes<CityRes> findByState(String state) {
        City city = cityMapper.findByState(state);
        if (city == null) {
            throw new HandleException("没有找到城市数据");
        }
        CityRes cityRes = CityRes.builder().build();
        BeanUtils.copyProperties(city, cityRes);
        return ApiRes.success(cityRes);
    }

    @Override
    public ApiRes<CityRes> findById(Long id) {
        // 先查缓存
        City city = cityDao.findById(id);
        if (city == null) {
            // 查数据库
            city = cityMapper.findById(id);
            if (city != null) {
                // 更新缓存
                cityDao.save(city);
            }
        }

        if (city == null) {
            throw new HandleException("没有找到城市数据");
        }
        CityRes cityRes = CityRes.builder().build();
        BeanUtils.copyProperties(city, cityRes);
        return ApiRes.success(cityRes);
    }

    @Override
    public void delete(Long id) {
        cityMapper.delete(id);
        cityDao.delete(id);
    }
}

这里的HandleException类,是自定义异常处理类,这里就不再给出详细实现了。CityMapper类是mybatis的相关定义实现,这不是这里需要关注的,故也不再给出详细实现了。

Controller层

HelloController.java

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;

/**
 * 测试模板
 * @author zyl
 */
@RefreshScope
@RestController
@RequestMapping("/hello")
public class HelloController {

    @Resource
    private CityService cityService;

    @GetMapping("/city/findById")
    public ResponseEntity<ApiRes<CityRes>> cityFindById(@RequestParam Long id) {
        return ResponseEntity.ok(cityService.findById(id));
    }

    @GetMapping("/city/delete")
    public ResponseEntity<ApiRes<String>> cityDelete(@RequestParam Long id) {
        cityService.delete(id);
        ApiRes<String> apiRes = ApiRes.success("删除成功");
        return ResponseEntity.ok(apiRes);
    }
}

SQL

drop table if exists city;
create table city (id int primary key auto_increment, name varchar(200), state varchar(200), country varchar(200));
insert into city (name, state, country) values ('San Francisco', 'CA', 'US');
insert into city (name, state, country) values ('San Francisco2', 'CA2', 'US2');

测试

这里只看看Redis里面存的数据效果图:

redis存数据效果
看看postman中的响应:
获取数据postman

总结

这里主要使用BoundHashOperations类来处理redis中的对象。为什么不使用HashOperations类?因为不能直接使用HashOperations类对对象进行过期时间设置,而BoundHashOperations类可以这弄。这里值得注意的是,我们只能对Redis里面的整个散列进行过期,不能对散列里面的具体key过期。这一点Redis规范要注意一下。具体如下图:
redis hashs
我们能对1过期,但是不能对2进行过期处理。HashOperations类就是把多个对象存在一个1里面,我们这里为了实现单个对象过期处理,就只能使用BoundHashOperations类,在一个1里面存一个对象,这样实现对一个对象的redis过期。
总的来说,BoundHashOperations类可以自己过期Redis数据,HashOperations类没有直接过期数据方法。

参考:

  • Redis hashes
  • Spring boot redis javadoc
  • Spring Boot Redis CRUD Example

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/662180.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大数据云计算运维之Nginx反向代理与负载均衡

Nginx 简介 一、Nginx概述 1.1 概述 Nginx&#xff08;“engine x”&#xff09;是一个高性能的 HTTP /反向代理的服务器及电子邮件&#xff08;IMAP/POP3)代理服务器。 官方测试nginx能够支撑5万并发&#xff0c;并且cpu&#xff0c;内存等资源消耗却非常低&#xff0c;运…

合并reducer

reducer工程化第一步&#xff1a;合并 各个模块下reducer的模板: 1.符是代表直接从src下面进行寻找 2.定义初始状态 3.深拷贝状态 4.进行行为判断 votereducer这么写&#xff1f; 合并reducer 导出总的reducer 模块化开发后往事件池放的更新方法&#xff0c;在disptch的时候…

交换机新设备版本升级(超详细!快进来学习!)

本文主要讲述了华三新上架交换机机设备升级全过程&#xff01;同理&#xff0c;其他的交换机设备进行升级也是同样的思路&#xff01; 升级流程 1、使用console线以及网线将电脑和交换机进行连接&#xff08;console口和网口&#xff09;; 2、打开以太网卡&#xff0c;“控制面…

25k字图文解读YOLOv8及实例分割(附python代码)

学习使用 未经详细专业审核 目录 0.引言1.概述1.1 Backbone1.2 Head1.3 Loss1.4 Train 2.模型结构2.1 Backbone和Neck的具体变化2.2 Head的具体变化 3.Loss计算3.1 正负样本分配策略3.2 Loss计算 4.训练数据增强5.训练策略6.模型推理过程7.网络模型解析7.1 卷积神经单元&#x…

软件设计模式之原型模式

一.定义 原型模式(Prototype Pattern)的简单程度仅次于单例模式和迭代器模式。正是由于简单&#xff0c;使用的场景才非常地多&#xff0c;其定义如下: Specify the kinds of objects to create using a prototypical instance, and create new objects by copyingthis protot…

基础设施SIG月度动态:ABS新增ISO、VHD镜像构建,自动热补丁制作流程正式上线

基础设施 SIG&#xff08;OpenAnolis Infra SIG&#xff09;目标&#xff1a;负责 OpenAnolis 社区基础设施工程平台的建设&#xff0c;包括官网、Bugzilla、Maillist、ABS、ANAS、CI 门禁以及社区 DevOps 相关的研发工程系统。 01 SIG 整体进展 1、龙蜥社区官网与 CSDN dev…

smigroup LAFERT 伺服电机 B7108P-03177

​ smigroup LAFERT 伺服电机 B7108P-03177 smigroup LAFERT 伺服电机 B7108P-03177 从系统的可扩展性和兼容性的方面来说&#xff1a; 市场上控制类产品繁多&#xff0c;无论DCS还是PLC&#xff0c;均有很多厂商在生产和销售。对于PLC系统来说&#xff0c;一般没有或很少有扩…

如何与领导团队沟通并赢得他们的支持以推动企业的敏捷转型进程?

在与领导团队沟通并赢得他们对敏捷转型的支持时&#xff0c;重要的是要从战略上有效地处理这种情况。建议采取的一些步骤&#xff1a; 了解他们的观点&#xff1a;在开始任何沟通之前&#xff0c;尝试了解领导团队对敏捷转型的担忧和保留意见。可以帮助调整方法并解决具体问题。…

2023年5月信息系统项目管理师试题及答案解析

请点击↑关注、收藏&#xff0c;本博客免费为你获取精彩知识分享&#xff01;有惊喜哟&#xff01;&#xff01; 1.“新型基础设施”主要包括信息技术设施&#xff0c;融合基础设施和创新基础设施三个方面&#xff0c;其中信息基础设施包括___1___。 ①通信基础设施 ②智能交…

【Mysql 存储过程 Or 存储函数 傻傻分不清? 】

MySQL的存储函数&#xff08;自定义函数&#xff09;和存储过程都是用于存储SQL语句的。但是什么时候用什么呢&#xff1f;是不是总是傻傻的分不清&#xff1f; 本文来详细的讲一下存储函数 和存储过程 &#xff0c;以后再也不会迷糊。 存储函数 | 存储过程 一、 异同点二、 存…

云原生之深入解析Kubernetes中Kubectl Top如何进行资源监控

一、Kubectl top 的使用 kubectl top 是基础命令&#xff0c;但是需要部署配套的组件才能获取到监控值&#xff1a; 1.8 以下&#xff1a;部署 heapter&#xff1b; 1.8 以上&#xff1a;部署 metric-server&#xff1b; kubectl top node&#xff1a;查看 node 的使用情况&a…

25.单元测试、反射

一.单元测试 1.1 什么是单元测试 单元测试就是针对最小的功能单元编写测试代码&#xff0c;Java程序最小的功能单元是方法。因此&#xff0c;单元测试就是针对Java方法进行的测试&#xff0c;进而检查 方法的正确性。 1.2 目前测试方法是怎么进行的 ①只有一个main方法&#x…

可观测性最佳实践 | 警惕!未知的风险正在摧毁你的系统

无声的刺客最为致命&#xff0c;往往表面看似云淡风轻&#xff0c;实际早已危机重重&#xff0c;血雨腥风一触即发。这样的场面看似离我们很遥远&#xff0c;但每个开发运维人员实际都遇到过。 在全球数字经济大潮下&#xff0c;现代企业纷纷投身于业务数字化转型的浪潮。越来越…

java8 (jdk 1.8) 新特性—— 方法引用+构造器引用

1. 方法引用 方法引用 其实 本质上 就是Lambda 表达式 &#xff0c;之前已经知道 Lambda 是作为一个函数式接口的实例 &#xff0c;因此&#xff0c;方法引用也就是一个函数式接口的实例 使用的情况&#xff1a; 当要将值传给Lambda 体&#xff0c;已经有实现的方法&#xff…

【Python 随练】判断101到200的素数

题目&#xff1a; 判断 101-200 之间有多少个素数&#xff0c;并输出所有素数。 简介&#xff1a; 在本篇博客中&#xff0c;我们将解决一个常见的问题&#xff1a;判断101到200之间的素数&#xff0c;并输出所有素数的列表。我们将给出问题的解析&#xff0c;并提供一个完整…

2023年了要怎么理解原型和原型链

1.prototype和__proto__有什么不可告人的关系&#xff1f; 说道原型对象&#xff0c;那一定绕不开几个概念&#xff1a; prototype&#xff0c;__proto__,constructor。 首先解释一下prototype是什么&#xff0c;原型对象。V8引擎给所有函数内置的一个对象。也就是只要创建的…

瑞丽-伯纳德对流的拉格朗日拟序结构(FTLE场结果对比)

FTLE场&#xff0c;即有限李雅普诺夫指数场是识别拉格朗日拟序结构的一种方法&#xff0c;其主要思路是如下&#xff1a; 1、t时刻在场内均匀布置粒子 2、计算t–>tT时刻后粒子的位置&#xff0c;这里粒子任意时刻的速度有速度场插值得到 3、根据两个时刻的粒子位置计算得…

资讯 |智汇云舟受邀出席WGDC大会并获“年度最具创新力企业“奖项

5月17日&#xff0c;由泰伯网主办的第十二届WGDC2023全球地理信息开发者大会在北京隆重召开。开幕式上重磅发布了“2023年度最具创新力”榜单&#xff0c;智汇云舟凭借技术创新研发与应用方面取得的诸多突破&#xff0c;获数字孪生赛道“年度最具创新力企业"奖项。公司产品…

Django高级扩展之Paginator分页实现

在项目中很常见的一种功能&#xff0c;主要用于大量数据在一页显示过于冗长&#xff0c;分为一页显示多条数据&#xff0c;分隔为多页显示&#xff1b;并常与条件筛选结合使用。 目录 Paginator对象 创建对象 属性 方法 异常 Page对象 创建对象 属性 方法 Paginator与…

华为OD机试之阿里巴巴找黄金宝箱(I)

阿里巴巴找黄金宝箱(I) 题目描述 一贫如洗的樵夫阿里巴巴在去砍柴的路上&#xff0c;无意中发现了强盗集团的藏宝地&#xff0c;藏宝地有编号从0~N的箱子&#xff0c;每个箱子上面贴有一个数字&#xff0c;箱子中可能有一个黄金宝箱。 黄金宝箱满足排在它之前的所有箱子数字…