目录
前言:文章有点长,希望客官能慢慢看,对您应该有一些帮助,网上的资料都太乱了。
MongoDB:
支持的数据类型:
Mongodb的优点:
实战使用:
前期准备
正式开始:
创建一个父模型类
创建一个子类模型类
编写service层接口
编写Impl层<重点>
编写controller层的接口
最像关系型数据库的非关系型数据库。
以二进制json的个数存储——BSON
String 、对象id 、布尔值 、数组 、整数 、 浮点数(默认) 、null值 、正则表达式 、 代码 、二进制
高性能:
支持索引
高可用:
高扩展:
其 他:
数据结构灵活,没有固定的列(无模式)
缺点:
对事物的支持不强
mongodb的安装笔者在这里就不说了,网上教程一大堆也很简单,推荐使用docker直接安装,方便好用。
导入依赖:
org.springframework.boot
spring-boot-starter-data-mongodb
cn.hutool
hutool-all
5.5.1
编写配置文件:
spring:
data:
mongodb:
#库名称
database: articledb
host: 127.0.0.1
port: 27017
编写配置类:
package com.juhe.web.config;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSBuckets;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author
* @date 2020/11/6 17:28
*/
@Configuration
public class MongoConfig {
//获取配置文件中数据库信息
@Value("${spring.data.mongodb.database}")
String db;
//GridFSBucket用于打开下载流
@Bean
public GridFSBucket getGridFSBucket(MongoClient mongoClient){
MongoDatabase mongoDatabase = mongoClient.getDatabase(db);
return GridFSBuckets.create(mongoDatabase);
}
}
创建工具类:
package com.liuh.commom.utils;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* @author
* @date 2020/12/9 15:29
*/
public class FileUtils {
/**
* @param response 响应
* @param fileName 文件名称
* @param contentType 文件类型
* @param content 文件内容
* @throws IOException
*/
public static void downloadFile(HttpServletResponse response, String fileName, String contentType, byte[] content) throws IOException {
// 通知浏览器进行文件下载
response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes(StandardCharsets.UTF_8), "ISO8859-1"));
response.setContentType(contentType);
response.setCharacterEncoding("utf-8");
OutputStream outputStream = response.getOutputStream();
outputStream.write(content);
outputStream.flush();
outputStream.close();
}
/**
* 获取该输入流的MD5值
*/
public static String getMD5(InputStream is) throws NoSuchAlgorithmException, IOException {
StringBuffer md5 = new StringBuffer();
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] dataBytes = new byte[1024];
int nread = 0;
while ((nread = is.read(dataBytes)) != -1) {
md.update(dataBytes, 0, nread);
}
;
byte[] mdbytes = md.digest();
// convert the byte to hex format
for (int i = 0; i < mdbytes.length; i++) {
md5.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1));
}
return md5.toString();
}
}
package com.liuh.mongodb.model;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.util.Date;
/**
* 父类模型类
* @author
* @date 2020/11/30 15:51
*/
@Data
public class CommonFileModel implements Serializable {
@Id
@ApiModelProperty(value = "主键id")
private String id;
@ApiModelProperty("文件名称")
private String name;
@ApiModelProperty("文件类型")
private String contentType;
@ApiModelProperty("文件大小")
private long size;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty("文件第一次上传时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date uploadDate;
@ApiModelProperty("文件md5值")
private String md5;
@ApiModelProperty("文件后辍名")
private String suffix;
@ApiModelProperty("文件内容")
private byte[] content;
@ApiModelProperty("大文件管理GridsFsID")
private String gridFsId;
}
每一个业务的文件继承父模型类,进行解耦,并通过@Document(collection = "自定义的表名")
灵活性:mongodb的表可以通过程序直接创建
package com.liuh.mongodb.model;
import lombok.Data;
import org.springframework.data.mongodb.core.mapping.Document;
/**
* 每一个业务应该有自己子模型类,继承父模型类,解耦
* @author
* @date 2020/12/9 14:46
*/
@Data
//设置对应的表名称
@Document(collection = "mongodbTest")
public class testFileModel extends CommonFileModel{
}
将数据存入mongodb
package com.liuh.mongodb.service;
import com.liuh.mongodb.model.TestFileModel;
import java.io.InputStream;
import java.util.Optional;
/**
* @author
* @date 2020/12/9 14:51
*/
public interface TestMongodbService {
/**
* @param in io输入流
* @param fileModel 对应文件的模型类
* @return 成功
*/
TestFileModel savaFile(InputStream in, TestFileModel fileModel);
/**
* 从mongodb中将文件内容查询出来
*
* @param fileId 文件id
* @return Optional
*/
Optional getFileContent(String fileId);
/**
* 删除mongodb 根据file_id
*
* @param fileId
* @return 1 success
*/
int removeFile(String fileId);
}
package com.liuh.mongodb.service.Impl;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import com.liuh.mongodb.model.TestFileModel;
import com.liuh.mongodb.service.TestMongodbService;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.mongodb.client.result.DeleteResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
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.stereotype.Service;
import java.io.InputStream;
import java.util.Optional;
/**
* @author
* @date 2020/12/9 15:08
*/
@Service
public class TestMongodbServiceImpl implements TestMongodbService {
@Autowired
GridFsTemplate gridFsTemplate;
@Autowired
MongoTemplate mongoTemplate;
@Autowired
GridFSBucket fsBucket;
@Override
public TestFileModel savaFile(InputStream in, TestFileModel fileModel) {
//设置存入GridFs中的文件名
String gridFsId = IdUtil.simpleUUID();
//将文件二进制数据存入GridFs中
//需要传递输入流,文件id,文件类型
gridFsTemplate.store(in, gridFsId, fileModel.getContentType());
fileModel.setGridFsId(gridFsId);
//在这里将文件对象数据存入monggdb当中
fileModel = mongoTemplate.save(fileModel);
//在将文件id和文件名称返回给前端
return fileModel;
//总监:先存储文件对象,在存储文件内容
}
@Override
public Optional getFileContent(String fileId) {
//根据id将文件对象数据从mongodb中查询出来
TestFileModel testFileModel = mongoTemplate.findById(fileId, TestFileModel.class);
//随手进行非空判断
if (testFileModel != null) {
//因为实际上真正的数据是存储到gridFs当中的,通过文件对象中的GridFsId就能操作gridFs了
Query gridQuery = new Query().addCriteria(Criteria.where("filename").is(testFileModel.getGridFsId()));
try {
//根据id查询单挑数据
final GridFSFile fsFile = gridFsTemplate.findOne(gridQuery);
//打开流下载对象
assert fsFile != null;
GridFSDownloadStream in = fsBucket.openDownloadStream(fsFile.getObjectId());
//在随手判断一手长度>0
if (in.getGridFSFile().getLength() > 0) {
//获取流对象
GridFsResource resource = new GridFsResource(fsFile, in);
//获取数据
testFileModel.setContent(IoUtil.readBytes(resource.getInputStream()));
return Optional.of(testFileModel);
} else {
return Optional.empty();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return Optional.empty();
//总结:先查出文件对象,在查出文件内容,在转换成流对象传递
}
@Override
public int removeFile(String fileId) {
//老办法先从mongodb中查询出对象数据,因为里面有我们需要的GridFs的id
TestFileModel fileModel = mongoTemplate.findById(fileId, TestFileModel.class);
//随手进行非空判断养成好习惯
if (fileModel != null) {
//根据对象中的gridfsid操作gridfs
Query deleteFile = new Query().addCriteria(Criteria.where("filename").is(fileModel.getGridFsId()));
//删除文件内容
gridFsTemplate.delete(deleteFile);
//删除文件对象
Query deleteQuery = new Query(Criteria.where("id").is(fileId));
DeleteResult remove = mongoTemplate.remove(deleteQuery, TestFileModel.class);
return (int) remove.getDeletedCount();
//总结先查询出 gridfsid 根据gridfsid删除gridfs中的文件内容,然后在删除mongodb中的文件对象。
}
return 0;
}
}
package com.juhe.demo.controller;
import com.liuh.commom.utils.FileUtils;
import com.liuh.mongodb.model.TestFileModel;
import com.liuh.mongodb.service.TestMongodbService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
/**
* @author
* @date 2020/12/9 14:37
*/
@RestController
@Api(tags = "mongodb测试API")
@RequestMapping("/test/mongodb")
@Slf4j
public class mongodbcontroller {
@Autowired
TestMongodbService testMongodbService;
/**
* 文件上传,并返回文件id和文件名称
*
* @param file
* @return map
*/
@PostMapping("/upload")
@ApiOperation("上传附件")
public Map uploadtest(MultipartFile file) {
try {
Map map = new HashMap<>(2);
//将上窜的文件存储到首先创建好的模型类
TestFileModel testFileModel = new TestFileModel();
//从file中获取到文件名称
testFileModel.setName(file.getOriginalFilename());
//从file中获取到文件的长度
testFileModel.setSize(file.getSize());
//从file中获取到文件类型
testFileModel.setContentType(file.getContentType());
//记录首次上传时间
testFileModel.setUploadDate(new Date());
//获取文件后缀 通过‘.’的索引进行切割
String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().indexOf("."));
testFileModel.setSuffix(suffix);
//获取这个输入流的MD5值
testFileModel.setMd5(FileUtils.getMD5(file.getInputStream()));
final TestFileModel fileModel = testMongodbService.savaFile(file.getInputStream(), testFileModel);
//将实现层生成的文件id和文件名称返回给前端
map.put("fileId", fileModel.getId());
map.put("fileName", fileModel.getName());
return map;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@GetMapping("/download")
@ApiOperation("文件下载")
public void downloadtest(@RequestParam("fileId") String fineId, HttpServletResponse response) {
try {
//直接从实现层获取数据
Optional fileContent = testMongodbService.getFileContent(fineId);
TestFileModel fileModel = fileContent.get();
//这里就用到了我们前期准备的工具类了,通知浏览器进行下载
FileUtils.downloadFile(response, fileModel.getName(), fileModel.getContentType(), fileModel.getContent());
} catch (Exception e) {
e.printStackTrace();
}
}
@DeleteMapping("/delete/file")
@ApiOperation("删除文件")
public int deletetestfile(@RequestParam String fileId){
//先删除mongodb数据
int i = testMongodbService.removeFile(fileId);
if(i!=1){
log.error("文件删除石板 文件id为:{}", fileId);
}
return i;
}
}
源码地址:
https://liuhong.lanzous.com/iPyGLj7dsyb