MongoDB图片上传下载 -- GridFsTemplate
1、引入jar包
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-mongodb -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
<version>2.1.5.RELEASE</version>
</dependency>
2、yml 配置文件
spring:
data:
mongodb:
uri: mongodb://192.168.124.217:27017/DocDB
# 这里 DocDB 是自己在mongoDB中创建的数据库,该配置是MongoDB无密码条件下的配置
# spring.data.mongodb.uri=mongodb://name:pass@localhost:27017/test,其中name是用户名,pass是密码
3、业务代码
package com.ziumur.manager.web.rest;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSBuckets;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.codec.binary.Base64;
import org.bson.types.ObjectId;
import org.h2.util.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
/**
* @ClassName: FileUploadController
* @Description:
* @author:
* @Date:2020/6/1 19:16
**/
@Api(tags = "文件上传")
@Controller
@RequestMapping(value = "/api", produces = { MediaType.APPLICATION_JSON_VALUE })
public class UploadFileResource {
private final Logger log = LoggerFactory.getLogger(FileUploadResource.class);
private final GridFsTemplate gridFsTemplate;
@Resource
private MongoDbFactory mongoDbFactory;
@Bean
public GridFSBucket getGridFSBuckets() {
MongoDatabase db = mongoDbFactory.getDb();
return GridFSBuckets.create(db);
}
@Resource
private GridFSBucket gridFSBucket;
private static final String[] FILE_TYPES =
new String[] {
"jpg", "bmp", "jpeg", "png", "gif", "tif", "pcx", "tga", "exif", "exif", "svg",
"psd", "cdr", "pcd", "dxf", "ufo", "eps", "ai", "raw", "WMF", "webp"
};
public UploadFileResource(GridFsTemplate gridFsTemplate) {
this.gridFsTemplate = gridFsTemplate;
}
@ApiOperation(value = "上传图片", notes = "上传文件")
@PostMapping(value = "uploadImage")
public ResponseEntity<Object> uploadImage(@RequestParam("file") MultipartFile file) {
String id = upload(file);
return ResponseEntity.ok(id);
}
@ApiOperation(value = "下载图片", notes = "下载文件")
@GetMapping(value = "downloadImage/{pictureGuid}")
public void downloadImage(@PathVariable String pictureGuid, HttpServletResponse response)throws Exception {
download(pictureGuid, response);
}
@ApiOperation(value = "显示图片", notes = "下载文件")
@GetMapping(value = "getImage/{pictureGuid}")
public void getImage(@PathVariable String pictureGuid, HttpServletResponse response)throws Exception {
viewImg(pictureGuid, response);
}
private String upload(MultipartFile files) {
//获取上传文件的原名
String fileName = files.getOriginalFilename();
String fileNameStr= Base64.encodeBase64String(fileName.getBytes());
String[] split = fileName.split("\\.");
//拿到文件后缀名
String suff = split[split.length - 1];
// 文件类型
String save = "";
try {
ObjectId store = gridFsTemplate.store(files.getInputStream(), fileName, files.getContentType());
String id = store.toString();
if (StringUtils.hasLength(id)) save = id;
} catch (IOException e) {
e.printStackTrace();
log.error(e.getMessage());
}
return save;
}
private void download(String fileId, HttpServletResponse response) {
if (!StringUtils.hasLength(fileId)) {
throw new RuntimeException("ID不能为空");
}
GridFSFile file = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(fileId)));
if (null == file) {
throw new RuntimeException("ID对应文件不存在");
}
String fileName = file.getFilename();
//转成GridFsResource类取文件类型
response.setContentType(convertGridFSFile2Resource(file).getContentType());
try {
// 解决文件名中文乱码
response.setCharacterEncoding("UTF-8");
fileName = URLEncoder.encode(fileName, "UTF-8");
response.addHeader("Content-Disposition", "attachment; filename=\""+ fileName+"\"");
//文件长度
response.setHeader("Content-Length", String.valueOf(file.getLength()));
OutputStream out = response.getOutputStream();
//IO复制
InputStream in=convertGridFSFile2Resource(file).getInputStream();
IOUtils.copy(convertGridFSFile2Resource(file).getInputStream(), out);
} catch (IOException e) {
log.error(e.getMessage());
}
log.info("文件传输完成,退出方法");
}
private void viewImg(String fileId,
HttpServletResponse response) throws IOException {
// 因为取出来的id带有后缀,因此做去除后缀处理
if (fileId.contains(".")) {
String[] split = fileId.split("\\.");
fileId = split[0];
}
GridFSFile file = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(fileId)));
if (null == file) {
throw new RuntimeException("ID对应文件不存在");
}
String fileName = file.getFilename();
OutputStream out = response.getOutputStream();
//取后缀
String contentType = (String)file.getMetadata().get("_contentType");
String fileType= contentType.substring(contentType.lastIndexOf("/") + 1);
boolean flag = false;
for (String obj : FILE_TYPES) {
if (fileType.equalsIgnoreCase(obj)) {
flag = true;
break;
}
}
if (flag) {
log.info("图片类型,进入预览");
response.setHeader("Content-disposition", "inline; filename=" + fileName);
response.setContentType(contentType);
// 不进行压缩的文件大小,单位为bit
int notCompressionBit = 512000;
//大于512000bit就压缩,这里可以用压缩的方式,
/* if (file.getLength() > notCompressionBit) {
Thumbnails.of(convertGridFSFile2Resource(file).getInputStream())
.scale(0.2f)
.outputQuality(0.5f)
.toOutputStream(out);
}
*/
/** 采用压缩方式,则需注释调这段代码-开始 **/
//IO复制
InputStream in=convertGridFSFile2Resource(file).getInputStream();
int contentLength = (int)convertGridFSFile2Resource(file).contentLength();
byte[] data = new byte[contentLength];
in.read(data);
//response here is the HttpServletResponse object
response.setContentLength(contentLength);
out.write(data);
/** 采用压缩方式,则需注释调这段代码-结束 **/
out.flush();
out.close();
} else {
log.info("非图片类型,进入下载");
//转成GridFsResource类取文件类型
response.setContentType(convertGridFSFile2Resource(file).getContentType());
response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
//文件长度
response.setHeader("Content-Length", String.valueOf(file.getLength()));
try {
//IO复制
InputStream in = convertGridFSFile2Resource(file).getInputStream();
IOUtils.copy(
convertGridFSFile2Resource(file).getInputStream(), out);
} catch (IOException e) {
log.error(e.getMessage());
}
}
}
private GridFsResource convertGridFSFile2Resource(GridFSFile gridFsFile) {
GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFsFile.getObjectId());
return new GridFsResource(gridFsFile, gridFSDownloadStream);
}
}
4、测试
4.1 上传测试
采用 Swagger API 接口上传图片:
调用该接口返回:
通过 MongoDB 可视化工具 Studio 3T 查看上传的文件:
4.2 显示接口测试
4.3 下载接口测试
5、缩略图补充说明
对于显示和下载接口,可以对图片进行缩略操作,代码中已写,只是注释调了。采用缩略图功能,需要引入下面的 jar 包,
<!--谷歌图片压缩组件-->
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.8</version>
</dependency>