Commit 23b676e48384b66fdd88c77d3b894e0924d0a65d

Authored by 648540858
1 parent 1cce3324

添加对旧录像文件的处理

Showing 29 changed files with 580 additions and 2785 deletions
libs/jdbc-aarch/kingbase8-8.6.0.jar 0 → 100644
No preview for this file type
libs/jdbc-aarch/kingbase8-8.6.0.jre7.jar 0 → 100644
No preview for this file type
libs/jdbc-aarch/postgresql-42.2.9.jar 0 → 100644
No preview for this file type
libs/jdbc-aarch/postgresql-42.2.9.jre7.jar 0 → 100644
No preview for this file type
... ... @@ -44,6 +44,49 @@
44 44 </dependency>
45 45  
46 46 <dependency>
  47 + <groupId>org.springframework.boot</groupId>
  48 + <artifactId>spring-boot-starter-jdbc</artifactId>
  49 + </dependency>
  50 +
  51 + <!-- mysql数据库 -->
  52 + <dependency>
  53 + <groupId>mysql</groupId>
  54 + <artifactId>mysql-connector-java</artifactId>
  55 + <version>8.0.30</version>
  56 + </dependency>
  57 +
  58 + <!--postgresql-->
  59 + <dependency>
  60 + <groupId>org.postgresql</groupId>
  61 + <artifactId>postgresql</artifactId>
  62 + <version>42.5.1</version>
  63 + </dependency>
  64 +
  65 + <!-- kingbase人大金仓 -->
  66 + <!-- 手动下载驱动后安装 -->
  67 + <!-- mvn install:install-file -Dfile=/home/lin/soft/kingbase/jdbc-aarch/kingbase8-8.6.0.jar -DgroupId=com.kingbase -DartifactId=kingbase8 -Dversion=8.6.0 -Dpackaging=jar
  68 + -->
  69 + <dependency>
  70 + <groupId>com.kingbase</groupId>
  71 + <artifactId>kingbase8</artifactId>
  72 + <version>8.6.0</version>
  73 + <scope>system</scope>
  74 + <systemPath>${basedir}/libs/jdbc-aarch/kingbase8-8.6.0.jar</systemPath>
  75 + </dependency>
  76 +
  77 + <dependency>
  78 + <groupId>org.mybatis.spring.boot</groupId>
  79 + <artifactId>mybatis-spring-boot-starter</artifactId>
  80 + <version>2.2.2</version>
  81 + <exclusions>
  82 + <exclusion>
  83 + <groupId>com.zaxxer</groupId>
  84 + <artifactId>HikariCP</artifactId>
  85 + </exclusion>
  86 + </exclusions>
  87 + </dependency>
  88 +
  89 + <dependency>
47 90 <groupId>net.bramp.ffmpeg</groupId>
48 91 <artifactId>ffmpeg</artifactId>
49 92 <version>0.6.2</version>
... ... @@ -56,18 +99,6 @@
56 99 <version>1.2.73</version>
57 100 </dependency>
58 101  
59   - <!--在线文档 -->
60   - <dependency>
61   - <groupId>org.springdoc</groupId>
62   - <artifactId>springdoc-openapi-ui</artifactId>
63   - <version>1.6.10</version>
64   - </dependency>
65   - <dependency>
66   - <groupId>com.github.xiaoymin</groupId>
67   - <artifactId>knife4j-springdoc-ui</artifactId>
68   - <version>3.0.3</version>
69   - </dependency>
70   -
71 102 <dependency>
72 103 <groupId>org.mp4parser</groupId>
73 104 <artifactId>muxer</artifactId>
... ...
src/main/java/top/panll/assist/config/FastJsonRedisSerializer.java deleted 100755 → 0
1   -package top.panll.assist.config;
2   -
3   -import com.alibaba.fastjson.JSON;
4   -import com.alibaba.fastjson.parser.ParserConfig;
5   -import com.alibaba.fastjson.serializer.SerializerFeature;
6   -import org.springframework.data.redis.serializer.RedisSerializer;
7   -import org.springframework.data.redis.serializer.SerializationException;
8   -
9   -import java.nio.charset.Charset;
10   -
11   -public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
12   - private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
13   - private Class<T> clazz;
14   -
15   - /**
16   - * 添加autotype白名单
17   - * 解决redis反序列化对象时报错 :com.alibaba.fastjson.JSONException: autoType is not support
18   - */
19   - static {
20   - ParserConfig.getGlobalInstance().addAccept("top.panll.assist");
21   - }
22   -
23   - public FastJsonRedisSerializer(Class<T> clazz) {
24   - super();
25   - this.clazz = clazz;
26   - }
27   -
28   - @Override
29   - public byte[] serialize(T t) throws SerializationException {
30   - if (null == t) {
31   - return new byte[0];
32   - }
33   - return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
34   - }
35   -
36   - @Override
37   - public T deserialize(byte[] bytes) throws SerializationException {
38   - if (null == bytes || bytes.length <= 0) {
39   - return null;
40   - }
41   - String str = new String(bytes, DEFAULT_CHARSET);
42   - return JSON.parseObject(str, clazz);
43   - }
44   -}
src/main/java/top/panll/assist/config/GlobalExceptionHandler.java deleted 100755 → 0
1   -package top.panll.assist.config;
2   -
3   -import org.slf4j.Logger;
4   -import org.slf4j.LoggerFactory;
5   -import org.springframework.http.HttpStatus;
6   -import org.springframework.web.bind.annotation.ExceptionHandler;
7   -import org.springframework.web.bind.annotation.ResponseStatus;
8   -import org.springframework.web.bind.annotation.RestControllerAdvice;
9   -import top.panll.assist.controller.bean.ControllerException;
10   -import top.panll.assist.controller.bean.ErrorCode;
11   -import top.panll.assist.controller.bean.WVPResult;
12   -
13   -/**
14   - * 全局异常处理
15   - */
16   -@RestControllerAdvice
17   -public class GlobalExceptionHandler {
18   -
19   - private final static Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
20   -
21   - /**
22   - * 默认异常处理
23   - * @param e 异常
24   - * @return 统一返回结果
25   - */
26   - @ExceptionHandler(Exception.class)
27   - @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
28   - public WVPResult<String> exceptionHandler(Exception e) {
29   - logger.error("[全局异常]: ", e);
30   - return WVPResult.fail(ErrorCode.ERROR500.getCode(), e.getMessage());
31   - }
32   -
33   - /**
34   - * 自定义异常处理, 处理controller中返回的错误
35   - * @param e 异常
36   - * @return 统一返回结果
37   - */
38   - @ExceptionHandler(ControllerException.class)
39   - @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
40   - public WVPResult<String> exceptionHandler(ControllerException e) {
41   - return WVPResult.fail(e.getCode(), e.getMsg());
42   - }
43   -
44   -}
src/main/java/top/panll/assist/config/GlobalResponseAdvice.java deleted 100755 → 0
1   -package top.panll.assist.config;
2   -
3   -import com.alibaba.fastjson.JSON;
4   -import org.springframework.core.MethodParameter;
5   -import org.springframework.http.MediaType;
6   -import org.springframework.http.converter.HttpMessageConverter;
7   -import org.springframework.http.server.ServerHttpRequest;
8   -import org.springframework.http.server.ServerHttpResponse;
9   -import org.springframework.web.bind.annotation.RestControllerAdvice;
10   -import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
11   -import top.panll.assist.controller.bean.ErrorCode;
12   -import top.panll.assist.controller.bean.WVPResult;
13   -
14   -import javax.validation.constraints.NotNull;
15   -
16   -/**
17   - * 全局统一返回结果
18   - * @author lin
19   - */
20   -@RestControllerAdvice
21   -public class GlobalResponseAdvice implements ResponseBodyAdvice<Object> {
22   -
23   -
24   - @Override
25   - public boolean supports(@NotNull MethodParameter returnType, @NotNull Class<? extends HttpMessageConverter<?>> converterType) {
26   - return true;
27   - }
28   -
29   - @Override
30   - public Object beforeBodyWrite(Object body, @NotNull MethodParameter returnType, @NotNull MediaType selectedContentType, @NotNull Class<? extends HttpMessageConverter<?>> selectedConverterType, @NotNull ServerHttpRequest request, @NotNull ServerHttpResponse response) {
31   - // 排除api文档的接口,这个接口不需要统一
32   - String[] excludePath = {"/v3/api-docs","/api/v1","/index/hook"};
33   - for (String path : excludePath) {
34   - if (request.getURI().getPath().startsWith(path)) {
35   - return body;
36   - }
37   - }
38   -
39   - if (body instanceof WVPResult) {
40   - return body;
41   - }
42   -
43   - if (body instanceof ErrorCode) {
44   - ErrorCode errorCode = (ErrorCode) body;
45   - return new WVPResult<>(errorCode.getCode(), errorCode.getMsg(), null);
46   - }
47   -
48   - if (body instanceof String) {
49   - return JSON.toJSONString(WVPResult.success(body));
50   - }
51   -
52   - return WVPResult.success(body);
53   - }
54   -}
src/main/java/top/panll/assist/config/RedisConfig.java deleted 100755 → 0
1   -package top.panll.assist.config;
2   -
3   -import com.alibaba.fastjson.parser.ParserConfig;
4   -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
5   -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
6   -import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
7   -import org.springframework.boot.context.properties.EnableConfigurationProperties;
8   -import org.springframework.context.annotation.Bean;
9   -import org.springframework.context.annotation.Configuration;
10   -import org.springframework.data.redis.connection.RedisConnectionFactory;
11   -import org.springframework.data.redis.core.RedisOperations;
12   -import org.springframework.data.redis.core.RedisTemplate;
13   -import org.springframework.data.redis.listener.RedisMessageListenerContainer;
14   -import org.springframework.data.redis.serializer.StringRedisSerializer;
15   -
16   -/**
17   - * @Description:Redis中间件配置类,使用spring-data-redis集成,自动从application.yml中加载redis配置
18   - * @author: swwheihei
19   - * @date: 2019年5月30日 上午10:58:25
20   - *
21   - */
22   -@Configuration
23   -@ConditionalOnClass(RedisOperations.class)
24   -@EnableConfigurationProperties(RedisProperties.class)
25   -public class RedisConfig {
26   -
27   - static {
28   - ParserConfig.getGlobalInstance().addAccept("top.panll.assist");
29   - }
30   -
31   - @Bean
32   - @ConditionalOnMissingBean(name = "redisTemplate")
33   - public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
34   - RedisTemplate<Object, Object> template = new RedisTemplate<>();
35   - template.setConnectionFactory(redisConnectionFactory);
36   - // 使用fastjson进行序列化处理,提高解析效率
37   - FastJsonRedisSerializer<Object> serializer = new FastJsonRedisSerializer<>(Object.class);
38   - // value值的序列化采用fastJsonRedisSerializer
39   - template.setValueSerializer(serializer);
40   - template.setHashValueSerializer(serializer);
41   - // key的序列化采用StringRedisSerializer
42   - template.setKeySerializer(new StringRedisSerializer());
43   - template.setHashKeySerializer(new StringRedisSerializer());
44   - template.setConnectionFactory(redisConnectionFactory);
45   - // 使用fastjson时需设置此项,否则会报异常not support type
46   -// ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
47   - return template;
48   -
49   - }
50   -
51   - /**
52   - * redis消息监听器容器 可以添加多个监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,该消息监听器
53   - * 通过反射技术调用消息订阅处理器的相关方法进行一些业务处理
54   - *
55   - * @param connectionFactory
56   - * @return
57   - */
58   - @Bean
59   - RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
60   -
61   - RedisMessageListenerContainer container = new RedisMessageListenerContainer();
62   - container.setConnectionFactory(connectionFactory);
63   - return container;
64   - }
65   -
66   -}
src/main/java/top/panll/assist/config/SpringDocConfig.java deleted 100755 → 0
1   -package top.panll.assist.config;
2   -
3   -import io.swagger.v3.oas.models.OpenAPI;
4   -import io.swagger.v3.oas.models.info.Contact;
5   -import io.swagger.v3.oas.models.info.Info;
6   -import io.swagger.v3.oas.models.info.License;
7   -import org.springdoc.core.GroupedOpenApi;
8   -import org.springframework.beans.factory.annotation.Value;
9   -import org.springframework.context.annotation.Bean;
10   -import org.springframework.context.annotation.Configuration;
11   -
12   -/**
13   - * @author lin
14   - */
15   -@Configuration
16   -public class SpringDocConfig {
17   -
18   - @Value("${doc.enabled: true}")
19   - private boolean enable;
20   -
21   - @Bean
22   - public OpenAPI springShopOpenApi() {
23   - Contact contact = new Contact();
24   - contact.setName("pan");
25   - contact.setEmail("648540858@qq.com");
26   - return new OpenAPI()
27   - .info(new Info().title("WVP-PRO-ASSIST 接口文档")
28   - .contact(contact)
29   - .description("WVP-PRO助手,补充ZLM功能")
30   - .version("v2.0")
31   - .license(new License().name("Apache 2.0").url("http://springdoc.org")));
32   - }
33   -
34   - /**
35   - * 添加分组
36   - * @return
37   - */
38   - @Bean
39   - public GroupedOpenApi publicApi() {
40   - return GroupedOpenApi.builder()
41   - .group("1. 全部")
42   - .packagesToScan("top.panll.assist")
43   - .build();
44   - }
45   -}
src/main/java/top/panll/assist/config/StartConfig.java
1 1 package top.panll.assist.config;
2 2  
3   -import net.bramp.ffmpeg.FFmpeg;
4   -import net.bramp.ffmpeg.FFprobe;
5 3 import org.slf4j.Logger;
6 4 import org.slf4j.LoggerFactory;
7 5 import org.springframework.beans.factory.annotation.Autowired;
8 6 import org.springframework.beans.factory.annotation.Value;
9 7 import org.springframework.boot.CommandLineRunner;
10 8 import org.springframework.core.annotation.Order;
  9 +import org.springframework.jdbc.datasource.DataSourceTransactionManager;
11 10 import org.springframework.stereotype.Component;
12   -import top.panll.assist.dto.UserSettings;
13   -import top.panll.assist.service.FFmpegExecUtils;
14   -import top.panll.assist.service.VideoFileService;
  11 +import org.springframework.transaction.TransactionDefinition;
  12 +import org.springframework.transaction.TransactionStatus;
  13 +import top.panll.assist.dto.CloudRecordItem;
  14 +import top.panll.assist.mapper.CloudRecordServiceMapper;
  15 +import top.panll.assist.utils.DateUtils;
15 16  
16 17 import java.io.*;
17   -import java.nio.charset.StandardCharsets;
  18 +import java.util.ArrayList;
  19 +import java.util.HashMap;
  20 +import java.util.List;
  21 +import java.util.Map;
18 22  
19 23 /**
20 24 * 用于启动检查环境
21 25 */
22 26 @Component
23   -@Order(value=1)
  27 +@Order(value=10)
24 28 public class StartConfig implements CommandLineRunner {
25 29  
26 30 private final static Logger logger = LoggerFactory.getLogger(StartConfig.class);
27 31  
28   - @Value("${server.port}")
29   - private String port;
  32 + @Value("${user-settings.record}")
  33 + private String record;
  34 +
  35 + @Value("${user-settings.media-server-id}")
  36 + private String mediaServerId;
  37 +
  38 + @Autowired
  39 + DataSourceTransactionManager dataSourceTransactionManager;
30 40  
31 41 @Autowired
32   - private UserSettings userSettings;
  42 + TransactionDefinition transactionDefinition;
33 43  
34 44 @Autowired
35   - private VideoFileService videoFileService;
  45 + private CloudRecordServiceMapper cloudRecordServiceMapper;
36 46  
37 47  
38 48 @Override
39 49 public void run(String... args) {
40   - String record = userSettings.getRecord();
41 50 if (!record.endsWith(File.separator)) {
42   - userSettings.setRecord(userSettings.getRecord() + File.separator);
  51 + record = record + File.separator;
43 52 }
44 53  
45 54 File recordFile = new File(record);
46 55 if (!recordFile.exists()){
47   - logger.warn("[userSettings.record]路径不存在,开始创建");
48   - boolean mkResult = recordFile.mkdirs();
49   - if (!mkResult) {
50   - logger.info("[userSettings.record]目录创建失败");
51   - System.exit(1);
52   - }
53   - }else {
54   - if ( !recordFile.isDirectory()) {
55   - logger.warn("[userSettings.record]路径是文件,请修改为目录");
56   - System.exit(1);
57   - }
58   - if (!recordFile.canRead()) {
59   - logger.error("[userSettings.record]路径无法读取");
60   - System.exit(1);
  56 + logger.warn("{}路径不存在", record);
  57 + System.exit(1);
  58 + }
  59 + logger.info("开始搜集数据");
  60 + File[] appFiles = recordFile.listFiles();
  61 + if (appFiles == null) {
  62 + logger.warn("{}路径下没有录像", record);
  63 + System.exit(1);
  64 + }
  65 + if (appFiles.length == 0) {
  66 + logger.warn("{}路径下没有录像", record);
  67 + System.exit(1);
  68 + }
  69 + List<CloudRecordItem> cloudRecordItemList = new ArrayList<>();
  70 + Map<String, String> renameMap = new HashMap<>();
  71 + // 搜集数据
  72 + for (File file : appFiles) {
  73 + if (!file.isDirectory()) {
  74 + continue;
61 75 }
62   - if (!recordFile.canWrite()) {
63   - logger.error("[userSettings.record]路径无法写入");
64   - System.exit(1);
  76 + String app = file.getName();
  77 + File[] streamFiles = file.listFiles();
  78 + if (streamFiles == null || streamFiles.length == 0) {
  79 + continue;
65 80 }
66   - }
67   -
68   - try {
69   -
70   - // 对目录进行预整理
71   - File[] appFiles = recordFile.listFiles();
72   - if (appFiles != null && appFiles.length > 0) {
73   - for (File appFile : appFiles) {
74   - if (appFile.getName().equals("recordTemp")) {
75   - continue;
76   - }
77   - File[] streamFiles = appFile.listFiles();
78   - if (streamFiles != null && streamFiles.length > 0) {
79   - for (File streamFile : streamFiles) {
80   - File[] dateFiles = streamFile.listFiles();
81   - if (dateFiles != null && dateFiles.length > 0) {
82   - for (File dateFile : dateFiles) {
83   - File[] files = dateFile.listFiles();
84   - if (files != null && files.length > 0) {
85   - for (File file : files) {
86   - videoFileService.handFile(file, appFile.getName(), streamFile.getName());
87   - }
  81 + for (File streamFile : streamFiles) {
  82 + String stream = streamFile.getName();
  83 + if ("rtp".equals(app)) {
  84 +
  85 + }else {
  86 + if (stream.indexOf("_") > 0) {
  87 + String[] streamInfoArray = stream.split("_");
  88 + if (streamInfoArray.length != 2) {
  89 + logger.warn("无法识别 {}/{}", app, stream);
  90 + continue;
  91 + }
  92 + stream = streamInfoArray[0];
  93 + String callId = streamInfoArray[1];
  94 + File[] dateFiles = streamFile.listFiles();
  95 + if (dateFiles == null || dateFiles.length == 0) {
  96 + continue;
  97 + }
  98 + // TODC 确定关联和归档分别使用了什么类型名称
  99 + boolean collect = false;
  100 + boolean reserve = false;
  101 + for (File dateFile : dateFiles) {
  102 + if (dateFile.isFile()) {
  103 + if (dateFile.getName().endsWith(".sign")) {
  104 + if (dateFile.getName().startsWith("a")) {
  105 + collect = true;
  106 + }else if (dateFile.getName().startsWith("b")) {
  107 + reserve = true;
88 108 }
89 109 }
  110 + }else {
  111 + // 检验是否是日期格式
  112 + if (!DateUtils.checkDateFormat(dateFile.getName())) {
  113 + continue;
  114 + }
  115 + String date = dateFile.getName();
  116 + File[] videoFiles = dateFile.listFiles();
  117 + if (videoFiles == null || videoFiles.length == 0) {
  118 + continue;
  119 + }
  120 + for (int i = 0; i < videoFiles.length; i++) {
  121 + File videoFile = videoFiles[i];
  122 + if (!videoFile.getName().endsWith(".mp4") && !videoFile.getName().contains("-")) {
  123 + continue;
  124 + }
  125 + String[] videoInfoArray = videoFile.getName().split("-");
  126 + if (videoInfoArray.length != 3) {
  127 + logger.info("非目标视频文件格式,忽略此文件: {}", videoFile.getAbsolutePath() );
  128 + continue;
  129 + }
  130 + if (!DateUtils.checkDateTimeFormat(date + " " + videoInfoArray[0])
  131 + || !DateUtils.checkDateTimeFormat(date + " " + videoInfoArray[1]) ) {
  132 + logger.info("目标视频文件明明异常,忽略此文件: {}", videoFile.getName() );
  133 + continue;
  134 + }
  135 + String startTime = date + " " + videoInfoArray[0];
  136 + String endTime = date + " " + videoInfoArray[1];
  137 + Long startTimeStamp = DateUtils.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime);
  138 + Long endTimeStamp = DateUtils.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime);
  139 +
  140 + long timeLength = Long.parseLong(videoInfoArray[2].substring(0, videoInfoArray[2].length() - 4));
  141 + CloudRecordItem cloudRecordItem = new CloudRecordItem();
  142 + cloudRecordItem.setApp(app);
  143 + cloudRecordItem.setStream(stream);
  144 + cloudRecordItem.setCallId(callId);
  145 + cloudRecordItem.setStartTime(startTimeStamp);
  146 + cloudRecordItem.setEndTime(endTimeStamp);
  147 + cloudRecordItem.setCollect(collect);
  148 + cloudRecordItem.setReserve(reserve);
  149 + cloudRecordItem.setMediaServerId(mediaServerId);
  150 + cloudRecordItem.setFileName(DateUtils.getTimeStr(startTimeStamp) + "-" + i + ".mp4");
  151 + cloudRecordItem.setFolder(streamFile.getAbsolutePath());
  152 + cloudRecordItem.setFileSize(videoFile.length());
  153 + cloudRecordItem.setTimeLen(timeLength);
  154 + cloudRecordItem.setFilePath(videoFile.getParentFile().getAbsolutePath() + File.separator + cloudRecordItem.getFileName());
  155 + cloudRecordItemList.add(cloudRecordItem);
  156 + renameMap.put(videoFile.getAbsolutePath(), cloudRecordItem.getFilePath());
  157 + System.out.println(cloudRecordItem.getFilePath());
  158 + }
90 159 }
91   -
92 160 }
93 161 }
94   -
95 162 }
96 163 }
97   -
98   - } catch (Exception exception){
99   - exception.printStackTrace();
100   - logger.error("环境错误: " + exception.getMessage());
  164 + logger.info("数据收集完成, 待处理数据为: {}条", cloudRecordItemList.size());
  165 + logger.info("开始将数据写入数据库");
  166 + TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
  167 + int limitCount = 50;
  168 + if (cloudRecordItemList.size() > 0) {
  169 + if (cloudRecordItemList.size() > limitCount) {
  170 + for (int i = 0; i < cloudRecordItemList.size(); i += limitCount) {
  171 + int toIndex = i + limitCount;
  172 + if (i + limitCount > cloudRecordItemList.size()) {
  173 + toIndex = cloudRecordItemList.size();
  174 + }
  175 + int length = cloudRecordServiceMapper.batchAdd(cloudRecordItemList.subList(i, toIndex));
  176 + if (length == 0) {
  177 + dataSourceTransactionManager.rollback(transactionStatus);
  178 + }
  179 + }
  180 + } else {
  181 + cloudRecordServiceMapper.batchAdd(cloudRecordItemList);
  182 + }
  183 + dataSourceTransactionManager.commit(transactionStatus);
  184 + }
  185 + logger.info("数据写入数据库完成");
101 186 }
  187 +
  188 +
102 189 }
103 190  
104   -// private void writeAssistDownPage(File recordFile) {
105   -// try {
106   -// File file = new File(recordFile.getParentFile().getAbsolutePath(), "download.html");
107   -// if (file.exists()) {
108   -// file.delete();
109   -// }
110   -// file.createNewFile();
111   -// FileOutputStream fs = new FileOutputStream(file);
112   -// StringBuffer stringBuffer = new StringBuffer();
113   -// String content = "<!DOCTYPE html>\n" +
114   -// "<html lang=\"en\">\n" +
115   -// "<head>\n" +
116   -// " <meta charset=\"UTF-8\">\n" +
117   -// " <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n" +
118   -// " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
119   -// " <title>下载</title>\n" +
120   -// "</head>\n" +
121   -// "<body>\n" +
122   -// " <a id=\"download\" download />\n" +
123   -// " <script>\n" +
124   -// " (function(){\n" +
125   -// " let searchParams = new URLSearchParams(location.search);\n" +
126   -// " var download = document.getElementById(\"download\");\n" +
127   -// " download.setAttribute(\"href\", searchParams.get(\"url\"))\n" +
128   -// " download.click()\n" +
129   -// " setTimeout(()=>{\n" +
130   -// " window.location.href=\"about:blank\";\n" +
131   -// "\t\t\t window.close();\n" +
132   -// " },200)\n" +
133   -// " })();\n" +
134   -// " \n" +
135   -// " </script>\n" +
136   -// "</body>\n" +
137   -// "</html>";
138   -// fs.write(content.getBytes(StandardCharsets.UTF_8));
139   -// logger.info("已写入html配置页面: " + file.getAbsolutePath());
140   -// } catch (FileNotFoundException e) {
141   -// logger.error("写入html页面错误", e);
142   -// } catch (IOException e) {
143   -// logger.error("写入html页面错误", e);
144   -// }
145   -//
146   -//
147   -// }
  191 +
148 192 }
... ...
src/main/java/top/panll/assist/config/WebMvcConfig.java deleted 100755 → 0
1   -package top.panll.assist.config;
2   -
3   -import org.springframework.beans.factory.annotation.Autowired;
4   -import org.springframework.context.annotation.Configuration;
5   -import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
6   -import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
7   -import top.panll.assist.dto.UserSettings;
8   -
9   -import java.io.File;
10   -
11   -
12   -@Configuration
13   -public class WebMvcConfig extends WebMvcConfigurerAdapter {
14   -
15   - @Autowired
16   - private UserSettings userSettings;
17   -
18   - @Override
19   - public void addResourceHandlers(ResourceHandlerRegistry registry) {
20   - File file = new File(userSettings.getRecord());
21   - registry.addResourceHandler("/download/**").addResourceLocations("file://" + file.getAbsolutePath() + "/");
22   - super.addResourceHandlers(registry);
23   - }
24   -}
src/main/java/top/panll/assist/controller/DownController.java deleted 100755 → 0
1   -package top.panll.assist.controller;
2   -
3   -
4   -import org.apache.catalina.connector.ClientAbortException;
5   -import org.mp4parser.BasicContainer;
6   -import org.mp4parser.Container;
7   -import org.mp4parser.muxer.Movie;
8   -import org.mp4parser.muxer.Track;
9   -import org.mp4parser.muxer.builder.DefaultMp4Builder;
10   -import org.mp4parser.muxer.builder.Mp4Builder;
11   -import org.mp4parser.muxer.container.mp4.MovieCreator;
12   -import org.mp4parser.muxer.tracks.AppendTrack;
13   -import org.slf4j.Logger;
14   -import org.slf4j.LoggerFactory;
15   -import org.springframework.beans.factory.annotation.Autowired;
16   -import org.springframework.stereotype.Controller;
17   -import org.springframework.web.bind.annotation.GetMapping;
18   -import org.springframework.web.bind.annotation.RequestMapping;
19   -import org.springframework.web.bind.annotation.ResponseBody;
20   -import top.panll.assist.dto.UserSettings;
21   -
22   -import javax.servlet.http.HttpServletRequest;
23   -import javax.servlet.http.HttpServletResponse;
24   -import java.io.*;
25   -import java.nio.channels.Channels;
26   -import java.nio.channels.WritableByteChannel;
27   -import java.nio.charset.StandardCharsets;
28   -import java.util.ArrayList;
29   -import java.util.LinkedList;
30   -import java.util.List;
31   -
32   -@Controller
33   -@RequestMapping("/down")
34   -public class DownController {
35   -
36   - private final static Logger logger = LoggerFactory.getLogger(DownController.class);
37   -
38   - @Autowired
39   - private UserSettings userSettings;
40   -
41   - /**
42   - * 获取app+stream列表
43   - *
44   - * @return
45   - */
46   - @GetMapping(value = "/**")
47   - @ResponseBody
48   - public void download(HttpServletRequest request, HttpServletResponse response) throws IOException {
49   -
50   - List<String> videoList = new ArrayList<>();
51   - videoList.add("/home/lin/server/test/zlm/Debug/www/record/rtp/34020000002000000003_34020000001310000001/2023-03-20/16-09-07.mp4");
52   - videoList.add("/home/lin/server/test/zlm/Debug/www/record/rtp/34020000002000000003_34020000001310000001/2023-03-20/17-12-10.mp4");
53   - videoList.add("/home/lin/server/test/zlm/Debug/www/record/rtp/34020000002000000003_34020000001310000001/2023-03-20/17-38-36.mp4");
54   - List<Movie> sourceMovies = new ArrayList<>();
55   - for (String video : videoList) {
56   - sourceMovies.add(MovieCreator.build(video));
57   - }
58   -
59   - List<Track> videoTracks = new LinkedList<>();
60   - List<Track> audioTracks = new LinkedList<>();
61   - for (Movie movie : sourceMovies) {
62   - for (Track track : movie.getTracks()) {
63   - if ("soun".equals(track.getHandler())) {
64   - audioTracks.add(track);
65   - }
66   -
67   - if ("vide".equals(track.getHandler())) {
68   - videoTracks.add(track);
69   - }
70   - }
71   - }
72   - Movie mergeMovie = new Movie();
73   - if (audioTracks.size() > 0) {
74   - mergeMovie.addTrack(new AppendTrack(audioTracks.toArray(new Track[audioTracks.size()])));
75   - }
76   -
77   - if (videoTracks.size() > 0) {
78   - mergeMovie.addTrack(new AppendTrack(videoTracks.toArray(new Track[videoTracks.size()])));
79   - }
80   -
81   - BasicContainer out = (BasicContainer)new DefaultMp4Builder().build(mergeMovie);
82   -
83   - // 文件名
84   - String fileName = "测试.mp4";
85   - // 文件类型
86   - String contentType = request.getServletContext().getMimeType(fileName);
87   -
88   - // 解决下载文件时文件名乱码问题
89   - byte[] fileNameBytes = fileName.getBytes(StandardCharsets.UTF_8);
90   - fileName = new String(fileNameBytes, 0, fileNameBytes.length, StandardCharsets.ISO_8859_1);
91   -
92   - response.setHeader("Content-Type", contentType);
93   - response.setHeader("Content-Length", String.valueOf(out));
94   - //inline表示浏览器直接使用,attachment表示下载,fileName表示下载的文件名
95   - response.setHeader("Content-Disposition", "inline;filename=" + fileName);
96   - response.setContentType(contentType);
97   -
98   - WritableByteChannel writableByteChannel = Channels.newChannel(response.getOutputStream());
99   - out.writeContainer(writableByteChannel);
100   - writableByteChannel.close();
101   -
102   - }
103   -}
src/main/java/top/panll/assist/controller/RecordController.java deleted 100755 → 0
1   -package top.panll.assist.controller;
2   -
3   -import com.alibaba.fastjson.JSON;
4   -import com.alibaba.fastjson.JSONObject;
5   -import io.swagger.v3.oas.annotations.Operation;
6   -import io.swagger.v3.oas.annotations.Parameter;
7   -import io.swagger.v3.oas.annotations.tags.Tag;
8   -import org.apache.commons.io.FileUtils;
9   -import org.slf4j.Logger;
10   -import org.slf4j.LoggerFactory;
11   -import org.springframework.beans.factory.annotation.Autowired;
12   -import org.springframework.http.HttpStatus;
13   -import org.springframework.http.ResponseEntity;
14   -import org.springframework.web.bind.annotation.*;
15   -import top.panll.assist.controller.bean.ControllerException;
16   -import top.panll.assist.controller.bean.ErrorCode;
17   -import top.panll.assist.controller.bean.RecordFile;
18   -import top.panll.assist.controller.bean.WVPResult;
19   -import top.panll.assist.dto.*;
20   -import top.panll.assist.service.VideoFileService;
21   -import top.panll.assist.utils.PageInfo;
22   -import top.panll.assist.utils.RedisUtil;
23   -
24   -import javax.servlet.http.HttpServletRequest;
25   -import java.io.File;
26   -import java.text.DateFormat;
27   -import java.text.ParseException;
28   -import java.text.SimpleDateFormat;
29   -import java.util.*;
30   -
31   -@Tag(name = "录像管理", description = "录像管理")
32   -@CrossOrigin
33   -@RestController
34   -@RequestMapping("/api/record")
35   -public class RecordController {
36   -
37   - private final static Logger logger = LoggerFactory.getLogger(RecordController.class);
38   -
39   - @Autowired
40   - private VideoFileService videoFileService;
41   -
42   - @Autowired
43   - private RedisUtil redisUtil;
44   -
45   - @Autowired
46   - private UserSettings userSettings;
47   -
48   - private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
49   -
50   -
51   - /**
52   - * 获取Assist服务配置信息
53   - */
54   - @Operation(summary ="获取Assist服务配置信息")
55   - @GetMapping(value = "/info")
56   - @ResponseBody
57   - public UserSettings getInfo(){
58   - return userSettings;
59   - }
60   -
61   - /**
62   - * 获取app+stream列表
63   - * @return
64   - */
65   - @Operation(summary ="分页获取app+stream的列表")
66   - @Parameter(name = "page", description = "当前页", required = true)
67   - @Parameter(name = "count", description = "每页查询数量", required = true)
68   - @GetMapping(value = "/list")
69   - @ResponseBody
70   - public PageInfo<Map<String, String>> getList(@RequestParam int page,
71   - @RequestParam int count){
72   - List<Map<String, String>> appList = videoFileService.getList();
73   -
74   - PageInfo<Map<String, String>> stringPageInfo = new PageInfo<>(appList);
75   - stringPageInfo.startPage(page, count);
76   - return stringPageInfo;
77   - }
78   -
79   - /**
80   - * 分页获取app列表
81   - * @return
82   - */
83   - @Operation(summary ="分页获取app列表")
84   - @Parameter(name = "page", description = "当前页", required = true)
85   - @Parameter(name = "count", description = "每页查询数量", required = true)
86   - @GetMapping(value = "/app/list")
87   - @ResponseBody
88   - public PageInfo<String> getAppList(@RequestParam int page,
89   - @RequestParam int count){
90   - List<String> resultData = new ArrayList<>();
91   - List<File> appList = videoFileService.getAppList(true);
92   - if (appList.size() > 0) {
93   - for (File file : appList) {
94   - resultData.add(file.getName());
95   - }
96   - }
97   - Collections.sort(resultData);
98   -
99   - PageInfo<String> stringPageInfo = new PageInfo<>(resultData);
100   - stringPageInfo.startPage(page, count);
101   - return stringPageInfo;
102   - }
103   -
104   - /**
105   - * 分页stream列表
106   - * @return
107   - */
108   - @Operation(summary ="分页stream列表")
109   - @Parameter(name = "page", description = "当前页", required = true)
110   - @Parameter(name = "count", description = "每页查询数量", required = true)
111   - @Parameter(name = "app", description = "应用名", required = true)
112   - @GetMapping(value = "/stream/list")
113   - @ResponseBody
114   - public PageInfo<String> getStreamList(@RequestParam int page,
115   - @RequestParam int count,
116   - @RequestParam String app ){
117   - List<String> resultData = new ArrayList<>();
118   - if (app == null) {
119   - throw new ControllerException(ErrorCode.ERROR400.getCode(), "app不能为空");
120   - }
121   - List<File> streamList = videoFileService.getStreamList(app, true);
122   - if (streamList != null) {
123   - for (File file : streamList) {
124   - resultData.add(file.getName());
125   - }
126   - }
127   - PageInfo<String> stringPageInfo = new PageInfo<>(resultData);
128   - stringPageInfo.startPage(page, count);
129   - return stringPageInfo;
130   - }
131   -
132   - /**
133   - * 获取日期文件夹列表
134   - * @return
135   - */
136   - @Operation(summary ="获取日期文件夹列表")
137   - @Parameter(name = "year", description = "月", required = true)
138   - @Parameter(name = "month", description = "年", required = true)
139   - @Parameter(name = "app", description = "应用名", required = true)
140   - @Parameter(name = "stream", description = "流ID", required = true)
141   - @GetMapping(value = "/date/list")
142   - @ResponseBody
143   - public List<String> getDateList( @RequestParam(required = false) Integer year,
144   - @RequestParam(required = false) Integer month,
145   - @RequestParam String app,
146   - @RequestParam String stream ){
147   - List<String> resultData = new ArrayList<>();
148   - if (app == null) {
149   - throw new ControllerException(ErrorCode.ERROR400.getCode(), "app不能为空");
150   - };
151   - if (stream == null) {
152   - throw new ControllerException(ErrorCode.ERROR400.getCode(), "stream不能为空");
153   - }
154   - List<File> dateList = videoFileService.getDateList(app, stream, year, month, true);
155   - for (File file : dateList) {
156   - resultData.add(file.getName());
157   - }
158   - return resultData;
159   - }
160   -
161   - /**
162   - * 获取视频文件列表
163   - * @return
164   - */
165   - @Operation(summary ="获取视频文件列表")
166   - @Parameter(name = "page", description = "当前页", required = true)
167   - @Parameter(name = "count", description = "每页查询数量", required = true)
168   - @Parameter(name = "app", description = "应用名", required = true)
169   - @Parameter(name = "stream", description = "流ID", required = true)
170   - @Parameter(name = "startTime", description = "开始时间(yyyy-MM-dd HH:mm:ss)", required = true)
171   - @Parameter(name = "endTime", description = "结束时间(yyyy-MM-dd HH:mm:ss)", required = true)
172   - @GetMapping(value = "/file/list")
173   - @ResponseBody
174   - public PageInfo<String> getRecordList(@RequestParam int page,
175   - @RequestParam int count,
176   - @RequestParam String app,
177   - @RequestParam String stream,
178   - @RequestParam(required = false) String startTime,
179   - @RequestParam(required = false) String endTime
180   - ){
181   -
182   - // 开始时间与结束时间可不传或只传其一
183   - List<String> recordList = new ArrayList<>();
184   - try {
185   - Date startTimeDate = null;
186   - Date endTimeDate = null;
187   - if (startTime != null ) {
188   - startTimeDate = formatter.parse(startTime);
189   - }
190   - if (endTime != null ) {
191   - endTimeDate = formatter.parse(endTime);
192   - }
193   -
194   - List<File> filesInTime = videoFileService.getFilesInTime(app, stream, startTimeDate, endTimeDate);
195   - if (filesInTime != null && filesInTime.size() > 0) {
196   - for (File file : filesInTime) {
197   - recordList.add(file.getName());
198   - }
199   - }
200   - PageInfo<String> stringPageInfo = new PageInfo<>(recordList);
201   - stringPageInfo.startPage(page, count);
202   - return stringPageInfo;
203   - } catch (ParseException e) {
204   - logger.error("错误的开始时间[{}]或结束时间[{}]", startTime, endTime);
205   - throw new ControllerException(ErrorCode.ERROR400.getCode(), "错误的开始时间或结束时间, e=" + e.getMessage());
206   - }
207   - }
208   -
209   - /**
210   - * 获取视频文件列表
211   - * @return
212   - */
213   - @Operation(summary ="获取视频文件列表")
214   - @Parameter(name = "page", description = "当前页", required = true)
215   - @Parameter(name = "count", description = "每页查询数量", required = true)
216   - @Parameter(name = "app", description = "应用名", required = true)
217   - @Parameter(name = "stream", description = "流ID", required = true)
218   - @Parameter(name = "startTime", description = "开始时间(yyyy-MM-dd HH:mm:ss)", required = true)
219   - @Parameter(name = "endTime", description = "结束时间(yyyy-MM-dd HH:mm:ss)", required = true)
220   - @GetMapping(value = "/file/listWithDate")
221   - @ResponseBody
222   - public PageInfo<RecordFile> getRecordListWithDate(@RequestParam int page,
223   - @RequestParam int count,
224   - @RequestParam String app,
225   - @RequestParam String stream,
226   - @RequestParam(required = false) String startTime,
227   - @RequestParam(required = false) String endTime
228   - ){
229   -
230   - // 开始时间与结束时间可不传或只传其一
231   - List<RecordFile> recordList = new ArrayList<>();
232   - try {
233   - Date startTimeDate = null;
234   - Date endTimeDate = null;
235   - if (startTime != null ) {
236   - startTimeDate = formatter.parse(startTime);
237   - }
238   - if (endTime != null ) {
239   - endTimeDate = formatter.parse(endTime);
240   - }
241   -
242   - List<File> filesInTime = videoFileService.getFilesInTime(app, stream, startTimeDate, endTimeDate);
243   - if (filesInTime != null && filesInTime.size() > 0) {
244   - for (File file : filesInTime) {
245   - recordList.add(RecordFile.instance(app, stream, file.getName(), file.getParentFile().getName()));
246   - }
247   - }
248   - PageInfo<RecordFile> stringPageInfo = new PageInfo<>(recordList);
249   - stringPageInfo.startPage(page, count);
250   - return stringPageInfo;
251   - } catch (ParseException e) {
252   - logger.error("错误的开始时间[{}]或结束时间[{}]", startTime, endTime);
253   - throw new ControllerException(ErrorCode.ERROR400.getCode(), "错误的开始时间或结束时间, e=" + e.getMessage());
254   - }
255   - }
256   -
257   -
258   - /**
259   - * 添加视频裁剪合并任务
260   - */
261   - @Operation(summary ="添加视频裁剪合并任务")
262   - @Parameter(name = "app", description = "应用名", required = true)
263   - @Parameter(name = "stream", description = "流ID", required = true)
264   - @Parameter(name = "startTime", description = "开始时间(yyyy-MM-dd HH:mm:ss)", required = true)
265   - @Parameter(name = "endTime", description = "结束时间(yyyy-MM-dd HH:mm:ss)", required = true)
266   - @Parameter(name = "remoteHost", description = "服务的IP:端口(用于直接返回完整播放地址以及下载地址)", required = true)
267   - @GetMapping(value = "/file/download/task/add")
268   - @ResponseBody
269   - public String addTaskForDownload(@RequestParam String app,
270   - @RequestParam String stream,
271   - @RequestParam(required = false) String startTime,
272   - @RequestParam(required = false) String endTime,
273   - @RequestParam(required = false) String remoteHost
274   - ){
275   - Date startTimeDate = null;
276   - Date endTimeDate = null;
277   - try {
278   - if (startTime != null ) {
279   - startTimeDate = formatter.parse(startTime);
280   - }
281   - if (endTime != null ) {
282   - endTimeDate = formatter.parse(endTime);
283   - }
284   - } catch (ParseException e) {
285   - e.printStackTrace();
286   - }
287   - String id = videoFileService.mergeOrCut(app, stream, startTimeDate, endTimeDate, remoteHost);
288   - if (id== null) {
289   - throw new ControllerException(ErrorCode.ERROR100.getCode(), "可能未找到视频文件");
290   - }
291   - return id;
292   - }
293   -
294   - /**
295   - * 查询视频裁剪合并任务列表
296   - */
297   - @Operation(summary ="查询视频裁剪合并任务列表")
298   - @Parameter(name = "app", description = "应用名", required = true)
299   - @Parameter(name = "stream", description = "流ID", required = true)
300   - @Parameter(name = "taskId", description = "任务ID", required = true)
301   - @Parameter(name = "isEnd", description = "是否结束", required = true)
302   - @GetMapping(value = "/file/download/task/list")
303   - @ResponseBody
304   - public List<MergeOrCutTaskInfo> getTaskListForDownload(
305   - @RequestParam(required = false) String app,
306   - @RequestParam(required = false) String stream,
307   - @RequestParam(required = false) String taskId,
308   - @RequestParam(required = false) Boolean isEnd){
309   - List<MergeOrCutTaskInfo> taskList = videoFileService.getTaskListForDownload(isEnd, app, stream, taskId);
310   - if (taskList == null) {
311   - throw new ControllerException(ErrorCode.ERROR100);
312   - }
313   - return taskList;
314   - }
315   -
316   - /**
317   - * 收藏录像(被收藏的录像不会被清理任务清理)
318   - */
319   - @Operation(summary ="收藏录像(被收藏的录像不会被清理任务清理)")
320   - @Parameter(name = "type", description = "类型", required = true)
321   - @Parameter(name = "app", description = "应用名", required = true)
322   - @Parameter(name = "stream", description = "流ID", required = true)
323   - @GetMapping(value = "/file/collection/add")
324   - @ResponseBody
325   - public void collection(
326   - @RequestParam(required = true) String type,
327   - @RequestParam(required = true) String app,
328   - @RequestParam(required = true) String stream){
329   -
330   - boolean collectionResult = videoFileService.collection(app, stream, type);
331   - if (!collectionResult) {
332   - throw new ControllerException(ErrorCode.ERROR100);
333   - }
334   - }
335   -
336   - /**
337   - * 移除收藏录像
338   - */
339   - @Operation(summary ="移除收藏录像")
340   - @Parameter(name = "type", description = "类型", required = true)
341   - @Parameter(name = "app", description = "应用名", required = true)
342   - @Parameter(name = "stream", description = "流ID", required = true)
343   - @GetMapping(value = "/file/collection/remove")
344   - @ResponseBody
345   - public void removeCollection(
346   - @RequestParam(required = true) String type,
347   - @RequestParam(required = true) String app,
348   - @RequestParam(required = true) String stream){
349   -
350   - boolean collectionResult = videoFileService.removeCollection(app, stream, type);
351   - if (!collectionResult) {
352   - throw new ControllerException(ErrorCode.ERROR100);
353   - }
354   - }
355   -
356   - /**
357   - * 收藏录像列表
358   - */
359   - @Operation(summary ="收藏录像列表")
360   - @Parameter(name = "type", description = "类型", required = false)
361   - @Parameter(name = "app", description = "应用名", required = false)
362   - @Parameter(name = "stream", description = "流ID", required = false)
363   - @GetMapping(value = "/file/collection/list")
364   - @ResponseBody
365   - public List<SignInfo> collectionList(
366   - @RequestParam(required = false) String type,
367   - @RequestParam(required = false) String app,
368   - @RequestParam(required = false) String stream){
369   -
370   - List<SignInfo> signInfos = videoFileService.getCollectionList(app, stream, type);
371   - return signInfos;
372   - }
373   -
374   - /**
375   - * 中止视频裁剪合并任务列表
376   - */
377   - @Operation(summary ="中止视频裁剪合并任务列表(暂不支持)")
378   - @GetMapping(value = "/file/download/task/stop")
379   - @ResponseBody
380   - public WVPResult<String> stopTaskForDownload(@RequestParam String taskId){
381   -// WVPResult<String> result = new WVPResult<>();
382   -// if (taskId == null) {
383   -// result.setCode(400);
384   -// result.setMsg("taskId 不能为空");
385   -// return result;
386   -// }
387   -// boolean stopResult = videoFileService.stopTask(taskId);
388   -// result.setCode(0);
389   -// result.setMsg(stopResult ? "success": "fail");
390   - return null;
391   - }
392   -
393   - /**
394   - * 录制完成的通知, 对用zlm的hook
395   - * @return
396   - */
397   - @ResponseBody
398   - @PostMapping(value = "/on_record_mp4", produces = "application/json;charset=UTF-8")
399   - public ResponseEntity<String> onRecordMp4(@RequestBody JSONObject json) {
400   - JSONObject ret = new JSONObject();
401   - ret.put("code", 0);
402   - ret.put("msg", "success");
403   - String file_path = json.getString("file_path");
404   -
405   - String app = json.getString("app");
406   - String stream = json.getString("stream");
407   - logger.debug("ZLM 录制完成,文件路径:" + file_path);
408   -
409   - if (file_path == null) {
410   - return new ResponseEntity<String>(ret.toString(), HttpStatus.OK);
411   - }
412   - if (userSettings.getRecordDay() <= 0) {
413   - logger.info("录像保存事件为{}天,直接删除: {}", userSettings.getRecordDay(), file_path);
414   - FileUtils.deleteQuietly(new File(file_path));
415   - }else {
416   - videoFileService.handFile(new File(file_path), app, stream);
417   - }
418   -
419   - return new ResponseEntity<String>(ret.toString(), HttpStatus.OK);
420   - }
421   -
422   - /**
423   - * 磁盘空间查询
424   - */
425   - @Operation(summary ="磁盘空间查询")
426   - @ResponseBody
427   - @GetMapping(value = "/space", produces = "application/json;charset=UTF-8")
428   - public SpaceInfo getSpace() {
429   - return videoFileService.getSpaceInfo();
430   - }
431   -
432   - /**
433   - * 增加推流的鉴权信息,用于录像存储使用
434   - */
435   - @Operation(summary ="增加推流的鉴权信息")
436   - @Parameter(name = "app", description = "应用名", required = true)
437   - @Parameter(name = "stream", description = "流ID", required = true)
438   - @Parameter(name = "callId", description = "录像自鉴权ID", required = true)
439   - @ResponseBody
440   - @GetMapping(value = "/addStreamCallInfo", produces = "application/json;charset=UTF-8")
441   - @PostMapping(value = "/addStreamCallInfo", produces = "application/json;charset=UTF-8")
442   - public void addStreamCallInfo(String app, String stream, String callId) {
443   - String key = AssistConstants.STREAM_CALL_INFO + userSettings.getId() + "_" + app + "_" + stream;
444   - redisUtil.set(key, callId, -1);
445   - }
446   -
447   - /**
448   - * 录像文件的时长
449   - */
450   - @Operation(summary ="录像文件的时长")
451   - @Parameter(name = "app", description = "应用名", required = true)
452   - @Parameter(name = "stream", description = "流ID", required = true)
453   - @Parameter(name = "recordIng", description = "是否录制中", required = true)
454   - @ResponseBody
455   - @GetMapping(value = "/file/duration", produces = "application/json;charset=UTF-8")
456   - @PostMapping(value = "/file/duration", produces = "application/json;charset=UTF-8")
457   - public long fileDuration( @RequestParam String app, @RequestParam String stream) {
458   - return videoFileService.fileDuration(app, stream);
459   - }
460   -}
src/main/java/top/panll/assist/controller/bean/WVPResult.java deleted 100755 → 0
1   -package top.panll.assist.controller.bean;
2   -
3   -
4   -import io.swagger.v3.oas.annotations.media.Schema;
5   -
6   -@Schema(description = "统一返回结果")
7   -public class WVPResult<T> {
8   -
9   - public WVPResult() {
10   - }
11   -
12   - public WVPResult(int code, String msg, T data) {
13   - this.code = code;
14   - this.msg = msg;
15   - this.data = data;
16   - }
17   -
18   -
19   - @Schema(description = "错误码,0为成功")
20   - private int code;
21   - @Schema(description = "描述,错误时描述错误原因")
22   - private String msg;
23   - @Schema(description = "数据")
24   - private T data;
25   -
26   -
27   - public static <T> WVPResult<T> success(T t, String msg) {
28   - return new WVPResult<>(ErrorCode.SUCCESS.getCode(), msg, t);
29   - }
30   -
31   - public static <T> WVPResult<T> success(T t) {
32   - return success(t, ErrorCode.SUCCESS.getMsg());
33   - }
34   -
35   - public static <T> WVPResult<T> fail(int code, String msg) {
36   - return new WVPResult<>(code, msg, null);
37   - }
38   -
39   - public static <T> WVPResult<T> fail(ErrorCode errorCode) {
40   - return fail(errorCode.getCode(), errorCode.getMsg());
41   - }
42   -
43   - public int getCode() {
44   - return code;
45   - }
46   -
47   - public void setCode(int code) {
48   - this.code = code;
49   - }
50   -
51   - public String getMsg() {
52   - return msg;
53   - }
54   -
55   - public void setMsg(String msg) {
56   - this.msg = msg;
57   - }
58   -
59   - public T getData() {
60   - return data;
61   - }
62   -
63   - public void setData(T data) {
64   - this.data = data;
65   - }
66   -}
src/main/java/top/panll/assist/dto/CloudRecordItem.java 0 → 100644
  1 +package top.panll.assist.dto;
  2 +
  3 +
  4 +/**
  5 + * 云端录像数据
  6 + */
  7 +public class CloudRecordItem {
  8 + /**
  9 + * 主键
  10 + */
  11 + private int id;
  12 +
  13 + /**
  14 + * 应用名
  15 + */
  16 + private String app;
  17 +
  18 + /**
  19 + * 流
  20 + */
  21 + private String stream;
  22 +
  23 + /**
  24 + * 健全ID
  25 + */
  26 + private String callId;
  27 +
  28 + /**
  29 + * 开始时间
  30 + */
  31 + private long startTime;
  32 +
  33 + /**
  34 + * 结束时间
  35 + */
  36 + private long endTime;
  37 +
  38 + /**
  39 + * ZLM Id
  40 + */
  41 + private String mediaServerId;
  42 +
  43 + /**
  44 + * 文件名称
  45 + */
  46 + private String fileName;
  47 +
  48 + /**
  49 + * 文件路径
  50 + */
  51 + private String filePath;
  52 +
  53 + /**
  54 + * 文件夹
  55 + */
  56 + private String folder;
  57 +
  58 + /**
  59 + * 收藏,收藏的文件不移除
  60 + */
  61 + private Boolean collect;
  62 +
  63 + /**
  64 + * 保留,收藏的文件不移除
  65 + */
  66 + private Boolean reserve;
  67 +
  68 + /**
  69 + * 文件大小
  70 + */
  71 + private long fileSize;
  72 +
  73 + /**
  74 + * 文件时长
  75 + */
  76 + private long timeLen;
  77 +
  78 + public int getId() {
  79 + return id;
  80 + }
  81 +
  82 + public void setId(int id) {
  83 + this.id = id;
  84 + }
  85 +
  86 + public String getApp() {
  87 + return app;
  88 + }
  89 +
  90 + public void setApp(String app) {
  91 + this.app = app;
  92 + }
  93 +
  94 + public String getStream() {
  95 + return stream;
  96 + }
  97 +
  98 + public void setStream(String stream) {
  99 + this.stream = stream;
  100 + }
  101 +
  102 + public String getCallId() {
  103 + return callId;
  104 + }
  105 +
  106 + public void setCallId(String callId) {
  107 + this.callId = callId;
  108 + }
  109 +
  110 + public long getStartTime() {
  111 + return startTime;
  112 + }
  113 +
  114 + public void setStartTime(long startTime) {
  115 + this.startTime = startTime;
  116 + }
  117 +
  118 + public long getEndTime() {
  119 + return endTime;
  120 + }
  121 +
  122 + public void setEndTime(long endTime) {
  123 + this.endTime = endTime;
  124 + }
  125 +
  126 + public String getMediaServerId() {
  127 + return mediaServerId;
  128 + }
  129 +
  130 + public void setMediaServerId(String mediaServerId) {
  131 + this.mediaServerId = mediaServerId;
  132 + }
  133 +
  134 + public String getFileName() {
  135 + return fileName;
  136 + }
  137 +
  138 + public void setFileName(String fileName) {
  139 + this.fileName = fileName;
  140 + }
  141 +
  142 + public String getFilePath() {
  143 + return filePath;
  144 + }
  145 +
  146 + public void setFilePath(String filePath) {
  147 + this.filePath = filePath;
  148 + }
  149 +
  150 + public String getFolder() {
  151 + return folder;
  152 + }
  153 +
  154 + public void setFolder(String folder) {
  155 + this.folder = folder;
  156 + }
  157 +
  158 + public long getFileSize() {
  159 + return fileSize;
  160 + }
  161 +
  162 + public void setFileSize(long fileSize) {
  163 + this.fileSize = fileSize;
  164 + }
  165 +
  166 + public long getTimeLen() {
  167 + return timeLen;
  168 + }
  169 +
  170 + public void setTimeLen(long timeLen) {
  171 + this.timeLen = timeLen;
  172 + }
  173 +
  174 + public Boolean getCollect() {
  175 + return collect;
  176 + }
  177 +
  178 + public void setCollect(Boolean collect) {
  179 + this.collect = collect;
  180 + }
  181 +
  182 + public Boolean getReserve() {
  183 + return reserve;
  184 + }
  185 +
  186 + public void setReserve(Boolean reserve) {
  187 + this.reserve = reserve;
  188 + }
  189 +}
... ...
src/main/java/top/panll/assist/dto/UserSettings.java
... ... @@ -9,25 +9,28 @@ import org.springframework.stereotype.Component;
9 9 @Component
10 10 public class UserSettings {
11 11  
12   - @Value("${userSettings.id}")
  12 + @Value("${user-settings.id}")
13 13 private String id;
14 14  
15   - @Value("${userSettings.record}")
  15 + @Value("${user-settings.record}")
16 16 private String record;
17 17  
18   - @Value("${userSettings.recordDay:7}")
  18 + @Value("${user-settings.recordDay:7}")
19 19 private int recordDay;
20 20  
21   - @Value("${userSettings.recordTempDay:-1}")
  21 + @Value("${user-settings.recordTempDay:-1}")
22 22 private int recordTempDay;
23 23  
24   - @Value("${userSettings.ffmpeg}")
  24 + @Value("${user-settings.ffmpeg}")
25 25 private String ffmpeg;
26 26  
27   - @Value("${userSettings.ffprobe}")
  27 + @Value("${user-settings.ffprobe}")
28 28 private String ffprobe;
29 29  
30   - @Value("${userSettings.threads:2}")
  30 + @Value("${user-settings.media-server-id}")
  31 + private String mediaServerId;
  32 +
  33 + @Value("${user-settings.threads:2}")
31 34 private int threads;
32 35  
33 36 public String getId() {
... ... @@ -89,4 +92,12 @@ public class UserSettings {
89 92 public void setThreads(int threads) {
90 93 this.threads = threads;
91 94 }
  95 +
  96 + public String getMediaServerId() {
  97 + return mediaServerId;
  98 + }
  99 +
  100 + public void setMediaServerId(String mediaServerId) {
  101 + this.mediaServerId = mediaServerId;
  102 + }
92 103 }
... ...
src/main/java/top/panll/assist/mapper/CloudRecordServiceMapper.java 0 → 100644
  1 +package top.panll.assist.mapper;
  2 +
  3 +import org.apache.ibatis.annotations.*;
  4 +import top.panll.assist.dto.CloudRecordItem;
  5 +
  6 +import java.util.List;
  7 +
  8 +@Mapper
  9 +public interface CloudRecordServiceMapper {
  10 +
  11 + @Insert(" <script>" +
  12 + "INSERT INTO wvp_cloud_record (" +
  13 + " app," +
  14 + " stream," +
  15 + "<if test=\"callId != null\"> call_id,</if>" +
  16 + " start_time," +
  17 + " end_time," +
  18 + " media_server_id," +
  19 + " file_name," +
  20 + " folder," +
  21 + " file_path," +
  22 + " file_size," +
  23 + " time_len ) " +
  24 + "VALUES (" +
  25 + " #{app}," +
  26 + " #{stream}," +
  27 + " <if test=\"callId != null\"> #{callId},</if>" +
  28 + " #{startTime}," +
  29 + " #{endTime}," +
  30 + " #{mediaServerId}," +
  31 + " #{fileName}," +
  32 + " #{folder}," +
  33 + " #{filePath}," +
  34 + " #{fileSize}," +
  35 + " #{timeLen})" +
  36 + " </script>")
  37 + int add(CloudRecordItem cloudRecordItem);
  38 +
  39 +
  40 + @Update(" <script>" +
  41 + "update wvp_cloud_record set collect = #{collect} where file_path in " +
  42 + " <foreach collection='cloudRecordItemList' item='item' open='(' separator=',' close=')' > #{item.filePath}</foreach>" +
  43 + " </script>")
  44 + void updateCollectList(@Param("collect") boolean collect, List<CloudRecordItem> cloudRecordItemList);
  45 +
  46 + @Delete(" <script>" +
  47 + "delete from wvp_cloud_record where media_server_id=#{mediaServerId} file_path in " +
  48 + " <foreach collection='filePathList' item='item' open='(' separator=',' close=')' > #{item}</foreach>" +
  49 + " </script>")
  50 + void deleteByFileList(List<String> filePathList, @Param("mediaServerId") String mediaServerId);
  51 +
  52 +
  53 + @Select(" <script>" +
  54 + "select file_path" +
  55 + " from wvp_cloud_record " +
  56 + " where collect = false and reserve = false " +
  57 + " <if test= 'endTimeStamp != null '> and start_time &lt;= #{endTimeStamp}</if>" +
  58 + " <if test= 'callId != null '> and call_id = #{callId}</if>" +
  59 + " <if test= 'mediaServerId != null ' > and media_server_id = #{mediaServerId} </if>" +
  60 + " </script>")
  61 + List<String> queryRecordFilePathListForDelete(@Param("endTimeStamp")Long endTimeStamp, String mediaServerId);
  62 +
  63 + @Update(" <script>" +
  64 + "update wvp_cloud_record set reserve = #{reserve} where file_path in " +
  65 + " <foreach collection='cloudRecordItems' item='item' open='(' separator=',' close=')' > #{item.filePath}</foreach>" +
  66 + " </script>")
  67 + void updateReserveList(@Param("reserve") boolean reserve,List<CloudRecordItem> cloudRecordItems);
  68 +
  69 + @Update(" <script>" +
  70 + "update wvp_cloud_record set collect = #{collect} where id = #{recordId} " +
  71 + " </script>")
  72 + void changeCollectById(@Param("collect") boolean collect, @Param("recordId") Integer recordId);
  73 +
  74 + @Update(" <script>" +
  75 + "update wvp_cloud_record set reserve = #{reserve} where id = #{recordId} " +
  76 + " </script>")
  77 + void changeReserveById(@Param("reserve") boolean reserve, Integer recordId);
  78 +
  79 +
  80 + @Insert("<script> " +
  81 + "insert into wvp_cloud_record " +
  82 + "(" +
  83 + " app," +
  84 + " stream," +
  85 + " call_id," +
  86 + " start_time," +
  87 + " end_time," +
  88 + " media_server_id," +
  89 + " file_name," +
  90 + " folder," +
  91 + " file_path," +
  92 + " file_size," +
  93 + " time_len " +
  94 + ") " +
  95 + "values " +
  96 + "<foreach collection='cloudRecordItems' index='index' item='item' separator=','> " +
  97 + "(#{item.app}, #{item.stream}, #{item.callId}, #{item.startTime}, " +
  98 + "#{item.endTime}, #{item.mediaServerId}, #{item.fileName},#{item.folder}," +
  99 + "#{item.filePath}, #{item.fileSize}, #{item.timeLen}) " +
  100 + "</foreach> " +
  101 + "</script>")
  102 + int batchAdd(@Param("cloudRecordItems") List<CloudRecordItem> cloudRecordItems);
  103 +}
... ...
src/main/java/top/panll/assist/service/FFmpegExecUtils.java
... ... @@ -18,7 +18,6 @@ import org.springframework.stereotype.Component;
18 18 import org.springframework.util.DigestUtils;
19 19 import top.panll.assist.dto.UserSettings;
20 20 import top.panll.assist.dto.VideoFile;
21   -import top.panll.assist.utils.RedisUtil;
22 21  
23 22 import java.io.BufferedWriter;
24 23 import java.io.File;
... ... @@ -32,21 +31,7 @@ import java.util.concurrent.TimeUnit;
32 31 public class FFmpegExecUtils implements InitializingBean{
33 32  
34 33 private final static Logger logger = LoggerFactory.getLogger(FFmpegExecUtils.class);
35   -// private static FFmpegExecUtils instance;
36   -//
37   -// public FFmpegExecUtils() {
38   -// }
39   -//
40   -// public static FFmpegExecUtils getInstance(){
41   -// if(instance==null){
42   -// synchronized (FFmpegExecUtils.class){
43   -// if(instance==null){
44   -// instance=new FFmpegExecUtils();
45   -// }
46   -// }
47   -// }
48   -// return instance;
49   -// }
  34 +
50 35 @Autowired
51 36 private UserSettings userSettings;
52 37  
... ...
src/main/java/top/panll/assist/service/FileManagerTimer.java deleted 100755 → 0
1   -package top.panll.assist.service;
2   -
3   -import org.apache.commons.io.FileUtils;
4   -import org.slf4j.Logger;
5   -import org.slf4j.LoggerFactory;
6   -import org.springframework.beans.factory.annotation.Autowired;
7   -import org.springframework.scheduling.annotation.Scheduled;
8   -import org.springframework.stereotype.Component;
9   -import org.springframework.util.StringUtils;
10   -import top.panll.assist.dto.AssistConstants;
11   -import top.panll.assist.dto.MergeOrCutTaskInfo;
12   -import top.panll.assist.dto.UserSettings;
13   -import top.panll.assist.utils.RedisUtil;
14   -
15   -import java.io.File;
16   -import java.text.ParseException;
17   -import java.text.SimpleDateFormat;
18   -import java.util.Calendar;
19   -import java.util.Date;
20   -import java.util.List;
21   -
22   -@Component
23   -public class FileManagerTimer {
24   -
25   - private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
26   - private final SimpleDateFormat simpleDateFormatForTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
27   -
28   - private final static Logger logger = LoggerFactory.getLogger(FileManagerTimer.class);
29   -
30   - @Autowired
31   - private UserSettings userSettings;
32   -
33   - @Autowired
34   - private VideoFileService videoFileService;
35   -
36   - @Autowired
37   - private RedisUtil redisUtil;
38   -
39   -// @Scheduled(fixedDelay = 2000) //测试 20秒执行一次
40   - @Scheduled(cron = "0 0 0 * * ?") //每天的0点执行
41   - public void execute(){
42   - if (userSettings.getRecord() == null) {
43   - return;
44   - }
45   - int recordDay = userSettings.getRecordDay();
46   - Date lastDate=new Date();
47   - Calendar lastCalendar = Calendar.getInstance();
48   - if (recordDay > 0) {
49   - lastCalendar.setTime(lastDate);
50   - lastCalendar.add(Calendar.DAY_OF_MONTH, 0 - recordDay);
51   - lastDate = lastCalendar.getTime();
52   - }
53   -
54   - logger.info("[录像巡查]移除 {} 之前的文件", formatter.format(lastDate));
55   - File recordFileDir = new File(userSettings.getRecord());
56   - if (recordFileDir.canWrite()) {
57   - List<File> appList = videoFileService.getAppList(false);
58   - if (appList != null && appList.size() > 0) {
59   - for (File appFile : appList) {
60   - if ("download.html".equals(appFile.getName())) {
61   - continue;
62   - }
63   - List<File> streamList = videoFileService.getStreamList(appFile, false);
64   - if (streamList != null && streamList.size() > 0) {
65   - for (File streamFile : streamList) {
66   - // 带有sig标记文件的为收藏文件,不被自动清理任务移除
67   - File[] signFiles = streamFile.listFiles((File dir, String name) -> {
68   - File currentFile = new File(dir.getAbsolutePath() + File.separator + name);
69   - return currentFile.isFile() && name.endsWith(".sign");
70   - });
71   - if (signFiles != null && signFiles.length > 0) {
72   - continue;
73   - }
74   - List<File> dateList = videoFileService.getDateList(streamFile, null, null, false);
75   - if (dateList != null && dateList.size() > 0) {
76   - for (File dateFile : dateList) {
77   - try {
78   - Date parse = formatter.parse(dateFile.getName());
79   - if (parse.before(lastDate)) {
80   - boolean result = FileUtils.deleteQuietly(dateFile);
81   - if (result) {
82   - logger.info("[录像巡查]成功移除 {} ", dateFile.getAbsolutePath());
83   - }else {
84   - logger.info("[录像巡查]移除失败 {} ", dateFile.getAbsolutePath());
85   - }
86   - }
87   - } catch (ParseException e) {
88   - e.printStackTrace();
89   - }
90   - }
91   - }
92   - if (streamFile.listFiles() == null || streamFile.listFiles().length == 0) {
93   - boolean result = FileUtils.deleteQuietly(streamFile);
94   - if (result) {
95   - logger.info("[录像巡查]成功移除 {} ", streamFile.getAbsolutePath());
96   - }else {
97   - logger.info("[录像巡查]移除失败 {} ", streamFile.getAbsolutePath());
98   - }
99   - }
100   - }
101   - }
102   - if (appFile.listFiles() == null || appFile.listFiles().length == 0) {
103   - boolean result = FileUtils.deleteQuietly(appFile);
104   - if (result) {
105   - logger.info("[录像巡查]成功移除 {} ", appFile.getAbsolutePath());
106   - }else {
107   - logger.info("[录像巡查]移除失败 {} ", appFile.getAbsolutePath());
108   - }
109   - }
110   - }
111   - }
112   - }
113   - // 清理任务临时文件
114   - int recordTempDay = userSettings.getRecordTempDay();
115   - Date lastTempDate = new Date();
116   - Calendar lastTempCalendar = Calendar.getInstance();
117   - lastTempCalendar.setTime(lastTempDate);
118   - lastTempCalendar.add(Calendar.DAY_OF_MONTH, 0 - recordTempDay);
119   - lastTempDate = lastTempCalendar.getTime();
120   - logger.info("[录像巡查]移除合并任务临时文件 {} 之前的文件", formatter.format(lastTempDate));
121   - File recordTempFile = new File(userSettings.getRecord() + "recordTemp");
122   - if (recordTempFile.exists() && recordTempFile.isDirectory() && recordTempFile.canWrite()) {
123   - File[] tempFiles = recordTempFile.listFiles();
124   - for (File tempFile : tempFiles) {
125   - if (tempFile.isDirectory() && new Date(tempFile.lastModified()).before(lastTempDate)) {
126   - boolean result = FileUtils.deleteQuietly(tempFile);
127   - if (result) {
128   - logger.info("[录像巡查]成功移除合并任务临时文件 {} ", tempFile.getAbsolutePath());
129   - }else {
130   - logger.info("[录像巡查]合并任务临时文件移除失败 {} ", tempFile.getAbsolutePath());
131   - }
132   - }
133   - }
134   - }
135   - // 清理redis记录
136   - String key = String.format("%S_%S_*_*_*", AssistConstants.MERGEORCUT, userSettings.getId());
137   - List<Object> taskKeys = redisUtil.scan(key);
138   - for (Object taskKeyObj : taskKeys) {
139   - String taskKey = (String) taskKeyObj;
140   - MergeOrCutTaskInfo mergeOrCutTaskInfo = (MergeOrCutTaskInfo)redisUtil.get(taskKey);
141   - try {
142   - if (StringUtils.isEmpty(mergeOrCutTaskInfo.getCreateTime())
143   - || simpleDateFormatForTime.parse(mergeOrCutTaskInfo.getCreateTime()).before(lastTempDate)) {
144   - redisUtil.del(taskKey);
145   - }
146   - } catch (ParseException e) {
147   - e.printStackTrace();
148   - }
149   - }
150   - }
151   -}
src/main/java/top/panll/assist/service/VideoFileService.java deleted 100755 → 0
1   -package top.panll.assist.service;
2   -
3   -import net.bramp.ffmpeg.FFprobe;
4   -import net.bramp.ffmpeg.probe.FFmpegProbeResult;
5   -import net.bramp.ffmpeg.progress.Progress;
6   -import org.apache.commons.io.FileUtils;
7   -import org.slf4j.Logger;
8   -import org.slf4j.LoggerFactory;
9   -import org.springframework.beans.factory.annotation.Autowired;
10   -import org.springframework.data.redis.core.RedisTemplate;
11   -import org.springframework.stereotype.Service;
12   -import org.springframework.util.DigestUtils;
13   -import top.panll.assist.dto.*;
14   -import top.panll.assist.utils.RedisUtil;
15   -import top.panll.assist.utils.DateUtils;
16   -
17   -import java.io.File;
18   -import java.io.IOException;
19   -import java.nio.file.Files;
20   -import java.nio.file.Path;
21   -import java.nio.file.Paths;
22   -import java.nio.file.attribute.BasicFileAttributes;
23   -import java.text.ParseException;
24   -import java.text.SimpleDateFormat;
25   -import java.util.*;
26   -
27   -@Service
28   -public class VideoFileService {
29   -
30   - private final static Logger logger = LoggerFactory.getLogger(VideoFileService.class);
31   -
32   - @Autowired
33   - private UserSettings userSettings;
34   -
35   - @Autowired
36   - private RedisUtil redisUtil;
37   -
38   - @Autowired
39   - private FFmpegExecUtils ffmpegExecUtils;
40   -
41   -
42   -
43   - private final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
44   - private final SimpleDateFormat simpleDateFormatForTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
45   -
46   - public List<File> getAppList(Boolean sort) {
47   - File recordFile = new File(userSettings.getRecord());
48   - if (recordFile.isDirectory()) {
49   - File[] files = recordFile.listFiles((File dir, String name) -> {
50   - File currentFile = new File(dir.getAbsolutePath() + File.separator + name);
51   - return currentFile.isDirectory() && !name.equals("recordTemp");
52   - });
53   - List<File> result = Arrays.asList(files);
54   - if (sort != null && sort) {
55   - Collections.sort(result);
56   - }
57   - return result;
58   - }else {
59   - return null;
60   - }
61   - }
62   -
63   - public SpaceInfo getSpaceInfo(){
64   - File recordFile = new File(userSettings.getRecord());
65   - SpaceInfo spaceInfo = new SpaceInfo();
66   - spaceInfo.setFree(recordFile.getFreeSpace());
67   - spaceInfo.setTotal(recordFile.getTotalSpace());
68   - return spaceInfo;
69   - }
70   -
71   - public List<File> getStreamList(String app, Boolean sort) {
72   - File appFile = new File(userSettings.getRecord() + File.separator + app);
73   - return getStreamList(appFile, sort);
74   - }
75   -
76   - public List<File> getStreamList(File appFile, Boolean sort) {
77   - if (appFile != null && appFile.isDirectory()) {
78   - File[] files = appFile.listFiles((File dir, String name) -> {
79   - File currentFile = new File(dir.getAbsolutePath() + File.separator + name);
80   - return currentFile.isDirectory();
81   - });
82   - List<File> result = Arrays.asList(files);
83   - if (sort != null && sort) {
84   - Collections.sort(result);
85   - }
86   - return result;
87   - }else {
88   - return null;
89   - }
90   - }
91   -
92   - /**
93   - * 对视频文件重命名
94   - */
95   - public void handFile(File file,String app, String stream) {
96   - VideoFile videoFile = VideoFileFactory.createFile(ffmpegExecUtils, file);
97   - if (videoFile == null || videoFile.isTargetFormat()) {
98   - return;
99   - }
100   -
101   - SimpleDateFormat dateFormat = new SimpleDateFormat("HHmmss");
102   -
103   - String key = AssistConstants.STREAM_CALL_INFO + userSettings.getId() + "_" + app + "_" + stream;
104   - String callId = (String) redisUtil.get(key);
105   -
106   - String streamNew = (callId == null? stream : stream + "_" + callId);
107   - File newPath = new File(userSettings.getRecord() + File.separator + app + File.separator + streamNew
108   - + File.separator + DateUtils.getDateStr(videoFile.getStartTime()));
109   - if (!newPath.exists()) {
110   - newPath.mkdirs();
111   - }
112   -
113   - String newName = newPath.getAbsolutePath() + File.separator+ dateFormat.format(videoFile.getStartTime())
114   - + "-" + dateFormat.format(videoFile.getEndTime()) + ".mp4";
115   - logger.info("[处理文件] {}->{}", file.getAbsolutePath(), newName);
116   - boolean renameTo = file.renameTo(new File(newName));
117   - if (!renameTo) {
118   - logger.info("[处理文件]文件重命名失败 {}->{}", file.getAbsolutePath(), newName);
119   - }
120   - }
121   -
122   - public List<Map<String, String>> getList() {
123   -
124   - List<Map<String, String>> result = new ArrayList<>();
125   -
126   - List<File> appList = getAppList(true);
127   - if (appList != null && appList.size() > 0) {
128   - for (File appFile : appList) {
129   - if (appFile.isDirectory()) {
130   - List<File> streamList = getStreamList(appFile.getName(), true);
131   - if (streamList != null && streamList.size() > 0) {
132   - for (File streamFile : streamList) {
133   - Map<String, String> data = new HashMap<>();
134   - data.put("app", appFile.getName());
135   - data.put("stream", streamFile.getName());
136   -
137   - BasicFileAttributes bAttributes = null;
138   - try {
139   - bAttributes = Files.readAttributes(streamFile.toPath(),
140   - BasicFileAttributes.class);
141   - } catch (IOException e) {
142   - e.printStackTrace();
143   - }
144   - data.put("time", simpleDateFormatForTime.format(new Date(bAttributes.lastModifiedTime().toMillis())));
145   - result.add(data);
146   - }
147   - }
148   - }
149   - }
150   - }
151   - result.sort((Map f1, Map f2)->{
152   - Date time1 = null;
153   - Date time2 = null;
154   - try {
155   - time1 = simpleDateFormatForTime.parse(f1.get("time").toString());
156   - time2 = simpleDateFormatForTime.parse(f2.get("time").toString());
157   - } catch (ParseException e) {
158   - logger.error("时间格式化失败", e);
159   - }
160   - return time1.compareTo(time2) * -1;
161   - });
162   - return result;
163   - }
164   -
165   - /**
166   - * 获取制定推流的指定时间段内的推流
167   - * @param app
168   - * @param stream
169   - * @param startTime
170   - * @param endTime
171   - * @return
172   - */
173   - public List<File> getFilesInTime(String app, String stream, Date startTime, Date endTime){
174   -
175   - List<File> result = new ArrayList<>();
176   - if (app == null || stream == null) {
177   - return result;
178   - }
179   -
180   - SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HHmmss");
181   - SimpleDateFormat formatterForDate = new SimpleDateFormat("yyyy-MM-dd");
182   - String startTimeStr = null;
183   - String endTimeStr = null;
184   - if (startTime != null) {
185   - startTimeStr = formatter.format(startTime);
186   - }
187   - if (endTime != null) {
188   - endTimeStr = formatter.format(endTime);
189   - }
190   -
191   - logger.debug("获取[app: {}, stream: {}, statime: {}, endTime: {}]的视频", app, stream,
192   - startTimeStr, endTimeStr);
193   -
194   - File recordFile = new File(userSettings.getRecord());
195   - File streamFile = new File(recordFile.getAbsolutePath() + File.separator + app + File.separator + stream + File.separator);
196   - if (!streamFile.exists()) {
197   - logger.warn("获取[app: {}, stream: {}, statime: {}, endTime: {}]的视频时未找到目录: {}", app, stream,
198   - startTimeStr, endTimeStr, stream);
199   - return null;
200   - }
201   -
202   - File[] dateFiles = streamFile.listFiles((File dir, String name) -> {
203   - Date fileDate = null;
204   - Date startDate = null;
205   - Date endDate = null;
206   - if (new File(dir + File.separator + name).isFile()) {
207   - return false;
208   - }
209   - if (startTime != null) {
210   - startDate = new Date(startTime.getTime() - ((startTime.getTime() + 28800000) % (86400000)));
211   - }
212   - if (endTime != null) {
213   - endDate = new Date(endTime.getTime() - ((endTime.getTime() + 28800000) % (86400000)));
214   - }
215   - try {
216   - fileDate = formatterForDate.parse(name);
217   - } catch (ParseException e) {
218   - logger.error("过滤日期文件时异常: {}-{}", name, e.getMessage());
219   - return false;
220   - }
221   - boolean filterResult = true;
222   -
223   - if (startDate != null) {
224   - filterResult = filterResult && DateUtils.getStartOfDay(startDate).compareTo(fileDate) <= 0;
225   - }
226   -
227   - if (endDate != null) {
228   - filterResult = filterResult && DateUtils.getEndOfDay(endDate).compareTo(fileDate) >= 0;
229   - }
230   -
231   - return filterResult ;
232   - });
233   -
234   - if (dateFiles != null && dateFiles.length > 0) {
235   - for (File dateFile : dateFiles) {
236   - File[] files = dateFile.listFiles((File dir, String name) ->{
237   - File currentFile = new File(dir + File.separator + name);
238   - VideoFile videoFile = VideoFileFactory.createFile(ffmpegExecUtils, currentFile);
239   - if (videoFile == null ) {
240   - return false;
241   - }else {
242   - if (!videoFile.isTargetFormat()) {
243   - return false;
244   - }
245   - if (startTime == null && endTime == null) {
246   - return true;
247   - }else if (startTime == null && endTime != null) {
248   - return videoFile.getEndTime().before(endTime)
249   - || videoFile.getEndTime().equals(endTime)
250   - || (videoFile.getEndTime().after(endTime) && videoFile.getStartTime().before(endTime));
251   - }else if (startTime != null && endTime == null) {
252   - return videoFile.getStartTime().after(startTime)
253   - || videoFile.getStartTime().equals(startTime)
254   - || (videoFile.getStartTime().before(startTime) && videoFile.getEndTime().after(startTime));
255   - }else {
256   - return videoFile.getStartTime().after(startTime)
257   - || videoFile.getStartTime().equals(startTime)
258   - || (videoFile.getStartTime().before(startTime) && videoFile.getEndTime().after(startTime))
259   - || videoFile.getEndTime().before(endTime)
260   - || videoFile.getEndTime().equals(endTime)
261   - || (videoFile.getEndTime().after(endTime) && videoFile.getStartTime().before(endTime));
262   - }
263   - }
264   - });
265   - if (files != null && files.length > 0) {
266   - result.addAll(Arrays.asList(files));
267   - }
268   - }
269   - }
270   - if (!result.isEmpty()) {
271   - result.sort((File f1, File f2) -> {
272   - VideoFile videoFile1 = VideoFileFactory.createFile(ffmpegExecUtils, f1);
273   - VideoFile videoFile2 = VideoFileFactory.createFile(ffmpegExecUtils, f2);
274   - if (videoFile1 == null || !videoFile1.isTargetFormat() || videoFile2 == null || !videoFile2.isTargetFormat()) {
275   - logger.warn("[根据时间获取视频文件] 排序错误,文件错误: {}/{}", f1.getName(), f2.getName());
276   - return 0;
277   - }
278   - return videoFile1.getStartTime().compareTo(videoFile2.getStartTime());
279   - });
280   - }
281   - return result;
282   - }
283   -
284   -
285   - public String mergeOrCut(String app, String stream, Date startTime, Date endTime, String remoteHost) {
286   - List<File> filesInTime = this.getFilesInTime(app, stream, startTime, endTime);
287   - if (filesInTime== null || filesInTime.isEmpty()){
288   - logger.info("此时间段未未找到视频文件, {}/{} {}->{}", app, stream,
289   - startTime == null? null:DateUtils.getDateTimeStr(startTime),
290   - endTime == null? null:DateUtils.getDateTimeStr(endTime));
291   - return null;
292   - }
293   - String taskId = DigestUtils.md5DigestAsHex(String.valueOf(System.currentTimeMillis()).getBytes());
294   - logger.info("[录像合并] 开始合并,APP:{}, STREAM: {}, 任务ID:{}", app, stream, taskId);
295   - String destDir = "recordTemp" + File.separator + taskId + File.separator + app;
296   - File recordFile = new File(userSettings.getRecord() + destDir );
297   - if (!recordFile.exists()) {
298   - recordFile.mkdirs();
299   - }
300   - MergeOrCutTaskInfo mergeOrCutTaskInfo = new MergeOrCutTaskInfo();
301   - mergeOrCutTaskInfo.setId(taskId);
302   - mergeOrCutTaskInfo.setApp(app);
303   - mergeOrCutTaskInfo.setStream(stream);
304   - mergeOrCutTaskInfo.setCreateTime(simpleDateFormatForTime.format(System.currentTimeMillis()));
305   - if(startTime != null) {
306   - mergeOrCutTaskInfo.setStartTime(simpleDateFormatForTime.format(startTime));
307   - }else {
308   - String startTimeInFile = filesInTime.get(0).getParentFile().getName() + " "
309   - + filesInTime.get(0).getName().split("-")[0];
310   - mergeOrCutTaskInfo.setStartTime(startTimeInFile);
311   - }
312   - if(endTime != null) {
313   - mergeOrCutTaskInfo.setEndTime(simpleDateFormatForTime.format(endTime));
314   - }else {
315   - String endTimeInFile = filesInTime.get(filesInTime.size()- 1).getParentFile().getName() + " "
316   - + filesInTime.get(filesInTime.size()- 1).getName().split("-")[1];
317   - mergeOrCutTaskInfo.setEndTime(endTimeInFile);
318   - }
319   - if (filesInTime.size() == 1) {
320   -
321   - // 文件只有一个则不合并,直接复制过去
322   - mergeOrCutTaskInfo.setPercentage("1");
323   - // 处理文件路径
324   - String recordFileResultPath = recordFile.getAbsolutePath() + File.separator + stream + ".mp4";
325   - Path relativize = Paths.get(userSettings.getRecord()).relativize(Paths.get(recordFileResultPath));
326   - try {
327   - Files.copy(filesInTime.get(0).toPath(), Paths.get(recordFileResultPath));
328   - } catch (IOException e) {
329   - e.printStackTrace();
330   - logger.info("[录像合并] 失败,APP:{}, STREAM: {}, 任务ID:{}", app, stream, taskId);
331   - return taskId;
332   - }
333   - mergeOrCutTaskInfo.setRecordFile("/download/" + relativize.toString());
334   - if (remoteHost != null) {
335   - mergeOrCutTaskInfo.setDownloadFile(remoteHost + "/download.html?url=download/" + relativize);
336   - mergeOrCutTaskInfo.setPlayFile(remoteHost + "/download/" + relativize);
337   - }
338   - String key = String.format("%S_%S_%S_%S_%S", AssistConstants.MERGEORCUT , userSettings.getId(), mergeOrCutTaskInfo.getApp(), mergeOrCutTaskInfo.getStream(), mergeOrCutTaskInfo.getId());
339   - redisUtil.set(key, mergeOrCutTaskInfo);
340   - logger.info("[录像合并] 合并完成,APP:{}, STREAM: {}, 任务ID:{}", app, stream, taskId);
341   - }else {
342   - ffmpegExecUtils.mergeOrCutFile(filesInTime, recordFile, stream, (status, percentage, result)->{
343   - // 发出redis通知
344   - if (status.equals(Progress.Status.END.name())) {
345   - mergeOrCutTaskInfo.setPercentage("1");
346   -
347   - // 处理文件路径
348   - Path relativize = Paths.get(userSettings.getRecord()).relativize(Paths.get(result));
349   - mergeOrCutTaskInfo.setRecordFile(relativize.toString());
350   - if (remoteHost != null) {
351   - mergeOrCutTaskInfo.setDownloadFile(remoteHost + "/download.html?url=download/" + relativize);
352   - mergeOrCutTaskInfo.setPlayFile(remoteHost + "/download/" + relativize);
353   - }
354   - logger.info("[录像合并] 合并完成,APP:{}, STREAM: {}, 任务ID:{}", app, stream, taskId);
355   - }else {
356   - mergeOrCutTaskInfo.setPercentage(percentage + "");
357   - }
358   - String key = String.format("%S_%S_%S_%S_%S", AssistConstants.MERGEORCUT, userSettings.getId(), mergeOrCutTaskInfo.getApp(), mergeOrCutTaskInfo.getStream(), mergeOrCutTaskInfo.getId());
359   - redisUtil.set(key, mergeOrCutTaskInfo);
360   - });
361   - }
362   -
363   - return taskId;
364   - }
365   -
366   - /**
367   - * 获取指定时间的日期文件夹
368   - * @param app
369   - * @param stream
370   - * @param year
371   - * @param month
372   - * @return
373   - */
374   - public List<File> getDateList(String app, String stream, Integer year, Integer month, Boolean sort) {
375   - File recordFile = new File(userSettings.getRecord());
376   - File streamFile = new File(recordFile.getAbsolutePath() + File.separator + app + File.separator + stream);
377   - return getDateList(streamFile, year, month, sort);
378   - }
379   - public List<File> getDateList(File streamFile, Integer year, Integer month, Boolean sort) {
380   - if (!streamFile.exists() && streamFile.isDirectory()) {
381   - logger.warn("获取[]的视频时未找到目录: {}",streamFile.getName());
382   - return null;
383   - }
384   - File[] dateFiles = streamFile.listFiles((File dir, String name)->{
385   - File currentFile = new File(dir.getAbsolutePath() + File.separator + name);
386   - if (!currentFile.isDirectory()){
387   - return false;
388   - }
389   - Date date = null;
390   - try {
391   - date = simpleDateFormat.parse(name);
392   - } catch (ParseException e) {
393   - logger.error("格式化时间{}错误", name);
394   - return false;
395   - }
396   - Calendar c = Calendar.getInstance();
397   - c.setTime(date);
398   - int y = c.get(Calendar.YEAR);
399   - int m = c.get(Calendar.MONTH) + 1;
400   - if (year != null) {
401   - if (month != null) {
402   - return y == year && m == month;
403   - }else {
404   - return y == year;
405   - }
406   - }else {
407   - return true;
408   - }
409   -
410   - });
411   - if (dateFiles == null) {
412   - return new ArrayList<>();
413   - }
414   - List<File> dateFileList = Arrays.asList(dateFiles);
415   - if (sort != null && sort) {
416   - dateFileList.sort((File f1, File f2)->{
417   - int sortResult = 0;
418   -
419   - try {
420   - sortResult = simpleDateFormat.parse(f1.getName()).compareTo(simpleDateFormat.parse(f2.getName()));
421   - } catch (ParseException e) {
422   - logger.error("格式化时间{}/{}错误", f1.getName(), f2.getName());
423   - }
424   - return sortResult;
425   - });
426   - }
427   -
428   - return dateFileList;
429   - }
430   -
431   - public List<MergeOrCutTaskInfo> getTaskListForDownload(Boolean idEnd, String app, String stream, String taskId) {
432   - ArrayList<MergeOrCutTaskInfo> result = new ArrayList<>();
433   - if (app == null) {
434   - app = "*";
435   - }
436   - if (stream == null) {
437   - stream = "*";
438   - }
439   - if (taskId == null) {
440   - taskId = "*";
441   - }
442   - List<Object> taskCatch = redisUtil.scan(String.format("%S_%S_%S_%S_%S", AssistConstants.MERGEORCUT,
443   - userSettings.getId(), app, stream, taskId));
444   - for (int i = 0; i < taskCatch.size(); i++) {
445   - String keyItem = taskCatch.get(i).toString();
446   - MergeOrCutTaskInfo mergeOrCutTaskInfo = (MergeOrCutTaskInfo)redisUtil.get(keyItem);
447   - if (mergeOrCutTaskInfo != null && mergeOrCutTaskInfo.getPercentage() != null){
448   - if (idEnd != null ) {
449   - if (idEnd) {
450   - if (Double.parseDouble(mergeOrCutTaskInfo.getPercentage()) == 1){
451   - result.add(mergeOrCutTaskInfo);
452   - }
453   - }else {
454   - if (Double.parseDouble(mergeOrCutTaskInfo.getPercentage()) < 1){
455   - result.add((MergeOrCutTaskInfo)redisUtil.get(keyItem));
456   - }
457   - }
458   - }else {
459   - result.add((MergeOrCutTaskInfo)redisUtil.get(keyItem));
460   - }
461   - }
462   - }
463   - result.sort((MergeOrCutTaskInfo m1, MergeOrCutTaskInfo m2)->{
464   - int sortResult = 0;
465   - try {
466   - sortResult = simpleDateFormatForTime.parse(m1.getCreateTime()).compareTo(simpleDateFormatForTime.parse(m2.getCreateTime()));
467   - if (sortResult == 0) {
468   - sortResult = simpleDateFormatForTime.parse(m1.getStartTime()).compareTo(simpleDateFormatForTime.parse(m2.getStartTime()));
469   - }
470   - if (sortResult == 0) {
471   - sortResult = simpleDateFormatForTime.parse(m1.getEndTime()).compareTo(simpleDateFormatForTime.parse(m2.getEndTime()));
472   - }
473   - } catch (ParseException e) {
474   - e.printStackTrace();
475   - }
476   - return sortResult * -1;
477   - });
478   -
479   - return result;
480   - }
481   -
482   - public boolean collection(String app, String stream, String type) {
483   - File streamFile = new File(userSettings.getRecord() + File.separator + app + File.separator + stream);
484   - boolean result = false;
485   - if (streamFile.exists() && streamFile.isDirectory() && streamFile.canWrite()) {
486   - File signFile = new File(streamFile.getAbsolutePath() + File.separator + type + ".sign");
487   - try {
488   - result = signFile.createNewFile();
489   - } catch (IOException e) {
490   - logger.error("[收藏文件]失败,{}/{}", app, stream);
491   - }
492   - }
493   - return result;
494   - }
495   -
496   - public boolean removeCollection(String app, String stream, String type) {
497   - File signFile = new File(userSettings.getRecord() + File.separator + app + File.separator + stream + File.separator + type + ".sign");
498   - boolean result = false;
499   - if (signFile.exists() && signFile.isFile()) {
500   - result = signFile.delete();
501   - }
502   - return result;
503   - }
504   -
505   - public List<SignInfo> getCollectionList(String app, String stream, String type) {
506   - List<File> appList = this.getAppList(true);
507   - List<SignInfo> result = new ArrayList<>();
508   - if (appList.size() > 0) {
509   - for (File appFile : appList) {
510   - if (app != null) {
511   - if (!app.equals(appFile.getName())) {
512   - continue;
513   - }
514   - }
515   - List<File> streamList = getStreamList(appFile, true);
516   - if (streamList.size() > 0) {
517   - for (File streamFile : streamList) {
518   - if (stream != null) {
519   - if (!stream.equals(streamFile.getName())) {
520   - continue;
521   - }
522   - }
523   -
524   - if (type != null) {
525   - File signFile = new File(streamFile.getAbsolutePath() + File.separator + type + ".sign");
526   - if (signFile.exists()) {
527   - SignInfo signInfo = new SignInfo();
528   - signInfo.setApp(appFile.getName());
529   - signInfo.setStream(streamFile.getName());
530   - signInfo.setType(type);
531   - result.add(signInfo);
532   - }
533   - }else {
534   - streamFile.listFiles((File dir, String name) -> {
535   - File currentFile = new File(dir.getAbsolutePath() + File.separator + name);
536   - if (currentFile.isFile() && name.endsWith(".sign")){
537   - String currentType = name.substring(0, name.length() - ".sign".length());
538   - SignInfo signInfo = new SignInfo();
539   - signInfo.setApp(appFile.getName());
540   - signInfo.setStream(streamFile.getName());
541   - signInfo.setType(currentType);
542   - result.add(signInfo);
543   - }
544   - return false;
545   - });
546   - }
547   - }
548   - }
549   - }
550   - }
551   - return result;
552   - }
553   -
554   - public long fileDuration(String app, String stream) {
555   - List<File> allFiles = getFilesInTime(app, stream, null, null);
556   - long durationResult = 0;
557   - if (allFiles != null && allFiles.size() > 0) {
558   - for (File file : allFiles) {
559   - try {
560   - durationResult += ffmpegExecUtils.duration(file);
561   - } catch (IOException e) {
562   - logger.error("获取{}视频时长错误:{}", file.getAbsolutePath(), e.getMessage());
563   - }
564   - }
565   - }
566   - return durationResult;
567   - }
568   -}
src/main/java/top/panll/assist/utils/DateUtils.java
1 1 package top.panll.assist.utils;
2 2  
  3 +import java.text.ParseException;
3 4 import java.text.SimpleDateFormat;
4 5 import java.time.Instant;
5 6 import java.time.LocalDateTime;
6 7 import java.time.LocalTime;
7 8 import java.time.ZoneId;
8 9 import java.time.format.DateTimeFormatter;
  10 +import java.time.temporal.TemporalAccessor;
9 11 import java.util.Date;
10 12 import java.util.Locale;
11 13  
... ... @@ -13,10 +15,14 @@ public class DateUtils {
13 15  
14 16 public static final String PATTERNForDateTime = "yyyy-MM-dd HH:mm:ss";
15 17  
  18 + public static final String PATTERNForTime = "HH:mm:ss";
  19 +
16 20 public static final String PATTERNForDate = "yyyy-MM-dd";
17 21  
18 22 public static final String zoneStr = "Asia/Shanghai";
19 23  
  24 + public static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERNForDateTime, Locale.getDefault()).withZone(ZoneId.of(zoneStr));
  25 + public static final DateTimeFormatter formatterForTime = DateTimeFormatter.ofPattern(PATTERNForTime, Locale.getDefault()).withZone(ZoneId.of(zoneStr));
20 26  
21 27  
22 28 // 获得某天最大时间 2020-02-19 23:59:59
... ... @@ -39,8 +45,38 @@ public class DateUtils {
39 45 }
40 46  
41 47 public static String getDateTimeStr(Date date) {
42   - SimpleDateFormat formatter = new SimpleDateFormat(PATTERNForDateTime);
  48 + SimpleDateFormat formatter = new SimpleDateFormat(PATTERNForDateTime);
43 49 return formatter.format(date);
44 50 }
  51 + public static String getTimeStr(Long dateTime) {
  52 + SimpleDateFormat formatter = new SimpleDateFormat(PATTERNForTime);
  53 + return formatter.format(new Date(dateTime));
  54 + }
  55 +
  56 + public static boolean checkDateFormat(String dateStr) {
  57 + SimpleDateFormat formatter = new SimpleDateFormat(PATTERNForDate);
  58 + try {
  59 + formatter.parse(dateStr);
  60 + return true;
  61 + } catch (ParseException e) {
  62 + return false;
  63 + }
  64 + }
  65 +
  66 + public static boolean checkDateTimeFormat(String dateStr) {
  67 + SimpleDateFormat formatter = new SimpleDateFormat(PATTERNForDateTime);
  68 + try {
  69 + formatter.parse(dateStr);
  70 + return true;
  71 + } catch (ParseException e) {
  72 + return false;
  73 + }
  74 + }
  75 +
  76 + public static long yyyy_MM_dd_HH_mm_ssToTimestamp(String formatTime) {
  77 + TemporalAccessor temporalAccessor = formatter.parse(formatTime);
  78 + Instant instant = Instant.from(temporalAccessor);
  79 + return instant.getEpochSecond();
  80 + }
45 81  
46 82 }
... ...
src/main/java/top/panll/assist/utils/PageInfo.java deleted 100755 → 0
1   -package top.panll.assist.utils;
2   -
3   -import java.util.ArrayList;
4   -import java.util.List;
5   -
6   -public class PageInfo<T> {
7   - //当前页
8   - private int pageNum;
9   - //每页的数量
10   - private int pageSize;
11   - //当前页的数量
12   - private int size;
13   - //总页数
14   - private int pages;
15   - //总数
16   - private int total;
17   -
18   - private List<T> resultData;
19   -
20   - private List<T> list;
21   -
22   - public PageInfo(List<T> resultData) {
23   - this.resultData = resultData;
24   - }
25   -
26   - public void startPage(int page, int count) {
27   - if (count <= 0) count = 10;
28   - if (page <= 0) page = 1;
29   - this.pageNum = page;
30   - this.pageSize = count;
31   - this.total = resultData.size();
32   -
33   - this.pages = total%count == 0 ? total/count : total/count + 1;
34   - int fromIndx = (page - 1) * count;
35   - if ( fromIndx > this.total - 1) {
36   - this.list = new ArrayList<>();
37   - this.size = 0;
38   - return;
39   - }
40   -
41   - int toIndx = page * count;
42   - if (toIndx > this.total) {
43   - toIndx = this.total;
44   - }
45   - this.list = this.resultData.subList(fromIndx, toIndx);
46   - this.size = this.list.size();
47   - }
48   -
49   - public int getPageNum() {
50   - return pageNum;
51   - }
52   -
53   - public void setPageNum(int pageNum) {
54   - this.pageNum = pageNum;
55   - }
56   -
57   - public int getPageSize() {
58   - return pageSize;
59   - }
60   -
61   - public void setPageSize(int pageSize) {
62   - this.pageSize = pageSize;
63   - }
64   -
65   - public int getSize() {
66   - return size;
67   - }
68   -
69   - public void setSize(int size) {
70   - this.size = size;
71   - }
72   -
73   - public int getPages() {
74   - return pages;
75   - }
76   -
77   - public void setPages(int pages) {
78   - this.pages = pages;
79   - }
80   -
81   - public int getTotal() {
82   - return total;
83   - }
84   -
85   - public void setTotal(int total) {
86   - this.total = total;
87   - }
88   -
89   - public List<T> getList() {
90   - return list;
91   - }
92   -
93   - public void setList(List<T> list) {
94   - this.list = list;
95   - }
96   -}
src/main/java/top/panll/assist/utils/RedisUtil.java deleted 100755 → 0
1   -package top.panll.assist.utils;
2   -
3   -import org.springframework.beans.factory.annotation.Autowired;
4   -import org.springframework.data.redis.core.*;
5   -import org.springframework.stereotype.Component;
6   -import org.springframework.util.CollectionUtils;
7   -
8   -import java.util.*;
9   -import java.util.concurrent.TimeUnit;
10   -
11   -/**
12   - * @Description:Redis工具类
13   - * @author: swwheihei
14   - * @date: 2020年5月6日 下午8:27:29
15   - */
16   -@Component
17   -@SuppressWarnings(value = {"rawtypes", "unchecked"})
18   -public class RedisUtil {
19   -
20   - @Autowired
21   - private RedisTemplate<Object, Object> redisTemplate;
22   -
23   - /**
24   - * 指定缓存失效时间
25   - * @param key 键
26   - * @param time 时间(秒)
27   - * @return true / false
28   - */
29   - public boolean expire(String key, long time) {
30   - try {
31   - if (time > 0) {
32   - redisTemplate.expire(key, time, TimeUnit.SECONDS);
33   - }
34   - return true;
35   - } catch (Exception e) {
36   - e.printStackTrace();
37   - return false;
38   - }
39   -
40   - }
41   -
42   - /**
43   - * 根据 key 获取过期时间
44   - * @param key 键
45   - * @return
46   - */
47   - public long getExpire(String key) {
48   - return redisTemplate.getExpire(key, TimeUnit.SECONDS);
49   - }
50   -
51   - /**
52   - * 判断 key 是否存在
53   - * @param key 键
54   - * @return true / false
55   - */
56   - public boolean hasKey(String key) {
57   - try {
58   - return redisTemplate.hasKey(key);
59   - } catch (Exception e) {
60   - e.printStackTrace();
61   - return false;
62   - }
63   - }
64   -
65   - /**
66   - * 删除缓存
67   - * @SuppressWarnings("unchecked") 忽略类型转换警告
68   - * @param key 键(一个或者多个)
69   - */
70   - public boolean del(String... key) {
71   - try {
72   - if (key != null && key.length > 0) {
73   - if (key.length == 1) {
74   - redisTemplate.delete(key[0]);
75   - } else {
76   -// 传入一个 Collection<String> 集合
77   - redisTemplate.delete(CollectionUtils.arrayToList(key));
78   - }
79   - }
80   - return true;
81   - } catch (Exception e) {
82   - e.printStackTrace();
83   - return false;
84   - }
85   - }
86   -
87   -// ============================== String ==============================
88   -
89   - /**
90   - * 普通缓存获取
91   - * @param key 键
92   - * @return 值
93   - */
94   - public Object get(String key) {
95   - return key == null ? null : redisTemplate.opsForValue().get(key);
96   - }
97   -
98   - /**
99   - * 普通缓存放入
100   - * @param key 键
101   - * @param value 值
102   - * @return true / false
103   - */
104   - public boolean set(String key, Object value) {
105   - try {
106   - redisTemplate.opsForValue().set(key, value);
107   - return true;
108   - } catch (Exception e) {
109   -// e.printStackTrace();
110   - return false;
111   - }
112   - }
113   -
114   - /**
115   - * 普通缓存放入并设置时间
116   - * @param key 键
117   - * @param value 值
118   - * @param time 时间(秒),如果 time < 0 则设置无限时间
119   - * @return true / false
120   - */
121   - public boolean set(String key, Object value, long time) {
122   - try {
123   - if (time > 0) {
124   - redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
125   - } else {
126   - set(key, value);
127   - }
128   - return true;
129   - } catch (Exception e) {
130   - e.printStackTrace();
131   - return false;
132   - }
133   - }
134   -
135   - /**
136   - * 递增
137   - * @param key 键
138   - * @param delta 递增大小
139   - * @return
140   - */
141   - public long incr(String key, long delta) {
142   - if (delta < 0) {
143   - throw new RuntimeException("递增因子必须大于 0");
144   - }
145   - return redisTemplate.opsForValue().increment(key, delta);
146   - }
147   -
148   - /**
149   - * 递减
150   - * @param key 键
151   - * @param delta 递减大小
152   - * @return
153   - */
154   - public long decr(String key, long delta) {
155   - if (delta < 0) {
156   - throw new RuntimeException("递减因子必须大于 0");
157   - }
158   - return redisTemplate.opsForValue().increment(key, delta);
159   - }
160   -
161   -// ============================== Map ==============================
162   -
163   - /**
164   - * HashGet
165   - * @param key 键(no null)
166   - * @param item 项(no null)
167   - * @return 值
168   - */
169   - public Object hget(String key, String item) {
170   - return redisTemplate.opsForHash().get(key, item);
171   - }
172   -
173   - /**
174   - * 获取 key 对应的 map
175   - * @param key 键(no null)
176   - * @return 对应的多个键值
177   - */
178   - public Map<Object, Object> hmget(String key) {
179   - return redisTemplate.opsForHash().entries(key);
180   - }
181   -
182   - /**
183   - * HashSet
184   - * @param key 键
185   - * @param map 值
186   - * @return true / false
187   - */
188   - public boolean hmset(String key, Map<Object, Object> map) {
189   - try {
190   - redisTemplate.opsForHash().putAll(key, map);
191   - return true;
192   - } catch (Exception e) {
193   - e.printStackTrace();
194   - return false;
195   - }
196   - }
197   -
198   - /**
199   - * HashSet 并设置时间
200   - * @param key 键
201   - * @param map 值
202   - * @param time 时间
203   - * @return true / false
204   - */
205   - public boolean hmset(String key, Map<Object, Object> map, long time) {
206   - try {
207   - redisTemplate.opsForHash().putAll(key, map);
208   - if (time > 0) {
209   - expire(key, time);
210   - }
211   - return true;
212   - } catch (Exception e) {
213   - e.printStackTrace();
214   - return false;
215   - }
216   - }
217   -
218   - /**
219   - * 向一张 Hash表 中放入数据,如不存在则创建
220   - * @param key 键
221   - * @param item 项
222   - * @param value 值
223   - * @return true / false
224   - */
225   - public boolean hset(String key, String item, Object value) {
226   - try {
227   - redisTemplate.opsForHash().put(key, item, value);
228   - return true;
229   - } catch (Exception e) {
230   - e.printStackTrace();
231   - return false;
232   - }
233   - }
234   -
235   - /**
236   - * 向一张 Hash表 中放入数据,并设置时间,如不存在则创建
237   - * @param key 键
238   - * @param item 项
239   - * @param value 值
240   - * @param time 时间(如果原来的 Hash表 设置了时间,这里会覆盖)
241   - * @return true / false
242   - */
243   - public boolean hset(String key, String item, Object value, long time) {
244   - try {
245   - redisTemplate.opsForHash().put(key, item, value);
246   - if (time > 0) {
247   - expire(key, time);
248   - }
249   - return true;
250   - } catch (Exception e) {
251   - e.printStackTrace();
252   - return false;
253   - }
254   - }
255   -
256   - /**
257   - * 删除 Hash表 中的值
258   - * @param key 键
259   - * @param item 项(可以多个,no null)
260   - */
261   - public void hdel(String key, Object... item) {
262   - redisTemplate.opsForHash().delete(key, item);
263   - }
264   -
265   - /**
266   - * 判断 Hash表 中是否有该键的值
267   - * @param key 键(no null)
268   - * @param item 值(no null)
269   - * @return true / false
270   - */
271   - public boolean hHasKey(String key, String item) {
272   - return redisTemplate.opsForHash().hasKey(key, item);
273   - }
274   -
275   - /**
276   - * Hash递增,如果不存在则创建一个,并把新增的值返回
277   - * @param key 键
278   - * @param item 项
279   - * @param by 递增大小 > 0
280   - * @return
281   - */
282   - public Double hincr(String key, String item, Double by) {
283   - return redisTemplate.opsForHash().increment(key, item, by);
284   - }
285   -
286   - /**
287   - * Hash递减
288   - * @param key 键
289   - * @param item 项
290   - * @param by 递减大小
291   - * @return
292   - */
293   - public Double hdecr(String key, String item, Double by) {
294   - return redisTemplate.opsForHash().increment(key, item, -by);
295   - }
296   -
297   -// ============================== Set ==============================
298   -
299   - /**
300   - * 根据 key 获取 set 中的所有值
301   - * @param key 键
302   - * @return 值
303   - */
304   - public Set<Object> sGet(String key) {
305   - try {
306   - return redisTemplate.opsForSet().members(key);
307   - } catch (Exception e) {
308   - e.printStackTrace();
309   - return null;
310   - }
311   - }
312   -
313   - /**
314   - * 从键为 key 的 set 中,根据 value 查询是否存在
315   - * @param key 键
316   - * @param value 值
317   - * @return true / false
318   - */
319   - public boolean sHasKey(String key, Object value) {
320   - try {
321   - return redisTemplate.opsForSet().isMember(key, value);
322   - } catch (Exception e) {
323   - e.printStackTrace();
324   - return false;
325   - }
326   - }
327   -
328   - /**
329   - * 将数据放入 set缓存
330   - * @param key 键值
331   - * @param values 值(可以多个)
332   - * @return 成功个数
333   - */
334   - public long sSet(String key, Object... values) {
335   - try {
336   - return redisTemplate.opsForSet().add(key, values);
337   - } catch (Exception e) {
338   - e.printStackTrace();
339   - return 0;
340   - }
341   - }
342   -
343   - /**
344   - * 将数据放入 set缓存,并设置时间
345   - * @param key 键
346   - * @param time 时间
347   - * @param values 值(可以多个)
348   - * @return 成功放入个数
349   - */
350   - public long sSet(String key, long time, Object... values) {
351   - try {
352   - long count = redisTemplate.opsForSet().add(key, values);
353   - if (time > 0) {
354   - expire(key, time);
355   - }
356   - return count;
357   - } catch (Exception e) {
358   - e.printStackTrace();
359   - return 0;
360   - }
361   - }
362   -
363   - /**
364   - * 获取 set缓存的长度
365   - * @param key 键
366   - * @return 长度
367   - */
368   - public long sGetSetSize(String key) {
369   - try {
370   - return redisTemplate.opsForSet().size(key);
371   - } catch (Exception e) {
372   - e.printStackTrace();
373   - return 0;
374   - }
375   - }
376   -
377   - /**
378   - * 移除 set缓存中,值为 value 的
379   - * @param key 键
380   - * @param values 值
381   - * @return 成功移除个数
382   - */
383   - public long setRemove(String key, Object... values) {
384   - try {
385   - return redisTemplate.opsForSet().remove(key, values);
386   - } catch (Exception e) {
387   - e.printStackTrace();
388   - return 0;
389   - }
390   - }
391   -// ============================== ZSet ==============================
392   -
393   - /**
394   - * 添加一个元素, zset与set最大的区别就是每个元素都有一个score,因此有个排序的辅助功能; zadd
395   - *
396   - * @param key
397   - * @param value
398   - * @param score
399   - */
400   - public void zAdd(Object key, Object value, double score) {
401   - redisTemplate.opsForZSet().add(key, value, score);
402   - }
403   -
404   - /**
405   - * 删除元素 zrem
406   - *
407   - * @param key
408   - * @param value
409   - */
410   - public void zRemove(Object key, Object value) {
411   - redisTemplate.opsForZSet().remove(key, value);
412   - }
413   -
414   - /**
415   - * score的增加or减少 zincrby
416   - *
417   - * @param key
418   - * @param value
419   - * @param score
420   - */
421   - public Double zIncrScore(Object key, Object value, double score) {
422   - return redisTemplate.opsForZSet().incrementScore(key, value, score);
423   - }
424   -
425   - /**
426   - * 查询value对应的score zscore
427   - *
428   - * @param key
429   - * @param value
430   - * @return
431   - */
432   - public Double zScore(Object key, Object value) {
433   - return redisTemplate.opsForZSet().score(key, value);
434   - }
435   -
436   - /**
437   - * 判断value在zset中的排名 zrank
438   - *
439   - * @param key
440   - * @param value
441   - * @return
442   - */
443   - public Long zRank(Object key, Object value) {
444   - return redisTemplate.opsForZSet().rank(key, value);
445   - }
446   -
447   - /**
448   - * 返回集合的长度
449   - *
450   - * @param key
451   - * @return
452   - */
453   - public Long zSize(Object key) {
454   - return redisTemplate.opsForZSet().zCard(key);
455   - }
456   -
457   - /**
458   - * 查询集合中指定顺序的值, 0 -1 表示获取全部的集合内容 zrange
459   - *
460   - * 返回有序的集合,score小的在前面
461   - *
462   - * @param key
463   - * @param start
464   - * @param end
465   - * @return
466   - */
467   - public Set<Object> ZRange(Object key, int start, int end) {
468   - return redisTemplate.opsForZSet().range(key, start, end);
469   - }
470   - /**
471   - * 查询集合中指定顺序的值和score,0, -1 表示获取全部的集合内容
472   - *
473   - * @param key
474   - * @param start
475   - * @param end
476   - * @return
477   - */
478   - public Set<ZSetOperations.TypedTuple<Object>> zRangeWithScore(Object key, int start, int end) {
479   - return redisTemplate.opsForZSet().rangeWithScores(key, start, end);
480   - }
481   - /**
482   - * 查询集合中指定顺序的值 zrevrange
483   - *
484   - * 返回有序的集合中,score大的在前面
485   - *
486   - * @param key
487   - * @param start
488   - * @param end
489   - * @return
490   - */
491   - public Set<Object> zRevRange(Object key, int start, int end) {
492   - return redisTemplate.opsForZSet().reverseRange(key, start, end);
493   - }
494   - /**
495   - * 根据score的值,来获取满足条件的集合 zrangebyscore
496   - *
497   - * @param key
498   - * @param min
499   - * @param max
500   - * @return
501   - */
502   - public Set<Object> zSortRange(Object key, int min, int max) {
503   - return redisTemplate.opsForZSet().rangeByScore(key, min, max);
504   - }
505   -
506   -
507   -// ============================== List ==============================
508   -
509   - /**
510   - * 获取 list缓存的内容
511   - * @param key 键
512   - * @param start 开始
513   - * @param end 结束(0 到 -1 代表所有值)
514   - * @return
515   - */
516   - public List<Object> lGet(String key, long start, long end) {
517   - try {
518   - return redisTemplate.opsForList().range(key, start, end);
519   - } catch (Exception e) {
520   - e.printStackTrace();
521   - return null;
522   - }
523   - }
524   -
525   - /**
526   - * 获取 list缓存的长度
527   - * @param key 键
528   - * @return 长度
529   - */
530   - public long lGetListSize(String key) {
531   - try {
532   - return redisTemplate.opsForList().size(key);
533   - } catch (Exception e) {
534   - e.printStackTrace();
535   - return 0;
536   - }
537   - }
538   -
539   - /**
540   - * 根据索引 index 获取键为 key 的 list 中的元素
541   - * @param key 键
542   - * @param index 索引
543   - * 当 index >= 0 时 {0:表头, 1:第二个元素}
544   - * 当 index < 0 时 {-1:表尾, -2:倒数第二个元素}
545   - * @return 值
546   - */
547   - public Object lGetIndex(String key, long index) {
548   - try {
549   - return redisTemplate.opsForList().index(key, index);
550   - } catch (Exception e) {
551   - e.printStackTrace();
552   - return null;
553   - }
554   - }
555   -
556   - /**
557   - * 将值 value 插入键为 key 的 list 中,如果 list 不存在则创建空 list
558   - * @param key 键
559   - * @param value 值
560   - * @return true / false
561   - */
562   - public boolean lSet(String key, Object value) {
563   - try {
564   - redisTemplate.opsForList().rightPush(key, value);
565   - return true;
566   - } catch (Exception e) {
567   - e.printStackTrace();
568   - return false;
569   - }
570   - }
571   -
572   - /**
573   - * 将值 value 插入键为 key 的 list 中,并设置时间
574   - * @param key 键
575   - * @param value 值
576   - * @param time 时间
577   - * @return true / false
578   - */
579   - public boolean lSet(String key, Object value, long time) {
580   - try {
581   - redisTemplate.opsForList().rightPush(key, value);
582   - if (time > 0) {
583   - expire(key, time);
584   - }
585   - return true;
586   - } catch (Exception e) {
587   - e.printStackTrace();
588   - return false;
589   - }
590   - }
591   -
592   - /**
593   - * 将 values 插入键为 key 的 list 中
594   - * @param key 键
595   - * @param values 值
596   - * @return true / false
597   - */
598   - public boolean lSetList(String key, List<Object> values) {
599   - try {
600   - redisTemplate.opsForList().rightPushAll(key, values);
601   - return true;
602   - } catch (Exception e) {
603   - e.printStackTrace();
604   - return false;
605   - }
606   - }
607   -
608   - /**
609   - * 将 values 插入键为 key 的 list 中,并设置时间
610   - * @param key 键
611   - * @param values 值
612   - * @param time 时间
613   - * @return true / false
614   - */
615   - public boolean lSetList(String key, List<Object> values, long time) {
616   - try {
617   - redisTemplate.opsForList().rightPushAll(key, values);
618   - if (time > 0) {
619   - expire(key, time);
620   - }
621   - return true;
622   - } catch (Exception e) {
623   - e.printStackTrace();
624   - return false;
625   - }
626   - }
627   -
628   - /**
629   - * 根据索引 index 修改键为 key 的值
630   - * @param key 键
631   - * @param index 索引
632   - * @param value 值
633   - * @return true / false
634   - */
635   - public boolean lUpdateIndex(String key, long index, Object value) {
636   - try {
637   - redisTemplate.opsForList().set(key, index, value);
638   - return true;
639   - } catch (Exception e) {
640   - e.printStackTrace();
641   - return false;
642   - }
643   - }
644   -
645   - /**
646   - * 在键为 key 的 list 中删除值为 value 的元素
647   - * @param key 键
648   - * @param count 如果 count == 0 则删除 list 中所有值为 value 的元素
649   - * 如果 count > 0 则删除 list 中最左边那个值为 value 的元素
650   - * 如果 count < 0 则删除 list 中最右边那个值为 value 的元素
651   - * @param value
652   - * @return
653   - */
654   - public long lRemove(String key, long count, Object value) {
655   - try {
656   - return redisTemplate.opsForList().remove(key, count, value);
657   - } catch (Exception e) {
658   - e.printStackTrace();
659   - return 0;
660   - }
661   - }
662   -
663   - /**
664   - * 模糊查询
665   - * @param key 键
666   - * @return true / false
667   - */
668   - public List<Object> keys(String key) {
669   - try {
670   - Set<Object> set = redisTemplate.keys(key);
671   - return new ArrayList<>(set);
672   - } catch (Exception e) {
673   - e.printStackTrace();
674   - return null;
675   - }
676   - }
677   -
678   -
679   - /**
680   - * 模糊查询
681   - * @param query 查询参数
682   - * @return
683   - */
684   -// public List<Object> scan(String query) {
685   -// List<Object> result = new ArrayList<>();
686   -// try {
687   -// Cursor<Map.Entry<Object,Object>> cursor = redisTemplate.opsForHash().scan("field",
688   -// ScanOptions.scanOptions().match(query).count(1000).build());
689   -// while (cursor.hasNext()) {
690   -// Map.Entry<Object,Object> entry = cursor.next();
691   -// result.add(entry.getKey());
692   -// Object key = entry.getKey();
693   -// Object valueSet = entry.getValue();
694   -// }
695   -// //关闭cursor
696   -// cursor.close();
697   -// } catch (Exception e) {
698   -// e.printStackTrace();
699   -// }
700   -// return result;
701   -// }
702   -
703   - /**
704   - * 模糊查询
705   - * @param query 查询参数
706   - * @return
707   - */
708   - public List<Object> scan(String query) {
709   - Set<String> resultKeys = redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
710   - ScanOptions scanOptions = ScanOptions.scanOptions().match("*" + query + "*").count(1000).build();
711   - Cursor<byte[]> scan = connection.scan(scanOptions);
712   - Set<String> keys = new HashSet<>();
713   - while (scan.hasNext()) {
714   - byte[] next = scan.next();
715   - keys.add(new String(next));
716   - }
717   - return keys;
718   - });
719   -
720   - return new ArrayList<>(resultKeys);
721   - }
722   -
723   -}
src/main/resources/all-application.yml deleted 100755 → 0
1   -spring:
2   - # REDIS数据库配置
3   - redis:
4   - # [必须修改] Redis服务器IP, REDIS安装在本机的,使用127.0.0.1
5   - host: 127.0.0.1
6   - # [必须修改] 端口号
7   - port: 6379
8   - # [可选] 数据库 DB
9   - database: 8
10   - # [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接
11   - password:
12   - # [可选] 超时时间
13   - timeout: 10000
14   -
15   -# [必选] WVP监听的HTTP端口, 网页和接口调用都是这个端口
16   -server:
17   - port: 18081
18   - # [可选] HTTPS配置, 默认不开启
19   - ssl:
20   - # [可选] 是否开启HTTPS访问
21   - enabled: false
22   - # [可选] 证书文件路径,放置在resource/目录下即可,修改xxx为文件名
23   - key-store: classpath:xxx.jks
24   - # [可选] 证书密码
25   - key-password: password
26   - # [可选] 证书类型, 默认为jks,根据实际修改
27   - key-store-type: JKS
28   -
29   -# [根据业务需求配置]
30   -user-settings:
31   - # [可选 ] zlm配置的录像路径,不配置则使用当前目录下的record目录 即: ./record
32   - record: /media/lin/Server/ZLMediaKit/dev/ZLMediaKit/release/linux/Debug/www/record
33   - # [可选 ] 录像保存时长(单位: 天)每天晚12点自动对过期文件执行清理, 不配置则不删除
34   - recordDay: 7
35   - # [可选 ] 录像下载合成临时文件保存时长, 不配置默认取值recordDay(单位: 天)每天晚12点自动对过期文件执行清理
36   - # recordTempDay: 7
37   - # [必选 ] ffmpeg路径
38   - ffmpeg: /usr/bin/ffmpeg
39   - # [必选 ] ffprobe路径, 一般安装ffmpeg就会自带, 一般跟ffmpeg在同一目录,用于查询文件的信息
40   - ffprobe: /usr/bin/ffprobe
41   - # [可选 ] 限制 ffmpeg 合并文件使用的线程数,间接限制cpu使用率, 默认2 限制到50%
42   - threads: 2
43   -
44   -swagger-ui:
45   -
46   -# [可选] 日志配置, 一般不需要改
47   -logging:
48   - file:
49   - name: logs/wvp.log
50   - max-history: 30
51   - max-size: 10MB
52   - total-size-cap: 300MB
53   - level:
54   - root: WARN
55   - top:
56   - panll:
57   - assist: info
58 0 \ No newline at end of file
src/main/resources/application-dev.yml deleted 100755 → 0
1   -spring:
2   - # REDIS数据库配置
3   - redis:
4   - # [必须修改] Redis服务器IP, REDIS安装在本机的,使用127.0.0.1
5   - host: 127.0.0.1
6   - # [必须修改] 端口号
7   - port: 6379
8   - # [可选] 数据库 DB
9   - database: 8
10   - # [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接
11   - password:
12   - # [可选] 超时时间
13   - timeout: 10000
14   -
15   -# [可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口
16   -server:
17   - port: 18081
18   - # [可选] HTTPS配置, 默认不开启
19   - ssl:
20   - # [可选] 是否开启HTTPS访问
21   - enabled: false
22   - # [可选] 证书文件路径,放置在resource/目录下即可,修改xxx为文件名
23   - key-store: classpath:xxx.jks
24   - # [可选] 证书密码
25   - key-password: password
26   - # [可选] 证书类型, 默认为jks,根据实际修改
27   - key-store-type: JKS
28   -
29   -# [根据业务需求配置]
30   -userSettings:
31   - # [可选 ] zlm配置的录像路径,
32   - record: /media/lin/Server/ZLMediaKit/dev/ZLMediaKit/release/linux/Debug/www/record
33   - # [可选 ] 录像保存时长(单位: 天)每天晚12点自动对过期文件执行清理
34   - recordDay: 7
35   - # [可选 ] 录像下载合成临时文件保存时长, 不配置默认取值recordDay(单位: 天)每天晚12点自动对过期文件执行清理
36   - # recordTempDay: 7
37   - # [必选 ] ffmpeg路径
38   - ffmpeg: /usr/bin/ffmpeg
39   - # [必选 ] ffprobe路径, 一般安装ffmpeg就会自带, 一般跟ffmpeg在同一目录,用于查询文件的信息
40   - ffprobe: /usr/bin/ffprobe
41   - # [可选 ] 限制 ffmpeg 合并文件使用的线程数,间接限制cpu使用率, 默认2 限制到50%
42   - threads: 2
43   -
44   -swagger-ui:
45   -
46   -# [可选] 日志配置, 一般不需要改
47   -logging:
48   - file:
49   - name: logs/wvp.log
50   - max-history: 30
51   - max-size: 10MB
52   - total-size-cap: 300MB
53   - level:
54   - root: WARN
55   - top:
56   - panll:
57   - assist: info
58 0 \ No newline at end of file
src/main/resources/application-local.yml deleted 100755 → 0
1   -spring:
2   - # REDIS数据库配置
3   - redis:
4   - # [可选] 超时时间
5   - timeout: 10000
6   - # 以下为单机配置
7   - # [必须修改] Redis服务器IP, REDIS安装在本机的,使用127.0.0.1
8   - host: 127.0.0.1
9   - # [必须修改] 端口号
10   - port: 6379
11   - # [可选] 数据库 DB
12   - database: 1
13   - # [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接
14   - password: adminadmin123.
15   - # 以下为集群配置
16   -# cluster:
17   -# nodes: 192.168.1.242:7001
18   -# password: 4767cb971b40a1300fa09b7f87b09d1c
19   -
20   -# [可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口
21   -server:
22   - port: 18089
23   - # [可选] HTTPS配置, 默认不开启
24   - ssl:
25   - # [可选] 是否开启HTTPS访问
26   - enabled: false
27   - # [可选] 证书文件路径,放置在resource/目录下即可,修改xxx为文件名
28   - key-store: classpath:xxx.jks
29   - # [可选] 证书密码
30   - key-password: password
31   - # [可选] 证书类型, 默认为jks,根据实际修改
32   - key-store-type: JKS
33   -
34   -# [根据业务需求配置]
35   -userSettings:
36   - # [必选 ] 服务ID
37   - id: 334533
38   - # [必选 ] 录像路径
39   - record: /home/lin/record/
40   - # [可选 ] 录像保存时长(单位: 天)每天晚12点自动对过期文件执行清理
41   - recordDay: 10
42   - # [可选 ] 录像下载合成临时文件保存时长, 不配置默认取值recordDay(单位: 天)每天晚12点自动对过期文件执行清理
43   - # recordTempDay: 7
44   - # [必选 ] ffmpeg路径
45   - ffmpeg: /home/lin/IdeaProjects/wvp-pro-assist/lib/ffmpeg
46   - # [必选 ] ffprobe路径, 一般安装ffmpeg就会自带, 一般跟ffmpeg在同一目录,用于查询文件的信息,
47   - ffprobe: /home/lin/IdeaProjects/wvp-pro-assist/lib/ffprobe
48   - # [可选 ] 限制 ffmpeg 合并文件使用的线程数,间接限制cpu使用率, 默认2 限制到50%
49   - threads: 2
50   -
51   -# [可选] 日志配置, 一般不需要改
52   -logging:
53   - file:
54   - name: logs/wvp.log
55   - max-history: 30
56   - max-size: 10MB
57   - total-size-cap: 300MB
58   - level:
59   - root: WARN
60   - top:
61   - panll:
62   - assist: info
63 0 \ No newline at end of file
src/main/resources/application.yml
1 1 spring:
2   - profiles:
3   - active: local
  2 + application:
  3 + name: wvp-assist
  4 + datasource:
  5 + type: com.zaxxer.hikari.HikariDataSource
  6 + driver-class-name: com.mysql.cj.jdbc.Driver
  7 + url: jdbc:mysql://127.0.0.1:3306/wvp_test?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true&allowPublicKeyRetrieval=true
  8 + username: root
  9 + password: 12345678
  10 +
  11 +# [必选] WVP监听的HTTP端口, 网页和接口调用都是这个端口
  12 +server:
  13 + port: 18081
  14 +
  15 +# [根据业务需求配置]
  16 +user-settings:
  17 + id: 1111
  18 + media-server-id: 11212
  19 + # [可选 ] zlm配置的录像路径,不配置则使用当前目录下的record目录 即: ./record
  20 + record: /home/lin/record/
  21 + # [可选 ] 录像保存时长(单位: 天)每天晚12点自动对过期文件执行清理, 不配置则不删除
  22 + recordDay: 7
  23 + # [可选 ] 录像下载合成临时文件保存时长, 不配置默认取值recordDay(单位: 天)每天晚12点自动对过期文件执行清理
  24 + # recordTempDay: 7
  25 + # [必选 ] ffmpeg路径
  26 + ffmpeg: /usr/bin/ffmpeg
  27 + # [必选 ] ffprobe路径, 一般安装ffmpeg就会自带, 一般跟ffmpeg在同一目录,用于查询文件的信息
  28 + ffprobe: /usr/bin/ffprobe
  29 + # [可选 ] 限制 ffmpeg 合并文件使用的线程数,间接限制cpu使用率, 默认2 限制到50%
  30 + threads: 2
  31 +
  32 +
  33 +# [可选] 日志配置, 一般不需要改
  34 +logging:
  35 + file:
  36 + name: logs/wvp.log
  37 + max-history: 30
  38 + max-size: 10MB
  39 + total-size-cap: 300MB
  40 + level:
  41 + root: WARN
  42 + top:
  43 + panll:
  44 + assist: info
4 45 \ No newline at end of file
... ...
src/main/resources/static/download.html deleted 100755 → 0
1   -<!DOCTYPE html>
2   -<html lang="en">
3   -<head>
4   - <meta charset="UTF-8">
5   - <meta http-equiv="X-UA-Compatible" content="IE=edge">
6   - <meta name="viewport" content="width=device-width, initial-scale=1.0">
7   - <title>下载</title>
8   -</head>
9   -<body>
10   -<a id="download" download></a>
11   -<script>
12   - (function () {
13   - let searchParams = new URLSearchParams(location.search);
14   - var download = document.getElementById("download");
15   - download.setAttribute("href", searchParams.get("url"))
16   - download.click()
17   - setTimeout(() => {
18   - window.location.href = "about:blank";
19   - window.close();
20   - }, 200)
21   - })();
22   -
23   -</script>
24   -</body>
25   -</html>
26 0 \ No newline at end of file