Mongodb GridFs 文件管理

pull/8/head
huziyang 2021-04-06 14:11:28 +08:00
parent 9f0df66419
commit a1c23bbdea
15 changed files with 582 additions and 1 deletions

View File

@ -16,4 +16,19 @@
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--文件对象使用-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--查询流程信息,需要用到分页相关类-->
<dependency>
<groupId>cn.stylefeng.roses</groupId>
<artifactId>db-api</artifactId>
<version>7.0.2</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,43 @@
package cn.stylefeng.roses.kernel.mongodb.api;
import cn.stylefeng.roses.kernel.db.api.pojo.page.PageResult;
import org.springframework.web.multipart.MultipartFile;
import java.util.Optional;
/**
* @author huziyang
* @create 2021-03-30 11:06
*/
public interface MongoFileApi<T,ID> {
/**
*
* @param file
* @return
*/
T saveFile(MultipartFile file);
/**
*
* @param id
*/
void removeFile(ID id);
/**
* id
* @param id
* @return
*/
Optional<T> getFileById(ID id);
/**
*
* @param fileDocument
* @return
*/
PageResult<T> getFilesByPage(T fileDocument);
}

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>kernel-d-mongodb</artifactId>
<groupId>cn.stylefeng.roses</groupId>
<version>7.0.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mongodb-integration-beetl</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--资源api模块-->
<!--用在资源控制器,资源扫描上-->
<dependency>
<groupId>cn.stylefeng.roses</groupId>
<artifactId>scanner-api</artifactId>
<version>7.0.2</version>
</dependency>
<!--Mongodb file自动配置-->
<dependency>
<groupId>cn.stylefeng.roses</groupId>
<artifactId>mongodb-spring-boot-starter</artifactId>
<version>7.0.2</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,21 @@
package cn.stylefeng.roses.kernel.mongodb.integration.controller;
import cn.stylefeng.roses.kernel.scanner.api.annotation.ApiResource;
import cn.stylefeng.roses.kernel.scanner.api.annotation.GetResource;
import org.springframework.stereotype.Controller;
/**
* @author huziyang
* @create 2021-03-30 15:21
*/
@Controller
@ApiResource(name = "MongoDB文件管理界面渲染控制器")
public class ModelViewController {
@GetResource(name = "Mongodb文件列表视图", path = "/view/mongodb/file")
public String mongodbFile() {
return "/modular/mongodb/fileList.html";
}
}

View File

@ -0,0 +1,63 @@
package cn.stylefeng.roses.kernel.mongodb.integration.controller;
import cn.stylefeng.roses.kernel.mongodb.api.MongoFileApi;
import cn.stylefeng.roses.kernel.mongodb.file.entity.MongoFileEntity;
import cn.stylefeng.roses.kernel.rule.pojo.response.ResponseData;
import cn.stylefeng.roses.kernel.rule.pojo.response.SuccessResponseData;
import cn.stylefeng.roses.kernel.scanner.api.annotation.ApiResource;
import cn.stylefeng.roses.kernel.scanner.api.annotation.GetResource;
import cn.stylefeng.roses.kernel.scanner.api.annotation.PostResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Optional;
/**
* @author huziyang
* @create 2021-03-31 17:28
*/
@RestController
@ApiResource(name = "Mongodb文件接口控制器")
public class MongoFileController {
@Resource
private MongoFileApi<MongoFileEntity,String> mongoFileApi;
@PostResource(name = "Mongodb文件新增", path = "/view/mongodb/file/add")
public ResponseData mongodbFileAdd(@RequestPart("file") MultipartFile file) {
return new SuccessResponseData(mongoFileApi.saveFile(file));
}
@PostResource(name = "Mongodb文件删除", path = "/view/mongodb/file/del")
public ResponseData mongodbFileDel(@RequestParam String id) {
mongoFileApi.removeFile(id);
return new SuccessResponseData();
}
@GetResource(name = "Mongodb文件列表", path = "/view/mongodb/file/list")
public ResponseData mongodbFileList(MongoFileEntity mongoFileEntity) {
return new SuccessResponseData(mongoFileApi.getFilesByPage(mongoFileEntity));
}
@GetResource(name = "Mongodb文件下载", path = "/view/mongodb/file/down")
public ResponseEntity mongodbFileDown(@RequestParam String id) throws UnsupportedEncodingException {
Optional<MongoFileEntity> file = mongoFileApi.getFileById(id);
if(file.isPresent()){
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; fileName=" + URLEncoder.encode(file.get().getName() , "utf-8"))
.header(HttpHeaders.CONTENT_TYPE, "application/octet-stream")
.body(file.get().getContent());
}else {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("not found");
}
}
}

View File

@ -0,0 +1,99 @@
layui.use(['table', 'form', 'func', 'HttpRequest', 'util', 'upload'], function () {
var $ = layui.$;
var table = layui.table;
var form = layui.form;
var func = layui.func;
var HttpRequest = layui.HttpRequest;
var util = layui.util;
var upload = layui.upload;
// 模型设计管理
var MongoFile = {
tableId: "fileList"
};
// 初始化表格的列
MongoFile.initColumn = function () {
return [[
{type: 'checkbox'},
{field: 'id', title: '文件编号', width: 200},
{field: 'name', title: '文件名称', width: 200},
{field: 'uploadUserId', title: '创建人编号'},
{field: 'uploadDate', title: '创建日期'},
{align: 'center', toolbar: '#tableBar', title: '操作', width: 250}
]];
};
// 点击查询按钮
MongoFile.search = function () {
var queryData = {};
queryData['name'] = $("#fileName").val();
table.reload(MongoFile.tableId, {
where: queryData,
page: {curr: 1}
});
};
// 点击删除
MongoFile.delete = function (data) {
var operation = function () {
var httpRequest = new HttpRequest(Feng.ctxPath + "/view/mongodb/file/del?id="+data.id, 'post', function (data) {
Feng.success("删除成功!");
table.reload(MongoFile.tableId);
}, function (data) {
Feng.error("删除失败!" + data.message + "!");
});
httpRequest.set(data);
httpRequest.start(true);
};
Feng.confirm("是否删除文件" + data.name + "?", operation);
};
// 渲染表格
var tableResult = table.render({
elem: '#' + MongoFile.tableId,
url: Feng.ctxPath + '/view/mongodb/file/list',
page: true,
request: {pageName: 'pageNo', limitName: 'pageSize'},
height: "full-158",
cellMinWidth: 100,
cols: MongoFile.initColumn(),
parseData: Feng.parseData
});
// 搜索按钮点击事件
$('#btnSearch').click(function () {
MongoFile.search();
});
// 上传文件的点击事件
upload.render({
elem: '#modelUpload',
url: Feng.ctxPath + '/view/mongodb/file/add',
accept: 'file',
size: 10000, // 单位kb
done: function (res) {
Feng.success("上传文件成功!");
MongoFile.search();
},
error: function (err) {
Feng.error("上传文件失败!" + err.message);
}
});
// 工具条点击事件
table.on('tool(' + MongoFile.tableId + ')', function (obj) {
var data = obj.data;
var event = obj.event;
if (event === 'down') {
window.open(Feng.ctxPath + '/view/mongodb/file/down?id=' + data.id);
} else if (event === 'delete') {
MongoFile.delete(data);
}
});
});

View File

@ -0,0 +1,35 @@
@layout("/layout/_container.html",{js:["/assets/modular/mongodb/fileList.js"]}){
<div class="layui-body-header">
<span class="layui-body-header-title">Mongodb文件存储</span>
</div>
<div class="layui-fluid">
<div class="layui-row layui-col-space15">
<div class="layui-col-sm12 layui-col-md12 layui-col-lg12">
<div class="layui-card">
<div class="layui-card-body">
<div class="layui-form toolbar">
<div class="layui-form-item">
<div class="layui-inline">
<input id="fileName" class="layui-input" type="text" placeholder="文件名称"/>
</div>
<div class="layui-inline">
<button id="btnSearch" class="layui-btn icon-btn"><i class="layui-icon">&#xe615;</i>搜索</button>
<button id="modelUpload" class="layui-btn icon-btn"><i class="layui-icon">&#xe681;</i>上传文件</button>
</div>
</div>
</div>
<table class="layui-table" id="fileList" lay-filter="fileList"></table>
</div>
</div>
</div>
</div>
</div>
<script type="text/html" id="tableBar">
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="down">下载</a>
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="delete">删除</a>
</script>
@}

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>kernel-d-mongodb</artifactId>
<groupId>cn.stylefeng.roses</groupId>
<version>7.0.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mongodb-sdk-file</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--auth模块的api-->
<!--记录日志时候有可能需要记录当前登录用户id-->
<!--如果不要记录当前登录用户id时就不用本模块所以optional=true-->
<dependency>
<groupId>cn.stylefeng.roses</groupId>
<artifactId>auth-api</artifactId>
<version>7.0.2</version>
<optional>true</optional>
</dependency>
<!--MongoDB模块的api-->
<dependency>
<groupId>cn.stylefeng.roses</groupId>
<artifactId>mongodb-api</artifactId>
<version>7.0.2</version>
</dependency>
<!--SpringBoot 与 MongoDB 整合-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,36 @@
package cn.stylefeng.roses.kernel.mongodb.file.entity;
import cn.stylefeng.roses.kernel.rule.pojo.request.BaseRequest;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.Date;
/**
* @author huziyang
* @create 2021-03-26 17:23
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Document("mongo_file")
public class MongoFileEntity extends BaseRequest {
@Id
private String id;
private String name;
private Date uploadDate;
private Long uploadUserId;
private String suffix;
private String description;
private String gridfsId;
/**
*
*/
private byte[] content;
}

View File

@ -0,0 +1,13 @@
package cn.stylefeng.roses.kernel.mongodb.file.mapper;
import cn.stylefeng.roses.kernel.mongodb.file.entity.MongoFileEntity;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.repository.MongoRepository;
/**
* @author huziyang
* @create 2021-03-26 17:27
*/
@Configuration
public interface MongoFileMapper extends MongoRepository<MongoFileEntity,String> {
}

View File

@ -0,0 +1,44 @@
package cn.stylefeng.roses.kernel.mongodb.file.service;
import cn.stylefeng.roses.kernel.db.api.pojo.page.PageResult;
import cn.stylefeng.roses.kernel.mongodb.file.entity.MongoFileEntity;
import org.springframework.web.multipart.MultipartFile;
import java.util.Optional;
/**
* @author huziyang
* @create 2021-03-26 17:28
*/
public interface MongoFileService {
/**
*
* @param file
* @return
*/
MongoFileEntity saveFile(MultipartFile file);
/**
*
* @param id
*/
void removeFile(String id);
/**
* id
* @param id
* @return
*/
Optional<MongoFileEntity> getFileById(String id);
/**
*
* @param fileDocument
* @return
*/
PageResult<MongoFileEntity> getFilesByPage(MongoFileEntity fileDocument);
}

View File

@ -0,0 +1,114 @@
package cn.stylefeng.roses.kernel.mongodb.file.service.impl;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import cn.stylefeng.roses.kernel.auth.api.context.LoginContext;
import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser;
import cn.stylefeng.roses.kernel.db.api.factory.PageResultFactory;
import cn.stylefeng.roses.kernel.db.api.pojo.page.PageResult;
import cn.stylefeng.roses.kernel.mongodb.api.MongoFileApi;
import cn.stylefeng.roses.kernel.mongodb.file.entity.MongoFileEntity;
import cn.stylefeng.roses.kernel.mongodb.file.mapper.MongoFileMapper;
import cn.stylefeng.roses.kernel.mongodb.file.service.MongoFileService;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import lombok.extern.slf4j.Slf4j;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
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 org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.Date;
import java.util.Optional;
/**
* @author huziyang
* @create 2021-03-26 17:29
*/
@Slf4j
@Service
public class MongoFileServiceImpl implements MongoFileService, MongoFileApi<MongoFileEntity,String> {
@Autowired
private MongoFileMapper mongoFileMapper;
@Autowired
private GridFsTemplate gridFsTemplate;
@Autowired
private GridFSBucket gridFSBucket;
@Override
public MongoFileEntity saveFile(MultipartFile file) {
MongoFileEntity fileDocument = new MongoFileEntity();
fileDocument.setName(file.getOriginalFilename());
fileDocument.setUploadDate(new Date());
try {
// 填充登录用户的userId
LoginUser loginUser = LoginContext.me().getLoginUser();
fileDocument.setUploadUserId(loginUser.getUserId());
}catch (Exception e){
// 获取不到用户登录信息,就不填充
}
fileDocument.setSuffix(file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")));
try {
ObjectId store = gridFsTemplate.store(file.getInputStream(), IdUtil.simpleUUID(), file.getContentType());
fileDocument.setGridfsId(String.valueOf(store));
return mongoFileMapper.save(fileDocument);
}catch (IOException ex){
log.error(ex.getMessage());
}
return fileDocument;
}
@Override
public void removeFile(String id) {
Optional<MongoFileEntity> fileDocumentOptional = mongoFileMapper.findById(id);
if(fileDocumentOptional.isPresent()){
mongoFileMapper.deleteById(id);
gridFsTemplate.delete(new Query().addCriteria(Criteria.where("_id").is(fileDocumentOptional.get().getGridfsId())));
}
}
@Override
public Optional<MongoFileEntity> getFileById(String id) {
Optional<MongoFileEntity> fileDocumentOptional = mongoFileMapper.findById(id);
if(fileDocumentOptional.isPresent()){
MongoFileEntity fileDocument = fileDocumentOptional.get();
Query gridQuery = new Query().addCriteria(Criteria.where("_id").is(fileDocument.getGridfsId()));
GridFSFile fsFile = gridFsTemplate.findOne(gridQuery);
GridFSDownloadStream in = gridFSBucket.openDownloadStream(fsFile.getObjectId());
try {
if(in.getGridFSFile().getLength() > 0){
GridFsResource resource = new GridFsResource(fsFile, in);
fileDocument.setContent(IoUtil.readBytes(resource.getInputStream()));
return Optional.of(fileDocument);
}else {
return Optional.empty();
}
}catch (IOException e){
log.error(e.getMessage());
}
}
return Optional.empty();
}
@Override
public PageResult<MongoFileEntity> getFilesByPage(MongoFileEntity fileDocument) {
Integer pageIndex = fileDocument.getPageNo();
Integer pageSize = fileDocument.getPageSize();
Sort sort = Sort.by(Sort.Direction.DESC, "uploadDate");
PageRequest pageRequest = PageRequest.of(pageIndex-1, pageSize, sort);
Example<MongoFileEntity> example = Example.of(fileDocument, ExampleMatcher.matching()
.withIgnoreCase(true)
.withIgnorePaths("_class","pageSize","pageNo","content")
);
Page<MongoFileEntity> all = mongoFileMapper.findAll(example, pageRequest);
return PageResultFactory.createPageResult(all.getContent(), mongoFileMapper.count(example), pageSize, pageIndex);
}
}

View File

@ -17,12 +17,19 @@
</properties>
<dependencies>
<!--MongoDB模块的sdk-->
<!--MongoDB api模块的sdk-->
<dependency>
<groupId>cn.stylefeng.roses</groupId>
<artifactId>mongodb-sdk-springboot</artifactId>
<version>7.0.2</version>
</dependency>
<!--MongoDB文件管理模块的sdk-->
<dependency>
<groupId>cn.stylefeng.roses</groupId>
<artifactId>mongodb-sdk-file</artifactId>
<version>7.0.2</version>
</dependency>
</dependencies>
</project>

View File

@ -1,6 +1,8 @@
package cn.stylefeng.roses.kernel.mongodb.starter;
import cn.stylefeng.roses.kernel.mongodb.api.MongoFileApi;
import cn.stylefeng.roses.kernel.mongodb.api.MongodbApi;
import cn.stylefeng.roses.kernel.mongodb.file.service.impl.MongoFileServiceImpl;
import cn.stylefeng.roses.kernel.mongodb.service.impl.GunsMapServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -13,11 +15,17 @@ import org.springframework.context.annotation.Configuration;
public class GunsMongodbAutoConfiguration {
@Bean
public MongodbApi mongodbApi() {
return new GunsMapServiceImpl();
}
@Bean
public MongoFileApi mongoFileApi() {
return new MongoFileServiceImpl();
}
}

View File

@ -15,6 +15,8 @@
<module>mongodb-api</module>
<module>mongodb-sdk-springboot</module>
<module>mongodb-spring-boot-starter</module>
<module>mongodb-sdk-file</module>
<module>mongodb-integration-beetl</module>
</modules>
<properties>