前端Pako.js 压缩解压库 与 Java 的 zlib 压缩与解压 的互通实现

ops/2024/12/26 14:49:59/

工具介绍:
pako.js 前端压缩解压的库(包含 zlib 和gzip 两种实现,这里只介绍 zlib)

pako 2.0.4 API documentation

Java8+ 原生支持 zlib 和 gzip

业务场景
因为数据太大,网络环境不可控。故前端需要将数据 A 先压缩 变为 a,然后才将 a 发送到 Java 服务器端后处理或存储。
后端 Java 也可以调取存储的压缩结果进行解压,重新发往前端
这里介绍 pako.js 的zlib 接口 与 Java 的互通。

首先是前端
由于 pako.js 库的压缩后的结果 是 Uint8Array

Uint8Array 数组类型表示一个8位无符号整型数组,创建时内容被初始化为0。创建完后,可以以对象的方式或使用数组下标索引的方式引用数组中的元素。

由于 它的 toString() 不包含特殊字符,故可以被 http 直接传输 (无需 转换为 base64)。

故发送到服务端的串 ,大致形式为 : 123,12,99,1,34

然后是 Java 的服务端
Java 原生支持 zlib 压缩和解压方式,百度上很多例子。这里不赘述。

略微麻烦的地方在于,

接受端:前端发送过来的上述的那种格式,需要转变为 java 的压缩解压接口的参数的固定格式。

发送端:发送给前端的数据(显然是 zlib 压缩后的数据),同样需要转换为 上述格式。

这里强调下,为什么前端解压后端的压缩数据时,一定要让后端发送给前端的数据格式,去和前端库发送给后端的数据格式保持一致呢?(不要吐槽我的逗号断句,这句实在太绕了)

因为 在前后端分离的开发模式下,对于前端开发人员,是不应该关注后端的技术实现。显然,后端努力去迎合 前端库的特有数据格式(因伟大而落泪)。

下面直接贴上 代码:

前端代码:(用 jquery 库)

// 首先你需要引入 pako.js 库,这里就不贴了

// 这里要压缩的内容
let content = “我是张三 **@*¥)*¥*)@#*#*@+—— ~kdfkda55d4 fd”;

// 前端压缩
let clientData = pako.deflate(content);

// 变成 串
clientData = clientData.toString()

console.log(“client 压缩后>>”,clientData)

$.post(“http://localhost:10003/demo/test2CompresAndUncompress”,{
data:clientData
},function(data){

console.log(“接受 server 压缩原文:”,data);

let b = data.split(‘,’).map(function (x) { return parseInt(x); });
// console.log(“client 解压后split:”,b);

let c = pako.inflate(b,{to :“string”});

// 完毕 撒花
console.log(“client 解压后:”,c);

});
后端代码(这里用的是 springboot 框架):

Controller:

@RequestMapping(value = “/test2CompresAndUncompress”)
@ResponseBody
public String test2CompresAndUncompress(@RequestParam String data) throws IOException {
System.out.println(“接収 client 原文<<”+data);

/**
* 将数字的字符串 转为 byte[]
*/
byte[] clientBytes = PakoUtil.receive(data);

byte[] bytes = ZlibUtil.decompress(clientBytes);
System.out.println(“server 解压后<<”+new String(bytes));

//重新压缩,打算向服务器 发送 压缩后的代码
byte[] encodingStr = ZlibUtil.compress(bytes);
System.out.println(“我自己尝试解压后1>>”+new String(encodingStr));
System.out.println(“我自己尝试解压后2>>”+new String(ZlibUtil.decompress(encodingStr)));

return PakoUtil.send(encodingStr);

}
上面代码涉及的工具类(ZlibUtil.java 和 PakoUtil.java):

ZlibUtil.java:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;

/**
* zlib 压缩算法
* java 就是牛,原生支持
* @author jx
*
*/
public class ZlibUtil {

/**
* 压缩
*
* @param data
* 待压缩数据
* @return byte[] 压缩后的数据
*/
public static byte[] compress(byte[] data) {
byte[] output = new byte[0];

Deflater compresser = new Deflater();

compresser.reset();
compresser.setInput(data);
compresser.finish();
ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length);
try {
byte[] buf = new byte[1024];
while (!compresser.finished()) {
int i = compresser.deflate(buf);
bos.write(buf, 0, i);
}
output = bos.toByteArray();
} catch (Exception e) {
output = data;
e.printStackTrace();
} finally {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
compresser.end();
return output;
}

/**
* 压缩
*
* @param data
* 待压缩数据
*
* @param os
* 输出流
*/
public static void compress(byte[] data, OutputStream os) {
DeflaterOutputStream dos = new DeflaterOutputStream(os);

try {
dos.write(data, 0, data.length);

dos.finish();

dos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}

/**
* 解压缩
*
* @param data
* 待压缩的数据
* @return byte[] 解压缩后的数据
*/
public static byte[] decompress(byte[] data) {
byte[] output = new byte[0];

Inflater decompresser = new Inflater();
decompresser.reset();
decompresser.setInput(data);

ByteArrayOutputStream o = new ByteArrayOutputStream(data.length);
try {
byte[] buf = new byte[1024];
while (!decompresser.finished()) {
int i = decompresser.inflate(buf);
o.write(buf, 0, i);
}
output = o.toByteArray();
} catch (Exception e) {
output = data;
e.printStackTrace();
} finally {
try {
o.close();
} catch (IOException e) {
e.printStackTrace();
}
}

decompresser.end();
return output;
}

/**
* 解压缩
*
* @param is
* 输入流
* @return byte[] 解压缩后的数据
*/
public static byte[] decompress(InputStream is) {
InflaterInputStream iis = new InflaterInputStream(is);
ByteArrayOutputStream o = new ByteArrayOutputStream(1024);
try {
int i = 1024;
byte[] buf = new byte[i];

while ((i = iis.read(buf, 0, i)) > 0) {
o.write(buf, 0, i);
}

} catch (IOException e) {
e.printStackTrace();
}
return o.toByteArray();
}

public static void main(String[] args) throws UnsupportedEncodingException {
String data = “aadfklafdafla我是中国人的啦啦啦”;
System.out.println(“原文:”+data);

// 报错
// String a = Base64Util.encode(ZlibUtil.compress(data.getBytes()));
//
// String b = new String(ZlibUtil.decompress(Base64Util.decode(a)));

byte[] a = ZlibUtil.compress(data.getBytes(“UTF-8”));
System.out.println(“>>”+Arrays.toString(a));

byte[] b = ZlibUtil.decompress(a);

// System.out.println(“压缩后:”+a);
System.out.println(“jieya后:”+new String(b));
}

void a(){
// try {
// // Encode a String into bytes
// String inputString = “Pehla nasha Pehla khumaar Naya pyaar hai naya intezaar Kar loon main kya apna haal Aye dil-e-bekaraar Mere dil-e-bekaraar Tu hi bata Pehla nasha Pehla khumaar Udta hi firoon in hawaon mein kahin Ya main jhool jaoon in ghataon mein kahin Udta hi firoon in hawaon mein kahin Ya main jhool jaoon in ghataon mein kahin Ek kar doon aasmaan zameen Kaho yaaron kya karoon kya nahin Pehla nasha Pehla khumaar Naya pyaar hai naya intezaar Kar loon main kya apna haal Aye dil-e-bekaraar Mere dil-e-bekaraar Tu hi bata Pehla nasha Pehla khumaar Usne baat ki kuchh aise dhang se Sapne de gaya vo hazaaron range ke Usne baat ki kuchh aise dhang se Sapne de gaya vo hazaaron range ke Reh jaoon jaise main haar ke Aur choome vo mujhe pyaar se Pehla nasha Pehla khumaar Naya pyaar hai naya intezaar Kar loon main kya apna haal Aye dil-e-bekaraar Mere dil-e-bekaraar”;
// byte[] input = inputString.getBytes(“UTF-8”);
// // Compress the bytes
// byte[] output1 = new byte[input.length];
// Deflater compresser = new Deflater();
// compresser.setInput(input);
// compresser.finish();
// int compressedDataLength = compresser.deflate(output1);
// compresser.end();
// String str = Base64.encode(output1);
// System.out.println(“Deflated String:” + str);
// byte[] output2 = Base64.decode(str);
// // Decompress the bytes
// Inflater decompresser = new Inflater();
// decompresser.setInput(output2);
// byte[] result = str.getBytes();
// int resultLength = decompresser.inflate(result);
// decompresser.end();
// // Decode the bytes into a String
// String outputString = new String(result, 0, resultLength, “UTF-8”);
// System.out.println(“Deflated String:” + outputString);
// } catch (UnsupportedEncodingException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// } catch (DataFormatException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
//
}
}
PakoUtil.java:

/**
* 针对 前端的 pako.js 压缩和解压插件 的发送、推送的数据处理
* 目标是使和Java 的zlib 压缩解压交互方便
* @see http://nodeca.github.io/pako/#inflate
* @author jx
*
*/
public class PakoUtil {

/**
* 从 Pako.js 中接受的数据
* @param arrStr 形如: 123,2,09,
* 字符串是由无符号整数构成,逗号分隔
* @return
*/
public static byte[] receive(String arrInt){

/**
* 将数字字符串 -> byte[]
*/
String[] a = arrInt.split(“,”);
byte[] clientBytes = new byte[a.length];
int i = 0;
for (String e : a) {
clientBytes[i] = Integer.valueOf(e).byteValue();

i++;
}
return clientBytes;
}

/**
* 发送给 Pako 的数据格式
* @param bytes 服务端生成的字节数组
* @return String 发送给 pako.js 的数据格式
*/
public static String send(byte[] bytes) {
String[] ints = new String[bytes.length];
int j=0;
for(byte e:bytes) {
int t = e;
if(t<0) {
t = 256+t;
}
ints[j++] = String.valueOf(t);

}

return String.join(“,”, ints);
}

}

原文链接:https://blog.csdn.net/rainyspring4540/article/details/121383490


http://www.ppmy.cn/ops/145143.html

相关文章

PCL点云库入门——PCL库点云滤波算法之直通滤波(PassThrough)和条件滤波(ConditionalRemoval)

0、滤波算法概述 PCL点云库中的滤波算法是处理点云数据不可或缺的一部分&#xff0c;它们能够有效地去除噪声、提取特征或进行数据降维。例如&#xff0c;使用体素网格滤波&#xff08;VoxelGrid&#xff09;可以减少点云数据量&#xff0c;同时保留重要的形状特征。此外&#…

Leetcode经典题20--长度最小的子数组

题目描述 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的子数组 [numsl, numsl1, ..., numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条件的子数组&#xff0c;返回 0 。 输入输出示例 输入&…

【Django】测试带有 CSRF 验证的 POST 表单 API 报错:Forbidden (CSRF cookie not set.)

【Django】测试带有 CSRF 验证的 POST 表单 API 报错&#xff1a;Forbidden (CSRF cookie not set.) 问题描述 Django 使用 Apifox 测试 POST 表单报错。 Forbidden (CSRF cookie not set.): /api/parse [20/Dec/2024 15:17:25] "POST //api/parse HTTP/1.1" 403 …

YoloDotNet OBB(定向边界框)

文章目录 前言1、代码示例引入命名空间:初始化 Yolo 对象:加载图像和执行 OBB 检测:处理检测结果:2、自定义 OBB 绘制(可选)3、性能和准确性考虑前言 OBB(Oriented Bounding Box)在目标检测中用于更精确地框定非水平或垂直放置的物体。与常规边界框不同,OBB 可以根据物…

vscode的keil assistant 中搜索不到全局变量

搜不到 但是在包含的文件中输入 ../../../,就是全局搜索的结果 我的文件结构是&#xff1a;\Desktop\LVGL文件系统移植&#xff08;lvgl8&#xff0e;&#xff13;&#xff09;\Projects\MDK-ARM 盲猜是keil assistant 当前文件夹打开的时候是进入到了MDK-ARM文件夹层次&…

园区网大综合实验

首先按照题目要求划分网络环境&#xff08;如图所示&#xff09; 进行 sw1 sw2 sw3 sw4 vlan基本配置 sw1 sw2 sw3 sw4 ip配置 r1 isp 在r1 0/0/0接口做nat设置 stp生成树配置 sw1 sw2 sw3 sw4 stp参数修改 根保护 mstp边缘接口 vrrp

Vue3 +Element-Plus el-select下拉菜单样式(局部生效)

下拉框代码 <el-selectclass"buttons-switch-group select-hub":teleported"false"style"width: 120px"v-model"queryParam.type"placeholder"请选择"size"mini"change"loadData"><el-option…

VBA技术资料MF245:创建嵌入式条形图

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…