From f27d8cdb7d2dbe993cf27b5f95ceaad9b878dd2e Mon Sep 17 00:00:00 2001
From: tangwenkang <2720983602@qq.com>
Date: Mon, 6 Nov 2023 19:03:35 +0800
Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 39 ++
Dockerfile | 18 +
health-video-common/pom.xml | 49 +++
.../health/video/common/domain/Comments.java | 37 ++
.../com/health/video/common/domain/Video.java | 54 +++
.../health/video/common/domain/VideoBuy.java | 41 +++
.../video/common/domain/VideoCollection.java | 41 +++
.../health/video/common/domain/VideoType.java | 19 +
.../domain/request/RequestInsertComments.java | 20 ++
.../domain/request/RequestPostVideos.java | 51 +++
.../common/domain/response/ResponseVideo.java | 103 ++++++
health-video-remote/pom.xml | 20 ++
health-video-server/pom.xml | 197 +++++++++++
.../health/video/server/VideoApplication.java | 18 +
.../server/config/ConfirmCallbackConfig.java | 50 +++
.../server/config/RabbitAdminConfig.java | 60 ++++
.../video/server/config/RabbitmqConfig.java | 18 +
.../video/server/config/RedissonConfig.java | 29 ++
.../server/config/ReturnCallbackConfig.java | 41 +++
.../server/controller/VideoController.java | 151 ++++++++
.../video/server/mapper/VideoMapper.java | 111 ++++++
.../video/server/service/VideoService.java | 102 ++++++
.../service/impl/InsertUserVideoQueue.java | 48 +++
.../server/service/impl/VideoServiceImpl.java | 334 ++++++++++++++++++
.../health/video/server/utils/DLXQueue.java | 77 ++++
.../video/server/utils/DelayedQueue.java | 80 +++++
.../health/video/server/utils/DogeUtil.java | 114 ++++++
.../health/video/server/utils/TtlQueue.java | 66 ++++
.../src/main/resources/bootstrap.yml | 57 +++
.../src/main/resources/logback.xml | 74 ++++
.../src/main/resources/mapper/VideoMapper.xml | 138 ++++++++
pom.xml | 44 +++
32 files changed, 2301 insertions(+)
create mode 100644 .gitignore
create mode 100644 Dockerfile
create mode 100644 health-video-common/pom.xml
create mode 100644 health-video-common/src/main/java/com/health/video/common/domain/Comments.java
create mode 100644 health-video-common/src/main/java/com/health/video/common/domain/Video.java
create mode 100644 health-video-common/src/main/java/com/health/video/common/domain/VideoBuy.java
create mode 100644 health-video-common/src/main/java/com/health/video/common/domain/VideoCollection.java
create mode 100644 health-video-common/src/main/java/com/health/video/common/domain/VideoType.java
create mode 100644 health-video-common/src/main/java/com/health/video/common/domain/request/RequestInsertComments.java
create mode 100644 health-video-common/src/main/java/com/health/video/common/domain/request/RequestPostVideos.java
create mode 100644 health-video-common/src/main/java/com/health/video/common/domain/response/ResponseVideo.java
create mode 100644 health-video-remote/pom.xml
create mode 100644 health-video-server/pom.xml
create mode 100644 health-video-server/src/main/java/com/health/video/server/VideoApplication.java
create mode 100644 health-video-server/src/main/java/com/health/video/server/config/ConfirmCallbackConfig.java
create mode 100644 health-video-server/src/main/java/com/health/video/server/config/RabbitAdminConfig.java
create mode 100644 health-video-server/src/main/java/com/health/video/server/config/RabbitmqConfig.java
create mode 100644 health-video-server/src/main/java/com/health/video/server/config/RedissonConfig.java
create mode 100644 health-video-server/src/main/java/com/health/video/server/config/ReturnCallbackConfig.java
create mode 100644 health-video-server/src/main/java/com/health/video/server/controller/VideoController.java
create mode 100644 health-video-server/src/main/java/com/health/video/server/mapper/VideoMapper.java
create mode 100644 health-video-server/src/main/java/com/health/video/server/service/VideoService.java
create mode 100644 health-video-server/src/main/java/com/health/video/server/service/impl/InsertUserVideoQueue.java
create mode 100644 health-video-server/src/main/java/com/health/video/server/service/impl/VideoServiceImpl.java
create mode 100644 health-video-server/src/main/java/com/health/video/server/utils/DLXQueue.java
create mode 100644 health-video-server/src/main/java/com/health/video/server/utils/DelayedQueue.java
create mode 100644 health-video-server/src/main/java/com/health/video/server/utils/DogeUtil.java
create mode 100644 health-video-server/src/main/java/com/health/video/server/utils/TtlQueue.java
create mode 100644 health-video-server/src/main/resources/bootstrap.yml
create mode 100644 health-video-server/src/main/resources/logback.xml
create mode 100644 health-video-server/src/main/resources/mapper/VideoMapper.xml
create mode 100644 pom.xml
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9369b72
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,39 @@
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+logs
+.idea
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..7edcc5b
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,18 @@
+#起始镜像
+FROM anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/openjdk:17-8.6
+#暴露端口号
+EXPOSE 10010
+#挂载目录的位置
+VOLUME /home/logs/health-video
+#构建复制外部文件到docker
+COPY health-video-server/target/health-video-server.jar /home/app.jar
+#工作目录 exec -it 进入容器内部后的默认的起始目录
+WORKDIR /home
+ENV TIME_ZONE Asia/Shanghai
+#指定东八区
+RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
+
+#启动java 程序
+ENTRYPOINT ["java","-Dfile.encoding=UTF-8","-jar","/home/app.jar"]
+
+
diff --git a/health-video-common/pom.xml b/health-video-common/pom.xml
new file mode 100644
index 0000000..999f5fa
--- /dev/null
+++ b/health-video-common/pom.xml
@@ -0,0 +1,49 @@
+
+
+ 4.0.0
+
+ com.health
+ health-video
+ 3.6.3
+
+ 3.6.3
+ health-video-common
+
+
+ 17
+ 17
+ UTF-8
+
+
+
+
+ com.health
+ health-common-core
+
+
+ com.health
+ health-common-security
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+ dragon-public
+ dragon-maven
+ http://10.100.1.7:8081/repository/maven-public/
+
+
+
+
+ dragon-release
+ dragon-releases
+ http://10.100.1.7:8081/repository/maven-releases/
+
+
+
diff --git a/health-video-common/src/main/java/com/health/video/common/domain/Comments.java b/health-video-common/src/main/java/com/health/video/common/domain/Comments.java
new file mode 100644
index 0000000..1beeff5
--- /dev/null
+++ b/health-video-common/src/main/java/com/health/video/common/domain/Comments.java
@@ -0,0 +1,37 @@
+package com.health.video.common.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+/**
+ * @author Wenkang Tang
+ * @date 2023/10/20 21:22
+ */
+@Data
+public class Comments {
+ /**
+ * 评论表主键
+ */
+ private Integer commentsId;
+ /**
+ * 评论内容
+ */
+ private String commentContent;
+ /**
+ * 发布评论用户ID
+ */
+ private Integer commentsUserId;
+ /**
+ * 评论时间
+ */
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
+ private Date createTime;
+ /**
+ * 视频表主键
+ */
+ private Integer videoId;
+}
diff --git a/health-video-common/src/main/java/com/health/video/common/domain/Video.java b/health-video-common/src/main/java/com/health/video/common/domain/Video.java
new file mode 100644
index 0000000..36349b5
--- /dev/null
+++ b/health-video-common/src/main/java/com/health/video/common/domain/Video.java
@@ -0,0 +1,54 @@
+package com.health.video.common.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * @author Wenkang Tang
+ * @date 2023/10/20 21:17
+ */
+@Data
+public class Video {
+ /**
+ * 视频表主键
+ */
+ private Integer videoId;
+ /**
+ * 标题
+ */
+ private String title;
+ /**
+ * 详情内容
+ */
+ private String details;
+ /**
+ * 完整视频
+ */
+ private String fullVideo;
+ /**
+ * 被购买数
+ */
+ private Integer purchaseNumber;
+ /**
+ * 视频分类表主键
+ */
+ private Integer videoTypeId;
+ /**
+ * 视频价格
+ */
+ private Integer price;
+ /**
+ * 发布视频的作者
+ */
+ private Integer founder;
+ /**
+ * 发布时间
+ */
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
+ private Date releaseTime;
+}
diff --git a/health-video-common/src/main/java/com/health/video/common/domain/VideoBuy.java b/health-video-common/src/main/java/com/health/video/common/domain/VideoBuy.java
new file mode 100644
index 0000000..2fe288d
--- /dev/null
+++ b/health-video-common/src/main/java/com/health/video/common/domain/VideoBuy.java
@@ -0,0 +1,41 @@
+package com.health.video.common.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+/**
+ * @author Wenkang Tang
+ * @date 2023/10/24 20:03
+ */
+@Data
+public class VideoBuy {
+ /**
+ * 视频购买表
+ */
+ private Integer videoBuyId;
+ /**
+ * 视频表主键
+ */
+ private Integer videoId;
+ /**
+ * 用户表主键
+ */
+ private Integer buyUserId;
+ /**
+ * 是否购买 1-是
+ */
+ private Integer isBuy;
+ /**
+ * 购买时间
+ */
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
+ private Date buyTime;
+ /**
+ * 是否删除购买视频 1-是 2-否
+ */
+ private Integer isDeleteBuy;
+}
diff --git a/health-video-common/src/main/java/com/health/video/common/domain/VideoCollection.java b/health-video-common/src/main/java/com/health/video/common/domain/VideoCollection.java
new file mode 100644
index 0000000..adb300f
--- /dev/null
+++ b/health-video-common/src/main/java/com/health/video/common/domain/VideoCollection.java
@@ -0,0 +1,41 @@
+package com.health.video.common.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+/**
+ * @author Wenkang Tang
+ * @date 2023/10/24 20:05
+ */
+@Data
+public class VideoCollection {
+ /**
+ * 视频收藏表主键
+ */
+ private Integer videoCollectionId;
+ /**
+ * 视频表主键
+ */
+ private Integer videoId;
+ /**
+ * 用户表主键
+ */
+ private Integer collectionUserId;
+ /**
+ * 是否收藏视频 1-是
+ */
+ private Integer isCollection;
+ /**
+ * 收藏时间
+ */
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
+ private Date collectTime;
+ /**
+ * 是否删除收藏视频 1-是 2-否
+ */
+ private Integer isDeleteCollection;
+}
diff --git a/health-video-common/src/main/java/com/health/video/common/domain/VideoType.java b/health-video-common/src/main/java/com/health/video/common/domain/VideoType.java
new file mode 100644
index 0000000..b7d952e
--- /dev/null
+++ b/health-video-common/src/main/java/com/health/video/common/domain/VideoType.java
@@ -0,0 +1,19 @@
+package com.health.video.common.domain;
+
+import lombok.Data;
+
+/**
+ * @author Wenkang Tang
+ * @date 2023/10/20 21:18
+ */
+@Data
+public class VideoType {
+ /**
+ * 视频分类表主键
+ */
+ private Integer videoTypeId;
+ /**
+ * 分类名称
+ */
+ private String videoTypeName;
+}
diff --git a/health-video-common/src/main/java/com/health/video/common/domain/request/RequestInsertComments.java b/health-video-common/src/main/java/com/health/video/common/domain/request/RequestInsertComments.java
new file mode 100644
index 0000000..4b00386
--- /dev/null
+++ b/health-video-common/src/main/java/com/health/video/common/domain/request/RequestInsertComments.java
@@ -0,0 +1,20 @@
+package com.health.video.common.domain.request;
+
+import lombok.Data;
+
+/**
+ * @author Wenkang Tang
+ * @date 2023/10/21 11:25
+ * 发送评论请求参数
+ */
+@Data
+public class RequestInsertComments {
+ /**
+ * 视频表主键
+ */
+ private Integer videoId;
+ /**
+ * 评论内容
+ */
+ private String commentContent;
+}
diff --git a/health-video-common/src/main/java/com/health/video/common/domain/request/RequestPostVideos.java b/health-video-common/src/main/java/com/health/video/common/domain/request/RequestPostVideos.java
new file mode 100644
index 0000000..9a8702c
--- /dev/null
+++ b/health-video-common/src/main/java/com/health/video/common/domain/request/RequestPostVideos.java
@@ -0,0 +1,51 @@
+package com.health.video.common.domain.request;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * @author Wenkang Tang
+ * @date 2023/10/31 13:27
+ * 发布视频请求参数
+ */
+@Data
+public class RequestPostVideos {
+ /**
+ * 标题
+ */
+ private String title;
+ /**
+ * 详情内容
+ */
+ private String details;
+ /**
+ * 完整视频
+ */
+ private String fullVideo;
+ /**
+ * 被购买数
+ */
+ private Integer purchaseNumber;
+ /**
+ * 视频分类表主键
+ */
+ private Integer videoTypeId;
+ /**
+ * 视频价格
+ */
+ private BigDecimal price;
+ /**
+ * 发布视频的作者
+ */
+ private Integer founder;
+ /**
+ * 发布时间
+ */
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
+ private Date releaseTime;
+}
diff --git a/health-video-common/src/main/java/com/health/video/common/domain/response/ResponseVideo.java b/health-video-common/src/main/java/com/health/video/common/domain/response/ResponseVideo.java
new file mode 100644
index 0000000..2201d3e
--- /dev/null
+++ b/health-video-common/src/main/java/com/health/video/common/domain/response/ResponseVideo.java
@@ -0,0 +1,103 @@
+package com.health.video.common.domain.response;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * @author Wenkang Tang
+ * @date 2023/10/20 21:45
+ * 视频列表响应参数
+ */
+@Data
+public class ResponseVideo {
+ /**
+ * 视频表主键
+ */
+ private Integer videoId;
+ /**
+ * 标题
+ */
+ private String title;
+ /**
+ * 详情内容
+ */
+ private String details;
+ /**
+ * 完整视频
+ */
+ private String fullVideo;
+ /**
+ * 被购买数
+ */
+ private Integer purchaseNumber;
+ /**
+ * 视频分类表主键
+ */
+ private Integer videoTypeId;
+ /**
+ * 分类名称
+ */
+ private String videoTypeName;
+ /**
+ * 视频价格
+ */
+ private BigDecimal price;
+ /**
+ * 视频购买表
+ */
+ private Integer videoBuyId;
+ /**
+ * 是否购买 1-是
+ */
+ private Integer isBuy;
+ /**
+ * 购买时间
+ */
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
+ private Date buyTime;
+ /**
+ * 是否删除购买视频 1-是 2-否
+ */
+ private Integer isDeleteBuy;
+ /**
+ * 视频收藏表主键
+ */
+ private Integer videoCollectionId;
+ /**
+ * 是否收藏视频 1-是
+ */
+ private Integer isCollection;
+ /**
+ * 收藏时间
+ */
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
+ private Date collectTime;
+ /**
+ * 是否删除收藏视频 1-是 2-否
+ */
+ private Integer isDeleteCollection;
+ /**
+ * 发布视频的作者
+ */
+ private Integer founder;
+ /**
+ * 发布时间
+ */
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
+ private Date releaseTime;
+ /**
+ * 收藏视频用户表主键
+ */
+ private Integer collectionUserId;
+ /**
+ * 购买视频用户表主键
+ */
+ private Integer buyUserId;
+}
diff --git a/health-video-remote/pom.xml b/health-video-remote/pom.xml
new file mode 100644
index 0000000..95980a7
--- /dev/null
+++ b/health-video-remote/pom.xml
@@ -0,0 +1,20 @@
+
+
+ 4.0.0
+
+ com.health
+ health-video
+ 3.6.3
+
+ 3.6.3
+ health-video-remote
+
+
+ 17
+ 17
+ UTF-8
+
+
+
diff --git a/health-video-server/pom.xml b/health-video-server/pom.xml
new file mode 100644
index 0000000..a28e433
--- /dev/null
+++ b/health-video-server/pom.xml
@@ -0,0 +1,197 @@
+
+
+ 4.0.0
+
+ com.health
+ health-video
+ 3.6.3
+
+ 3.6.3
+ health-video-server
+
+
+ 17
+ 17
+ UTF-8
+
+
+
+
+
+ com.health
+ health-video-common
+ 3.6.3
+
+
+ com.health
+ health-wallet-common
+ 3.6.5
+
+
+ com.health
+ health-wallet-remote
+ 3.6.5
+
+
+
+ com.health
+ health-common-security
+ 3.6.3
+
+
+
+
+ cn.hutool
+ hutool-all
+ 4.5.16
+
+
+
+ com.health
+ base-file-remote
+
+
+
+ com.health
+ base-system-common
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-config
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-sentinel
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+
+
+ io.springfox
+ springfox-swagger-ui
+ ${swagger.fox.version}
+
+
+
+
+ com.mysql
+ mysql-connector-j
+
+
+
+
+ com.health
+ health-common-datasource
+
+
+
+
+ com.health
+ health-common-datascope
+
+
+
+ com.health
+ health-common-security
+
+
+
+ com.amazonaws
+ aws-java-sdk-core
+ 1.11.813
+
+
+
+ software.amazon.awssdk
+ s3
+ 2.18.30
+
+
+
+ com.amazonaws
+ aws-java-sdk-s3
+ 1.11.813
+
+
+
+ org.springframework.boot
+ spring-boot-starter-amqp
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+
+ org.redisson
+ redisson
+ 3.16.0
+
+
+
+
+
+
+
+
+ dragon-public
+ dragon-maven
+ http://10.100.1.7:8081/repository/maven-public/
+
+
+
+
+ dragon-release
+ dragon-releases
+ http://10.100.1.7:8081/repository/maven-releases/
+
+
+
+ ${project.artifactId}
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-deploy-plugin
+
+ true
+
+
+
+
+
+
diff --git a/health-video-server/src/main/java/com/health/video/server/VideoApplication.java b/health-video-server/src/main/java/com/health/video/server/VideoApplication.java
new file mode 100644
index 0000000..e54338d
--- /dev/null
+++ b/health-video-server/src/main/java/com/health/video/server/VideoApplication.java
@@ -0,0 +1,18 @@
+package com.health.video.server;
+
+import com.health.common.security.annotation.EnableRyFeignClients;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * @author Wenkang Tang
+ * @date 2023/10/20 20:01
+ */
+@SpringBootApplication
+@EnableRyFeignClients
+public class VideoApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(VideoApplication.class);
+ }
+}
diff --git a/health-video-server/src/main/java/com/health/video/server/config/ConfirmCallbackConfig.java b/health-video-server/src/main/java/com/health/video/server/config/ConfirmCallbackConfig.java
new file mode 100644
index 0000000..f2d0b4e
--- /dev/null
+++ b/health-video-server/src/main/java/com/health/video/server/config/ConfirmCallbackConfig.java
@@ -0,0 +1,50 @@
+package com.health.video.server.config;
+
+import org.springframework.amqp.rabbit.connection.CorrelationData;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+
+/**
+ * 消息发送确认配置 消息发送到交换机的确认
+ *
+ * @author 唐文康
+ */
+@Component
+public class ConfirmCallbackConfig implements RabbitTemplate.ConfirmCallback {
+
+ @Autowired
+ private RabbitTemplate rabbitTemplate;
+
+ /**
+ * @PostContruct是spring框架的注解,在⽅法上加该注解会在项⽬启动的时候执⾏该⽅法,也可以理解为在spring容器初始化的时候执
+ * @PostConstruct bean 被初始化的时候执行的方法的注解
+ * @PreDestory bean 被销毁的时候执行的方法的注解
+ */
+ @PostConstruct
+ public void init() {
+ rabbitTemplate.setConfirmCallback(this);
+ }
+
+ /**
+ * 交换机不管是否收到消息的一个回调方法(生产者消息不丢失)
+ *
+ * @param correlationData 消息相关数据
+ * @param ack 交换机是否收到消息
+ * @param cause 失败原因
+ */
+ @Override
+ public void confirm(CorrelationData correlationData, boolean ack, String cause) {
+ if (ack) {
+ // 消息投递到 broker 的状态,true表示成功
+ System.out.println("消息发送成功!");
+ } else {
+ // 发送异常
+ System.out.println("发送异常原因 = " + cause);
+ // TODO 可以将消息 内容 以及 失败的原因 记录到 日志表中
+ }
+ }
+
+}
diff --git a/health-video-server/src/main/java/com/health/video/server/config/RabbitAdminConfig.java b/health-video-server/src/main/java/com/health/video/server/config/RabbitAdminConfig.java
new file mode 100644
index 0000000..f19002c
--- /dev/null
+++ b/health-video-server/src/main/java/com/health/video/server/config/RabbitAdminConfig.java
@@ -0,0 +1,60 @@
+package com.health.video.server.config;
+
+import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
+import org.springframework.amqp.rabbit.connection.ConnectionFactory;
+import org.springframework.amqp.rabbit.connection.CorrelationData;
+import org.springframework.amqp.rabbit.core.RabbitAdmin;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * RabbitAdmin是RabbitMQ的一个Java客户端库,它提供了管理RabbitMQ资源的功能。它是通过与RabbitMQ服务器进行交互来执行管理操作的。
+ *
+ * @author 唐文康
+ */
+@Configuration
+public class RabbitAdminConfig {
+
+ @Value("${spring.rabbitmq.host}")
+ private String host;
+ @Value("${spring.rabbitmq.username}")
+ private String username;
+ @Value("${spring.rabbitmq.password}")
+ private String password;
+ @Value("${spring.rabbitmq.virtualhost}")
+ private String virtualhost;
+
+ /**
+ * 构建 RabbitMQ的连接工厂
+ *
+ * @return
+ */
+ @Bean
+ public ConnectionFactory connectionFactory() {
+ CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
+ connectionFactory.setAddresses(host);
+ connectionFactory.setUsername(username);
+ connectionFactory.setPassword(password);
+ connectionFactory.setVirtualHost(virtualhost);//虚拟主机
+ // 配置发送确认回调时,次配置必须配置,否则即使在RabbitTemplate配置了ConfirmCallback也不会生效
+ connectionFactory.setPublisherConfirmType(CachingConnectionFactory.ConfirmType.CORRELATED);//开启confirm机制 消息到达MQ的确认机制
+ connectionFactory.setPublisherReturns(true);//开启消息返回机制 消息无法送到Exchange时返回到生产者
+ return connectionFactory;
+ }
+
+ /**
+ * 自己初始化 RabbitAdmin
+ *
+ * @param connectionFactory
+ * @return
+ */
+ @Bean
+ public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
+ RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
+ rabbitAdmin.setAutoStartup(true);
+ return rabbitAdmin;
+ }
+}
diff --git a/health-video-server/src/main/java/com/health/video/server/config/RabbitmqConfig.java b/health-video-server/src/main/java/com/health/video/server/config/RabbitmqConfig.java
new file mode 100644
index 0000000..4ffe420
--- /dev/null
+++ b/health-video-server/src/main/java/com/health/video/server/config/RabbitmqConfig.java
@@ -0,0 +1,18 @@
+package com.health.video.server.config;
+
+import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
+import org.springframework.amqp.support.converter.MessageConverter;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author 唐文康
+ */
+@Configuration
+public class RabbitmqConfig {
+ // 消息转换配置
+ @Bean
+ public MessageConverter jsonMessageConverter() {
+ return new Jackson2JsonMessageConverter();
+ }
+}
diff --git a/health-video-server/src/main/java/com/health/video/server/config/RedissonConfig.java b/health-video-server/src/main/java/com/health/video/server/config/RedissonConfig.java
new file mode 100644
index 0000000..a0d1a08
--- /dev/null
+++ b/health-video-server/src/main/java/com/health/video/server/config/RedissonConfig.java
@@ -0,0 +1,29 @@
+package com.health.video.server.config;
+
+import org.redisson.Redisson;
+import org.redisson.api.RedissonClient;
+import org.redisson.config.Config;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author 唐文康
+ */
+@Configuration
+@Component
+public class RedissonConfig {
+
+ @Bean(destroyMethod = "shutdown") // 服务停止后调用 shutdown 方法。
+ public RedissonClient redisson() {
+ System.out.println("Redisson配置类初始加载......");
+ // 1.创建配置
+ Config config = new Config();
+ // 集群模式
+ // config.useClusterServers().addNodeAddress("127.0.0.1:6379", "127.0.0.1:6378");
+ // 2.根据 Config 创建出 RedissonClient 实例。
+ config.useSingleServer().setAddress("redis://10.100.1.2:6379");
+ return Redisson.create(config);
+ }
+
+}
diff --git a/health-video-server/src/main/java/com/health/video/server/config/ReturnCallbackConfig.java b/health-video-server/src/main/java/com/health/video/server/config/ReturnCallbackConfig.java
new file mode 100644
index 0000000..df15e8f
--- /dev/null
+++ b/health-video-server/src/main/java/com/health/video/server/config/ReturnCallbackConfig.java
@@ -0,0 +1,41 @@
+package com.health.video.server.config;
+
+import org.springframework.amqp.core.ReturnedMessage;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+
+/**
+ * 消息发送到 队列的 确认 【 只有消息发送失败的时候执行 】
+ *
+ * @author 唐文康
+ */
+@Component
+public class ReturnCallbackConfig implements RabbitTemplate.ReturnsCallback {
+
+ @Autowired
+ private RabbitTemplate rabbitTemplate;
+
+ /**
+ * @PostContruct是spring框架的注解,在⽅法上加该注解会在项⽬启动的时候执⾏该⽅法,也可以理解为在spring容器初始化的时候执
+ */
+ @PostConstruct
+ public void init() {
+ rabbitTemplate.setReturnsCallback(this);
+ }
+
+ /**
+ * 只要消息发送失败 就会执行
+ *
+ * @param returnedMessage the returned message and metadata.
+ */
+ @Override
+ public void returnedMessage(ReturnedMessage returnedMessage) {
+ System.out.println("消息" + returnedMessage.getMessage().toString() + "被交换机" + returnedMessage.getExchange() + "回退!"
+ + "退回原因为:" + returnedMessage.getReplyText());
+ // TODO 回退了所有的信息,可做补偿机制 记录日志
+ }
+
+}
diff --git a/health-video-server/src/main/java/com/health/video/server/controller/VideoController.java b/health-video-server/src/main/java/com/health/video/server/controller/VideoController.java
new file mode 100644
index 0000000..05e212e
--- /dev/null
+++ b/health-video-server/src/main/java/com/health/video/server/controller/VideoController.java
@@ -0,0 +1,151 @@
+package com.health.video.server.controller;
+
+import com.health.common.core.domain.Result;
+import com.health.video.common.domain.Comments;
+import com.health.video.common.domain.VideoType;
+import com.health.video.common.domain.request.RequestInsertComments;
+import com.health.video.common.domain.request.RequestPostVideos;
+import com.health.video.common.domain.response.ResponseVideo;
+import com.health.video.server.service.VideoService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.util.List;
+
+
+/**
+ * @author Wenkang Tang
+ * @date 2023/10/20 20:02
+ */
+@RestController
+@RequestMapping("/video")
+public class VideoController {
+ @Autowired
+ private VideoService videoService;
+
+ /**
+ * 查询视频类型列表
+ *
+ * @return
+ */
+ @GetMapping("/listVideoType")
+ public Result> listVideoType() {
+ List videoTypes = videoService.listVideoType();
+ return Result.success(videoTypes, "操作成功!");
+ }
+
+ /**
+ * 视频列表
+ *
+ * @param videoTypeId
+ * @return
+ */
+ @PostMapping("/listVideo/{videoTypeId}")
+ public Result> listVideo(@PathVariable Integer videoTypeId) {
+ List responseVideos = videoService.listVideo(videoTypeId);
+ return Result.success(responseVideos, "操作成功!");
+ }
+
+ /**
+ * 发送评论
+ *
+ * @param requestInsertComments
+ */
+ @PostMapping("/insertComments")
+ public Result insertComments(@RequestBody RequestInsertComments requestInsertComments) {
+ videoService.insertComments(requestInsertComments);
+ return Result.success(null, "操作成功!");
+ }
+
+ /**
+ * 收藏视频
+ *
+ * @param videoId
+ */
+ @PostMapping("/insertVideoCollection/{videoId}")
+ public Result insertVideoCollection(@PathVariable Integer videoId) {
+ videoService.insertVideoCollection(videoId);
+ return Result.success(null, "操作成功!");
+ }
+
+ /**
+ * 购买视频
+ *
+ * @param videoId
+ */
+ @PostMapping("/insertVideoBuy/{videoId}")
+ public void insertVideoBuy(@PathVariable Integer videoId) {
+ videoService.insertVideoBuy(videoId);
+ }
+
+ /**
+ * 查询我收藏的视频
+ *
+ * @param collectionUserId
+ * @return
+ */
+ @PostMapping("/listVideoCollection/{collectionUserId}")
+ public Result> listVideoCollection(@PathVariable Integer collectionUserId) {
+ List responseVideos = videoService.listVideoCollection(collectionUserId);
+ return Result.success(responseVideos, "操作成功!");
+ }
+
+ /**
+ * 删除我收藏的视频
+ *
+ * @param videoCollectionId
+ */
+ @PostMapping("/deleteVideoCollection/{videoCollectionId}")
+ public Result deleteVideoCollection(@PathVariable Integer videoCollectionId) {
+ videoService.deleteVideoCollection(videoCollectionId);
+ return Result.success(null, "操作成功!");
+ }
+
+ /**
+ * 查询我购买的视频
+ *
+ * @param buyUserId
+ * @return
+ */
+ @PostMapping("/listVideoBuy/{buyUserId}")
+ public Result> listVideoBuy(@PathVariable Integer buyUserId) {
+ List responseVideos = videoService.listVideoBuy(buyUserId);
+ return Result.success(responseVideos, "操作成功!");
+ }
+
+ /**
+ * 上传视频
+ *
+ * @param file
+ * @return
+ */
+ @PostMapping("/uploadVideo")
+ public Result uploadVideo(@RequestParam MultipartFile file) throws IOException, InterruptedException {
+ return videoService.uploadVideo(file);
+ }
+
+ /**
+ * 发布视频
+ *
+ * @param requestPostVideos
+ */
+ @PostMapping("/PostVideos")
+ public Result postVideos(@RequestBody RequestPostVideos requestPostVideos) {
+ return videoService.postVideos(requestPostVideos);
+ }
+
+ /**
+ * 查询评论列表
+ *
+ * @param videoId
+ * @return
+ */
+ @PostMapping("/listComments/{videoId}")
+ public Result> listComments(@PathVariable Integer videoId) {
+ List commentsList = videoService.listComments(videoId);
+ return Result.success(commentsList, "操作成功!");
+ }
+
+}
diff --git a/health-video-server/src/main/java/com/health/video/server/mapper/VideoMapper.java b/health-video-server/src/main/java/com/health/video/server/mapper/VideoMapper.java
new file mode 100644
index 0000000..91776b0
--- /dev/null
+++ b/health-video-server/src/main/java/com/health/video/server/mapper/VideoMapper.java
@@ -0,0 +1,111 @@
+package com.health.video.server.mapper;
+
+import com.health.video.common.domain.*;
+import com.health.video.common.domain.request.RequestPostVideos;
+import com.health.video.common.domain.response.ResponseVideo;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * @author Wenkang Tang
+ * @date 2023/10/20 20:03
+ */
+@Mapper
+public interface VideoMapper {
+ /**
+ * 查询视频类型列表
+ *
+ * @return
+ */
+ List listVideoType();
+
+ /**
+ * 视频列表
+ *
+ * @return
+ */
+ List listVideo(@Param("videoTypeId") Integer videoTypeId);
+
+ /**
+ * 发送评论
+ *
+ * @param comments
+ */
+ void insertComments(Comments comments);
+
+ /**
+ * 根据videoId查询视频表
+ *
+ * @param videoId
+ */
+ Video getVideoByVideoId(@Param("videoId") Integer videoId);
+
+
+ /**
+ * 收藏视频
+ *
+ * @param videoCollection
+ */
+ void insertVideoCollection(VideoCollection videoCollection);
+
+ /**
+ * 视频添加视频购买列表中
+ *
+ * @param videoBuy
+ */
+ void insertVideoBuy(VideoBuy videoBuy);
+
+ /**
+ * 查询我收藏的视频
+ *
+ * @param collectionUserId
+ * @return
+ */
+ List listVideoCollection(@Param("collectionUserId") Integer collectionUserId);
+
+ /**
+ * 删除我收藏的视频
+ *
+ * @param videoCollection
+ */
+ void deleteVideoCollection(VideoCollection videoCollection);
+
+ /**
+ * 查询我购买的视频
+ *
+ * @param buyUserId
+ * @return
+ */
+ List listVideoBuy(@Param("buyUserId") Integer buyUserId);
+
+ /**
+ * 发布视频
+ *
+ * @param requestPostVideos
+ */
+ void postVideos(RequestPostVideos requestPostVideos);
+
+ /**
+ * 查询评论列表
+ *
+ * @param videoId
+ * @return
+ */
+ List listComments(@Param("videoId") Integer videoId);
+
+ /**
+ * 修改购买后的视频购买总人数
+ *
+ * @param videoId
+ */
+ void updateVideo(@Param("videoId") Integer videoId);
+
+ /**
+ * 查询视频价格
+ * @param videoId
+ * @return
+ */
+ Video getVideoPrice(@Param("videoId") Integer videoId);
+}
diff --git a/health-video-server/src/main/java/com/health/video/server/service/VideoService.java b/health-video-server/src/main/java/com/health/video/server/service/VideoService.java
new file mode 100644
index 0000000..df79a24
--- /dev/null
+++ b/health-video-server/src/main/java/com/health/video/server/service/VideoService.java
@@ -0,0 +1,102 @@
+package com.health.video.server.service;
+
+import com.health.common.core.domain.Result;
+import com.health.video.common.domain.Comments;
+import com.health.video.common.domain.VideoType;
+import com.health.video.common.domain.request.RequestInsertComments;
+import com.health.video.common.domain.request.RequestPostVideos;
+import com.health.video.common.domain.response.ResponseVideo;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * @author Wenkang Tang
+ * @date 2023/10/20 20:03
+ */
+public interface VideoService {
+ /**
+ * 查询视频类型列表
+ *
+ * @return
+ */
+ List listVideoType();
+
+ /**
+ * 视频列表
+ *
+ * @param videoTypeId
+ * @return
+ */
+ List listVideo(Integer videoTypeId);
+
+ /**
+ * 发送评论
+ *
+ * @param requestInsertComments
+ */
+ void insertComments(RequestInsertComments requestInsertComments);
+
+ /**
+ * 收藏视频
+ *
+ * @param videoId
+ */
+ void insertVideoCollection(Integer videoId);
+
+ /**
+ * 购买视频
+ *
+ * @param videoId
+ */
+ void insertVideoBuy(Integer videoId);
+
+ /**
+ * 查询我收藏的视频
+ *
+ * @param collectionUserId
+ * @return
+ */
+ List listVideoCollection(Integer collectionUserId);
+
+ /**
+ * 删除我收藏的视频
+ *
+ * @param videoCollectionId
+ */
+ void deleteVideoCollection(Integer videoCollectionId);
+
+ /**
+ * 查询我购买的视频
+ *
+ * @param buyUserId
+ * @return
+ */
+ List listVideoBuy(Integer buyUserId);
+
+ /**
+ * 上传视频
+ *
+ * @param file
+ * @return
+ */
+ Result uploadVideo(MultipartFile file) throws InterruptedException, IOException;
+
+ /**
+ * 发布视频
+ *
+ * @param requestPostVideos
+ * @return
+ */
+ Result postVideos(RequestPostVideos requestPostVideos);
+
+ /**
+ * 查询评论列表
+ *
+ * @param videoId
+ * @return
+ */
+ List listComments(Integer videoId);
+
+}
diff --git a/health-video-server/src/main/java/com/health/video/server/service/impl/InsertUserVideoQueue.java b/health-video-server/src/main/java/com/health/video/server/service/impl/InsertUserVideoQueue.java
new file mode 100644
index 0000000..ecd4add
--- /dev/null
+++ b/health-video-server/src/main/java/com/health/video/server/service/impl/InsertUserVideoQueue.java
@@ -0,0 +1,48 @@
+package com.health.video.server.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.health.video.common.domain.VideoBuy;
+import com.health.video.server.mapper.VideoMapper;
+import com.rabbitmq.client.Channel;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.annotation.Queue;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author Wenkang Tang
+ * @date 2023/10/24 10:51
+ */
+@Log4j2
+@Service
+public class InsertUserVideoQueue {
+ @Autowired
+ private RedisTemplate redisTemplate;
+ @Autowired
+ private VideoMapper videoMapper;
+
+ @RabbitListener(queuesToDeclare = {@Queue("insert_video_buy")})
+ public void insertUserVideo(String msg, Message message, Channel channel) {
+ try {
+ log.info("消费者接收到消息,消息是:{}", msg);
+ String messageId = message.getMessageProperties().getMessageId();
+ Long insertUserVideo = redisTemplate.opsForSet().add("insert_video_buy", messageId);//消息不重复
+ if (null != insertUserVideo && 0 < insertUserVideo) {
+ VideoBuy videoBuy = JSONObject.parseObject(msg, VideoBuy.class);
+ videoMapper.insertVideoBuy(videoBuy);
+ channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);//消息成功消费后发送消息给生产者
+ log.info("消费者成功消费消息,消息是:{}", msg);
+ }
+ } catch (Exception e) {
+ log.error("消费者消费消息异常,消息内容是:{},异常信息是:{}", msg, e);
+ try {
+ channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);//消费失败 消息回退到队列 ,其他消费者继续消费
+ } catch (Exception ex) {
+ log.error("消费者回退消息异常,消息内容是:{},异常信息是:{}", msg, ex);
+ }
+ }
+ }
+}
diff --git a/health-video-server/src/main/java/com/health/video/server/service/impl/VideoServiceImpl.java b/health-video-server/src/main/java/com/health/video/server/service/impl/VideoServiceImpl.java
new file mode 100644
index 0000000..97b996a
--- /dev/null
+++ b/health-video-server/src/main/java/com/health/video/server/service/impl/VideoServiceImpl.java
@@ -0,0 +1,334 @@
+package com.health.video.server.service.impl;
+
+import com.health.common.core.constant.SecurityConstants;
+import com.health.wallet.common.domain.req.MoneyChangeRecordReq;
+import com.alibaba.fastjson.JSONObject;
+import com.amazonaws.AmazonClientException;
+import com.amazonaws.auth.AWSStaticCredentialsProvider;
+import com.amazonaws.auth.BasicSessionCredentials;
+import com.amazonaws.client.builder.AwsClientBuilder;
+import com.amazonaws.event.ProgressEventType;
+import com.amazonaws.event.ProgressListener;
+import com.amazonaws.services.s3.AmazonS3;
+import com.amazonaws.services.s3.AmazonS3ClientBuilder;
+import com.amazonaws.services.s3.model.PutObjectRequest;
+import com.amazonaws.services.s3.transfer.TransferManager;
+import com.amazonaws.services.s3.transfer.TransferManagerBuilder;
+import com.amazonaws.services.s3.transfer.Upload;
+import com.health.common.core.domain.Result;
+import com.health.common.security.utils.SecurityUtils;
+import com.health.video.common.domain.*;
+import com.health.video.common.domain.request.RequestInsertComments;
+import com.health.video.common.domain.request.RequestPostVideos;
+import com.health.video.common.domain.response.ResponseVideo;
+import com.health.video.server.mapper.VideoMapper;
+import com.health.video.server.service.VideoService;
+import com.health.wallet.remote.RemoteWalletService;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import org.springframework.amqp.core.MessageDeliveryMode;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import com.health.video.server.utils.DogeUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author Wenkang Tang
+ * @date 2023/10/20 20:03
+ */
+@Service
+@SuppressWarnings("ALL")
+public class VideoServiceImpl implements VideoService {
+ @Autowired
+ private VideoMapper videoMapper;
+ @Autowired
+ private RabbitTemplate rabbitTemplate;
+ @Autowired
+ private RedissonClient redissonClient;
+ @Autowired
+ private RemoteWalletService remoteWalletService;
+
+ /**
+ * 查询视频类型列表
+ *
+ * @return
+ */
+ @Override
+ public List listVideoType() {
+ return videoMapper.listVideoType();
+ }
+
+ /**
+ * 视频列表
+ *
+ * @return
+ */
+ @Override
+ public List listVideo(Integer videoTypeId) {
+ return videoMapper.listVideo(videoTypeId);
+ }
+
+ /**
+ * 发送评论
+ *
+ * @param requestInsertComments
+ */
+ @Override
+ public void insertComments(RequestInsertComments requestInsertComments) {
+ Comments comments = new Comments();//创建Comments对象
+ //赋值
+ comments.setCommentsUserId(Math.toIntExact(SecurityUtils.getUserId()));
+ comments.setCommentContent(requestInsertComments.getCommentContent());
+ comments.setVideoId(requestInsertComments.getVideoId());
+ videoMapper.insertComments(comments);
+
+ }
+
+ /**
+ * 收藏视频
+ *
+ * @param videoId
+ */
+ @Override
+ public void insertVideoCollection(Integer videoId) {
+ VideoCollection videoCollection = new VideoCollection();//创建VideoCollection对象
+ videoCollection.setVideoId(videoId);
+ videoCollection.setCollectionUserId(Math.toIntExact(SecurityUtils.getUserId()));//获取当前登录人ID给用户ID赋值
+ videoCollection.setIsCollection(1);
+ videoCollection.setIsDeleteCollection(2);
+ videoMapper.insertVideoCollection(videoCollection);
+ }
+
+ /**
+ * 购买视频
+ *
+ * @param videoId
+ */
+ @Override
+ @Transactional
+ public void insertVideoBuy(Integer videoId) {
+ Video video = videoMapper.getVideoPrice(videoId);//查询视频价格
+ //创建分布式锁对象
+ RLock myLock = redissonClient.getLock("myLock");
+ try {
+ //加锁 最多等待5秒 10秒后自动释放
+ boolean tryLock = myLock.tryLock(5, 10, TimeUnit.SECONDS);
+ if (Boolean.TRUE.equals(tryLock)) { //获取锁成功
+ //创建VideoBuy对象
+ VideoBuy videoBuy = new VideoBuy();
+ videoBuy.setVideoId(videoId);
+ videoBuy.setIsBuy(1);
+ videoBuy.setIsDeleteBuy(2);
+ videoBuy.setBuyUserId(Math.toIntExact(SecurityUtils.getUserId()));
+
+ //rabbitMq发送消息
+ rabbitTemplate.convertAndSend("insert_video_buy", JSONObject.toJSONString(videoBuy), msg -> {
+ msg.getMessageProperties().setMessageId(UUID.randomUUID().toString().replaceAll("-", ""));
+ msg.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);//生产者开启消息持久化
+ return msg;
+ });
+
+ //修改用户余额
+ MoneyChangeRecordReq moneyChangeRecordReq = new MoneyChangeRecordReq();
+ moneyChangeRecordReq.setChangeAmount(video.getPrice());
+ moneyChangeRecordReq.setChangeOrigin("视频购买");
+ moneyChangeRecordReq.setChangeType(0);
+ moneyChangeRecordReq.setCreateUser(SecurityUtils.getUserId());
+ remoteWalletService.moneyChangeByOtherOperate(moneyChangeRecordReq, SecurityConstants.INNER);
+
+ //异步修改购买后的视频购买总人数
+ CompletableFuture.runAsync(()->{
+ videoMapper.updateVideo(videoId);
+ });
+ } else {//获取锁失败
+ throw new RuntimeException("等待时间过长,请重试!");
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("异常内容:"+e);
+ } finally {
+ //释放锁
+ myLock.unlock();
+ }
+ }
+
+ /**
+ * 查询我收藏的视频
+ *
+ * @param collectionUserId
+ * @return
+ */
+ @Override
+ public List listVideoCollection(Integer collectionUserId) {
+ return videoMapper.listVideoCollection(collectionUserId);
+ }
+
+ /**
+ * 删除我收藏的视频
+ *
+ * @param videoCollectionId
+ */
+ @Override
+ public void deleteVideoCollection(Integer videoCollectionId) {
+ VideoCollection videoCollection = new VideoCollection();//创建VideoCollection对象
+ videoCollection.setVideoCollectionId(videoCollectionId);
+ videoCollection.setIsCollection(2);
+ videoCollection.setIsDeleteCollection(1);
+ videoMapper.deleteVideoCollection(videoCollection);
+ }
+
+ /**
+ * 查询我购买的视频
+ *
+ * @param buyUserId
+ * @return
+ */
+ @Override
+ public List listVideoBuy(Integer buyUserId) {
+ return videoMapper.listVideoBuy(buyUserId);
+ }
+
+ /**
+ * 上传视频
+ *
+ * @param file
+ * @return
+ */
+ @Override
+ public Result uploadVideo(MultipartFile file) {
+ // 初始化JSONObject对象
+ JSONObject vodConfig = new JSONObject();
+ // 获取文件名称
+ String originalFilename = file.getOriginalFilename();
+ int dotIndex = originalFilename.lastIndexOf(".");
+ String result = originalFilename.substring(0, dotIndex);
+ // 获取文件后缀,因此此后端代码可接收一切文件,上传格式前端限定
+ String fileExt = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1).toLowerCase();
+ // 重构文件名称
+ String newVideoName = UUID.randomUUID().toString().replaceAll("-", "") + "." + fileExt;// 新的文件名
+
+ vodConfig.put("filename", originalFilename + fileExt); // 此参数不重要,只要能保留文件后缀名如 a.mp4 即可
+ vodConfig.put("vn", newVideoName); // .. . 分组配置、回调参数
+ JSONObject body = new JSONObject();// 构建body对象
+ body.put("channel", "VOD_UPLOAD");
+ body.put("vodConfig", vodConfig);
+
+ JSONObject api = DogeUtil.dogeAPIGet("/auth/tmp_token.json", body);//获取临时密码和上传信息
+ JSONObject credentials = api.getJSONObject("Credentials"); // 包含本次上传视频使用的临时密钥,下面初始化 S3 实例时会用到
+ JSONObject uploadInfo = api.getJSONObject("VodUploadInfo"); // 包含本次上传视频的目标信息(s3Bucket、s3Endpoint、key,系统提供,无需修改)以及本次上传的唯一 ID:did ,下面上传时会用到
+ System.out.println(uploadInfo);
+
+ // 使用临时密钥信息初始化 BasicSessionCredentials 对象
+ BasicSessionCredentials awsCredentials = new BasicSessionCredentials(
+ credentials.getString("accessKeyId"),
+ credentials.getString("secretAccessKey"),
+ credentials.getString("sessionToken"));
+
+ // 使用上传信息中的S3配置信息和认证信息初始化 AmazonS3 对象
+ AmazonS3 s3 = AmazonS3ClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(awsCredentials)).
+ withEndpointConfiguration(new AwsClientBuilder.
+ EndpointConfiguration(uploadInfo.getString("s3Endpoint"), "automatic")).build();
+ try {
+ // 利用 s3 初始化,并配置上传进度回调
+ TransferManager tm = TransferManagerBuilder
+ .standard()
+ .withS3Client(s3)
+ .build();
+
+ // 获取上传的文件名
+ String filename = file.getOriginalFilename();
+ // 设置本地存储路径
+ String localPath = "/tmp/tomcat.10010.12973406643068623510/work/Tomcat/localhost/ROOT";
+ // 拼接本地文件路径,使用了文件分隔符来保证路径的正确性
+ String filePath = localPath + File.separator + "D:\\uploadVideo" + File.separator + filename;
+ // 创建本地文件对象
+ File localFile = new File(filePath);
+ // 检查目录是否存在,如果不存在则创建
+ File localDirectory = localFile.getParentFile();
+ if (!localDirectory.exists()) {
+ localDirectory.mkdirs();
+ }
+ // 将上传的文件保存到本地文件
+ file.transferTo(localFile);
+ // 获取本地文件的大小
+ long fileSize = localFile.length();
+
+ System.out.println("开始分片上传");
+
+ // 指定上传的目标空间路径、目标文件名和本地文件
+ PutObjectRequest req = new PutObjectRequest(
+ uploadInfo.getString("s3Bucket"),
+ uploadInfo.getString("key"),
+ localFile);
+ // 目标空间路径,由上面获取到的 VodUploadInfo 指定,不可更改
+
+ // 设置各过程进度回调
+ req.setGeneralProgressListener(new ProgressListener() {
+ Long totalByteRead = 0L;
+
+ @Override
+ public void progressChanged(com.amazonaws.event.ProgressEvent progressEvent) {
+ if (progressEvent.getEventType() == ProgressEventType.REQUEST_BYTE_TRANSFER_EVENT && totalByteRead < fileSize) {
+ totalByteRead += progressEvent.getBytesTransferred();
+ System.out.println("传输中:" + totalByteRead + "/" + fileSize + " (" + ((totalByteRead * 100.0F / fileSize)) + "%)");
+ } else if (progressEvent.getEventType() == ProgressEventType.TRANSFER_COMPLETED_EVENT) {
+ System.out.println("传输完成");
+ } else if (progressEvent.getEventType() == ProgressEventType.TRANSFER_FAILED_EVENT) {
+ System.out.println("传输失败");
+ }
+ }
+ });
+ // TransferManager 的处理默认是异步的,下面的 upload 方法调用完成后不会等待
+ // 调用 tm.upload(req) 方法开始上传文件
+ Upload upload = tm.upload(req);
+ // 不过,你也可以使用 waitForCompletion 来等待上传完成
+ upload.waitForCompletion();
+ System.out.println("分片上传完成");
+ // 向多吉云汇报此次上传已完成并获得本次上传的视频 ID,did 参数来自上面获取临时密钥时获取到的 VodUploadInfo 。
+ JSONObject cbapi = DogeUtil.dogeAPIGet("/callback/upload.json?did=" + uploadInfo.getString("did"));
+ System.out.println(cbapi);
+ Integer vid = cbapi.getInteger("vid");
+ System.out.println("上传完成,视频 ID:" + vid);
+ // 获取视频的详细信息
+ JSONObject msg = DogeUtil.dogeAPIGet("/video/info.json?vid=" + vid);
+ System.out.println("视频详细信息:" + msg);
+ return Result.success(msg.get("vcode"), "操作成功!");
+ } catch (AmazonClientException | InterruptedException | IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * 发布视频
+ *
+ * @param requestPostVideos
+ * @return
+ */
+ @Override
+ public Result postVideos(RequestPostVideos requestPostVideos) {
+ Video video = new Video();// 创建Video对象
+ video.setFounder(Math.toIntExact(SecurityUtils.getUserId()));
+ //发布视频
+ videoMapper.postVideos(requestPostVideos);
+ return Result.success(null, "成功发布视频!");
+ }
+
+ /**
+ * 查询评论列表
+ *
+ * @param videoId
+ * @return
+ */
+ @Override
+ public List listComments(Integer videoId) {
+ return videoMapper.listComments(videoId);
+ }
+
+}
diff --git a/health-video-server/src/main/java/com/health/video/server/utils/DLXQueue.java b/health-video-server/src/main/java/com/health/video/server/utils/DLXQueue.java
new file mode 100644
index 0000000..65cf13a
--- /dev/null
+++ b/health-video-server/src/main/java/com/health/video/server/utils/DLXQueue.java
@@ -0,0 +1,77 @@
+package com.health.video.server.utils;
+
+import org.springframework.amqp.core.Binding;
+import org.springframework.amqp.core.BindingBuilder;
+import org.springframework.amqp.core.DirectExchange;
+import org.springframework.amqp.core.Queue;
+import org.springframework.amqp.rabbit.core.RabbitAdmin;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.HashMap;
+import java.util.Map;
+
+@Component
+public class DLXQueue {
+ // routingKey
+ private static final String DEAD_ROUTING_KEY = "dead.routingkey";
+ private static final String ROUTING_KEY = "routingkey";
+ private static final String DEAD_EXCHANGE = "dead.exchange";
+ private static final String EXCHANGE = "common.exchange";
+ @Autowired
+ RabbitTemplate rabbitTemplate;
+ @Resource
+ RabbitAdmin rabbitAdmin;
+
+ /**
+ * 发送死信队列,过期后进入死信交换机,进入死信队列
+ *
+ * @param queueName 队列名称
+ * @param deadQueueName 死信队列名称
+ * @param params 消息内容
+ * @param expiration 过期时间 毫秒
+ */
+ public void sendDLXQueue(String queueName, String deadQueueName, Object params, Integer expiration) {
+ /**
+ * ----------------------------------先创建一个ttl队列和死信队列--------------------------------------------
+ */
+ Map map = new HashMap<>();
+ // 队列设置存活时间,单位ms, 必须是整形数据。
+ map.put("x-message-ttl", expiration);
+ // 设置死信交换机
+ map.put("x-dead-letter-exchange", DEAD_EXCHANGE);
+ // 设置死信交换器路由
+ map.put("x-dead-letter-routing-key", DEAD_ROUTING_KEY);
+ /*参数1:队列名称 参数2:持久化 参数3:是否排他 参数4:自动删除队列 参数5:队列参数*/
+ Queue queue = new Queue(queueName, true, false, false, map);
+ rabbitAdmin.declareQueue(queue);
+ /**
+ * ---------------------------------创建交换机---------------------------------------------
+ */
+ DirectExchange directExchange = new DirectExchange(EXCHANGE, true, false);
+ rabbitAdmin.declareExchange(directExchange);
+ /**
+ * ---------------------------------队列绑定交换机---------------------------------------------
+ */
+ Binding binding = BindingBuilder.bind(queue).to(directExchange).with(ROUTING_KEY);
+ rabbitAdmin.declareBinding(binding);
+ /**
+ * ---------------------------------在创建一个死信交换机和队列,接收死信队列---------------------------------------------
+ */
+ DirectExchange deadExchange = new DirectExchange(DEAD_EXCHANGE, true, false);
+ rabbitAdmin.declareExchange(deadExchange);
+
+ Queue deadQueue = new Queue(deadQueueName, true, false, false);
+ rabbitAdmin.declareQueue(deadQueue);
+ /**
+ * ---------------------------------队列绑定死信交换机---------------------------------------------
+ */
+ // 将队列和交换机绑定
+ Binding deadbinding = BindingBuilder.bind(deadQueue).to(deadExchange).with(DEAD_ROUTING_KEY);
+ rabbitAdmin.declareBinding(deadbinding);
+ // 发送消息
+ rabbitTemplate.convertAndSend(EXCHANGE, ROUTING_KEY, params);
+ }
+}
diff --git a/health-video-server/src/main/java/com/health/video/server/utils/DelayedQueue.java b/health-video-server/src/main/java/com/health/video/server/utils/DelayedQueue.java
new file mode 100644
index 0000000..96512fb
--- /dev/null
+++ b/health-video-server/src/main/java/com/health/video/server/utils/DelayedQueue.java
@@ -0,0 +1,80 @@
+package com.health.video.server.utils;
+
+import org.springframework.amqp.core.Binding;
+import org.springframework.amqp.core.BindingBuilder;
+import org.springframework.amqp.core.CustomExchange;
+import org.springframework.amqp.core.Queue;
+import org.springframework.amqp.rabbit.core.RabbitAdmin;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * 发送延迟队列的工具类
+ * @author 唐文康
+ */
+@Component
+public class DelayedQueue {
+
+ // routingKey
+ private static final String DELAYED_ROUTING_KEY = "delayed.routingkey";
+
+ // 延迟队列交换机
+ private static final String DELAYED_EXCHANGE = "delayed.exchange";
+
+ @Autowired
+ RabbitTemplate rabbitTemplate;
+
+ @Resource
+ RabbitAdmin rabbitAdmin;
+
+ /**
+ * 发送延迟队列
+ *
+ * @param queueName 队列名称
+ * @param params 消息内容
+ * @param expiration 延迟时间 毫秒
+ */
+ public void sendDelayedQueue(String queueName, Object params, Integer expiration) {
+ // 先创建一个队列
+ Queue queue = new Queue(queueName);
+ rabbitAdmin.declareQueue(queue);
+
+ // 创建延迟队列交换机
+ CustomExchange customExchange = createCustomExchange();
+ rabbitAdmin.declareExchange(customExchange);
+
+ // 将队列和交换机绑定
+ Binding binding = BindingBuilder.bind(queue).to(customExchange).with(DELAYED_ROUTING_KEY).noargs();
+ rabbitAdmin.declareBinding(binding);
+
+ // 发送延迟消息
+ rabbitTemplate.convertAndSend(DELAYED_EXCHANGE, DELAYED_ROUTING_KEY, params, msg -> {
+ // 发送消息的时候 延迟时长
+ msg.getMessageProperties().setMessageId(UUID.randomUUID().toString().replaceAll("-", ""));
+ msg.getMessageProperties().setDelay(expiration);
+ return msg;
+ });
+ }
+
+ private CustomExchange createCustomExchange() {
+ Map arguments = new HashMap<>();
+ /**
+ * 参数说明:
+ * 1.交换机的名称
+ * 2.交换机的类型
+ * 3.是否需要持久化
+ * 4.是否自动删除
+ * 5.其它参数
+ */
+ arguments.put("x-delayed-type", "direct");
+ return new CustomExchange(DELAYED_EXCHANGE, "x-delayed-message", true, false, arguments);
+ }
+
+}
+
diff --git a/health-video-server/src/main/java/com/health/video/server/utils/DogeUtil.java b/health-video-server/src/main/java/com/health/video/server/utils/DogeUtil.java
new file mode 100644
index 0000000..7dd0f20
--- /dev/null
+++ b/health-video-server/src/main/java/com/health/video/server/utils/DogeUtil.java
@@ -0,0 +1,114 @@
+package com.health.video.server.utils;
+
+import com.alibaba.fastjson.JSONObject;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.http.impl.io.ChunkedOutputStream;
+import org.apache.http.io.SessionOutputBuffer;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.stereotype.Component;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Map;
+
+/**
+ * @author Wenkang Tang
+ * @date 2023/10/27 20:33
+ */
+@Configuration
+@Component
+public class DogeUtil {
+ // 普通 API 请使用这个方法
+ public static JSONObject dogeAPIGet(String apiPath, Map params) {
+ StringBuilder sb = new StringBuilder();
+ for (Map.Entry hm : params.entrySet()) {
+ try {
+ sb.append(URLEncoder.encode(hm.getKey(), String.valueOf(StandardCharsets.UTF_8))).append('=').append(URLEncoder.encode(hm.getValue(), String.valueOf(StandardCharsets.UTF_8))).append("&");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ String bodyText = sb.toString().replace("&$", "");
+ try {
+ return dogeAPIGet(apiPath, bodyText, false);
+ } catch (IOException e) {
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+ // 要求请求内容 Body 是一个 JSON 的 API,请使用这个方法
+ public static JSONObject dogeAPIGet(String apiPath, JSONObject params) {
+ String bodyText = params.toString();
+ try {
+ return dogeAPIGet(apiPath, bodyText, true);
+ } catch (IOException e) {
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+ // 无参数 API
+ public static JSONObject dogeAPIGet(String apiPath) {
+ try {
+ return dogeAPIGet(apiPath, "", true);
+ } catch (IOException e) {
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+ public static JSONObject dogeAPIGet(String apiPath, String paramsText, Boolean jsonMode) throws IOException {
+ // 这里返回值类型是 JSONObject,你也可以根据你的具体情况使用不同的 JSON 库并修改最下方 JSON 处理代码
+
+ // 这里替换为你的多吉云永久 AccessKey 和 SecretKey,可在用户中心 - 密钥管理中查看
+ // 请勿在客户端暴露 AccessKey 和 SecretKey,那样恶意用户将获得账号完全控制权
+ String accessKey = "02a4810cb73129c4";
+ String secretKey = "4d9a1342fcee91d96698ce9425d5a23a";
+
+ String signStr = apiPath + "\n" + paramsText;
+ String sign = "";
+ try {
+ Mac mac = Mac.getInstance("HmacSHA1");
+ mac.init(new SecretKeySpec(secretKey.getBytes(), "HmacSHA1"));
+ sign = new String(new Hex().encode(mac.doFinal(signStr.getBytes())), StandardCharsets.UTF_8); // 这里 Hex 来自 org.apache.commons.codec.binary.Hex
+ } catch (NoSuchAlgorithmException | InvalidKeyException e) {
+ throw new RuntimeException(e.getMessage());
+ }
+ String authorization = "TOKEN " + accessKey + ':' + sign;
+
+ URL u = new URL("https://api.dogecloud.com" + apiPath);
+ HttpURLConnection conn = (HttpURLConnection) u.openConnection();
+ conn.setDoOutput(true);
+ conn.setRequestMethod("POST");
+ conn.setRequestProperty("Content-Type", jsonMode ? "application/json" : "application/x-www-form-urlencoded");
+ conn.setRequestProperty("Authorization", authorization);
+ conn.setRequestProperty("Content-Length", String.valueOf(paramsText.length()));
+ OutputStream os = conn.getOutputStream();
+ os.write(paramsText.getBytes());
+ os.flush();
+ os.close();
+ StringBuilder retJSON = new StringBuilder();
+ if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
+ String readLine = "";
+ try (BufferedReader responseReader = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
+ while ((readLine = responseReader.readLine()) != null) {
+ retJSON.append(readLine).append("\n");
+ }
+ }
+ JSONObject ret = JSONObject.parseObject(retJSON.toString());
+ if (ret.getInteger("code") != 200) {
+ System.err.println("{\"error\":\"API 返回错误:" + ret.getString("msg") + "\"}");
+ } else {
+ return ret.getJSONObject("data");
+ }
+ } else {
+ System.err.println("{\"error\":\"网络错误:" + conn.getResponseCode() + "\"}");
+ }
+ return null;
+ }
+}
diff --git a/health-video-server/src/main/java/com/health/video/server/utils/TtlQueue.java b/health-video-server/src/main/java/com/health/video/server/utils/TtlQueue.java
new file mode 100644
index 0000000..9f2ce92
--- /dev/null
+++ b/health-video-server/src/main/java/com/health/video/server/utils/TtlQueue.java
@@ -0,0 +1,66 @@
+package com.health.video.server.utils;
+
+import org.springframework.amqp.core.Binding;
+import org.springframework.amqp.core.BindingBuilder;
+import org.springframework.amqp.core.DirectExchange;
+import org.springframework.amqp.core.Queue;
+import org.springframework.amqp.rabbit.core.RabbitAdmin;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 发送TTL队列 设置 消息的存活时间 如果超过了存活时间
+ * 该条消息还没有被消费 则自动从队列中消息 ,如果配置了死信队列则消息会进入死信队列
+ */
+@Component
+public class TtlQueue {
+ // routingKey
+ private static final String TTL_KEY = "ttl.routingkey";
+ private static final String TTL_EXCHANGE = "ttl.exchange";
+
+ @Autowired
+ RabbitTemplate rabbitTemplate;
+
+ @Resource
+ RabbitAdmin rabbitAdmin;
+
+ /**
+ * 发送TTL队列
+ *
+ * @param queueName 队列名称
+ * @param params 消息内容
+ * @param expiration 过期时间 毫秒
+ */
+ public void sendTtlQueue(String queueName, Object params, Integer expiration) {
+ /**
+ * ----------------------------------先创建一个ttl队列--------------------------------------------
+ */
+ Map map = new HashMap<>();
+ // 队列设置存活时间,单位ms,必须是整形数据。
+ map.put("x-message-ttl", expiration);
+ /*参数1:队列名称 参数2:持久化 参数3:是否排他 参数4:自动删除队列 参数5:队列参数*/
+ Queue queue = new Queue(queueName, true, false, false, map);
+ rabbitAdmin.declareQueue(queue);
+
+ /**
+ * ---------------------------------创建交换机---------------------------------------------
+ */
+ DirectExchange directExchange = new DirectExchange(TTL_EXCHANGE, true, false);
+ rabbitAdmin.declareExchange(directExchange);
+ /**
+ * ---------------------------------队列绑定交换机---------------------------------------------
+ */
+ // 将队列和交换机绑定
+ Binding binding = BindingBuilder.bind(queue).to(directExchange).with(TTL_KEY);
+ rabbitAdmin.declareBinding(binding);
+
+ // 发送消息
+ rabbitTemplate.convertAndSend(TTL_EXCHANGE, TTL_KEY, params);
+ }
+}
+
diff --git a/health-video-server/src/main/resources/bootstrap.yml b/health-video-server/src/main/resources/bootstrap.yml
new file mode 100644
index 0000000..243c3b9
--- /dev/null
+++ b/health-video-server/src/main/resources/bootstrap.yml
@@ -0,0 +1,57 @@
+# Tomcat
+server:
+ port: 10010
+
+# Spring
+spring:
+ jackson:
+ date-format: yyyy-MM-dd HH:mm:ss
+ time-zone: GMT+8
+ servlet:
+ multipart:
+ max-file-size: 50MB
+ max-request-size: 300MB
+ application:
+ # 应用名称
+ name: health-video
+ profiles:
+ # 环境配置
+ active: dev
+ cloud:
+ nacos:
+ discovery:
+ # 服务注册地址
+ server-addr: 10.100.1.5:8848
+ config:
+ # 配置中心地址
+ server-addr: 10.100.1.5:8848
+ # 配置文件格式
+ file-extension: yml
+ # 共享配置
+ shared-configs:
+ - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
+ rabbitmq:
+ host: 10.100.1.3
+ port: 5072
+ username: guest
+ password: guest
+ virtual-host: /
+ publisher-confirm-type: correlated #确认消息已发送到交换机(Exchange)
+ publisher-returns: true #确认消息已发送到队列(Queue)
+ listener:
+ simple:
+ prefetch: 1 # 每次只能获取一条,处理完成才能获取下一条
+ acknowledge-mode: manual # 设置消费端手动ack确认
+ retry:
+ enabled: true # 是否支持重试
+ template:
+ # 只要消息抵达Queue,就会异步发送优先回调return firm
+ mandatory: true
+ redis:
+ host: 10.100.1.2
+ # 关闭健康检查
+management:
+ health:
+ rabbit:
+ enabled: false
+
diff --git a/health-video-server/src/main/resources/logback.xml b/health-video-server/src/main/resources/logback.xml
new file mode 100644
index 0000000..bff4d3f
--- /dev/null
+++ b/health-video-server/src/main/resources/logback.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+ ${log.pattern}
+
+
+
+
+
+ ${log.path}/info.log
+
+
+
+ ${log.path}/info.%d{yyyy-MM-dd}.log
+
+ 60
+
+
+ ${log.pattern}
+
+
+
+ INFO
+
+ ACCEPT
+
+ DENY
+
+
+
+
+ ${log.path}/error.log
+
+
+
+ ${log.path}/error.%d{yyyy-MM-dd}.log
+
+ 60
+
+
+ ${log.pattern}
+
+
+
+ ERROR
+
+ ACCEPT
+
+ DENY
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/health-video-server/src/main/resources/mapper/VideoMapper.xml b/health-video-server/src/main/resources/mapper/VideoMapper.xml
new file mode 100644
index 0000000..da58ca5
--- /dev/null
+++ b/health-video-server/src/main/resources/mapper/VideoMapper.xml
@@ -0,0 +1,138 @@
+
+
+
+
+
+
+
+
+
+ INSERT INTO `health-video`.`t_video_collection` (`video_collection_id`, `video_id`, `collection_user_id`,
+ `is_collection`, `collect_time`, `is_delete_collection`)
+ VALUES (0, #{videoId}, #{collectionUserId}, #{isCollection}, NOW(), #{isDeleteCollection});
+
+
+
+
+ INSERT INTO `health-video`.`t_video` (`video_id`, `title`, `details`, `full_video`, `purchase_number`,
+ `video_type_id`, `price`, `founder`, `release_time`)
+ VALUES (0, #{title}, #{details}, #{fullVideo}, 0, #{videoTypeId}, #{price}, #{founder}, NOW());
+
+
+
+
+ INSERT INTO `health-video`.`t_video_buy` (`video_buy_id`, `video_id`, `buy_user_id`, `is_buy`, `buy_time`,
+ `is_delete_buy`)
+ VALUES (0, #{videoId}, #{buyUserId}, #{isBuy}, now(), #{isDeleteBuy});
+
+
+
+
+ UPDATE `health-video`.`t_video_collection`
+ SET `is_collection` = 2,
+ `is_delete_collection` = 1
+ WHERE `video_collection_id` = #{videoCollectionId};
+
+
+
+
+ UPDATE `health-video`.`t_video`
+ SET `purchase_number` = purchase_number + 1
+ WHERE `video_id` = #{videoId};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..07153c4
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,44 @@
+
+
+ 4.0.0
+
+
+ com.health
+ health-modules
+ 3.6.3
+
+
+ health-video
+ 3.6.3
+ pom
+
+
+ health-video-common
+ health-video-remote
+ health-video-server
+
+
+
+ 17
+ 17
+ UTF-8
+
+
+
+
+ dragon-public
+ dragon-maven
+ http://10.100.1.7:8081/repository/maven-public/
+
+
+
+
+ dragon-release
+ dragon-releases
+ http://10.100.1.7:8081/repository/maven-releases/
+
+
+
+