Jimmer-Postgresql-存储文件

本文最后更新于:几秒前

1
2
3
4
5
6
7
8
9
create table public.sys_file
(
id bigint generated by default as identity primary key,
uid varchar(255) not null,
original_name varchar(255) not null,
type varchar(255) not null,
file_data text[] not null,
);

类型转换器

这里直接使用 ByteArray 会出现一些稀奇古怪的错误, 例如类型为 Text[]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147

@Entity
@Table(name = "sys_file")
interface DataBaseFile : TenantAware {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long

val uid: String

val originalName: String

val type: FileType

val fileData: InputStream
}

@Component
class FileScalarProvider : ScalarProvider<InputStream, ByteArray> {
override fun toScalar(sqlValue: ByteArray): InputStream {
val decompress = FileZipUtils.decompress(sqlValue)
return ByteArrayInputStream(decompress)
}

override fun toSql(scalarValue: InputStream): ByteArray {
val compress = FileZipUtils.compress(scalarValue.readAllBytes())
return compress
}
}

@ConditionalOnProperty(prefix = "file", name = ["storage"], havingValue = "database")
@Service
class DataBaseFileService(
private val dataBaseFileRepository: DataBaseFileRepository,
) : FileService {
/**
* 上传图片
* @param [multipartFile] 文件
* @return [String]
*/
override fun uploadFile(multipartFile: MultipartFile): String {
if (multipartFile.size > 0) {

val baseFile =
new(DataBaseFile::class).by {
this.uid = UUID.randomUUID().toString()
this.originalName = multipartFile.originalFilename ?: UUID.randomUUID().toString()
this.type = getFileType(multipartFile)
this.fileData = ByteArrayInputStream(multipartFile.bytes)
}
dataBaseFileRepository.insert(baseFile)
return baseFile.uid
}
throw EmptyFileException("文件不能为空")
}

/**
* 获取文件
* @param [fileName]
* @return [Pair<String, ByteArray>]
*/
override fun getFile(fileName: String): Pair<String, ByteArrayInputStream> {
val dataBaseFile = dataBaseFileRepository.findByUid(fileName)
return dataBaseFile.originalName to ByteArrayInputStream(dataBaseFile.fileData.readAllBytes())
}
}


object FileZipUtils {
const val BITE_SIZE: Int = 4 * 1024
fun compress(data: ByteArray): ByteArray {
val deflater = Deflater()
deflater.setLevel(Deflater.BEST_COMPRESSION)
deflater.setInput(data)
deflater.finish()
val outputStream = ByteArrayOutputStream(data.size)
val tmp = ByteArray(BITE_SIZE)

while (!deflater.finished()) {
val size = deflater.deflate(tmp)
outputStream.write(tmp, 0, size)
}

outputStream.close()

return outputStream.toByteArray()
}

fun decompress(data: ByteArray): ByteArray {
val inflater = Inflater()
inflater.setInput(data)
val outputStream = ByteArrayOutputStream(data.size)
val tmp = ByteArray(BITE_SIZE)

while (!inflater.finished()) {
val count = inflater.inflate(tmp)
outputStream.write(tmp, 0, count)
}

outputStream.close()

return outputStream.toByteArray()
}
}

/**
* 上传文件
* @param [file] 文件
* @return [R<String>]
*/
@PostMapping(path = ["/upload/file"], consumes = [MediaType.MULTIPART_FORM_DATA_VALUE])
fun uploadFile(
@RequestParam("file") file: MultipartFile,
): R<String> {
val uploadImage = this.fileService.uploadFile(file)
return R.success(data = uploadImage)
}

// 下载文件

@GetMapping("/download/file")
fun downloadFile(
@RequestParam(name = "uid") uid: String,
request: HttpServletRequest,
response: HttpServletResponse,
) {
val data = this.fileService.getFile(uid)
writeFileToResponse(data.first, data.second, request, response)
}

fun writeFileToResponse(
fileName: String,
stream: InputStream,
request: HttpServletRequest,
response: HttpServletResponse,
) {
val readAllBytes = stream.readAllBytes()
// 设置响应头
response.contentType = "application/octet-stream"
response.setHeader("Content-Disposition", "attachment; filename=\"$fileName\"")
response.setContentLength(readAllBytes.size)
// 获取 ServletOutputStream 对象
val servletOutputStream: OutputStream = response.outputStream
// 直接写入数据
servletOutputStream.write(readAllBytes)
servletOutputStream.flush()
}

Jimmer-Postgresql-存储文件
https://zhengchalei.github.io/2024/08/30/Jimmer-Postgresql-存储文件/
作者
ZhengChaLei
发布于
2024年8月30日
许可协议