当前位置: 首页 > news >正文

Spring Boot如何压缩Json并写入redis?

1.为什么需要压缩json?

由于业务需要,存入redis中的缓存数据过大,占用了10+G的内存,内存作为重要资源,需要优化一下大对象缓存,采用gzip压缩存储,可以将 redis 的 kv 对大小缩小大约 7-8 倍,加快存储、读取速度

2.环境搭建

详建redis模块的docker目录

version: '3'
services:redis:image: registry.cn-hangzhou.aliyuncs.com/zhengqing/redis:6.0.8                   container_name: redis                                                             restart: unless-stopped                                                                  command: redis-server /etc/redis/redis.conf --requirepass 123456 --appendonly no
#    command: redis-server --requirepass 123456 --appendonly yes environment:                        TZ: Asia/ShanghaiLANG: en_US.UTF-8volumes:                           - "./redis/data:/data"- "./redis/config/redis.conf:/etc/redis/redis.conf"  ports:                              - "6379:6379"

3.代码工程

 实验目标

实验存入redis的json数据压缩和解压缩

pom.xml

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springboot-demo</artifactId><groupId>com.et</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>gzip</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.9.0</version></dependency></dependencies>
</project>

controller

package com.et.gzip.controller;import com.et.gzip.model.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;
import java.util.Map;@RestController
@Slf4j
public class HelloWorldController {@Autowiredprivate RedisTemplate redisTemplateWithJackson;@PostMapping("/hello")public User showHelloWorld(@RequestBody User user){log.info("user:"+ user);return user;}@PostMapping("/redis")public User redis(@RequestBody User user){log.info("user:"+ user);redisTemplateWithJackson.opsForValue().set("user",user);User redisUser = (User) redisTemplateWithJackson.opsForValue().get("user");return redisUser;}
}

redis压缩和解压缩配置

压缩类

package com.et.gzip.config;import com.et.gzip.model.User;import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.IOUtils;import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import sun.misc.BASE64Encoder;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.text.SimpleDateFormat;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;@Slf4j
public class CompressRedis extends JdkSerializationRedisSerializer {public static final int BUFFER_SIZE = 4096;private JacksonRedisSerializer<User>  jacksonRedisSerializer;public CompressRedis() {this.jacksonRedisSerializer = getValueSerializer();}@Overridepublic byte[] serialize(Object graph) throws SerializationException {if (graph == null) {return new byte[0];}ByteArrayOutputStream bos = null;GZIPOutputStream gzip = null;try {// serializebyte[] bytes = jacksonRedisSerializer.serialize(graph);log.info("bytes size{}",bytes.length);bos = new ByteArrayOutputStream();gzip = new GZIPOutputStream(bos);// compressgzip.write(bytes);gzip.finish();byte[] result = bos.toByteArray();log.info("result size{}",result.length);//return result;return new BASE64Encoder().encode(result).getBytes();} catch (Exception e) {throw new SerializationException("Gzip Serialization Error", e);} finally {IOUtils.closeQuietly(bos);IOUtils.closeQuietly(gzip);}}@Overridepublic Object deserialize(byte[] bytes) throws SerializationException {if (bytes == null || bytes.length == 0) {return null;}ByteArrayOutputStream bos = null;ByteArrayInputStream bis = null;GZIPInputStream gzip = null;try {bos = new ByteArrayOutputStream();byte[] compressed = new sun.misc.BASE64Decoder().decodeBuffer( new String(bytes));;bis = new ByteArrayInputStream(compressed);gzip = new GZIPInputStream(bis);byte[] buff = new byte[BUFFER_SIZE];int n;// uncompresswhile ((n = gzip.read(buff, 0, BUFFER_SIZE)) > 0) {bos.write(buff, 0, n);}//deserializeObject result = jacksonRedisSerializer.deserialize(bos.toByteArray());return result;} catch (Exception e) {throw new SerializationException("Gzip deserizelie error", e);} finally {IOUtils.closeQuietly(bos);IOUtils.closeQuietly(bis);IOUtils.closeQuietly(gzip);}}private static JacksonRedisSerializer<User> getValueSerializer() {JacksonRedisSerializer<User> jackson2JsonRedisSerializer = new JacksonRedisSerializer<>(User.class);ObjectMapper mapper=new ObjectMapper();jackson2JsonRedisSerializer.setObjectMapper(mapper);return jackson2JsonRedisSerializer;}}

java序列化


package com.et.gzip.config;import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import lombok.extern.slf4j.Slf4j;import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;@Slf4j
public class JacksonRedisSerializer<T> implements RedisSerializer<T> {public static final Charset DEFAULT_CHARSET;private final JavaType javaType;private ObjectMapper objectMapper = new ObjectMapper();public JacksonRedisSerializer(Class<T> type) {this.javaType = this.getJavaType(type);}public JacksonRedisSerializer(JavaType javaType) {this.javaType = javaType;}public T deserialize(@Nullable byte[] bytes) throws SerializationException {if (bytes == null || bytes.length == 0) {return null;} else {try {return this.objectMapper.readValue(bytes, 0, bytes.length, this.javaType);} catch (Exception var3) {throw new SerializationException("Could not read JSON: " + var3.getMessage(), var3);}}}public byte[] serialize(@Nullable Object t) throws SerializationException {if (t == null) {return  new byte[0];} else {try {return this.objectMapper.writeValueAsBytes(t);} catch (Exception var3) {throw new SerializationException("Could not write JSON: " + var3.getMessage(), var3);}}}public void setObjectMapper(ObjectMapper objectMapper) {Assert.notNull(objectMapper, "'objectMapper' must not be null");this.objectMapper = objectMapper;}protected JavaType getJavaType(Class<?> clazz) {return TypeFactory.defaultInstance().constructType(clazz);}static {DEFAULT_CHARSET = StandardCharsets.UTF_8;}
}

redis序列化

package com.et.gzip.config;import com.et.gzip.model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;@Configuration
public class RedisWithJacksonConfig {@Bean(name="redisTemplateWithJackson")public RedisTemplate<String, User> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {CompressRedis  compressRedis =  new CompressRedis();//redisTemplateRedisTemplate<String, User> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(lettuceConnectionFactory);RedisSerializer<?> stringSerializer = new StringRedisSerializer();redisTemplate.setKeySerializer(stringSerializer);redisTemplate.setValueSerializer(compressRedis);redisTemplate.setHashKeySerializer(stringSerializer);redisTemplate.setHashValueSerializer(compressRedis);redisTemplate.afterPropertiesSet();return redisTemplate;}
}

application.yaml

spring:redis:host: 127.0.0.1port: 6379database: 10password: 123456timeout: 10slettuce:pool:min-idle: 0max-idle: 8max-active: 8max-wait: -1ms
server:port: 8088compression:enabled: truemime-types: application/json,application/xml,text/html,text/plain,text/css,application/x-javascript

以上只是一些关键代码,所有代码请参见下面代码仓库

代码仓库

  • https://github.com/Harries/springboot-demo(gzip)

4.测试

  1. 启动spring boot应用
  2. 用postman访问http://127.0.0.1:8088/redis

3

可以看到redis里面存储的是gzip压缩的内容

4

查看控制台日志

2024-08-26 14:37:56.445 INFO 43832 --- [nio-8088-exec-5] com.et.gzip.config.CompressRedis : bytes size371
2024-08-26 14:37:56.445 INFO 43832 --- [nio-8088-exec-5] com.et.gzip.config.CompressRedis : result size58

JSON经过gzip压缩,371-->58, 数据大小减少7-8倍

5.引用

  •  Spring Boot如何压缩Json并写入redis? | Harries Blog™

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Window Performance API
  • 苹果机器人计划:能否成为智能家居的破局者?
  • MyBatis查询 ▎修改 ▎删除
  • postman请求设置
  • 对接微信小程序授权登录
  • qt处理表格,Qtxlsx库文件的安装以及导入
  • Python 点云ISS关键点提取算法
  • 文本向量化的六种常见模式
  • Spark MLlib模型训练—分类算法Multinomial Logistic Regression
  • SAP 表格设置全部隐藏后的恢复问题
  • Centos服务器配置使用密钥登录
  • oracle 重做日志(Redo LogBuffer)
  • uni-app开发日志:schema2code生成的新增页和修改页因字段太多用分段器实现分段分类
  • 【iOS端】基于Uniapp跨平台接入即构RTC+相芯美颜
  • 使用 Python TorchRL 进行多代理强化学习
  • [分享]iOS开发-关于在xcode中引用文件夹右边出现问号的解决办法
  • 2017-09-12 前端日报
  • Angularjs之国际化
  • Apache Pulsar 2.1 重磅发布
  • JavaScript 基本功--面试宝典
  • JavaScript设计模式与开发实践系列之策略模式
  • pdf文件如何在线转换为jpg图片
  • SegmentFault 社区上线小程序开发频道,助力小程序开发者生态
  • 基于组件的设计工作流与界面抽象
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 实战:基于Spring Boot快速开发RESTful风格API接口
  • 学习笔记:对象,原型和继承(1)
  • 一天一个设计模式之JS实现——适配器模式
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • Linux权限管理(week1_day5)--技术流ken
  • PostgreSQL 快速给指定表每个字段创建索引 - 1
  • ​如何使用ArcGIS Pro制作渐变河流效果
  • #1014 : Trie树
  • #Datawhale AI夏令营第4期#AIGC方向 文生图 Task2
  • #vue3 实现前端下载excel文件模板功能
  • #绘制圆心_R语言——绘制一个诚意满满的圆 祝你2021圆圆满满
  • (175)FPGA门控时钟技术
  • (C语言)球球大作战
  • (pojstep1.1.1)poj 1298(直叙式模拟)
  • (附源码)计算机毕业设计SSM疫情社区管理系统
  • (论文阅读23/100)Hierarchical Convolutional Features for Visual Tracking
  • (免费领源码)python#django#mysql校园校园宿舍管理系统84831-计算机毕业设计项目选题推荐
  • (四)事件系统
  • (终章)[图像识别]13.OpenCV案例 自定义训练集分类器物体检测
  • (转)LINQ之路
  • (转)mysql使用Navicat 导出和导入数据库
  • (转载)Linux网络编程入门
  • ***通过什么方式***网吧
  • .NET Entity FrameWork 总结 ,在项目中用处个人感觉不大。适合初级用用,不涉及到与数据库通信。
  • .net websocket 获取http登录的用户_如何解密浏览器的登录密码?获取浏览器内用户信息?...
  • .NET WPF 抖动动画
  • .NET/C# 获取一个正在运行的进程的命令行参数
  • .NET/C# 推荐一个我设计的缓存类型(适合缓存反射等耗性能的操作,附用法)
  • .NET关于 跳过SSL中遇到的问题
  • .net连接oracle数据库