Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
C
cmeeting
概览
概览
详情
活动
周期分析
版本库
存储库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
Issue Boards
Open sidebar
翟斌
cmeeting
Commits
b87c127c
提交
b87c127c
authored
5月 24, 2025
作者:
duanxincheng
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
纪要生成服务优化
父级
8a23a94c
隐藏空白字符变更
内嵌
并排
正在显示
21 个修改的文件
包含
803 行增加
和
558 行删除
+803
-558
pom.xml
+23
-0
src/main/java/com/cmeeting/TencentMeetingCallbackApplication.java
+1
-0
src/main/java/com/cmeeting/config/MasterDataSourceConfig.java
+44
-0
src/main/java/com/cmeeting/config/PrimaryDataSourceConfig.java
+0
-47
src/main/java/com/cmeeting/config/SecondaryDataSourceConfig.java
+0
-47
src/main/java/com/cmeeting/config/SlaveDataSourceConfig.java
+39
-0
src/main/java/com/cmeeting/controller/TencentMeetingController.java
+2
-2
src/main/java/com/cmeeting/email/EmailSender.java
+58
-56
src/main/java/com/cmeeting/job/CmeetingJob.java
+1
-12
src/main/java/com/cmeeting/job/FileProcessTask.java
+213
-135
src/main/java/com/cmeeting/mapper/primary/MeetingInfoMapper.java
+18
-0
src/main/java/com/cmeeting/pojo/MeetingInfo.java
+52
-131
src/main/java/com/cmeeting/service/FileProcessProducer.java
+14
-1
src/main/java/com/cmeeting/service/MeetingInfoService.java
+7
-0
src/main/java/com/cmeeting/service/TecentMeetingService.java
+1
-1
src/main/java/com/cmeeting/service/impl/MeetingInfoServiceImpl.java
+13
-0
src/main/java/com/cmeeting/service/impl/TecentMeetingServiceImpl.java
+100
-76
src/main/java/com/cmeeting/util/MinioUtils.java
+77
-0
src/main/resources/application.properties
+0
-50
src/main/resources/application.yml
+109
-0
src/main/resources/mapper/primary/MeetingInfoMapper.xml
+31
-0
没有找到文件。
pom.xml
浏览文件 @
b87c127c
...
@@ -122,6 +122,11 @@
...
@@ -122,6 +122,11 @@
<version>
2.7.0
</version>
<version>
2.7.0
</version>
</dependency>
</dependency>
<dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-jdbc
</artifactId>
<version>
2.7.0
</version>
<!-- 与你的 Spring Boot 版本保持一致 -->
</dependency>
<dependency>
<groupId>
commons-codec
</groupId>
<groupId>
commons-codec
</groupId>
<artifactId>
commons-codec
</artifactId>
<artifactId>
commons-codec
</artifactId>
<version>
1.15
</version>
<version>
1.15
</version>
...
@@ -313,6 +318,24 @@
...
@@ -313,6 +318,24 @@
<artifactId>
mybatis-plus-boot-starter
</artifactId>
<artifactId>
mybatis-plus-boot-starter
</artifactId>
<version>
${mybatis-plus.version}
</version>
<version>
${mybatis-plus.version}
</version>
</dependency>
</dependency>
<dependency>
<groupId>
io.minio
</groupId>
<artifactId>
minio
</artifactId>
<version>
3.0.10
</version>
<exclusions>
<exclusion>
<groupId>
com.squareup.okhttp3
</groupId>
<artifactId>
okhttp
</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>
junit
</groupId>
<artifactId>
junit
</artifactId>
<version>
RELEASE
</version>
<scope>
test
</scope>
</dependency>
</dependencies>
</dependencies>
...
...
src/main/java/com/cmeeting/TencentMeetingCallbackApplication.java
浏览文件 @
b87c127c
...
@@ -7,6 +7,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
...
@@ -7,6 +7,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@SpringBootApplication
@EnableScheduling
@EnableScheduling
@MapperScan
(
"com.cmeeting.mapper.primary"
)
public
class
TencentMeetingCallbackApplication
{
public
class
TencentMeetingCallbackApplication
{
public
static
void
main
(
String
[]
args
)
{
public
static
void
main
(
String
[]
args
)
{
SpringApplication
.
run
(
TencentMeetingCallbackApplication
.
class
,
args
);
SpringApplication
.
run
(
TencentMeetingCallbackApplication
.
class
,
args
);
...
...
src/main/java/com/cmeeting/config/MasterDataSourceConfig.java
0 → 100644
浏览文件 @
b87c127c
package
com
.
cmeeting
.
config
;
import
com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean
;
import
org.apache.ibatis.session.SqlSessionFactory
;
import
org.mybatis.spring.SqlSessionTemplate
;
import
org.mybatis.spring.annotation.MapperScan
;
import
org.springframework.beans.factory.annotation.Qualifier
;
import
org.springframework.boot.context.properties.ConfigurationProperties
;
import
org.springframework.boot.jdbc.DataSourceBuilder
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Primary
;
import
org.springframework.core.io.support.PathMatchingResourcePatternResolver
;
import
javax.sql.DataSource
;
// 主数据源配置
@Configuration
@MapperScan
(
basePackages
=
"com.cmeeting.mapper.primary"
,
sqlSessionFactoryRef
=
"masterSqlSessionFactory"
)
public
class
MasterDataSourceConfig
{
@Primary
@Bean
(
name
=
"masterDataSource"
)
@ConfigurationProperties
(
prefix
=
"spring.datasource.master"
)
public
DataSource
masterDataSource
()
{
return
DataSourceBuilder
.
create
().
build
();
}
@Primary
@Bean
(
name
=
"masterSqlSessionFactory"
)
public
SqlSessionFactory
masterSqlSessionFactory
(
@Qualifier
(
"masterDataSource"
)
DataSource
dataSource
)
throws
Exception
{
MybatisSqlSessionFactoryBean
bean
=
new
MybatisSqlSessionFactoryBean
();
bean
.
setDataSource
(
dataSource
);
bean
.
setMapperLocations
(
new
PathMatchingResourcePatternResolver
().
getResources
(
"classpath:mapper/primary/*.xml"
));
return
bean
.
getObject
();
}
@Primary
@Bean
(
name
=
"masterSqlSessionTemplate"
)
public
SqlSessionTemplate
masterSqlSessionTemplate
(
@Qualifier
(
"masterSqlSessionFactory"
)
SqlSessionFactory
sqlSessionFactory
)
{
return
new
SqlSessionTemplate
(
sqlSessionFactory
);
}
}
\ No newline at end of file
src/main/java/com/cmeeting/config/PrimaryDataSourceConfig.java
deleted
100644 → 0
浏览文件 @
8a23a94c
package
com
.
cmeeting
.
config
;
import
org.apache.ibatis.session.SqlSessionFactory
;
import
org.mybatis.spring.SqlSessionFactoryBean
;
import
org.mybatis.spring.annotation.MapperScan
;
import
org.springframework.beans.factory.annotation.Qualifier
;
import
org.springframework.boot.context.properties.ConfigurationProperties
;
import
org.springframework.boot.jdbc.DataSourceBuilder
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.core.io.support.PathMatchingResourcePatternResolver
;
import
org.springframework.jdbc.datasource.DataSourceTransactionManager
;
import
org.springframework.transaction.PlatformTransactionManager
;
import
javax.sql.DataSource
;
@Configuration
@MapperScan
(
basePackages
=
"com.cmeeting.mapper.primary"
,
// 主数据源的 Mapper 包路径
sqlSessionFactoryRef
=
"primarySqlSessionFactory"
)
public
class
PrimaryDataSourceConfig
{
@Bean
(
name
=
"primaryDataSource"
)
@ConfigurationProperties
(
prefix
=
"spring.datasource.primary"
)
// 绑定主数据源配置
public
DataSource
primaryDataSource
()
{
return
DataSourceBuilder
.
create
().
build
();
}
@Bean
(
name
=
"primarySqlSessionFactory"
)
public
SqlSessionFactory
primarySqlSessionFactory
(
@Qualifier
(
"primaryDataSource"
)
DataSource
dataSource
)
throws
Exception
{
SqlSessionFactoryBean
factoryBean
=
new
SqlSessionFactoryBean
();
factoryBean
.
setDataSource
(
dataSource
);
// 可额外配置 MyBatis 的 mapperLocations、typeAliases 等
factoryBean
.
setMapperLocations
(
new
PathMatchingResourcePatternResolver
()
.
getResources
(
"classpath:mapper/primary/*.xml"
));
return
factoryBean
.
getObject
();
}
@Bean
(
name
=
"primaryTransactionManager"
)
public
PlatformTransactionManager
primaryTransactionManager
(
@Qualifier
(
"primaryDataSource"
)
DataSource
dataSource
)
{
return
new
DataSourceTransactionManager
(
dataSource
);
}
}
\ No newline at end of file
src/main/java/com/cmeeting/config/SecondaryDataSourceConfig.java
deleted
100644 → 0
浏览文件 @
8a23a94c
package
com
.
cmeeting
.
config
;
import
org.apache.ibatis.session.SqlSessionFactory
;
import
org.mybatis.spring.SqlSessionFactoryBean
;
import
org.mybatis.spring.annotation.MapperScan
;
import
org.springframework.beans.factory.annotation.Qualifier
;
import
org.springframework.boot.context.properties.ConfigurationProperties
;
import
org.springframework.boot.jdbc.DataSourceBuilder
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.core.io.support.PathMatchingResourcePatternResolver
;
import
org.springframework.jdbc.datasource.DataSourceTransactionManager
;
import
org.springframework.transaction.PlatformTransactionManager
;
import
javax.sql.DataSource
;
@Configuration
@MapperScan
(
basePackages
=
"com.cmeeting.mapper.secondary"
,
// 次数据源的 Mapper 包路径
sqlSessionFactoryRef
=
"secondarySqlSessionFactory"
)
public
class
SecondaryDataSourceConfig
{
@Bean
(
name
=
"secondaryDataSource"
)
@ConfigurationProperties
(
prefix
=
"spring.datasource.secondary"
)
// 绑定次数据源配置
public
DataSource
secondaryDataSource
()
{
return
DataSourceBuilder
.
create
().
build
();
}
@Bean
(
name
=
"secondarySqlSessionFactory"
)
public
SqlSessionFactory
secondarySqlSessionFactory
(
@Qualifier
(
"secondaryDataSource"
)
DataSource
dataSource
)
throws
Exception
{
SqlSessionFactoryBean
factoryBean
=
new
SqlSessionFactoryBean
();
factoryBean
.
setDataSource
(
dataSource
);
// 可额外配置 MyBatis 的 mapperLocations、typeAliases 等
// 指定次数据源的 XML 映射文件路径
factoryBean
.
setMapperLocations
(
new
PathMatchingResourcePatternResolver
()
.
getResources
(
"classpath:mapper/secondary/*.xml"
));
return
factoryBean
.
getObject
();
}
@Bean
(
name
=
"secondaryTransactionManager"
)
public
PlatformTransactionManager
secondaryTransactionManager
(
@Qualifier
(
"secondaryDataSource"
)
DataSource
dataSource
)
{
return
new
DataSourceTransactionManager
(
dataSource
);
}
}
\ No newline at end of file
src/main/java/com/cmeeting/config/SlaveDataSourceConfig.java
0 → 100644
浏览文件 @
b87c127c
package
com
.
cmeeting
.
config
;
import
com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean
;
import
org.apache.ibatis.session.SqlSessionFactory
;
import
org.mybatis.spring.SqlSessionTemplate
;
import
org.mybatis.spring.annotation.MapperScan
;
import
org.springframework.beans.factory.annotation.Qualifier
;
import
org.springframework.boot.context.properties.ConfigurationProperties
;
import
org.springframework.boot.jdbc.DataSourceBuilder
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.core.io.support.PathMatchingResourcePatternResolver
;
import
javax.sql.DataSource
;
// 从数据源配置
@Configuration
@MapperScan
(
basePackages
=
"com.cmeeting.mapper.secondary"
,
sqlSessionFactoryRef
=
"slaveSqlSessionFactory"
)
public
class
SlaveDataSourceConfig
{
@Bean
(
name
=
"slaveDataSource"
)
@ConfigurationProperties
(
prefix
=
"spring.datasource.slave"
)
public
DataSource
slaveDataSource
()
{
return
DataSourceBuilder
.
create
().
build
();
}
@Bean
(
name
=
"slaveSqlSessionFactory"
)
public
SqlSessionFactory
slaveSqlSessionFactory
(
@Qualifier
(
"slaveDataSource"
)
DataSource
dataSource
)
throws
Exception
{
MybatisSqlSessionFactoryBean
bean
=
new
MybatisSqlSessionFactoryBean
();
bean
.
setDataSource
(
dataSource
);
bean
.
setMapperLocations
(
new
PathMatchingResourcePatternResolver
().
getResources
(
"classpath:mapper/secondary/*.xml"
));
return
bean
.
getObject
();
}
@Bean
(
name
=
"slaveSqlSessionTemplate"
)
public
SqlSessionTemplate
slaveSqlSessionTemplate
(
@Qualifier
(
"slaveSqlSessionFactory"
)
SqlSessionFactory
sqlSessionFactory
)
{
return
new
SqlSessionTemplate
(
sqlSessionFactory
);
}
}
src/main/java/com/cmeeting/controller/TencentMeetingController.java
浏览文件 @
b87c127c
...
@@ -25,7 +25,7 @@ public class TencentMeetingController {
...
@@ -25,7 +25,7 @@ public class TencentMeetingController {
}
}
@GetMapping
(
"/getMeetingFiles"
)
@GetMapping
(
"/getMeetingFiles"
)
public
void
getMeetingFiles
(
TencentMeetingVO
.
TencentMeetingRequest
requestVO
){
public
void
getMeetingFiles
(){
tecentMeetingService
.
getMeetingFiles
(
requestVO
);
tecentMeetingService
.
getMeetingFiles
();
}
}
}
}
src/main/java/com/cmeeting/email/EmailSender.java
浏览文件 @
b87c127c
...
@@ -2,6 +2,7 @@ package com.cmeeting.email;
...
@@ -2,6 +2,7 @@ package com.cmeeting.email;
import
lombok.extern.slf4j.Slf4j
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.stereotype.Service
;
import
javax.activation.DataHandler
;
import
javax.activation.DataHandler
;
import
javax.activation.DataSource
;
import
javax.activation.DataSource
;
...
@@ -13,12 +14,13 @@ import java.util.Properties;
...
@@ -13,12 +14,13 @@ import java.util.Properties;
import
java.util.concurrent.atomic.AtomicInteger
;
import
java.util.concurrent.atomic.AtomicInteger
;
@Slf4j
@Slf4j
@Service
public
class
EmailSender
{
public
class
EmailSender
{
@Value
(
"${email.sender}"
)
@Value
(
"${email.sender}"
)
private
String
SENDER
;
private
String
SENDER
;
@Value
(
"${email.sender
.
pwd}"
)
@Value
(
"${email.sender
-
pwd}"
)
private
String
EMAIL_PWD
;
private
String
EMAIL_PWD
;
@Value
(
"${email.smtp
.
host}"
)
@Value
(
"${email.smtp
-
host}"
)
private
String
SMTP_HOST
;
private
String
SMTP_HOST
;
private
static
final
Integer
MAX_RETRY
=
3
;
private
static
final
Integer
MAX_RETRY
=
3
;
...
@@ -30,10 +32,10 @@ public class EmailSender {
...
@@ -30,10 +32,10 @@ public class EmailSender {
* @param recordFileId 转录文件ID
* @param recordFileId 转录文件ID
* @return
* @return
*/
*/
public
boolean
sendEmailWithAttachment
(
String
toEmail
,
String
subject
,
String
attachmentPath
,
String
recordFileId
)
{
public
boolean
sendEmailWithAttachment
(
String
toEmail
,
String
subject
,
String
attachmentPath
,
String
recordFileId
)
throws
Exception
{
// 邮件服务器配置
// 邮件服务器配置
Properties
props
=
new
Properties
();
Properties
props
=
new
Properties
();
props
.
put
(
"mail.smtp.host"
,
"smtp.office365.com"
);
props
.
put
(
"mail.smtp.host"
,
SMTP_HOST
);
props
.
put
(
"mail.smtp.auth"
,
"true"
);
props
.
put
(
"mail.smtp.auth"
,
"true"
);
// props.put("mail.smtp.port", "465");
// props.put("mail.smtp.port", "465");
...
@@ -50,7 +52,8 @@ public class EmailSender {
...
@@ -50,7 +52,8 @@ public class EmailSender {
Session
session
=
Session
.
getInstance
(
props
,
Session
session
=
Session
.
getInstance
(
props
,
new
javax
.
mail
.
Authenticator
()
{
new
javax
.
mail
.
Authenticator
()
{
protected
PasswordAuthentication
getPasswordAuthentication
()
{
protected
PasswordAuthentication
getPasswordAuthentication
()
{
return
new
PasswordAuthentication
(
"cmeeting_assistant@cimc.com"
,
"scyou@xih45g6@xih4"
);
// return new PasswordAuthentication("cmeeting_assistant@cimc.com", "scyou@xih45g6@xih4");
return
new
PasswordAuthentication
(
SENDER
,
EMAIL_PWD
);
}
}
});
});
String
body
=
"您好:\n"
+
String
body
=
"您好:\n"
+
...
@@ -58,60 +61,60 @@ public class EmailSender {
...
@@ -58,60 +61,60 @@ public class EmailSender {
" 附件为您本次会议的会议纪要,烦请下载查看"
;
" 附件为您本次会议的会议纪要,烦请下载查看"
;
AtomicInteger
retryCount
=
new
AtomicInteger
(
0
);
AtomicInteger
retryCount
=
new
AtomicInteger
(
0
);
try
{
boolean
isSent
=
false
;
boolean
isSent
=
false
;
while
(
retryCount
.
intValue
()
<
MAX_RETRY
&&
!
isSent
){
while
(
retryCount
.
intValue
()
<
MAX_RETRY
&&
!
isSent
){
// 创建邮件消息
try
{
Message
message
=
new
MimeMessage
(
session
);
// 创建邮件消息
message
.
setFrom
(
new
InternetAddress
(
"cmeeting_assistant@cimc.com"
));
Message
message
=
new
MimeMessage
(
session
);
message
.
setRecipients
(
Message
.
RecipientType
.
TO
,
message
.
setFrom
(
new
InternetAddress
(
SENDER
));
InternetAddress
.
parse
(
toEmail
));
message
.
setRecipients
(
Message
.
RecipientType
.
TO
,
message
.
setSubject
(
subject
);
InternetAddress
.
parse
(
toEmail
));
message
.
setSubject
(
subject
);
// 创建消息体部分(正文)
MimeBodyPart
messageBodyPart
=
new
MimeBodyPart
();
// 创建消息体部分(正文)
messageBodyPart
.
setText
(
body
);
MimeBodyPart
messageBodyPart
=
new
MimeBodyPart
();
messageBodyPart
.
setText
(
body
);
// 创建多部分消息
Multipart
multipart
=
new
MimeMultipart
();
// 创建多部分消息
Multipart
multipart
=
new
MimeMultipart
();
// 添加文本部分
multipart
.
addBodyPart
(
messageBodyPart
);
// 添加文本部分
multipart
.
addBodyPart
(
messageBodyPart
);
// 添加附件部分
if
(
attachmentPath
!=
null
&&
!
attachmentPath
.
isEmpty
())
{
// 添加附件部分
MimeBodyPart
attachmentPart
=
new
MimeBodyPart
();
if
(
attachmentPath
!=
null
&&
!
attachmentPath
.
isEmpty
())
{
DataSource
source
=
new
FileDataSource
(
attachmentPath
);
MimeBodyPart
attachmentPart
=
new
MimeBodyPart
();
attachmentPart
.
setDataHandler
(
new
DataHandler
(
source
));
DataSource
source
=
new
FileDataSource
(
attachmentPath
);
attachmentPart
.
setFileName
(
new
File
(
attachmentPath
).
getName
());
attachmentPart
.
setDataHandler
(
new
DataHandler
(
source
));
multipart
.
addBodyPart
(
attachmentPart
);
attachmentPart
.
setFileName
(
new
File
(
attachmentPath
).
getName
());
}
multipart
.
addBodyPart
(
attachmentPart
);
}
// 设置完整消息内容
message
.
setContent
(
multipart
);
// 发送邮件
// 设置完整消息内容
Transport
.
send
(
message
);
message
.
setContent
(
multipart
);
log
.
error
(
"邮件已成功发送: recordFileId->{}"
,
recordFileId
);
isSent
=
true
;
// 发送邮件
}
Transport
.
send
(
message
);
}
catch
(
MessagingException
e
)
{
log
.
error
(
"邮件已成功发送: recordFileId->{}"
,
recordFileId
);
//todo 邮件失败记录
isSent
=
true
;
// 异常处理
}
catch
(
MessagingException
e
)
{
retryCount
.
getAndIncrement
();
//todo 邮件失败记录
if
(
retryCount
.
intValue
()
>
MAX_RETRY
)
{
// 异常处理
log
.
error
(
"邮件发送达到最大重试次数: recordFileId->{}"
,
recordFileId
);
retryCount
.
getAndIncrement
();
throw
new
RuntimeException
(
e
);
if
(
retryCount
.
intValue
()
>
MAX_RETRY
)
{
}
log
.
error
(
"邮件发送达到最大重试次数: recordFileId->{}"
,
recordFileId
);
// 指数退避
throw
new
RuntimeException
(
e
);
try
{
}
Thread
.
sleep
((
long
)
Math
.
pow
(
2
,
retryCount
.
intValue
())
*
1000
);
// 指数退避
}
catch
(
InterruptedException
ie
)
{
try
{
Thread
.
currentThread
().
interrupt
();
Thread
.
sleep
((
long
)
Math
.
pow
(
2
,
retryCount
.
intValue
())
*
1000
);
throw
new
RuntimeException
(
"邮件发送重试失败"
,
ie
);
}
catch
(
InterruptedException
ie
)
{
Thread
.
currentThread
().
interrupt
();
throw
new
RuntimeException
(
"邮件发送重试失败"
,
ie
);
}
return
false
;
}
}
}
return
false
;
}
return
true
;
return
true
;
}
}
}
}
\ No newline at end of file
src/main/java/com/cmeeting/job/CmeetingJob.java
浏览文件 @
b87c127c
...
@@ -90,18 +90,7 @@ public class CmeetingJob {
...
@@ -90,18 +90,7 @@ public class CmeetingJob {
logger
.
info
(
"结束时间: "
+
now
.
format
(
formatter
)
+
" | Unix 时间戳: "
+
nowTimestamp
);
logger
.
info
(
"结束时间: "
+
now
.
format
(
formatter
)
+
" | Unix 时间戳: "
+
nowTimestamp
);
logger
.
info
(
"----------------------------------"
);
logger
.
info
(
"----------------------------------"
);
// dojob(beforeDayTimestamp, nowTimestamp);
List
<
TencentMeetingVO
.
RecordFile
>
meetingFiles
=
tecentMeetingService
.
getMeetingFiles
();
AtomicInteger
currentPage
=
new
AtomicInteger
(
1
);
TencentMeetingVO
.
TencentMeetingRequest
request
=
TencentMeetingVO
.
TencentMeetingRequest
.
builder
()
.
page
(
1
)
.
pageSize
(
10
)
.
startTime
(
beforeDayTimestamp
)
.
endTime
(
nowTimestamp
)
.
operatorId
(
tencentAdminUserId
)
.
operatorIdType
(
1
)
.
build
();
List
<
TencentMeetingVO
.
RecordFile
>
meetingFiles
=
tecentMeetingService
.
getMeetingFiles
(
request
);
if
(
meetingFiles
==
null
||
meetingFiles
.
isEmpty
())
{
if
(
meetingFiles
==
null
||
meetingFiles
.
isEmpty
())
{
...
...
src/main/java/com/cmeeting/job/FileProcessTask.java
浏览文件 @
b87c127c
...
@@ -5,8 +5,18 @@ import cn.chatbot.openai.completion.chat.ChatMessage;
...
@@ -5,8 +5,18 @@ import cn.chatbot.openai.completion.chat.ChatMessage;
import
cn.chatbot.openai.completion.chat.ChatMessageRole
;
import
cn.chatbot.openai.completion.chat.ChatMessageRole
;
import
cn.chatbot.openai.completion.chat.Message
;
import
cn.chatbot.openai.completion.chat.Message
;
import
cn.chatbot.openai.service.LLMService
;
import
cn.chatbot.openai.service.LLMService
;
import
cn.hutool.core.date.DateUtil
;
import
cn.hutool.core.util.IdUtil
;
import
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
;
import
com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper
;
import
com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper
;
import
com.cmeeting.email.EmailSender
;
import
com.cmeeting.email.EmailSender
;
import
com.cmeeting.mapper.primary.MeetingInfoMapper
;
import
com.cmeeting.pojo.MeetingInfo
;
import
com.cmeeting.service.MeetingInfoService
;
import
com.cmeeting.util.MinioUtils
;
import
com.deepoove.poi.XWPFTemplate
;
import
com.deepoove.poi.XWPFTemplate
;
import
com.fasterxml.jackson.databind.JsonNode
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
com.fasterxml.jackson.dataformat.xml.XmlMapper
;
import
com.fasterxml.jackson.dataformat.xml.XmlMapper
;
import
com.tencentcloudapi.wemeet.Client
;
import
com.tencentcloudapi.wemeet.Client
;
...
@@ -27,6 +37,7 @@ import okhttp3.Response;
...
@@ -27,6 +37,7 @@ import okhttp3.Response;
import
org.apache.commons.lang3.StringUtils
;
import
org.apache.commons.lang3.StringUtils
;
import
org.apache.poi.xwpf.extractor.XWPFWordExtractor
;
import
org.apache.poi.xwpf.extractor.XWPFWordExtractor
;
import
org.apache.poi.xwpf.usermodel.XWPFDocument
;
import
org.apache.poi.xwpf.usermodel.XWPFDocument
;
import
org.springframework.stereotype.Service
;
import
java.io.*
;
import
java.io.*
;
import
java.math.BigInteger
;
import
java.math.BigInteger
;
...
@@ -46,6 +57,7 @@ import java.util.stream.Collectors;
...
@@ -46,6 +57,7 @@ import java.util.stream.Collectors;
@Data
@Data
@NoArgsConstructor
@NoArgsConstructor
@Slf4j
@Slf4j
@Service
public
class
FileProcessTask
{
public
class
FileProcessTask
{
private
String
recordFileId
;
private
String
recordFileId
;
private
String
meetingId
;
private
String
meetingId
;
...
@@ -62,136 +74,139 @@ public class FileProcessTask {
...
@@ -62,136 +74,139 @@ public class FileProcessTask {
private
String
tencentSecretKey
;
private
String
tencentSecretKey
;
private
String
tencentAdminUserId
;
private
String
tencentAdminUserId
;
private
MeetingInfoMapper
meetingInfoMapper
;
private
MinioUtils
minioUtils
;
private
EmailSender
emailSender
;
// 实际处理逻辑
// 实际处理逻辑
public
void
process
()
{
public
void
process
()
{
try
{
boolean
isSuccess
=
false
;
boolean
isSuccess
=
false
;
while
(
retryCount
<=
MAX_RETRY
&&
!
isSuccess
)
{
while
(
retryCount
<=
MAX_RETRY
&&
!
isSuccess
)
{
try
{
Client
client
=
new
Client
.
Builder
()
Client
client
=
new
Client
.
Builder
()
.
withAppId
(
tencentAppId
).
withSdkId
(
tencentSdkId
)
.
withAppId
(
tencentAppId
).
withSdkId
(
tencentSdkId
)
.
withSecret
(
tencentSecretId
,
tencentSecretKey
)
.
withSecret
(
tencentSecretId
,
tencentSecretKey
)
.
build
();
.
build
();
// 获取参会成员明细
MeetingsApi
.
ApiV1MeetingsMeetingIdParticipantsGetRequest
participantsRequest
=
new
MeetingsApi
.
ApiV1MeetingsMeetingIdParticipantsGetRequest
.
Builder
(
meetingId
).
subMeetingId
(
subMeetingId
).
operatorId
(
tencentAdminUserId
).
operatorIdType
(
"1"
).
build
();
AuthenticatorBuilder
<
JWTAuthenticator
>
participantsAuthenticatorBuilder
=
new
JWTAuthenticator
.
Builder
()
.
nonce
(
BigInteger
.
valueOf
(
Math
.
abs
((
new
SecureRandom
()).
nextInt
())))
.
timestamp
(
String
.
valueOf
(
System
.
currentTimeMillis
()
/
1000L
));
Map
<
String
,
Object
>
participantsMap
=
new
ConcurrentHashMap
<>();
//主持人角色,以下角色都可以表示主持人
//用户角色:
//0:普通成员角色
//1:创建者角色
//2:主持人
//3:创建者+主持人
//4:游客
//5:游客+主持人
//6:联席主持人
//7:创建者+联席主持人
List
<
Long
>
hostRoleList
=
Arrays
.
asList
(
2L
,
3L
,
5L
,
6L
,
7L
);
try
{
MeetingsApi
.
ApiV1MeetingsMeetingIdParticipantsGetResponse
participantsResponse
=
client
.
meetings
().
v1MeetingsMeetingIdParticipantsGet
(
participantsRequest
,
participantsAuthenticatorBuilder
);
V1MeetingsMeetingIdParticipantsGet200Response
data
=
participantsResponse
.
getData
();
String
scheduleStartTime
=
data
.
getScheduleStartTime
();
String
scheduleEndTime
=
data
.
getScheduleEndTime
();
ZoneId
zoneId
=
ZoneId
.
of
(
"Asia/Shanghai"
);
DateTimeFormatter
df
=
DateTimeFormatter
.
ofPattern
(
"yyyy-MM-dd"
);
String
zonedDateTimeStart
=
Instant
.
ofEpochSecond
(
Long
.
valueOf
(
scheduleStartTime
)).
atZone
(
zoneId
).
format
(
df
);
// String zonedDateTimeEnd = Instant.ofEpochSecond(Long.valueOf(scheduleEndTime)).atZone(zoneId).format(df);
participantsMap
.
put
(
"meeting_date"
,
zonedDateTimeStart
);
participantsMap
.
put
(
"meeting_location"
,
"线上腾讯会议"
);
List
<
V1MeetingsMeetingIdParticipantsGet200ResponseParticipantsInner
>
participants
=
data
.
getParticipants
();
participantsMap
.
put
(
"meeting_participants"
,
participants
.
stream
()
.
map
(
item
->
new
String
(
Base64
.
getDecoder
().
decode
(
item
.
getUserName
()))).
collect
(
Collectors
.
joining
(
"、"
)));
Optional
<
V1MeetingsMeetingIdParticipantsGet200ResponseParticipantsInner
>
host
=
participants
.
stream
().
filter
(
item
->
hostRoleList
.
contains
(
item
.
getUserRole
())).
findFirst
();
participantsMap
.
put
(
"meeting_host"
,
host
.
isPresent
()
?
new
String
(
Base64
.
getDecoder
().
decode
(
host
.
get
().
getUserName
()))
:
"未知主持人"
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
log
.
error
(
e
.
getMessage
());
throw
new
RuntimeException
(
e
);
}
//查询录制转写详情
RecordsApi
.
ApiV1AddressesRecordFileIdGetRequest
addressRequest
=
new
RecordsApi
.
ApiV1AddressesRecordFileIdGetRequest
.
Builder
(
recordFileId
)
.
operatorId
(
tencentAdminUserId
)
.
operatorIdType
(
"1"
)
.
build
();
RecordsApi
.
ApiV1AddressesRecordFileIdGetResponse
addressResponse
=
client
.
records
().
v1AddressesRecordFileIdGet
(
addressRequest
,
new
JWTAuthenticator
.
Builder
().
nonce
(
BigInteger
.
valueOf
(
Math
.
abs
((
new
SecureRandom
()).
nextInt
())))
.
timestamp
(
String
.
valueOf
(
System
.
currentTimeMillis
()
/
1000L
)));
// 处理响应
if
(
addressResponse
!=
null
&&
addressResponse
.
getData
()
!=
null
)
{
log
.
info
(
"Successfully got address for record file {}"
,
recordFileId
);
V1AddressesRecordFileIdGet200Response
addressData
=
addressResponse
.
getData
();
// 获取AI会议转录文件
List
<
V1AddressesRecordFileIdGet200ResponseAiMeetingTranscriptsInner
>
transcripts
=
addressData
.
getAiMeetingTranscripts
();
if
(
transcripts
!=
null
&&
!
transcripts
.
isEmpty
())
{
log
.
info
(
"Found {} AI meeting transcripts for record file {}"
,
transcripts
.
size
(),
recordFileId
);
// 处理每个转录文件
for
(
V1AddressesRecordFileIdGet200ResponseAiMeetingTranscriptsInner
transcript
:
transcripts
)
{
String
fileType
=
transcript
.
getFileType
();
String
downloadUrl
=
transcript
.
getDownloadAddress
();
if
(
"txt"
.
equalsIgnoreCase
(
fileType
))
{
// 获取参会成员明细
log
.
info
(
"AI Transcript - Type: {}, URL: {}"
,
fileType
,
downloadUrl
);
MeetingsApi
.
ApiV1MeetingsMeetingIdParticipantsGetRequest
participantsRequest
=
new
MeetingsApi
.
ApiV1MeetingsMeetingIdParticipantsGetRequest
.
Builder
(
meetingId
).
subMeetingId
(
subMeetingId
).
operatorId
(
tencentAdminUserId
).
operatorIdType
(
"1"
).
build
();
AuthenticatorBuilder
<
JWTAuthenticator
>
participantsAuthenticatorBuilder
=
new
JWTAuthenticator
.
Builder
()
.
nonce
(
BigInteger
.
valueOf
(
Math
.
abs
((
new
SecureRandom
()).
nextInt
())))
.
timestamp
(
String
.
valueOf
(
System
.
currentTimeMillis
()
/
1000L
));
Map
<
String
,
Object
>
participantsMap
=
new
ConcurrentHashMap
<>();
//主持人角色,以下角色都可以表示主持人
//用户角色:
//0:普通成员角色
//1:创建者角色
//2:主持人
//3:创建者+主持人
//4:游客
//5:游客+主持人
//6:联席主持人
//7:创建者+联席主持人
List
<
Long
>
hostRoleList
=
Arrays
.
asList
(
2L
,
3L
,
5L
,
6L
,
7L
);
try
{
MeetingsApi
.
ApiV1MeetingsMeetingIdParticipantsGetResponse
participantsResponse
=
client
.
meetings
().
v1MeetingsMeetingIdParticipantsGet
(
participantsRequest
,
participantsAuthenticatorBuilder
);
V1MeetingsMeetingIdParticipantsGet200Response
data
=
participantsResponse
.
getData
();
String
scheduleStartTime
=
data
.
getScheduleStartTime
();
String
scheduleEndTime
=
data
.
getScheduleEndTime
();
ZoneId
zoneId
=
ZoneId
.
of
(
"Asia/Shanghai"
);
DateTimeFormatter
df
=
DateTimeFormatter
.
ofPattern
(
"yyyy-MM-dd"
);
String
zonedDateTimeStart
=
Instant
.
ofEpochSecond
(
Long
.
valueOf
(
scheduleStartTime
)).
atZone
(
zoneId
).
format
(
df
);
// String zonedDateTimeEnd = Instant.ofEpochSecond(Long.valueOf(scheduleEndTime)).atZone(zoneId).format(df);
// 1. 下载文件
participantsMap
.
put
(
"meeting_date"
,
zonedDateTimeStart
);
byte
[]
fileData
=
downloadFile
(
downloadUrl
);
participantsMap
.
put
(
"meeting_location"
,
"线上腾讯会议"
);
List
<
V1MeetingsMeetingIdParticipantsGet200ResponseParticipantsInner
>
participants
=
data
.
getParticipants
();
participantsMap
.
put
(
"meeting_participants"
,
participants
.
stream
()
.
map
(
item
->
new
String
(
Base64
.
getDecoder
().
decode
(
item
.
getUserName
()))).
distinct
().
collect
(
Collectors
.
joining
(
"、"
)));
Optional
<
V1MeetingsMeetingIdParticipantsGet200ResponseParticipantsInner
>
host
=
participants
.
stream
().
filter
(
item
->
hostRoleList
.
contains
(
item
.
getUserRole
())).
findFirst
();
participantsMap
.
put
(
"meeting_host"
,
host
.
isPresent
()
?
new
String
(
Base64
.
getDecoder
().
decode
(
host
.
get
().
getUserName
()))
:
"未知主持人"
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
log
.
error
(
e
.
getMessage
());
throw
new
RuntimeException
(
e
);
}
// 2. 将二进制文件转换为文本
//查询录制转写详情
String
recordTextContent
=
new
String
(
fileData
);
RecordsApi
.
ApiV1AddressesRecordFileIdGetRequest
addressRequest
=
new
RecordsApi
.
ApiV1AddressesRecordFileIdGetRequest
.
Builder
(
recordFileId
)
.
operatorId
(
tencentAdminUserId
)
.
operatorIdType
(
"1"
)
.
build
();
RecordsApi
.
ApiV1AddressesRecordFileIdGetResponse
addressResponse
=
client
.
records
().
v1AddressesRecordFileIdGet
(
addressRequest
,
new
JWTAuthenticator
.
Builder
().
nonce
(
BigInteger
.
valueOf
(
Math
.
abs
((
new
SecureRandom
()).
nextInt
())))
.
timestamp
(
String
.
valueOf
(
System
.
currentTimeMillis
()
/
1000L
)));
// 处理响应
if
(
addressResponse
!=
null
&&
addressResponse
.
getData
()
!=
null
)
{
log
.
info
(
"Successfully got address for record file {}"
,
recordFileId
);
V1AddressesRecordFileIdGet200Response
addressData
=
addressResponse
.
getData
();
// 获取AI会议转录文件
List
<
V1AddressesRecordFileIdGet200ResponseAiMeetingTranscriptsInner
>
transcripts
=
addressData
.
getAiMeetingTranscripts
();
if
(
transcripts
!=
null
&&
!
transcripts
.
isEmpty
())
{
log
.
info
(
"Found {} AI meeting transcripts for record file {}"
,
transcripts
.
size
(),
recordFileId
);
// 处理每个转录文件
for
(
V1AddressesRecordFileIdGet200ResponseAiMeetingTranscriptsInner
transcript
:
transcripts
)
{
String
fileType
=
transcript
.
getFileType
();
String
downloadUrl
=
transcript
.
getDownloadAddress
();
if
(
"txt"
.
equalsIgnoreCase
(
fileType
))
{
log
.
info
(
"AI Transcript - Type: {}, URL: {}"
,
fileType
,
downloadUrl
);
// 1. 下载文件
byte
[]
fileData
=
downloadFile
(
downloadUrl
);
// 2. 将二进制文件转换为文本
String
recordTextContent
=
new
String
(
fileData
);
// String recordTextContent = new String(Files.readAllBytes(Paths.get("/20250321145249-天达物流AIGC维修助手需要沟通-转写原文版-1.txt")));
// String recordTextContent = new String(Files.readAllBytes(Paths.get("/20250321145249-天达物流AIGC维修助手需要沟通-转写原文版-1.txt")));
if
(
StringUtils
.
isEmpty
(
recordTextContent
.
replaceAll
(
"\\n"
,
""
).
trim
())){
if
(
StringUtils
.
isEmpty
(
recordTextContent
.
replaceAll
(
"\\n"
,
""
).
trim
())){
log
.
info
(
"获取的转录文本为空,跳过纪要生成,URL:{},fileRecordId:{}"
,
fileType
,
downloadUrl
,
recordFileId
);
log
.
info
(
"获取的转录文本为空,跳过纪要生成,URL:{},fileRecordId:{}"
,
fileType
,
downloadUrl
,
recordFileId
);
continue
;
continue
;
}
}
// 3. 处理文件 (调用Claude API等)
// 3. 处理文件 (调用Claude API等)
String
processedResult
=
processWithClaude
(
recordTextContent
);
String
processedResult
=
processWithClaude
(
recordTextContent
);
// 4. 保存结果
// 4. 保存结果
saveResult
(
savePath
,
processedResult
,
participantsMap
);
saveResult
(
savePath
,
processedResult
,
participantsMap
,
fileData
);
}
}
}
}
else
{
log
.
info
(
"No AI meeting transcripts found for record file {}"
,
recordFileId
);
}
}
}
else
{
}
else
{
log
.
warn
(
"Empty response for record file:
{}"
,
recordFileId
);
log
.
info
(
"No AI meeting transcripts found for record file
{}"
,
recordFileId
);
}
}
isSuccess
=
true
;
}
}
else
{
}
catch
(
Exception
e
)
{
log
.
warn
(
"Empty response for record file: {}"
,
recordFileId
);
// 异常处理
retryCount
++;
if
(
retryCount
>
MAX_RETRY
)
{
log
.
error
(
"达到最大重试次数: {}"
,
recordFileId
);
throw
new
RuntimeException
(
e
);
}
}
// 指数退避
isSuccess
=
true
;
try
{
}
catch
(
Exception
e
)
{
Thread
.
sleep
((
long
)
Math
.
pow
(
2
,
retryCount
)
*
1000
);
// 异常处理
}
catch
(
InterruptedException
ie
)
{
retryCount
++;
Thread
.
currentThread
().
interrupt
();
if
(
retryCount
>
MAX_RETRY
)
{
throw
new
RuntimeException
(
"重试失败"
,
ie
);
log
.
error
(
"达到最大重试次数: {}"
,
recordFileId
);
throw
new
RuntimeException
(
e
);
}
// 指数退避
try
{
Thread
.
sleep
((
long
)
Math
.
pow
(
2
,
retryCount
)
*
1000
);
}
catch
(
InterruptedException
ie
)
{
Thread
.
currentThread
().
interrupt
();
throw
new
RuntimeException
(
"重试失败"
,
ie
);
}
}
}
}
}
}
}
private
byte
[]
downloadFile
(
String
url
)
{
private
byte
[]
downloadFile
(
String
url
)
{
...
@@ -238,7 +253,7 @@ public class FileProcessTask {
...
@@ -238,7 +253,7 @@ public class FileProcessTask {
int
maxTokens
=
5000
;
int
maxTokens
=
5000
;
List
<
Message
>
messages
=
new
ArrayList
<>();
List
<
Message
>
messages
=
new
ArrayList
<>();
ChatMessage
chatMessage
=
new
ChatMessage
(
ChatMessageRole
.
USER
.
value
(),
"你是会议纪要助手,基于提供的会议记录,生成一份详细的会议纪要,并严格按照指定的XML格式输出。\\n\\n要求:\\n1. 会议名称:应简洁明了地反映会议主题,不超过30个字\\n2. 会议目的:需清晰阐述召开此次会议的原因和期望达成的目标,不超过50字\\n3. 会议要点:需全面概括会议内容,让读者理解会议讨论的核心问题,不要遗漏任何有价值的信息,每个要点需用序号标注并另起一行\\n4. 会议内容:需详细记录会议的背景信息、主要讨论内容、各参会人员的发言要点、达成的共识和决策等。内容应有逻辑性,分段清晰,重点突出,不可遗漏关键信息\\n5. 会议沟通内容:需按照一定的顺序组织内容,详细描述每个事项的内容,不要使用流水账形式,应包含具体的沟通过程、各方观点和达成的一致意见\\n6. 会后跟
进事项:详细描述会议结束之后,每个后续事项的责任人、事项内容、完成时间(若会议记录中没有提及,则填写待定)等信息,事项要具体到责任人\\n\\n注意事项:\\n1. 所有内容需基于原始会议记录,不要添加虚构信息\\n2. 会议纪要内容需详细充分,建议总字数不少于3000字,实际字数可根据原始会议记录的丰富程度进行适当调整\\n\\n输出格式必须严格按照以下XML结构,不允许有任何嵌套标签:\\n\\n<meeting_name>会议名称</meeting_name>\\n<meeting_purpose>会议目的</meeting_purpose>\\n<meeting_key_points>会议要点</meeting_key_points>\\n<meeting_content>会议内容</meeting_content>\\n<meeting_communication>会议沟通内容</meeting_communication>\\n<meeting_follow_up>\\n在此填写会议跟踪事项,格式为:\\n1. 内容:XXX;责任人:XXX;完成时间:XXXX-XX-XX\\n2. 内容:XXX;责任人:XXX;完成时间:XXXX-XX-XX\\n...\\n</meeting_follow_up>\\n\\n完成XML格式的会议纪要后,必须在XML之外单独添加猜您想问部分,生成3-4条与会议内容相关的推荐问题。\\n\\n会议记录如下:\\n
"
);
ChatMessage
chatMessage
=
new
ChatMessage
(
ChatMessageRole
.
USER
.
value
(),
"你是会议纪要助手,基于提供的会议记录,生成一份详细的会议纪要,并严格按照指定的XML格式输出。\\n\\n要求:\\n1. 会议名称:应简洁明了地反映会议主题,不超过30个字\\n2. 会议目的:需清晰阐述召开此次会议的原因和期望达成的目标,不超过50字\\n3. 会议要点:需全面概括会议内容,让读者理解会议讨论的核心问题,不要遗漏任何有价值的信息,每个要点需用序号标注并另起一行\\n4. 会议内容:需详细记录会议的背景信息、主要讨论内容、各参会人员的发言要点、达成的共识和决策等。内容应有逻辑性,分段清晰,重点突出,不可遗漏关键信息\\n5. 会议沟通内容:需按照一定的顺序组织内容,详细描述每个事项的内容,不要使用流水账形式,应包含具体的沟通过程、各方观点和达成的一致意见\\n6. 会后跟
踪事项:详细描述会议结束之后,每个后续事项的责任人、事项内容、完成时间(若会议记录中没有提及,则填写待定)等信息,事项要具体到责任人\\n\\n注意事项:\\n1. 所有内容需基于原始会议记录,不要添加虚构信息\\n2. 会议纪要内容需详细充分,建议总字数不少于3000字,实际字数可根据原始会议记录的丰富程度进行适当调整\\n\\n输出格式必须严格按照以下XML结构,不允许有任何嵌套标签:\\n\\n<meeting_name label=\\\"会议名称\\\">会议名称</meeting_name>\\n<meeting_purpose label=\\\"会议目的\\\">会议目的</meeting_purpose>\\n<meeting_key_points label=\\\"会议要点\\\">会议要点</meeting_key_points>\\n<meeting_content label=\\\"会议内容\\\">会议内容</meeting_content>\\n<meeting_communication label=\\\"会议沟通内容\\\">会议沟通内容</meeting_communication>\\n<meeting_follow_up label=\\\"会后跟踪事项\\\">\\n在此填写会后跟踪事项,格式为:\\n1. 内容:XXX;责任人:XXX;完成时间:XXXX-XX-XX\\n2. 内容:XXX;责任人:XXX;完成时间:XXXX-XX-XX\\n...\\n</meeting_follow_up>\\n\\n完成XML格式的会议纪要后,必须在XML之外单独添加猜您想问部分,生成3-4条与会议内容相关的推荐问题。\\n\\n会议记录如下:
"
);
messages
.
add
(
chatMessage
);
messages
.
add
(
chatMessage
);
chatMessage
=
new
ChatMessage
(
ChatMessageRole
.
ASSISTANT
.
value
(),
"好的请提供会议记录"
);
chatMessage
=
new
ChatMessage
(
ChatMessageRole
.
ASSISTANT
.
value
(),
"好的请提供会议记录"
);
messages
.
add
(
chatMessage
);
messages
.
add
(
chatMessage
);
...
@@ -251,36 +266,88 @@ public class FileProcessTask {
...
@@ -251,36 +266,88 @@ public class FileProcessTask {
return
ret
;
return
ret
;
}
}
private
void
saveResult
(
String
path
,
String
content
,
Map
<
String
,
Object
>
participantsMap
)
{
private
void
saveResult
(
String
path
,
String
content
,
Map
<
String
,
Object
>
participantsMap
,
byte
[]
recordData
)
{
String
nowTime
=
LocalDateTime
.
now
().
format
(
DateTimeFormatter
.
ofPattern
(
"yyyy-MM-dd-HHmmss"
));
String
nowTime
=
LocalDateTime
.
now
().
format
(
DateTimeFormatter
.
ofPattern
(
"yyyy-MM-dd-HHmmss"
));
String
targetPath
=
path
+
nowTime
+
".
md"
;
// 改为.md
扩展名;
String
targetPath
=
path
+
nowTime
+
".
json"
;
// 改为.json
扩展名;
String
targetFileName
;
String
targetFileName
;
String
meetingName
;
String
meetingName
;
// 保存处理结果
String
xml
=
extractXmlFromMarkdown
(
content
);
try
{
// 将字符串写入Markdown文件
Files
.
write
(
Paths
.
get
(
targetPath
),
content
.
getBytes
());
log
.
info
(
"Markdown文件已保存到: {}"
,
targetPath
);
// convert(targetPath,targetWordPath);
// 将xml格式的内容转换为特殊json
String
markdownContent
=
new
String
(
Files
.
readAllBytes
(
Paths
.
get
(
targetPath
)));
String
json
=
convertXmlToJSON
(
xml
);
Map
<
String
,
Object
>
dataModel
=
convertXmlToMap
(
markdownContent
);
String
recordContentPath
=
meetingId
+
"-recordContent-"
+
IdUtil
.
fastSimpleUUID
()
+
"txt"
;
minioUtils
.
upload
(
recordContentPath
,
recordData
);
String
recordXmlPath
=
meetingId
+
"-recordXmlPath-"
+
IdUtil
.
fastSimpleUUID
()
+
"xml"
;
try
{
//写入json文件,这里的json文件用于用户可编辑
Files
.
write
(
Paths
.
get
(
targetPath
),
json
.
getBytes
());
log
.
info
(
"json文件已保存到: {}"
,
targetPath
);
//将xml格式的内容转换为map,用于填充模板
Map
<
String
,
Object
>
dataModel
=
convertXmlToMap
(
xml
);
dataModel
.
putAll
(
participantsMap
);
dataModel
.
putAll
(
participantsMap
);
XWPFTemplate
template
=
XWPFTemplate
.
compile
(
"/data_net_template.docx"
).
render
(
dataModel
);
XWPFTemplate
template
=
XWPFTemplate
.
compile
(
"/data_net_template.docx"
).
render
(
dataModel
);
meetingName
=
dataModel
.
get
(
"meeting_name"
)
!=
null
?
String
.
valueOf
(
dataModel
.
get
(
"meeting_name"
))
:
"腾讯会议纪要"
;
meetingName
=
dataModel
.
get
(
"meeting_name"
)
!=
null
?
String
.
valueOf
(
dataModel
.
get
(
"meeting_name"
))
:
"腾讯会议纪要"
;
targetFileName
=
meetingName
+
"_"
+
nowTime
;
targetFileName
=
meetingName
+
"_"
+
nowTime
;
template
.
writeAndClose
(
new
FileOutputStream
(
path
+
targetFileName
+
".docx"
));
template
.
writeAndClose
(
new
FileOutputStream
(
path
+
targetFileName
+
".docx"
));
byte
[]
recordXmlData
=
Files
.
readAllBytes
(
Paths
.
get
(
path
+
targetFileName
+
".docx"
));
minioUtils
.
upload
(
recordXmlPath
,
recordXmlData
);
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
log
.
error
(
"填充会议纪要失败: {}"
,
e
.
getMessage
(),
e
);
log
.
error
(
"填充会议纪要失败: {}"
,
e
.
getMessage
(),
e
);
throw
new
RuntimeException
(
"填充会议纪要失败"
);
throw
new
RuntimeException
(
"填充会议纪要失败"
);
}
}
MeetingInfo
meetingInfo
=
meetingInfoMapper
.
selectOne
(
new
LambdaQueryWrapper
<
MeetingInfo
>().
eq
(
MeetingInfo:
:
getMeetingId
,
meetingId
));
//邮件推送
Boolean
isPushed
;
EmailSender
emailSender
=
new
EmailSender
();
try
{
emailSender
.
sendEmailWithAttachment
(
"duanxincheng@chatbot.cn"
,
meetingName
,
path
+
targetFileName
+
".docx"
,
recordFileId
);
//邮件推送
emailSender
.
sendEmailWithAttachment
(
"duanxincheng@chatbot.cn"
,
meetingName
,
path
+
targetFileName
+
".docx"
,
recordFileId
);
// emailSender.sendEmailWithAttachment("xuwentao@chatbot.cn",meetingName,path + targetFileName + ".docx",recordFileId);
// emailSender.sendEmailWithAttachment("xuwentao@chatbot.cn",meetingName,path + targetFileName + ".docx",recordFileId);
// emailSender.sendEmailWithAttachment("jiaqi.cai@cimc.com",meetingName,path + targetFileName + ".docx",recordFileId);
// emailSender.sendEmailWithAttachment("jiaqi.cai@cimc.com",meetingName,path + targetFileName + ".docx",recordFileId);
isPushed
=
Boolean
.
TRUE
;
}
catch
(
Exception
e
)
{
isPushed
=
Boolean
.
FALSE
;
e
.
printStackTrace
();
log
.
error
(
e
.
getMessage
());
}
meetingInfoMapper
.
update
(
meetingInfo
,
new
LambdaUpdateWrapper
<
MeetingInfo
>()
.
eq
(
MeetingInfo:
:
getMeetingId
,
meetingId
)
.
set
(
MeetingInfo:
:
getRecordContent
,
recordContentPath
)
.
set
(
MeetingInfo:
:
getRecordXml
,
recordXmlPath
)
.
set
(
MeetingInfo:
:
getIsGenerated
,
Boolean
.
TRUE
)
.
set
(
MeetingInfo:
:
getIsPushed
,
isPushed
)
);
}
private
String
convertXmlToJSON
(
String
xml
)
{
String
json
;
try
{
XmlMapper
xmlMapper
=
new
XmlMapper
();
JsonNode
rootNode
=
xmlMapper
.
readTree
(
xml
.
getBytes
());
// 正确获取节点和属性的方式
List
<
Map
>
list
=
new
ArrayList
<>();
Iterator
<
String
>
iterator
=
rootNode
.
fieldNames
();
while
(
iterator
.
hasNext
()){
String
tagName
=
iterator
.
next
();
JsonNode
subNode
=
rootNode
.
path
(
tagName
);
String
displayName
=
subNode
.
path
(
"label"
).
asText
();
String
content
=
subNode
.
path
(
""
).
asText
();
list
.
add
(
new
HashMap
(){{
put
(
"key"
,
tagName
+
"/"
+
displayName
);
put
(
"value"
,
content
);
}});
}
// 构建JSON对象
ObjectMapper
jsonMapper
=
new
ObjectMapper
();
json
=
jsonMapper
.
writeValueAsString
(
list
);
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
());
throw
new
RuntimeException
(
e
.
getMessage
());
}
return
json
;
}
}
public
static
String
call_llm
(
String
apiAddr
,
String
model
,
String
token
,
List
<
Message
>
messages
,
int
maxTokens
)
{
public
static
String
call_llm
(
String
apiAddr
,
String
model
,
String
token
,
List
<
Message
>
messages
,
int
maxTokens
)
{
...
@@ -312,17 +379,23 @@ public class FileProcessTask {
...
@@ -312,17 +379,23 @@ public class FileProcessTask {
service
.
shutdownExecutor
();
service
.
shutdownExecutor
();
return
stringBuilder
.
toString
();
return
stringBuilder
.
toString
();
}
}
public
static
Map
<
String
,
Object
>
convertXmlToMap
(
String
markdownContent
)
throws
Exception
{
public
static
Map
<
String
,
Object
>
convertXmlToMap
(
String
xml
)
throws
Exception
{
String
xmlContent
=
extractXmlFromMarkdown
(
markdownContent
);
XmlMapper
xmlMapper
=
new
XmlMapper
();
XmlMapper
xmlMapper
=
new
XmlMapper
();
ObjectMapper
objectMapper
=
new
ObjectMapper
();
ObjectMapper
objectMapper
=
new
ObjectMapper
();
// 先将 XML 读取为 Map
// 先将 XML 读取为 Map
Map
<?,
?>
xmlMap
=
xmlMapper
.
readValue
(
xml
Content
,
Map
.
class
);
Map
<?,
?>
xmlMap
=
xmlMapper
.
readValue
(
xml
,
Map
.
class
);
// 转换为更标准的 Map<String, Object>
// 转换为更标准的 Map<String, Object>
return
objectMapper
.
convertValue
(
xmlMap
,
Map
.
class
);
Map
<
String
,
Object
>
map
=
objectMapper
.
convertValue
(
xmlMap
,
Map
.
class
);
//特殊处理map格式
for
(
Map
.
Entry
<
String
,
Object
>
entry
:
map
.
entrySet
())
{
Map
<
String
,
Object
>
value
=
(
Map
<
String
,
Object
>)
entry
.
getValue
();
Object
realValue
=
value
.
get
(
""
);
entry
.
setValue
(
realValue
);
}
return
map
;
}
}
/**
/**
...
@@ -348,7 +421,8 @@ public class FileProcessTask {
...
@@ -348,7 +421,8 @@ public class FileProcessTask {
public
FileProcessTask
(
String
recordFileId
,
String
meetingId
,
String
subMeetingId
,
String
savePath
,
Map
<
String
,
Object
>
metadata
,
String
tencentAppId
,
public
FileProcessTask
(
String
recordFileId
,
String
meetingId
,
String
subMeetingId
,
String
savePath
,
Map
<
String
,
Object
>
metadata
,
String
tencentAppId
,
String
tencentSdkId
,
String
tencentSecretId
,
String
tencentSecretKey
,
String
tencentAdminUserId
)
{
String
tencentSdkId
,
String
tencentSecretId
,
String
tencentSecretKey
,
String
tencentAdminUserId
,
MeetingInfoMapper
meetingInfoMapper
,
MinioUtils
minioUtils
,
EmailSender
emailSender
)
{
this
.
recordFileId
=
recordFileId
;
this
.
recordFileId
=
recordFileId
;
this
.
savePath
=
savePath
;
this
.
savePath
=
savePath
;
this
.
metadata
=
metadata
;
this
.
metadata
=
metadata
;
...
@@ -359,5 +433,8 @@ public class FileProcessTask {
...
@@ -359,5 +433,8 @@ public class FileProcessTask {
this
.
tencentAdminUserId
=
tencentAdminUserId
;
this
.
tencentAdminUserId
=
tencentAdminUserId
;
this
.
meetingId
=
meetingId
;
this
.
meetingId
=
meetingId
;
this
.
subMeetingId
=
subMeetingId
;
this
.
subMeetingId
=
subMeetingId
;
this
.
meetingInfoMapper
=
meetingInfoMapper
;
this
.
minioUtils
=
minioUtils
;
this
.
emailSender
=
emailSender
;
}
}
}
}
\ No newline at end of file
src/main/java/com/cmeeting/mapper/primary/MeetingInfoMapper.java
0 → 100644
浏览文件 @
b87c127c
package
com
.
cmeeting
.
mapper
.
primary
;
import
com.baomidou.mybatisplus.core.mapper.BaseMapper
;
import
com.cmeeting.pojo.MeetingInfo
;
import
org.apache.ibatis.annotations.Mapper
;
import
org.apache.ibatis.annotations.Param
;
import
org.springframework.stereotype.Repository
;
import
java.util.List
;
@Mapper
public
interface
MeetingInfoMapper
extends
BaseMapper
<
MeetingInfo
>
{
void
batchInsert
(
@Param
(
"meetingSaveList"
)
List
<
MeetingInfo
>
meetingSaveList
);
List
<
String
>
getAllMeetingIds
();
}
\ No newline at end of file
src/main/java/com/cmeeting/pojo/MeetingInfo.java
浏览文件 @
b87c127c
package
com
.
cmeeting
.
pojo
;
package
com
.
cmeeting
.
pojo
;
import
java.util.Objects
;
import
com.baomidou.mybatisplus.annotation.IdType
;
import
com.baomidou.mybatisplus.annotation.TableId
;
import
com.baomidou.mybatisplus.annotation.TableName
;
import
lombok.*
;
import
lombok.experimental.Accessors
;
import
java.io.Serializable
;
import
java.time.LocalDateTime
;
/**
/**
* 会议信息实体类
* 会议信息实体类
*/
*/
public
class
MeetingInfo
{
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@EqualsAndHashCode
(
callSuper
=
false
)
@Accessors
(
chain
=
true
)
@TableName
(
"cmt_meeting_info"
)
public
class
MeetingInfo
implements
Serializable
{
/**
* 主键id
*/
@TableId
(
type
=
IdType
.
AUTO
)
private
Integer
id
;
/**
/**
* 会议主题
* 会议主题
*/
*/
...
@@ -15,6 +34,11 @@ public class MeetingInfo {
...
@@ -15,6 +34,11 @@ public class MeetingInfo {
* 会议ID(字符串类型)
* 会议ID(字符串类型)
*/
*/
private
String
meetingId
;
private
String
meetingId
;
/**
* 子会议ID
*/
private
String
subMeetingId
;
/**
/**
* 会议号码
* 会议号码
...
@@ -22,153 +46,49 @@ public class MeetingInfo {
...
@@ -22,153 +46,49 @@ public class MeetingInfo {
private
String
meetingCode
;
private
String
meetingCode
;
/**
/**
*
用户ID
*
主持人
*/
*/
private
String
user
Id
;
private
String
host
Id
;
/**
/**
*
用户昵称
*
参会人员名单
*/
*/
private
String
nickName
;
private
String
participantUserIds
;
/**
/**
* 会议开始时间(时间戳)
* 会议开始时间(时间戳)
*/
*/
private
Lo
ng
startTime
;
private
Lo
calDateTime
startTime
;
/**
/**
* 会议结束时间(时间戳)
* 会议结束时间(时间戳)
*/
*/
private
Lo
ng
endTime
;
private
Lo
calDateTime
endTime
;
/**
/**
*
参会人数
*
是否生成会议纪要完成
*/
*/
private
Integer
participantsNum
;
private
Boolean
isGenerated
;
/**
/**
*
会议总时长(秒)
*
推送邮件许可 为false不推送
*/
*/
private
Integer
meetingDuration
;
private
Boolean
emailPushAccess
;
/**
/**
*
用户参会时长(秒)
*
是否推送邮件完成
*/
*/
private
Integer
userMeetingDuration
;
private
Boolean
isPushed
;
/**
// 构造方法
* 同步时间
public
MeetingInfo
()
{
*/
}
private
LocalDateTime
syncTime
;
// Getter 和 Setter 方法
public
String
getSubject
()
{
return
subject
;
}
public
void
setSubject
(
String
subject
)
{
this
.
subject
=
subject
;
}
public
String
getMeetingId
()
{
return
meetingId
;
}
public
void
setMeetingId
(
String
meetingId
)
{
this
.
meetingId
=
meetingId
;
}
public
String
getMeetingCode
()
{
return
meetingCode
;
}
public
void
setMeetingCode
(
String
meetingCode
)
{
this
.
meetingCode
=
meetingCode
;
}
public
String
getUserId
()
{
return
userId
;
}
public
void
setUserId
(
String
userId
)
{
this
.
userId
=
userId
;
}
public
String
getNickName
()
{
return
nickName
;
}
public
void
setNickName
(
String
nickName
)
{
this
.
nickName
=
nickName
;
}
public
Long
getStartTime
()
{
return
startTime
;
}
public
void
setStartTime
(
Long
startTime
)
{
this
.
startTime
=
startTime
;
}
public
Long
getEndTime
()
{
return
endTime
;
}
public
void
setEndTime
(
Long
endTime
)
{
this
.
endTime
=
endTime
;
}
public
Integer
getParticipantsNum
()
{
return
participantsNum
;
}
public
void
setParticipantsNum
(
Integer
participantsNum
)
{
this
.
participantsNum
=
participantsNum
;
}
public
Integer
getMeetingDuration
()
{
return
meetingDuration
;
}
public
void
setMeetingDuration
(
Integer
meetingDuration
)
{
this
.
meetingDuration
=
meetingDuration
;
}
public
Integer
getUserMeetingDuration
()
{
return
userMeetingDuration
;
}
public
void
setUserMeetingDuration
(
Integer
userMeetingDuration
)
{
this
.
userMeetingDuration
=
userMeetingDuration
;
}
// toString 方法
@Override
public
String
toString
()
{
return
"MeetingInfo{"
+
"subject='"
+
subject
+
'\''
+
", meetingId='"
+
meetingId
+
'\''
+
", meetingCode='"
+
meetingCode
+
'\''
+
", userId='"
+
userId
+
'\''
+
", nickName='"
+
nickName
+
'\''
+
", startTime="
+
startTime
+
", endTime="
+
endTime
+
", participantsNum="
+
participantsNum
+
", meetingDuration="
+
meetingDuration
+
", userMeetingDuration="
+
userMeetingDuration
+
'}'
;
}
// equals 和 hashCode 方法
/**
@Override
* 转录文本
public
boolean
equals
(
Object
o
)
{
*/
if
(
this
==
o
)
return
true
;
private
String
recordContent
;
if
(
o
==
null
||
getClass
()
!=
o
.
getClass
())
return
false
;
MeetingInfo
that
=
(
MeetingInfo
)
o
;
return
Objects
.
equals
(
meetingId
,
that
.
meetingId
);
}
@Override
/**
public
int
hashCode
()
{
* 纪要xml
return
Objects
.
hash
(
meetingId
);
*/
}
private
String
recordXml
;
}
}
\ No newline at end of file
src/main/java/com/cmeeting/service/FileProcessProducer.java
浏览文件 @
b87c127c
package
com
.
cmeeting
.
service
;
package
com
.
cmeeting
.
service
;
import
com.cmeeting.email.EmailSender
;
import
com.cmeeting.job.FileProcessTask
;
import
com.cmeeting.job.FileProcessTask
;
import
com.cmeeting.mapper.primary.MeetingInfoMapper
;
import
com.cmeeting.util.MinioUtils
;
import
com.cmeeting.vo.TencentMeetingVO
;
import
com.cmeeting.vo.TencentMeetingVO
;
import
lombok.extern.slf4j.Slf4j
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
...
@@ -8,6 +11,7 @@ import org.springframework.beans.factory.annotation.Value;
...
@@ -8,6 +11,7 @@ import org.springframework.beans.factory.annotation.Value;
import
org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
;
import
org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
;
import
org.springframework.stereotype.Service
;
import
org.springframework.stereotype.Service
;
import
javax.annotation.Resource
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.List
;
...
@@ -33,6 +37,12 @@ public class FileProcessProducer {
...
@@ -33,6 +37,12 @@ public class FileProcessProducer {
private
String
tencentSecretKey
;
private
String
tencentSecretKey
;
@Value
(
value
=
"${tencent.admin.userId}"
)
@Value
(
value
=
"${tencent.admin.userId}"
)
private
String
tencentAdminUserId
;
private
String
tencentAdminUserId
;
@Resource
private
MeetingInfoMapper
meetingInfoMapper
;
@Resource
private
MinioUtils
minioUtils
;
@Resource
private
EmailSender
emailSender
;
// 批量提交任务
// 批量提交任务
public
void
submitBatchTasks
(
List
<
TencentMeetingVO
.
RecordFile
>
recordFiles
,
String
baseSavePath
)
{
public
void
submitBatchTasks
(
List
<
TencentMeetingVO
.
RecordFile
>
recordFiles
,
String
baseSavePath
)
{
...
@@ -50,7 +60,10 @@ public class FileProcessProducer {
...
@@ -50,7 +60,10 @@ public class FileProcessProducer {
tencentSdkId
,
tencentSdkId
,
tencentSecretId
,
tencentSecretId
,
tencentSecretKey
,
tencentSecretKey
,
tencentAdminUserId
tencentAdminUserId
,
meetingInfoMapper
,
minioUtils
,
emailSender
);
);
// 提交任务到线程池
// 提交任务到线程池
...
...
src/main/java/com/cmeeting/service/MeetingInfoService.java
0 → 100644
浏览文件 @
b87c127c
package
com
.
cmeeting
.
service
;
import
com.baomidou.mybatisplus.extension.service.IService
;
import
com.cmeeting.pojo.MeetingInfo
;
public
interface
MeetingInfoService
extends
IService
<
MeetingInfo
>
{
}
src/main/java/com/cmeeting/service/TecentMeetingService.java
浏览文件 @
b87c127c
...
@@ -11,6 +11,6 @@ public interface TecentMeetingService extends IService<TencentMeetingUser> {
...
@@ -11,6 +11,6 @@ public interface TecentMeetingService extends IService<TencentMeetingUser> {
void
doUsers
();
void
doUsers
();
List
<
TencentMeetingVO
.
RecordFile
>
getMeetingFiles
(
TencentMeetingVO
.
TencentMeetingRequest
requestVO
);
List
<
TencentMeetingVO
.
RecordFile
>
getMeetingFiles
();
}
}
src/main/java/com/cmeeting/service/impl/MeetingInfoServiceImpl.java
0 → 100644
浏览文件 @
b87c127c
package
com
.
cmeeting
.
service
.
impl
;
import
com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
;
import
com.cmeeting.mapper.primary.MeetingInfoMapper
;
import
com.cmeeting.pojo.MeetingInfo
;
import
com.cmeeting.service.MeetingInfoService
;
import
org.springframework.stereotype.Service
;
@Service
public
class
MeetingInfoServiceImpl
extends
ServiceImpl
<
MeetingInfoMapper
,
MeetingInfo
>
implements
MeetingInfoService
{
}
src/main/java/com/cmeeting/service/impl/TecentMeetingServiceImpl.java
浏览文件 @
b87c127c
package
com
.
cmeeting
.
service
.
impl
;
package
com
.
cmeeting
.
service
.
impl
;
import
cn.hutool.core.util.IdUtil
;
import
com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
;
import
com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
;
import
com.cmeeting.mapper.primary.MeetingInfoMapper
;
import
com.cmeeting.mapper.primary.TecentMeetingMapper
;
import
com.cmeeting.mapper.primary.TecentMeetingMapper
;
import
com.cmeeting.pojo.MeetingInfo
;
import
com.cmeeting.pojo.TencentMeetingUser
;
import
com.cmeeting.pojo.TencentMeetingUser
;
import
com.cmeeting.service.TecentMeetingService
;
import
com.cmeeting.service.TecentMeetingService
;
import
com.cmeeting.vo.TencentMeetingVO
;
import
com.cmeeting.vo.TencentMeetingVO
;
...
@@ -11,6 +14,7 @@ import com.tencentcloudapi.wemeet.core.authenticator.JWTAuthenticator;
...
@@ -11,6 +14,7 @@ import com.tencentcloudapi.wemeet.core.authenticator.JWTAuthenticator;
import
com.tencentcloudapi.wemeet.core.exception.ClientException
;
import
com.tencentcloudapi.wemeet.core.exception.ClientException
;
import
com.tencentcloudapi.wemeet.core.exception.ServiceException
;
import
com.tencentcloudapi.wemeet.core.exception.ServiceException
;
import
com.tencentcloudapi.wemeet.service.meetings.api.MeetingsApi
;
import
com.tencentcloudapi.wemeet.service.meetings.api.MeetingsApi
;
import
com.tencentcloudapi.wemeet.service.meetings.model.V1MeetingsGet200ResponseMeetingInfoListInnerCurrentCoHostsInner
;
import
com.tencentcloudapi.wemeet.service.meetings.model.V1MeetingsMeetingIdGet200Response
;
import
com.tencentcloudapi.wemeet.service.meetings.model.V1MeetingsMeetingIdGet200Response
;
import
com.tencentcloudapi.wemeet.service.meetings.model.V1MeetingsMeetingIdGet200ResponseMeetingInfoListInner
;
import
com.tencentcloudapi.wemeet.service.meetings.model.V1MeetingsMeetingIdGet200ResponseMeetingInfoListInner
;
import
com.tencentcloudapi.wemeet.service.records.api.RecordsApi
;
import
com.tencentcloudapi.wemeet.service.records.api.RecordsApi
;
...
@@ -35,6 +39,7 @@ import java.nio.charset.StandardCharsets;
...
@@ -35,6 +39,7 @@ import java.nio.charset.StandardCharsets;
import
java.security.InvalidKeyException
;
import
java.security.InvalidKeyException
;
import
java.security.NoSuchAlgorithmException
;
import
java.security.NoSuchAlgorithmException
;
import
java.security.SecureRandom
;
import
java.security.SecureRandom
;
import
java.time.Instant
;
import
java.time.LocalDateTime
;
import
java.time.LocalDateTime
;
import
java.time.ZoneId
;
import
java.time.ZoneId
;
import
java.time.ZonedDateTime
;
import
java.time.ZonedDateTime
;
...
@@ -42,6 +47,7 @@ import java.util.ArrayList;
...
@@ -42,6 +47,7 @@ import java.util.ArrayList;
import
java.util.Base64
;
import
java.util.Base64
;
import
java.util.List
;
import
java.util.List
;
import
java.util.concurrent.atomic.AtomicInteger
;
import
java.util.concurrent.atomic.AtomicInteger
;
import
java.util.stream.Collectors
;
import
static
com
.
cmeeting
.
WeComAndTencentMeeting
.
fetchUsersInBatches
;
import
static
com
.
cmeeting
.
WeComAndTencentMeeting
.
fetchUsersInBatches
;
import
static
com
.
cmeeting
.
WeComAndTencentMeeting
.
markDuplicateNamesTecent
;
import
static
com
.
cmeeting
.
WeComAndTencentMeeting
.
markDuplicateNamesTecent
;
...
@@ -51,6 +57,8 @@ import static com.cmeeting.WeComAndTencentMeeting.markDuplicateNamesTecent;
...
@@ -51,6 +57,8 @@ import static com.cmeeting.WeComAndTencentMeeting.markDuplicateNamesTecent;
public
class
TecentMeetingServiceImpl
extends
ServiceImpl
<
TecentMeetingMapper
,
TencentMeetingUser
>
implements
TecentMeetingService
{
public
class
TecentMeetingServiceImpl
extends
ServiceImpl
<
TecentMeetingMapper
,
TencentMeetingUser
>
implements
TecentMeetingService
{
@Resource
@Resource
private
TecentMeetingMapper
tecentMeetingMapper
;
private
TecentMeetingMapper
tecentMeetingMapper
;
@Resource
private
MeetingInfoMapper
meetingInfoMapper
;
private
static
final
String
HMAC_ALGORITHM
=
"HmacSHA256"
;
private
static
final
String
HMAC_ALGORITHM
=
"HmacSHA256"
;
private
static
final
char
[]
HEX_CHAR
=
{
'0'
,
'1'
,
'2'
,
'3'
,
'4'
,
'5'
,
'6'
,
'7'
,
'8'
,
'9'
,
'a'
,
'b'
,
'c'
,
'd'
,
'e'
,
'f'
};
private
static
final
char
[]
HEX_CHAR
=
{
'0'
,
'1'
,
'2'
,
'3'
,
'4'
,
'5'
,
'6'
,
'7'
,
'8'
,
'9'
,
'a'
,
'b'
,
'c'
,
'd'
,
'e'
,
'f'
};
...
@@ -93,98 +101,114 @@ public class TecentMeetingServiceImpl extends ServiceImpl<TecentMeetingMapper,Te
...
@@ -93,98 +101,114 @@ public class TecentMeetingServiceImpl extends ServiceImpl<TecentMeetingMapper,Te
}
}
@Override
@Override
public
List
<
TencentMeetingVO
.
RecordFile
>
getMeetingFiles
(
TencentMeetingVO
.
TencentMeetingRequest
requestVO
)
{
public
List
<
TencentMeetingVO
.
RecordFile
>
getMeetingFiles
()
{
StringBuffer
url
=
new
StringBuffer
();
url
.
append
(
"https://api.meeting.qq.com/v1/corp/records?page_size="
+
requestVO
.
getPageSize
()+
"&page="
+
requestVO
.
getPage
()
+
"&operator_id="
+
requestVO
.
getOperatorId
()+
"&operator_id_type=1&query_record_type=0"
);
// 1.构造 client 客户端(jwt 鉴权需要配置 appId sdkId secretID 和 secretKey)
Client
client
=
new
Client
.
Builder
()
Client
client
=
new
Client
.
Builder
()
.
withAppId
(
tencentAppId
).
withSdkId
(
tencentSdkId
)
.
withAppId
(
tencentAppId
).
withSdkId
(
tencentSdkId
)
.
withSecret
(
tencentSecretId
,
tencentSecretKey
)
.
withSecret
(
tencentSecretId
,
tencentSecretKey
)
.
build
();
.
build
();
// 2.构造 JWT 鉴权器
AuthenticatorBuilder
<
JWTAuthenticator
>
authenticatorBuilder
=
new
JWTAuthenticator
.
Builder
()
.
nonce
(
BigInteger
.
valueOf
(
Math
.
abs
((
new
SecureRandom
()).
nextInt
())))
.
timestamp
(
String
.
valueOf
(
System
.
currentTimeMillis
()
/
1000L
));
List
<
TencentMeetingVO
.
RecordFile
>
recordFileUrlList
=
new
ArrayList
<>();
List
<
TencentMeetingVO
.
RecordFile
>
recordFileUrlList
=
new
ArrayList
<>();
// 3.查询近两天的会议录制列表
List
<
MeetingInfo
>
meetingSaveList
=
new
ArrayList
<>();
// 查询近两天的会议录制列表
try
{
try
{
ZonedDateTime
now
=
ZonedDateTime
.
now
();
ZonedDateTime
now
=
ZonedDateTime
.
now
();
String
startTime
=
String
.
valueOf
(
now
.
minusDays
(
2
).
toEpochSecond
());
String
endTime
=
String
.
valueOf
(
now
.
toEpochSecond
());
AtomicInteger
currentPage
=
new
AtomicInteger
(
1
);
AtomicInteger
currentPage
=
new
AtomicInteger
(
1
);
RecordsApi
.
ApiV1RecordsGetRequest
request
=
Long
totalPage
=
1L
;
new
RecordsApi
.
ApiV1RecordsGetRequest
.
Builder
()
.
operatorId
(
tencentAdminUserId
)
.
operatorIdType
(
"1"
)
.
startTime
(
String
.
valueOf
(
now
.
minusDays
(
2
).
toEpochSecond
()))
.
endTime
(
String
.
valueOf
(
now
.
toEpochSecond
()))
.
pageSize
(
"20"
)
.
page
(
String
.
valueOf
(
currentPage
.
getAndIncrement
()))
.
mediaSetType
(
"0"
)
.
queryRecordType
(
"0"
)
.
build
();
RecordsApi
.
ApiV1RecordsGetResponse
response
=
client
.
records
().
v1RecordsGet
(
request
,
authenticatorBuilder
);
V1RecordsGet200Response
data
=
response
.
getData
();
if
(
data
!=
null
&&
data
.
getRecordMeetings
()
!=
null
&&
!
data
.
getRecordMeetings
().
isEmpty
())
{
List
<
V1RecordsGet200ResponseRecordMeetingsInner
>
meetings
=
data
.
getRecordMeetings
();
//录制状态:
//目前已存储的会议id
//1:录制中
List
<
String
>
meetingIds
=
meetingInfoMapper
.
getAllMeetingIds
();
//2:转码中
while
(
currentPage
.
intValue
()
<=
totalPage
.
intValue
()){
//3:转码完成
RecordsApi
.
ApiV1RecordsGetRequest
request
=
if
(
meetings
.
stream
().
allMatch
(
item
->
item
.
getState
()
!=
3
)){
new
RecordsApi
.
ApiV1RecordsGetRequest
.
Builder
()
return
null
;
.
operatorId
(
tencentAdminUserId
)
}
.
operatorIdType
(
"1"
)
for
(
V1RecordsGet200ResponseRecordMeetingsInner
meeting
:
meetings
)
{
.
startTime
(
startTime
)
if
(
meeting
.
getState
()
!=
3
)
continue
;
.
endTime
(
endTime
)
.
pageSize
(
"20"
)
.
page
(
String
.
valueOf
(
currentPage
.
getAndIncrement
()))
.
mediaSetType
(
"0"
)
.
queryRecordType
(
"0"
)
.
build
();
RecordsApi
.
ApiV1RecordsGetResponse
response
=
client
.
records
().
v1RecordsGet
(
request
,
new
JWTAuthenticator
.
Builder
()
.
nonce
(
BigInteger
.
valueOf
(
Math
.
abs
((
new
SecureRandom
()).
nextInt
())))
.
timestamp
(
String
.
valueOf
(
System
.
currentTimeMillis
()
/
1000L
)));
V1RecordsGet200Response
data
=
response
.
getData
();
//设置总页数
totalPage
=
data
.
getTotalPage
();
if
(
data
!=
null
&&
data
.
getRecordMeetings
()
!=
null
&&
!
data
.
getRecordMeetings
().
isEmpty
())
{
List
<
V1RecordsGet200ResponseRecordMeetingsInner
>
meetings
=
data
.
getRecordMeetings
();
//查询会议详情
//录制状态:
String
meetingId
=
meeting
.
getMeetingId
();
//1:录制中
String
subMeetingId
=
null
;
//2:转码中
MeetingsApi
.
ApiV1MeetingsMeetingIdGetRequest
meetingRequest
=
//3:转码完成
new
MeetingsApi
.
ApiV1MeetingsMeetingIdGetRequest
.
Builder
(
meetingId
)
if
(
meetings
.
stream
().
allMatch
(
item
->
item
.
getState
()
!=
3
)){
.
operatorId
(
tencentAdminUserId
)
return
null
;
.
operatorIdType
(
"1"
)
.
instanceid
(
"0"
)
.
build
();
try
{
MeetingsApi
.
ApiV1MeetingsMeetingIdGetResponse
meetingResponse
=
client
.
meetings
().
v1MeetingsMeetingIdGet
(
meetingRequest
,
new
JWTAuthenticator
.
Builder
()
.
nonce
(
BigInteger
.
valueOf
(
Math
.
abs
((
new
SecureRandom
()).
nextInt
())))
.
timestamp
(
String
.
valueOf
(
System
.
currentTimeMillis
()
/
1000L
)));
V1MeetingsMeetingIdGet200Response
meetingResponseData
=
meetingResponse
.
getData
();
List
<
V1MeetingsMeetingIdGet200ResponseMeetingInfoListInner
>
meetingInfoList
=
meetingResponseData
.
getMeetingInfoList
();
//尝试获取会议详情
if
(
meetingInfoList
!=
null
&&
meetingInfoList
.
size
()
>
0
){
V1MeetingsMeetingIdGet200ResponseMeetingInfoListInner
meetingInfo
=
meetingInfoList
.
get
(
0
);
//会议类型。
//0:一次性会议
//1:周期性会议
Long
meetingType
=
meetingInfo
.
getMeetingType
();
if
(
meetingType
.
intValue
()
==
1
){
subMeetingId
=
meetingInfo
.
getCurrentSubMeetingId
();
}
}
}
catch
(
ClientException
e
)
{
throw
new
RuntimeException
(
e
);
}
catch
(
ServiceException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
for
(
V1RecordsGet200ResponseRecordMeetingsInner
meeting
:
meetings
)
{
if
(
meeting
.
getState
()
!=
3
)
continue
;
List
<
V1RecordsGet200ResponseRecordMeetingsInnerRecordFilesInner
>
recordFiles
=
meeting
.
getRecordFiles
();
//查询会议详情
for
(
V1RecordsGet200ResponseRecordMeetingsInnerRecordFilesInner
recordFile
:
recordFiles
)
{
String
meetingId
=
meeting
.
getMeetingId
();
TencentMeetingVO
.
RecordFile
recordFileItem
=
TencentMeetingVO
.
RecordFile
.
builder
()
String
subMeetingId
=
null
;
.
recordFileId
(
recordFile
.
getRecordFileId
())
MeetingsApi
.
ApiV1MeetingsMeetingIdGetRequest
meetingRequest
=
.
meetingId
(
meetingId
).
subMeetingId
(
subMeetingId
).
build
();
new
MeetingsApi
.
ApiV1MeetingsMeetingIdGetRequest
.
Builder
(
meetingId
)
recordFileUrlList
.
add
(
recordFileItem
);
.
operatorId
(
tencentAdminUserId
)
.
operatorIdType
(
"1"
)
.
instanceid
(
"0"
)
.
build
();
try
{
MeetingsApi
.
ApiV1MeetingsMeetingIdGetResponse
meetingResponse
=
client
.
meetings
().
v1MeetingsMeetingIdGet
(
meetingRequest
,
new
JWTAuthenticator
.
Builder
()
.
nonce
(
BigInteger
.
valueOf
(
Math
.
abs
((
new
SecureRandom
()).
nextInt
())))
.
timestamp
(
String
.
valueOf
(
System
.
currentTimeMillis
()
/
1000L
)));
V1MeetingsMeetingIdGet200Response
meetingResponseData
=
meetingResponse
.
getData
();
List
<
V1MeetingsMeetingIdGet200ResponseMeetingInfoListInner
>
meetingInfoList
=
meetingResponseData
.
getMeetingInfoList
();
//尝试获取会议详情
if
(
meetingInfoList
!=
null
&&
meetingInfoList
.
size
()
>
0
){
V1MeetingsMeetingIdGet200ResponseMeetingInfoListInner
meetingInfo
=
meetingInfoList
.
get
(
0
);
//会议类型
//0:一次性会议
//1:周期性会议
Long
meetingType
=
meetingInfo
.
getMeetingType
();
if
(
meetingType
.
intValue
()
==
1
){
subMeetingId
=
meetingInfo
.
getCurrentSubMeetingId
();
}
//如果数据库中已有相同会议id的记录,跳过同步
if
(!
meetingIds
.
contains
(
meetingId
)){
MeetingInfo
meetingItem
=
MeetingInfo
.
builder
().
meetingId
(
meetingId
).
meetingCode
(
meetingInfo
.
getMeetingCode
())
.
subject
(
meetingInfo
.
getSubject
())
.
startTime
(
LocalDateTime
.
ofInstant
(
Instant
.
ofEpochSecond
(
Long
.
valueOf
(
meetingInfo
.
getStartTime
())),
ZoneId
.
systemDefault
()))
.
endTime
(
LocalDateTime
.
ofInstant
(
Instant
.
ofEpochSecond
(
Long
.
valueOf
(
meetingInfo
.
getEndTime
())),
ZoneId
.
systemDefault
()))
// .hostId(meetingInfo.getHosts().stream().map(V1MeetingsGet200ResponseMeetingInfoListInnerCurrentCoHostsInner::getUserid).collect(Collectors.joining(",")))
// .participantUserIds(meetingInfo.getParticipants().stream().map(V1MeetingsGet200ResponseMeetingInfoListInnerCurrentCoHostsInner::getUserid).collect(Collectors.joining(",")))
.
isGenerated
(
Boolean
.
FALSE
).
emailPushAccess
(
Boolean
.
TRUE
).
isPushed
(
Boolean
.
FALSE
).
syncTime
(
LocalDateTime
.
now
())
.
subMeetingId
(
subMeetingId
)
.
build
();
meetingSaveList
.
add
(
meetingItem
);
List
<
V1RecordsGet200ResponseRecordMeetingsInnerRecordFilesInner
>
recordFiles
=
meeting
.
getRecordFiles
();
for
(
V1RecordsGet200ResponseRecordMeetingsInnerRecordFilesInner
recordFile
:
recordFiles
)
{
TencentMeetingVO
.
RecordFile
recordFileItem
=
TencentMeetingVO
.
RecordFile
.
builder
()
.
recordFileId
(
recordFile
.
getRecordFileId
()).
meetingId
(
meetingId
).
subMeetingId
(
subMeetingId
).
build
();
recordFileUrlList
.
add
(
recordFileItem
);
}
}
}
}
catch
(
ClientException
e
)
{
throw
new
RuntimeException
(
e
);
}
catch
(
ServiceException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
}
}
}
}
}
if
(
meetingSaveList
.
size
()
>
0
){
meetingInfoMapper
.
batchInsert
(
meetingSaveList
);
}
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
());
log
.
error
(
e
.
getMessage
());
throw
new
RuntimeException
(
e
.
getMessage
());
throw
new
RuntimeException
(
e
.
getMessage
());
...
...
src/main/java/com/cmeeting/util/MinioUtils.java
0 → 100644
浏览文件 @
b87c127c
package
com
.
cmeeting
.
util
;
import
io.minio.MinioClient
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.stereotype.Component
;
import
java.io.ByteArrayInputStream
;
import
java.io.FileInputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
@Component
public
class
MinioUtils
{
@Value
(
"${minio.endpoint}"
)
private
String
endpoint
;
@Value
(
"${minio.bucketName}"
)
private
String
bucketName
;
@Value
(
"${minio.accessKey}"
)
private
String
accessKey
;
@Value
(
"${minio.secretKey}"
)
private
String
secretKey
;
private
MinioClient
minioClient
;
public
synchronized
MinioClient
getMinioClient
()
{
try
{
if
(
minioClient
==
null
){
minioClient
=
new
MinioClient
(
endpoint
,
accessKey
,
secretKey
);
}
return
minioClient
;
}
catch
(
Exception
e
){
throw
new
RuntimeException
(
e
);
}
}
public
InputStream
getFile
(
MinioClient
minioClient
,
String
fileName
){
try
{
InputStream
inputStream
=
minioClient
.
getObject
(
bucketName
,
fileName
);
return
inputStream
;
}
catch
(
Exception
e
){
throw
new
RuntimeException
(
e
);
}
}
public
void
upload
(
String
path
,
InputStream
inputStream
)
throws
Exception
{
getMinioClient
().
putObject
(
bucketName
,
path
,
inputStream
,
"application/octet-stream"
);
}
public
void
upload
(
String
path
,
byte
[]
bytes
)
{
try
(
ByteArrayInputStream
inputStream
=
new
ByteArrayInputStream
(
bytes
))
{
// 自动管理流的生命周期,无需手动close
int
data
;
while
((
data
=
inputStream
.
read
())
!=
-
1
)
{
System
.
out
.
print
((
char
)
data
);
}
upload
(
path
,
inputStream
);
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
e
);
}
}
public
Boolean
isFileExist
(
MinioClient
minioClient
,
String
fileName
){
boolean
found
=
false
;
try
{
InputStream
inputStream
=
minioClient
.
getObject
(
bucketName
,
fileName
);
found
=
true
;
return
found
;
}
catch
(
Exception
e
){
found
=
false
;
return
false
;
}
}
}
src/main/resources/application.properties
deleted
100644 → 0
浏览文件 @
8a23a94c
server.port
=
8080
# ????????
tencent.meeting.token
=
QQZNb7xWQB47MpZF4C2DFAkv8
tencent.meeting.aesKey
=
agy6ALUePp34lljWz1uIQWa7yQq3dgxxQNmfaN9GROm
# application.yml
# spring.datasource.url=jdbc:mysql://192.168.10.155:3306/cmeeting?useSSL=false&characterEncoding=utf8
# spring.datasource.username=root
# spring.datasource.password=qizhi123
# spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# ?????primary?
spring.datasource.primary.jdbc-url
=
jdbc:mysql://192.168.10.155:3306/robot-standard-enterprise-aigc?useSSL=false&characterEncoding=utf8&serverTimezone=UTC
spring.datasource.primary.username
=
root
spring.datasource.primary.password
=
qizhi123
spring.datasource.primary.driver-class-name
=
com.mysql.jdbc.Driver
# ?????secondary?
spring.datasource.secondary.jdbc-url
=
jdbc:mysql://192.168.10.155:3306/user-admin?useSSL=false&characterEncoding=utf8&serverTimezone=UTC
spring.datasource.secondary.username
=
root
spring.datasource.secondary.password
=
qizhi123
spring.datasource.secondary.driver-class-name
=
com.mysql.jdbc.Driver
# MyBatis ??
# mybatis.mapper-locations=classpath:mapper/primary/*.xml
mybatis.type-aliases-package
=
com.cmeeting.pojo
\
# ??????
mybatis.configuration.map-underscore-to-camel-case: true
logging.level.com.zaxxer.hikari
=
INFO
# tencent meeting
# local
tencent.appId
=
211153201
tencent.sdkId
=
28370276340
tencent.secretId
=
BKOMDZVbvh0iT7k6UHsSizAWBCOVDtT6
tencent.secretKey
=
3Y1j0mzNp7KChKFJGyaEnZHLobFoAQ8eLwfaMx8nLbtXAerO
#tencent.admin.userId=woaJARCQAAJU1EsO73Ww5rn8YHMW6iYA
tencent.admin.userId
=
woaJARCQAAhkyWGuf8n9InhZsxQstjjA
# prod
#tencent.appId=210468336
#tencent.sdkId=28790143843
#tencent.secretId=0ks7u8cgQ8DGVtlYZeRA9TxZCjvUT3oL
#tencent.secretKey=gQU09rkJjiQfiGcUYdhiKq5Ol6LebXg4w7F7Ol0rwvvdv3Xy
#tencent.admin.userId=woaJARCQAAftcvU6GGoOn66rdSZ4IrOA
email.sender
=
cmeeting_assistant@cimc.com
email.sender.pwd
=
scyou@xih45g6@xih4
email.smtp.host
=
smtp.office365.com
src/main/resources/application.yml
0 → 100644
浏览文件 @
b87c127c
server
:
port
:
8080
# ????????
# application.yml
# spring.datasource.url=jdbc:mysql://192.168.10.155:3306/cmeeting?useSSL=false&characterEncoding=utf8
# spring.datasource.username=root
# spring.datasource.password=qizhi123
# spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# ?????primary?
#spring.datasource.primary.jdbc-url=jdbc:mysql://192.168.10.154:3307/aigc-zhongji-test?useSSL=false&characterEncoding=utf8&serverTimezone=UTC
##spring.datasource.primary.username=root
##spring.datasource.primary.password=123456
##spring.datasource.primary.driver-class-name=com.mysql.jdbc.Driver
##
### ?????secondary?
##spring.datasource.secondary.jdbc-url=jdbc:mysql://192.168.10.154:3307/useradmin-zhongji-test?useSSL=false&characterEncoding=utf8&serverTimezone=UTC
##spring.datasource.secondary.username=root
##spring.datasource.secondary.password=123456
##spring.datasource.secondary.driver-class-name=com.mysql.jdbc.Driver
spring
:
datasource
:
# 主数据源
master
:
jdbc-url
:
jdbc:mysql://192.168.10.154:3307/aigc-zhongji-test?useSSL=false&characterEncoding=utf8&serverTimezone=UTC
username
:
root
password
:
123456
driver-class-name
:
com.mysql.jdbc.Driver
# 从数据源
slave
:
jdbc-url
:
jdbc:mysql://192.168.10.154:3307/useradmin-zhongji-test?useSSL=false&characterEncoding=utf8&serverTimezone=UTC
username
:
root
password
:
123456
driver-class-name
:
com.mysql.jdbc.Driver
# MyBatis ??
# mybatis.mapper-locations=classpath:mapper/primary/*.xml
mybatis.type-aliases-package
:
com.cmeeting.pojo\
# ??????
mybatis
:
configuration
:
map-underscore-to-camel-case
:
true
mybatis-plus
:
mapper-locations
:
classpath*:mapper/**/*.xml
configuration
:
map-underscore-to-camel-case
:
true
# 也建议开启
global-config
:
db-config
:
column-underline
:
true
#logging:
# level:
# com:
# zaxxer:
# hikari: INFO
############################################################## minIO
MINIO_ADDRESS
:
http://192.168.10.154:9000
MINIO_BUCKET
:
zhongji
MINIO_USERNAME
:
minio
MINIO_PASSWORD
:
minio123
#Minio服务所在地址
minio.endpoint
:
${MINIO_ADDRESS}
#存储桶名称
minio.bucketName
:
${MINIO_BUCKET}
#访问的key
minio.accessKey
:
${MINIO_USERNAME}
#访问的秘钥
minio.secretKey
:
${MINIO_PASSWORD}
############################################################## minIO
############################################################## tencent meeting
# local
#tencent.appId=211153201
#tencent.sdkId=28370276340
#tencent.secretId=BKOMDZVbvh0iT7k6UHsSizAWBCOVDtT6
#tencent.secretKey=3Y1j0mzNp7KChKFJGyaEnZHLobFoAQ8eLwfaMx8nLbtXAerO
#tencent.admin.userId=woaJARCQAAJU1EsO73Ww5rn8YHMW6iYA
#tencent.admin.userId=woaJARCQAAhkyWGuf8n9InhZsxQstjjA
# prod
tencent
:
appId
:
210468336
sdkId
:
28790143843
secretId
:
0ks7u8cgQ8DGVtlYZeRA9TxZCjvUT3oL
secretKey
:
gQU09rkJjiQfiGcUYdhiKq5Ol6LebXg4w7F7Ol0rwvvdv3Xy
admin.userId
:
woaJARCQAAftcvU6GGoOn66rdSZ4IrOA
meeting
:
token
:
QQZNb7xWQB47MpZF4C2DFAkv8
aesKey
:
agy6ALUePp34lljWz1uIQWa7yQq3dgxxQNmfaN9GROm
email
:
sender
:
cmeeting_assistant@cimc.com
sender-pwd
:
scyou@xih45g6@xih4
smtp-host
:
smtp.office365.com
############################################################## tencent meeting
logging
:
level
:
com.cmeeting.mapper.primary
:
TRACE
com.cmeeting.mapper.secondary
:
TRACE
root
:
DEBUG
\ No newline at end of file
src/main/resources/mapper/primary/MeetingInfoMapper.xml
0 → 100644
浏览文件 @
b87c127c
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace=
"com.cmeeting.mapper.primary.MeetingInfoMapper"
>
<insert
id=
"batchInsert"
parameterType=
"list"
>
INSERT IGNORE INTO cmt_meeting_info (subject, meeting_id, meeting_code, host_id, participant_user_ids, start_time,
end_time, is_generated, email_push_access, is_pushed, sync_time, sub_meeting_id, record_content, record_xml)
VALUES
<foreach
collection=
"meetingSaveList"
item=
"meeting"
separator=
","
>
(
#{meeting.subject},
#{meeting.meetingId},
#{meeting.meetingCode},
#{meeting.hostId},
#{meeting.participantUserIds},
#{meeting.startTime},
#{meeting.endTime},
#{meeting.isGenerated},
#{meeting.emailPushAccess},
#{meeting.isPushed},
#{meeting.syncTime},
#{meeting.subMeetingId},
#{meeting.recordContent},
#{meeting.recordXml}
)
</foreach>
</insert>
<select
id=
"getAllMeetingIds"
resultType=
"java.lang.String"
>
select meeting_id from cmt_meeting_info
</select>
</mapper>
\ No newline at end of file
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论