|
|
springboot对redis存取二进制数据
可以用 RedisTemplate 配置成“值为 byte[] 的模板”,用 ByteArrayRedisSerializer 确保按原始二进制读写(不做字符编码/对象序列化)。 配置 - package com.example.config;
- 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.ByteArrayRedisSerializer;
- import org.springframework.data.redis.serializer.StringRedisSerializer;
- @Configuration
- public class RedisBinaryConfig {
- @Bean
- public RedisTemplate<String, byte[]> binaryRedisTemplate(RedisConnectionFactory cf) {
- RedisTemplate<String, byte[]> t = new RedisTemplate<>();
- t.setConnectionFactory(cf);
- t.setKeySerializer(StringRedisSerializer.UTF_8);
- t.setValueSerializer(ByteArrayRedisSerializer.INSTANCE);
- t.setHashKeySerializer(StringRedisSerializer.UTF_8);
- t.setHashValueSerializer(ByteArrayRedisSerializer.INSTANCE);
- t.afterPropertiesSet();
- return t;
- }
- }
复制代码
使用
- import org.springframework.data.redis.core.RedisTemplate;
- import org.springframework.beans.factory.annotation.Autowired;
- import java.time.Duration;
- public class BinService {
- @Autowired
- private RedisTemplate<String, byte[]> binaryRedisTemplate;
- public void save(String key, byte[] data, Duration ttl) {
- binaryRedisTemplate.opsForValue().set(key, data, ttl);
- }
- public byte[] get(String key) {
- return binaryRedisTemplate.opsForValue().get(key);
- }
- public void saveHash(String hkey, String field, byte[] data) {
- binaryRedisTemplate.opsForHash().put(hkey, field, data);
- }
- public byte[] getHash(String hkey, String field) {
- Object v = binaryRedisTemplate.opsForHash().get(hkey, field);
- return v instanceof byte[] ? (byte[]) v : null;
- }
- }
复制代码
要点 - 不要用 StringRedisTemplate 保存二进制,否则会按 UTF-8 编码导致损坏。
- Redis 单个 value 最大 512MB;超大文件建议分片或改用对象存储。
- 若直接用底层连接也可:connection.set(key.getBytes(StandardCharsets.UTF_8), bytes)。
下面给出一个最小可用的服务端与客户端示例,演示通过 HTTP 存/取 Redis 中的二进制数据。 服务端(Spring Boot) - PUT /bin/{key}:请求体即二进制;可选 ttl 秒
- GET /bin/{key}:返回 application/octet-stream 的二进制
- package com.example.web;
- import org.springframework.http.*;
- import org.springframework.web.bind.annotation.*;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.data.redis.core.RedisTemplate;
- import java.time.Duration;
- import java.util.Optional;
- @RestController
- @RequestMapping("/bin")
- public class BinaryController {
- @Autowired
- private RedisTemplate<String, byte[]> binaryRedisTemplate;
- @PutMapping("/{key}")
- public ResponseEntity<Void> put(@PathVariable String key,
- @RequestBody byte[] body,
- @RequestParam(name = "ttl", required = false) Optional<Long> ttlSec) {
- if (ttlSec.isPresent()) {
- binaryRedisTemplate.opsForValue().set(key, body, Duration.ofSeconds(ttlSec.get()));
- } else {
- binaryRedisTemplate.opsForValue().set(key, body);
- }
- return ResponseEntity.accepted().build();
- }
- @GetMapping("/{key}")
- public ResponseEntity<byte[]> get(@PathVariable String key) {
- byte[] data = binaryRedisTemplate.opsForValue().get(key);
- if (data == null) return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
- HttpHeaders h = new HttpHeaders();
- h.setContentType(MediaType.APPLICATION_OCTET_STREAM);
- h.setContentLength(data.length);
- // 可选下载文件名:
- // h.setContentDisposition(ContentDisposition.attachment().filename(key + ".bin").build());
- return new ResponseEntity<>(data, h, HttpStatus.OK);
- }
- }
复制代码客户端调用示例 - # 上传二进制,设置 1 小时过期
- curl -X PUT --data-binary @image.png "http://localhost:8080/bin/pic1?ttl=3600"
- # 下载二进制到文件
- curl -o out.png "http://localhost:8080/bin/pic1"
复制代码- import java.net.http.*;
- import java.net.URI;
- import java.nio.file.*;
- public class ClientDemo {
- public static void main(String[] args) throws Exception {
- HttpClient http = HttpClient.newHttpClient();
- // PUT 上传
- byte[] bytes = Files.readAllBytes(Path.of("image.png"));
- HttpRequest put = HttpRequest.newBuilder(URI.create("http://localhost:8080/bin/pic1?ttl=3600"))
- .PUT(HttpRequest.BodyPublishers.ofByteArray(bytes))
- .header("Content-Type", "application/octet-stream")
- .build();
- http.send(put, HttpResponse.BodyHandlers.discarding());
- // GET 下载
- HttpRequest get = HttpRequest.newBuilder(URI.create("http://localhost:8080/bin/pic1")).GET().build();
- HttpResponse<byte[]> resp = http.send(get, HttpResponse.BodyHandlers.ofByteArray());
- if (resp.statusCode() == 200) Files.write(Path.of("download.png"), resp.body());
- }
- }
复制代码说明 - 需配合你前面配置的 RedisTemplate<String, byte[]>(ByteArrayRedisSerializer)使用。
- value 最大 512MB;大对象建议分片或对象存储。
下面给出一个可在 Java 8 (1.8.0_152) 运行的 Spring Boot 2.7 示例:用 RedisTemplate<String, byte[]> 读写二进制,并通过 HTTP 接口让客户端上传/下载。 pom.xml - <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">
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.example</groupId>
- <artifactId>redis-binary-demo</artifactId>
- <version>1.0.0</version>
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>2.7.18</version>
- </parent>
- <properties>
- <java.version>1.8</java.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</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>
- </dependency>
- </dependencies>
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
- </project>
复制代码 application.yml- spring:
- redis:
- host: 127.0.0.1
- port: 6379
- server:
- port: 8080
复制代码 配置 RedisTemplate(值为 byte[])
- package com.example.config;
- 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.ByteArrayRedisSerializer;
- import org.springframework.data.redis.serializer.StringRedisSerializer;
- @Configuration
- public class RedisBinaryConfig {
- @Bean
- public RedisTemplate<String, byte[]> binaryRedisTemplate(RedisConnectionFactory cf) {
- RedisTemplate<String, byte[]> t = new RedisTemplate<>();
- t.setConnectionFactory(cf);
- t.setKeySerializer(StringRedisSerializer.UTF_8);
- t.setValueSerializer(ByteArrayRedisSerializer.INSTANCE);
- t.setHashKeySerializer(StringRedisSerializer.UTF_8);
- t.setHashValueSerializer(ByteArrayRedisSerializer.INSTANCE);
- t.afterPropertiesSet();
- return t;
- }
- }
复制代码 Controller:上传/下载二进制
- package com.example.web;
- import org.springframework.http.*;
- import org.springframework.web.bind.annotation.*;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.data.redis.core.RedisTemplate;
- import java.time.Duration;
- @RestController
- @RequestMapping("/bin")
- public class BinaryController {
- @Autowired
- private RedisTemplate<String, byte[]> binaryRedisTemplate;
- @PutMapping("/{key}")
- public ResponseEntity<Void> put(@PathVariable String key,
- @RequestBody byte[] body,
- @RequestParam(name = "ttl", required = false) Long ttlSec) {
- if (ttlSec != null && ttlSec > 0) {
- binaryRedisTemplate.opsForValue().set(key, body, Duration.ofSeconds(ttlSec));
- } else {
- binaryRedisTemplate.opsForValue().set(key, body);
- }
- return ResponseEntity.accepted().build();
- }
- @GetMapping("/{key}")
- public ResponseEntity<byte[]> get(@PathVariable String key) {
- byte[] data = binaryRedisTemplate.opsForValue().get(key);
- if (data == null) return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
- HttpHeaders h = new HttpHeaders();
- h.setContentType(MediaType.APPLICATION_OCTET_STREAM);
- h.setContentLength(data.length);
- return new ResponseEntity<>(data, h, HttpStatus.OK);
- }
- }
复制代码 启动类
- package com.example;
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
- @SpringBootApplication
- public class RedisBinaryDemoApplication {
- public static void main(String[] args) {
- SpringApplication.run(RedisBinaryDemoApplication.class, args);
- }
- }
复制代码 Java 8 客户端调用示例(使用 RestTemplate)
- // 普通 Java 项目或测试里使用
- import org.springframework.http.*;
- import org.springframework.web.client.RestTemplate;
- import java.nio.file.Files;
- import java.nio.file.Paths;
- public class ClientDemo {
- public static void main(String[] args) throws Exception {
- RestTemplate rt = new RestTemplate();
- // 上传二进制
- byte[] bytes = Files.readAllBytes(Paths.get("D:/tmp/image.png"));
- HttpHeaders h = new HttpHeaders();
- h.setContentType(MediaType.APPLICATION_OCTET_STREAM);
- HttpEntity<byte[]> req = new HttpEntity<>(bytes, h);
- rt.exchange("http://localhost:8080/bin/pic1?ttl=3600", HttpMethod.PUT, req, Void.class);
- // 下载二进制
- ResponseEntity<byte[]> resp = rt.getForEntity("http://localhost:8080/bin/pic1", byte[].class);
- if (resp.getStatusCode().is2xxSuccessful()) {
- Files.write(Paths.get("D:/tmp/out.png"), resp.getBody());
- }
- }
- }
复制代码- 用 curl 调用也行:
- 上传:curl -X PUT --data-binary @image.png "http://localhost:8080/bin/pic1?ttl=3600"
- 下载:curl -o out.png "http://localhost:8080/bin/pic1"
|
|