查看图片使用 sendfile

This commit is contained in:
jasminexz 2023-09-11 15:58:14 +08:00
parent 9607e16023
commit 5173fd6f26

View File

@ -1,24 +1,31 @@
package com.blossom.backend.server.picture;
import cn.hutool.core.io.FastByteArrayOutputStream;
import cn.hutool.core.io.IoUtil;
import com.blossom.backend.base.auth.AuthContext;
import com.blossom.backend.base.auth.annotation.AuthIgnore;
import com.blossom.backend.server.picture.pojo.PictureEntity;
import com.blossom.common.base.pojo.R;
import com.blossom.common.base.util.ServletUtil;
import com.blossom.common.base.util.spring.AntPathMatcherUtil;
import com.blossom.common.iaas.OSManager;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* 图片上传下载, 当使用本地图片存储时, 简短的接口名有助于优化文档布局
@ -62,78 +69,73 @@ public class PictureBlosController {
return R.ok(picture.getUrl());
}
/**
* 查看图片 [OP]
*
* @param filename 文件名
* @param scale 图片分辨率缩放
* @param quality 图片质量缩放
*/
@AuthIgnore
@GetMapping("/pic/{filename}/**")
public void getFile(
@PathVariable String filename,
@RequestParam(value = "scale", required = false) Float scale,
@RequestParam(value = "quality", required = false) Float quality,
HttpServletRequest request,
HttpServletResponse resp) {
if (scale == null) {
scale = 1f;
}
if (quality == null) {
quality = 1f;
}
private String getFilename(String filename, HttpServletRequest request) {
final String path = request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE).toString();
final String bestMatchingPattern = request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE).toString();
String arguments = AntPathMatcherUtil.getAntPathMatcher().extractPathWithinPattern(bestMatchingPattern, path);
if (!arguments.isEmpty()) {
filename = "/" + filename + '/' + arguments;
}
File file = osManager.get(filename);
return filename;
}
InputStream ips = null;
FastByteArrayOutputStream ops = null;
try {
// 图片大于 COMPRESS_MIN_SIZE 大小, 且请求进行压缩时
if (file.length() > COMPRESS_MIN_SIZE && (scale < 1f || quality < 1f)) {
try {
ops = new FastByteArrayOutputStream();
Thumbnails.of(file)
// 图片大小长宽压缩比例 从0-11表示原图
.scale(scale)
// 图片质量压缩比例 从0-1越接近1质量越好
.outputQuality(quality)
.toOutputStream(ops);
} catch (IOException e) {
e.printStackTrace();
log.error(e.toString());
ips = new FileInputStream(file);
ops = IoUtil.read(ips, true);
}
} else {
ips = new FileInputStream(file);
ops = IoUtil.read(ips, true);
/**
* 查看图片 [OP]
*
* @param filename 文件名
*/
@AuthIgnore
@GetMapping("/pic/{filename}/**")
public ResponseEntity<StreamingResponseBody> getFile(@PathVariable String filename,
HttpServletRequest request, HttpServletResponse resp) {
filename = getFilename(filename, request);
// sendfile 方式下载图片
sendfile(filename, resp);
return ResponseEntity.ok(null);
// File file = osManager.get(filename);
// resp.setContentType("");
// resp.setContentLengthLong(file.length());
// try {
// InputStream is = new FileInputStream(file);
// StreamingResponseBody body = os -> {
// int nRead;
// byte[] data = new byte[1024];
// while ((nRead = is.read(data, 0, data.length)) != -1) {
// os.write(data, 0, nRead);
// }
// };
// return ResponseEntity.ok().body(body);
// } catch (FileNotFoundException e) {
// e.printStackTrace();
// return ResponseEntity.ok().body(null);
// }
}
private void sendfile(String filename, HttpServletResponse resp) {
Path file = Paths.get(filename);
try (FileChannel fileChannel = FileChannel.open(file); ServletOutputStream os = resp.getOutputStream()) {
long size = fileChannel.size();
String contentType = Files.probeContentType(file);
if (contentType == null) {
contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE;
}
resp.setContentType(contentType);
resp.setContentLengthLong(size);
resp.setContentType(ServletUtil.getContentTypeImage(filename));
OutputStream os = resp.getOutputStream();
os.write(ops.toByteArray());
os.flush();
os.close();
long position = 0;
WritableByteChannel channel = Channels.newChannel(os);
while (size > 0) {
long count = fileChannel.transferTo(position, size, channel);
if (count > 0) {
position += count;
size -= count;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (ips != null) {
ips.close();
}
if (ops != null) {
ops.close();
}
} catch (IOException e) {
e.printStackTrace();
}
log.info(e.getMessage());
}
}