项目实例:
@GetMapping("getPermitSignFile")
@ApiOperation(value = "获取许可证签名文件")
public ResponseEntity<Resource> getPermitSignFile(
@ApiParam(name = "permitId", value = "许可证ID") String permitId) throws UnsupportedEncodingException {
//判断所要下载的文件ID是否存在!!!
//专门有个存图的表在其中查 fileId ,存在才可以下载!!!
String fileId = this.service.getPermitSignFileId(permitId);
if (!StringUtils.isEmpty(fileId)) {
Map<String, Object> file = this.documentService.loadAsResource(fileId);
//这种方式返回body 内容!!!
ResponseEntity.BodyBuilder ok = ResponseEntity.ok().header("Content-Disposition", new String[]{"attachment; filename= \"" + URLEncoder.encode((String) file.get("fileName"), "UTF-8") + "\""})).body((Resource) file.get("resource"));
return ok;
}
return null;
}
解释上文:
ResponseEntity概念是可以添加HttpStatus状态码的HttpEntity的扩展类;那么不难推测出这个OK状态其实就是HttpStatus状态码
//无参ok
public static ResponseEntity.BodyBuilder ok() {
return status(HttpStatus.OK);
}
HttpStatus状态码中代表OK的是200
BodyBuilder又是什么鬼:
通过ResponseEntity的结构,我们知道BodyBuilder是ResponseEntity中的接口
直译:
定义一个可以添加body到response entity的builder
简单粗暴理解:
ResponseEntity可以通过这个builder返回任意类型的body内容。
BodyBuilder源码:
public interface BodyBuilder extends ResponseEntity.HeadersBuilder<ResponseEntity.BodyBuilder> {
ResponseEntity.BodyBuilder contentLength(long var1);
ResponseEntity.BodyBuilder contentType(MediaType var1);
<T> ResponseEntity<T> body(@Nullable T var1);
}
通过BodyBuilder源码,不难发现
BodyBuilder接口中的body方法的参数可以为空值(有@Nullable标签名字推测其允许空值)
loadAsResource 接口(直接用):
public Map<String, Object> loadAsResource(String fileId) {
Map<String, Object> result = new HashedMap();
FileInfo fileInfo = (FileInfo)this.fileInfoRepository.findOne(fileId);
if (fileInfo != null) {
String fileName = fileInfo.getFileOriginalName();
try {
Resource resource = new InputStreamResource(MinioUtil.getInstance().getObjectStream(fileInfo.getFileStorageId()));
if (!resource.exists() && !resource.isReadable()) {
throw new StorageFileNotFoundException("读取文件失败: " + fileName);
} else {
result.put("fileName", fileName);
result.put("resource", resource);
return result;
}
} catch (MalformedURLException var6) {
throw new StorageFileNotFoundException("读取文件失败: " + fileName, var6);
} catch (Exception var7) {
var7.printStackTrace();
throw new StorageFileNotFoundException("读取文件失败: " + fileName, var7);
}
} else {
throw new StorageFileNotFoundException("读取文件失败: " + fileId);
}
}
Resource(应该可以直接用):
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.core.io;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
public interface Resource extends InputStreamSource {
boolean exists();
boolean isReadable();
boolean isOpen();
URL getURL() throws IOException;
URI getURI() throws IOException;
File getFile() throws IOException;
long contentLength() throws IOException;
long lastModified() throws IOException;
Resource createRelative(String var1) throws IOException;
String getFilename();
String getDescription();
}
MinioUtil:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.richfit.ip.document.minio;
import com.richfit.ip.utils.StringUtil;
import com.richfit.ip.webmvc.SpringContextHelper;
import io.minio.MinioClient;
import io.minio.Result;
import io.minio.errors.ErrorResponseException;
import io.minio.errors.InsufficientDataException;
import io.minio.errors.InternalException;
import io.minio.errors.InvalidArgumentException;
import io.minio.errors.InvalidBucketNameException;
import io.minio.errors.NoResponseException;
import io.minio.messages.Item;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmlpull.v1.XmlPullParserException;
public class MinioUtil {
private static final Logger log = LoggerFactory.getLogger(MinioUtil.class);
private static MinioUtil minioUtil;
private MinioProperty minioProperty = (MinioProperty)SpringContextHelper.getBean(MinioProperty.class);
private MinioClient minioClient;
private static int RETRY_NUM = 3;
public static MinioUtil getInstance() {
if (null != minioUtil) {
return minioUtil;
} else {
Class var0 = MinioUtil.class;
synchronized(MinioUtil.class) {
if (null == minioUtil) {
minioUtil = new MinioUtil();
}
}
return minioUtil;
}
}
private MinioUtil() {
if (null == this.minioProperty) {
this.minioProperty = new MinioProperty();
}
this.init();
}
private void init() {
try {
if (StringUtils.isNotEmpty(this.minioProperty.getUrl()) && StringUtils.isNotEmpty(this.minioProperty.getAccessKey()) && StringUtils.isNotEmpty(this.minioProperty.getSecretKey())) {
this.minioClient = new MinioClient(this.minioProperty.getUrl(), this.minioProperty.getAccessKey(), this.minioProperty.getSecretKey(), false);
if (!StringUtil.isNullOrEmpty(this.minioProperty.getDefaultBucketName())) {
this.createBucket(this.minioProperty.getDefaultBucketName());
}
}
} catch (Exception var2) {
log.error("初始化minio客户端失败:", var2);
}
}
public MinioClient getMinioClient() {
return this.minioClient;
}
public boolean createBucket(String bucketName) {
boolean isCreated;
try {
if (!this.minioClient.bucketExists(bucketName)) {
this.minioClient.makeBucket(bucketName);
}
isCreated = true;
} catch (Exception var4) {
isCreated = false;
log.error("创建Bucket失败", var4);
var4.printStackTrace();
}
return isCreated;
}
public String uploadStream(String bucketName, String minioFilePath, InputStream inputStream, String mediaType) {
if (StringUtils.isBlank(mediaType)) {
mediaType = "application/octet-stream";
}
try {
this.putObjectWithRetry(bucketName, minioFilePath, inputStream, mediaType);
return this.cleanUrlByRemoveIp(this.minioClient.getObjectUrl(bucketName, minioFilePath));
} catch (Exception var6) {
log.error("上传文件流发生错误:", var6);
throw new RuntimeException(var6);
}
}
public String uploadStream(String minioFilePath, InputStream inputStream, String mediaType) {
return this.uploadStream(this.minioProperty.getDefaultBucketName(), minioFilePath, inputStream, mediaType);
}
public String uploadFile(String minioFilePath, String localFile, String mediaType) {
return this.uploadFile(this.minioProperty.getDefaultBucketName(), minioFilePath, localFile, mediaType);
}
public String uploadFile(String bucketName, String minioFilePath, String localFile, String mediaType) {
if (StringUtils.isBlank(mediaType)) {
mediaType = "application/octet-stream";
}
try {
this.putObjectWithRetry(bucketName, minioFilePath, localFile, mediaType);
return this.cleanUrlByRemoveIp(this.minioClient.getObjectUrl(bucketName, minioFilePath));
} catch (Exception var6) {
log.error("上传文件发生错误:", var6);
throw new RuntimeException(var6);
}
}
public List<MinioFile> listFilesSwap(String bucketName, String prefix, boolean recursive) {
return this.swapResultToEntityList(this.minioClient.listObjects(bucketName, prefix, recursive));
}
public Iterable<Result<Item>> listFiles(String bucketName, String prefix, boolean recursive) {
return this.minioClient.listObjects(bucketName, prefix, recursive);
}
public List<MinioFile> listFilesByBucketNameSwap(String bucketName) {
return this.swapResultToEntityList(this.minioClient.listObjects(bucketName, (String)null, true));
}
public Iterable<Result<Item>> listFilesByBucketName(String bucketName) {
return this.minioClient.listObjects(bucketName, (String)null, true);
}
public Iterable<Result<Item>> listFilesByBucketAndPrefix(String bucketName, String prefix) {
return this.minioClient.listObjects(bucketName, prefix, true);
}
public List<MinioFile> listFilesByBucketAndPrefixSwap(String bucketName, String prefix) {
return this.swapResultToEntityList(this.minioClient.listObjects(bucketName, prefix, true));
}
private MinioFile swapResultToEntity(Result<Item> result) {
MinioFile entity = new MinioFile();
try {
if (result.get() != null) {
Item item = (Item)result.get();
entity.setObjectName(this.cleanUrlByRemoveIp(item.objectName()));
entity.setIsDir(item.isDir());
entity.setEtag(item.etag());
entity.setLastModified(item.lastModified());
entity.setObjectSize(item.objectSize());
entity.setStorageClass(item.storageClass());
}
} catch (Exception var4) {
log.error("获取文件信息出错, e={}", var4.getMessage());
}
return entity;
}
private String cleanUrlByRemoveIp(String s) {
return s;
}
private List<MinioFile> swapResultToEntityList(Iterable<Result<Item>> results) {
List<MinioFile> files = new ArrayList();
Iterator var3 = results.iterator();
while(var3.hasNext()) {
Result<Item> result = (Result)var3.next();
files.add(this.swapResultToEntity(result));
}
return files;
}
public void putObjectWithRetry(String bucketName, String objectName, InputStream stream, String contentType) throws IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, InvalidArgumentException, NoResponseException, InvalidBucketNameException, XmlPullParserException, InternalException {
int current = 0;
boolean isSuccess = false;
while(!isSuccess && current < RETRY_NUM) {
try {
this.minioClient.putObject(bucketName, objectName, stream, contentType);
stream.close();
isSuccess = true;
} catch (ErrorResponseException var8) {
log.warn("[minio] putObject stream, ErrorResponseException occur for time =" + current, var8);
++current;
}
}
if (current == RETRY_NUM) {
log.error("[minio] putObject, backetName={}, objectName={}, failed finally!");
}
}
public String getObjectUrl(String objectName) throws Exception {
return this.getObjectUrl(this.minioProperty.getDefaultBucketName(), objectName, 86400);
}
public void removeObject(String objectName) throws Exception {
this.minioClient.removeObject(this.minioProperty.getDefaultBucketName(), objectName);
}
public void removeObject(String bucketName, String objectName) throws Exception {
this.minioClient.removeObject(bucketName, objectName);
}
public void removeObjects(String bucketName, List<String> objectNames) throws Exception {
this.minioClient.removeObject(bucketName, objectNames);
}
public void removeObjects(List<String> objectNames) throws Exception {
this.minioClient.removeObject(this.minioProperty.getDefaultBucketName(), objectNames);
}
public String getObjectUrl(String bucketName, String objectName) throws Exception {
return this.getObjectUrl(bucketName, objectName, 86400);
}
public InputStream getObjectStream(String bucketName, String objectName) throws Exception {
return this.minioClient.getObject(bucketName, objectName);
}
public InputStream getObjectStream(String objectName) throws Exception {
return this.getObjectStream(this.minioProperty.getDefaultBucketName(), objectName);
}
public String getObjectUrl(String bucketName, String objectName, Integer expires) throws Exception {
return this.minioClient.presignedGetObject(bucketName, objectName, expires);
}
public void putObjectWithRetry(String bucketName, String objectName, String fileName, String contentType) throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException, InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException, InternalException, InvalidArgumentException, InsufficientDataException {
int current = 0;
boolean isSuccess = false;
while(!isSuccess && current < RETRY_NUM) {
try {
this.minioClient.putObject(bucketName, objectName, fileName, contentType);
isSuccess = true;
} catch (ErrorResponseException var8) {
++current;
log.debug("[minio] putObject file, ErrorResponseException occur!");
}
}
if (current == RETRY_NUM) {
log.error("[minio] putObject, backetName={}, objectName={}, failed finally!");
}
}
public static void main(String[] args) throws Exception {
List<MinioFile> files = getInstance().listFilesByBucketNameSwap("image");
String url = getInstance().getObjectUrl("image", ((MinioFile)files.get(0)).getObjectName());
}
}
@RequestMapping("/testResponseEntity")
public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException{
byte [] body = null;
ServletContext servletContext = session.getServletContext();
InputStream in = servletContext.getResourceAsStream("/files/abc.txt");
body = new byte[in.available()];
in.read(body);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "attachment;filename=abc.txt");
HttpStatus statusCode = HttpStatus.OK;
ResponseEntity<byte[]> response = new ResponseEntity<byte[]>(body, headers, statusCode);
return response;
}
其中对Content-Disposition 响应头 进行解析:
在页面内打开代码:
File file = new File("rfc1806.txt");
String filename = file.getName();
response.setHeader("Content-Type","text/plain");
response.addHeader("Content-Disposition","inline;filename=" + new String(filename.getBytes(),"utf-8"));
response.addHeader("Content-Length","" + file.length());
弹出保存框代码:
File file = new File("rfc1806.txt");
String filename = file.getName();
response.setHeader("Content-Type","text/plain");
response.addHeader("Content-Disposition","attachment;filename=" + new String(filename.getBytes(),"utf-8"));
response.addHeader("Content-Length","" + file.length());