故障录波文件查询

This commit is contained in:
huguanghan 2024-11-11 16:41:25 +08:00
parent 73c6b46e40
commit 6d7fac330b
10 changed files with 547 additions and 1 deletions

View File

@ -31,6 +31,7 @@
<taosdata.verson>3.2.10</taosdata.verson>
<disruptor.version>3.4.4</disruptor.version>
<aviator.version>5.4.3</aviator.version>
<minio.version>8.4.3</minio.version>
</properties>
<dependencies>
@ -201,6 +202,13 @@
</exclusions>
</dependency>
<!-- minio -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>${minio.version}</version>
</dependency>
</dependencies>
<build>

View File

@ -0,0 +1,27 @@
package com.das.common.constant;
/**
* @Author liuyuxia
* @ClassName FilesvrConstants
* @Date 2018/12/10 0010 11:02
* @Version 2.5
* @Description 文件服务基础常量
**/
public class FileConstants {
public static final String FILE_SEPARATOR = "/";
public static final String FILE_CHARSET = "UTF-8";
/**
* 递归
*/
public static final Integer YES_RECURSIVE=1;
public static final Integer NO_RECURSIVE=0;
public static final int META_R = 1001;
public static final int META_W = 1002;
public static final String META_R_NAME = "";
public static final String META_W_NAME = "";
}

View File

@ -0,0 +1,71 @@
package com.das.modules.fdr.config;
import io.minio.*;
import io.minio.errors.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Slf4j
@Configuration
@ConditionalOnClass(MinioClient.class)
public class MinioConfig {
@Resource
private MinioProperties minioAutoProperties;
@Bean
public MinioClient minioClient() {
log.info("开始初始化MinioClient, url为{}, accessKey为:{}", minioAutoProperties.getUrl(), minioAutoProperties.getAccessKey());
MinioClient minioClient = MinioClient
.builder()
.endpoint(minioAutoProperties.getUrl())
.credentials(minioAutoProperties.getAccessKey(), minioAutoProperties.getSecretKey())
.build();
minioClient.setTimeout(
minioAutoProperties.getConnectTimeout(),
minioAutoProperties.getWriteTimeout(),
minioAutoProperties.getReadTimeout()
);
// Start detection
if (minioAutoProperties.isCheckBucket()) {
log.info("checkBucket为{}, 开始检测桶是否存在", minioAutoProperties.isCheckBucket());
String bucketName = minioAutoProperties.getBucket();
if (!checkBucket(bucketName, minioClient)) {
log.info("文件桶[{}]不存在, 开始检查是否可以新建桶", bucketName);
if (minioAutoProperties.isCreateBucket()) {
log.info("createBucket为{},开始新建文件桶", minioAutoProperties.isCreateBucket());
createBucket(bucketName, minioClient);
}
}
log.info("文件桶[{}]已存在, minio客户端连接成功!", bucketName);
} else {
throw new RuntimeException("桶不存在, 请检查桶名称是否正确或者将checkBucket属性改为false");
}
return minioClient;
}
private boolean checkBucket(String bucketName, MinioClient minioClient) {
boolean isExists = false;
try {
isExists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
} catch (Exception e) {
throw new RuntimeException("failed to check if the bucket exists", e);
}
return isExists;
}
private void createBucket(String bucketName, MinioClient minioClient) {
try {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
log.info("文件桶[{}]新建成功, minio客户端已连接", bucketName);
} catch (Exception e) {
throw new RuntimeException("failed to create default bucket", e);
}
}
}

View File

@ -0,0 +1,70 @@
package com.das.modules.fdr.config;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import org.hibernate.validator.constraints.URL;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
@Data
@Validated
@Component
public class MinioProperties {
/**
* 服务地址
*/
@NotEmpty(message = "minio服务地址不可为空")
@URL(message = "minio服务地址格式错误")
@Value("${minio.url}")
private String url;
/**
* 认证账户
*/
@NotEmpty(message = "minio认证账户不可为空")
@Value("${minio.accessKey}")
private String accessKey;
/**
* 认证密码
*/
@NotEmpty(message = "minio认证密码不可为空")
@Value("${minio.secretKey}")
private String secretKey;
/**
* 桶名称, 优先级最低
*/
@Value("${minio.bucket}")
private String bucket;
/**
* 桶不在的时候是否新建桶
*/
private boolean createBucket = true;
/**
* 启动的时候检查桶是否存在
*/
private boolean checkBucket = true;
/**
* 设置HTTP连接写入和读取超时值为0意味着没有超时
* HTTP连接超时以毫秒为单位
*/
private long connectTimeout;
/**
* 设置HTTP连接写入和读取超时值为0意味着没有超时
* HTTP写超时以毫秒为单位
*/
private long writeTimeout;
/**
* 设置HTTP连接写入和读取超时值为0意味着没有超时
* HTTP读取超时以毫秒为单位
*/
private long readTimeout;
}

View File

@ -0,0 +1,31 @@
package com.das.modules.fdr.controller;
import com.das.common.result.R;
import com.das.modules.fdr.domain.FileNode;
import com.das.modules.fdr.service.FaultRecorderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 故障录波controller
*/
@Slf4j
@RequestMapping("/api/fdr")
@RestController
public class FaultRecorderController {
@Autowired
private FaultRecorderService faultRecorderService;
@RequestMapping(value = "/files", method = RequestMethod.POST)
public R<List<FileNode>> findList(@RequestParam(required = false) String name, String startTime, String endTime) {
List<FileNode> result = faultRecorderService.getDirOrFileList(name,startTime,endTime);
return R.success(result);
}
}

View File

@ -0,0 +1,22 @@
package com.das.modules.fdr.domain;
import lombok.*;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class FileNode {
//节点名称
private String name;
// 0代表文件夹1代表文件
private int type;
private String size;
private String lastModified;
private String path;
}

View File

@ -0,0 +1,19 @@
package com.das.modules.fdr.service;
import com.das.modules.fdr.domain.FileNode;
import org.springframework.web.multipart.MultipartFile;
import java.io.OutputStream;
import java.nio.file.Path;
import java.util.List;
public interface FaultRecorderService {
List<FileNode> getDirOrFileList(String name,String startTime, String endTime);
String upload(String parent, String folderName, MultipartFile file);
void readFileToSteam(String path, OutputStream stream);
void download(String path, Path tempDir);
}

View File

@ -0,0 +1,218 @@
package com.das.modules.fdr.service;
import cn.hutool.core.io.FileUtil;
import com.das.common.constant.FileConstants;
import com.das.modules.fdr.config.MinioProperties;
import com.das.modules.fdr.domain.FileNode;
import io.micrometer.common.util.StringUtils;
import io.minio.*;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.nio.file.Path;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
@Service
@Slf4j
public class MinioViewsServcie {
@Autowired
private MinioClient minioClient;
@Autowired
private MinioProperties minioProperties;
/**
* 删除文件
*
* @param bucketName 存储桶
* @param objectName 文件名称
*/
public void removeFile(String bucketName, String objectName, Boolean recursive) throws Exception {
Iterable<Result<Item>> results = minioClient.listObjects(
ListObjectsArgs.builder().bucket(bucketName).prefix(objectName).recursive(true).build());
List<Result<Item>> list = StreamSupport.stream(results.spliterator(), false)
.collect(Collectors.toList());
if (list.size() >= 2 && !recursive) {
throw new IOException("请清空文件后再删除目录");
}
for (Result<Item> result : results) {
Item item = result.get();
minioClient.removeObject(
RemoveObjectArgs.builder()
.bucket(bucketName)
.object(item.objectName())
.build());
}
}
public Boolean deleteFileViews(String path, Boolean recursive) throws IOException {
if (StringUtils.isBlank(path)) {
throw new IOException("请确认删除文件路径");
}
Boolean success = null;
try {
path = path.substring(path.indexOf("/") + 1);
removeFile(minioProperties.getBucket(), path, recursive);
} catch (Exception e) {
throw new RuntimeException(e);
}
return success;
}
public boolean deleteFile(File file) {
return file.delete();
}
public String upload(String path, String folderName,MultipartFile file) {
String targetFile = null;
try {
// 上传一个空对象来模拟文件夹
if (!StringUtils.isBlank(folderName)){
targetFile = path + folderName + FileConstants.FILE_SEPARATOR;
ByteArrayInputStream bais = new ByteArrayInputStream(new byte[0]);
minioClient.putObject(
PutObjectArgs.builder()
.bucket(minioProperties.getBucket())
.object(targetFile)
.stream(bais, 0, -1)
.build());
}
else {
targetFile= path +"/" + file.getOriginalFilename();
uploadFile(minioProperties.getBucket(), file, targetFile, "application/octet-stream");
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return targetFile;
}
/**
* 使用MultipartFile进行文件上传
*
* @param bucketName 存储桶
* @param file 文件名
* @param objectName 对象名
* @param contentType 类型
* @throws Exception
*/
public void uploadFile(String bucketName, MultipartFile file, String objectName, String contentType) throws Exception {
InputStream inputStream = file.getInputStream();
try{
minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.contentType(contentType)
.stream(inputStream, inputStream.available(), -1)
.build());
}catch (Exception e){
log.error("minio文件上传失败{}", e);
}
}
//获取路径下的文件夹文件列表
public List<FileNode> getFileTree(String directoryName) {
List<FileNode> fileNodes = new ArrayList<>();
ListObjectsArgs build;
try {
if (StringUtils.isBlank(directoryName)) {
build = ListObjectsArgs.builder().bucket(minioProperties.getBucket()).recursive(false).build();
} else {
build = ListObjectsArgs.builder().bucket(minioProperties.getBucket()).prefix(directoryName+"/").recursive(false).build();
}
Iterable<Result<Item>> results = minioClient.listObjects(build);
for (Result<Item> result : results) {
Item item = result.get();
String itemName = item.objectName();
boolean isDir = item.isDir();
String size = FileUtil.readableFileSize(item.size());
String relativePath = null;
String[] parts = null;
if (!StringUtils.isBlank(directoryName)){
relativePath = itemName.substring(directoryName.length());
parts = relativePath.split("/");
}
else {
parts = itemName.split("/");
}
String lastModifyTime = null;
DateTimeFormatter dateFormat =DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
if (!isDir){
ZonedDateTime zonedDateTime = item.lastModified();
lastModifyTime = zonedDateTime.format(dateFormat);
}
if (parts.length > 0) {
String nodeName = parts[0];
int type = isDir ? 0 : 1;
itemName= isDir ? itemName.substring(0,itemName.lastIndexOf("/")) : itemName;
FileNode node = new FileNode(nodeName, type,size,lastModifyTime,"/"+itemName);
if (!fileNodes.contains(node)) {
fileNodes.add(node);
}
}
}
} catch (Exception e) {
log.error("minio获取树列表失败", e);
}
return fileNodes;
}
public void readFileToStream(String path, OutputStream stream) {
try ( GetObjectResponse res = minioClient.getObject(
GetObjectArgs.builder().bucket(minioProperties.getBucket()).object(path).build())){
res.transferTo(stream);
} catch (Exception e) {
log.error("minio读取文件失败", e);
}
}
public void download(String path, Path tempDir) {
try (InputStream inputStream = minioClient.getObject(GetObjectArgs.builder()
.bucket(minioProperties.getBucket())
.object(path)
.build())) {
// 保存到临时文件夹
File tempFile = tempDir.resolve(tempDir+path).toFile();
FileUtil.writeFromStream(inputStream,tempFile);
}
catch (Exception ignored){
}
}
// 递归方式 计算文件的大小
public long getTotalSizeOfFilesInDir(File file) {
if (file.isFile()) {
return file.length();
}
File[] children = file.listFiles();
long total = 0;
if (children != null) {
for (final File child : children) {
total += getTotalSizeOfFilesInDir(child);
}
}
return total;
}
}

View File

@ -0,0 +1,74 @@
package com.das.modules.fdr.service.impl;
import com.das.common.constant.FileConstants;
import com.das.modules.fdr.domain.FileNode;
import com.das.modules.fdr.service.FaultRecorderService;
import com.das.modules.fdr.service.MinioViewsServcie;
import io.micrometer.common.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.OutputStream;
import java.nio.file.Path;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class FaultRecorderServiceImpl implements FaultRecorderService {
@Autowired
private MinioViewsServcie minioViewsServcie;
@Override
public List<FileNode> getDirOrFileList(String name, String startTime, String endTime) {
List<FileNode> fileResult = new ArrayList<>();
List<String> monthsBetween = getMonthsBetween(startTime, endTime);
for (String item : monthsBetween){
String directoryName = name + FileConstants.FILE_SEPARATOR + item.substring(0,item.indexOf("-")) + FileConstants.FILE_SEPARATOR + item.substring(item.indexOf("-")+1);
List<FileNode> fileTree = minioViewsServcie.getFileTree(directoryName);
fileResult.addAll(fileTree);
}
Comparator<FileNode> fileNodeComparator = Comparator.comparing(FileNode::getLastModified)
.thenComparing(FileNode::getName);
fileResult.sort(fileNodeComparator);
return fileResult;
}
@Override
public String upload(String parent, String folderName, MultipartFile file) {
return minioViewsServcie.upload(parent, folderName, file);
}
@Override
public void readFileToSteam(String path, OutputStream stream) {
minioViewsServcie.readFileToStream(path, stream);
}
@Override
public void download(String path, Path tempDir) {
minioViewsServcie.download(path, tempDir);
}
private List<String> getMonthsBetween(String startTime, String endTime) {
List<String> months = new ArrayList<>();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate start = LocalDate.parse(startTime + "-01", formatter);
LocalDate end = LocalDate.parse(endTime + "-01", formatter);
DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy-MM");
while (!start.isAfter(end)) {
months.add(start.format(monthFormatter));
start = start.plusMonths(1);
}
return months;
}
}

View File

@ -99,3 +99,9 @@ tdengine:
password: taosdata
url: jdbc:TAOS-RS://192.168.109.160:6041/das
username: root
minio:
url: http://192.168.109.187:9000
bucket: das
accessKey: das
secretKey: zaq12WSX