parent
1551cc1263
commit
45512694b6
27
pom.xml
27
pom.xml
|
@ -278,6 +278,33 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>com.agentsflex</groupId>-->
|
||||||
|
<!-- <artifactId>agents-flex-bom</artifactId>-->
|
||||||
|
<!-- <version>1.0.0-rc.3</version>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
|
|
||||||
|
<!-- springboot -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.mongoplus</groupId>
|
||||||
|
<artifactId>mongo-plus-boot-starter</artifactId>
|
||||||
|
<version>2.1.6.1</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- solon -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.mongoplus</groupId>
|
||||||
|
<artifactId>mongo-plus-solon-plugin</artifactId>
|
||||||
|
<version>2.1.6.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.kafka</groupId>
|
||||||
|
<artifactId>spring-kafka</artifactId>
|
||||||
|
<version>3.0.9</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,10 @@ import java.util.List;
|
||||||
public class OkHttpExample {
|
public class OkHttpExample {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
String url = "http://localhost:9000/txt/8357cf6b-9637-4354-9ee6-2717141f665a.txt"; // 目标 URL
|
// String url = "http://localhost:9000/txt/f7886718-cb64-4495-9975-733f498d4706.txt"; // 目标 URL
|
||||||
|
|
||||||
|
String url = "http://localhost:9000/txt/712f63af-a974-4462-ac70-22ce8dc43b19.txt";
|
||||||
|
|
||||||
OkHttpClient client = new OkHttpClient();
|
OkHttpClient client = new OkHttpClient();
|
||||||
|
|
||||||
// 创建一个请求对象
|
// 创建一个请求对象
|
||||||
|
@ -24,7 +27,7 @@ public class OkHttpExample {
|
||||||
// 发起同步请求
|
// 发起同步请求
|
||||||
try {
|
try {
|
||||||
String content = getTextUsingOkHttp(client, request);
|
String content = getTextUsingOkHttp(client, request);
|
||||||
System.out.println("File Content:");
|
// System.out.println("File Content:" + content);
|
||||||
// 提取 "第几卷" 和 "第几节"
|
// 提取 "第几卷" 和 "第几节"
|
||||||
processContent(content);
|
processContent(content);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -47,7 +50,8 @@ public class OkHttpExample {
|
||||||
public static void processContent(String content) {
|
public static void processContent(String content) {
|
||||||
// 正则表达式,提取卷和节
|
// 正则表达式,提取卷和节
|
||||||
String volumePattern = "第([一二三四五六七八九十]+)卷"; // 提取卷
|
String volumePattern = "第([一二三四五六七八九十]+)卷"; // 提取卷
|
||||||
String sectionPattern = "第([一二三四五六七八九十零百]+)节:(.*)"; // 提取节及其节名
|
// String sectionPattern = "第([一二三四五六七八九十零百]+)节:(.*)"; // 提取节及其节名
|
||||||
|
String sectionPattern = "第([一二三四五六七八九十百千零]+)章\\s*(.*)";
|
||||||
|
|
||||||
// 提取卷
|
// 提取卷
|
||||||
Pattern volumeRegex = Pattern.compile(volumePattern);
|
Pattern volumeRegex = Pattern.compile(volumePattern);
|
||||||
|
@ -68,9 +72,26 @@ public class OkHttpExample {
|
||||||
|
|
||||||
// 收集节的信息
|
// 收集节的信息
|
||||||
while (sectionMatcher.find()) {
|
while (sectionMatcher.find()) {
|
||||||
String section = "第" + sectionMatcher.group(1) + "节:" + sectionMatcher.group(2).trim(); // 这里去掉节名前后空格
|
String section = "第" + sectionMatcher.group(1) + "章:" + sectionMatcher.group(2).trim(); // 这里去掉节名前后空格
|
||||||
|
|
||||||
|
|
||||||
|
if (sections.stream().noneMatch(s -> s.contains("第" + sectionMatcher.group(1) + "章"))) {
|
||||||
sections.add(section);
|
sections.add(section);
|
||||||
}
|
}
|
||||||
|
// sections.add(section);
|
||||||
|
|
||||||
|
|
||||||
|
// if (sectionMatcher.find()) {
|
||||||
|
// System.out.println("章节号: " + sectionMatcher.group(1)); // 中文数字部分
|
||||||
|
// System.out.println("章节名: " + sectionMatcher.group(2)); // 章节名称
|
||||||
|
// } else {
|
||||||
|
// System.out.println("没有匹配到章节信息");
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
System.out.println("sections = " + sections);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,8 @@ import java.util.List;
|
||||||
public class OkHttpExample2 {
|
public class OkHttpExample2 {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
String url = "http://localhost:9000/txt/8357cf6b-9637-4354-9ee6-2717141f665a.txt"; // 目标 URL
|
/* String url = "http://localhost:9000/txt/712f63af-a974-4462-ac70-22ce8dc43b19.txt"; // 目标 URL
|
||||||
|
// String url = "http://localhost:9000/txt/f7886718-cb64-4495-9975-733f498d4706.txt"; // 目标 URL
|
||||||
OkHttpClient client = new OkHttpClient();
|
OkHttpClient client = new OkHttpClient();
|
||||||
|
|
||||||
// 创建一个请求对象
|
// 创建一个请求对象
|
||||||
|
@ -24,12 +25,14 @@ public class OkHttpExample2 {
|
||||||
// 发起同步请求
|
// 发起同步请求
|
||||||
try {
|
try {
|
||||||
String content = getTextUsingOkHttp(client, request);
|
String content = getTextUsingOkHttp(client, request);
|
||||||
System.out.println("File Content:");
|
System.out.println("File Content:" + content);
|
||||||
// 提取 "第几卷" 和 "第几节"
|
// 提取 "第几卷" 和 "第几节"
|
||||||
processContent(content);
|
processContent(content);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
test();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通过 OkHttpClient 发起同步请求获取文件内容
|
// 通过 OkHttpClient 发起同步请求获取文件内容
|
||||||
|
@ -47,8 +50,8 @@ public class OkHttpExample2 {
|
||||||
public static void processContent(String content) {
|
public static void processContent(String content) {
|
||||||
// 正则表达式,提取卷和节
|
// 正则表达式,提取卷和节
|
||||||
String volumePattern = "第([一二三四五六七八九十]+)卷"; // 提取卷
|
String volumePattern = "第([一二三四五六七八九十]+)卷"; // 提取卷
|
||||||
String sectionPattern = "第([一二三四五六七八九十零百]+)节:(.*)"; // 提取节及其节名
|
//String sectionPattern = "第([一二三四五六七八九十零百]+)章:(.*)"; // 提取节及其节名
|
||||||
|
String sectionPattern = "第([一二三四五六七八九十百千零]+)章\\s*(.*)";
|
||||||
// 提取卷
|
// 提取卷
|
||||||
Pattern volumeRegex = Pattern.compile(volumePattern);
|
Pattern volumeRegex = Pattern.compile(volumePattern);
|
||||||
Matcher volumeMatcher = volumeRegex.matcher(content);
|
Matcher volumeMatcher = volumeRegex.matcher(content);
|
||||||
|
@ -122,4 +125,22 @@ public class OkHttpExample2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void test() {
|
||||||
|
String a = "第二章 骨文";
|
||||||
|
|
||||||
|
// 改进后的正则表达式,处理数字、空格以及章节名称
|
||||||
|
String sectionPattern = "第([一二三四五六七八九十百千零]+)章\\s*(.*)";
|
||||||
|
|
||||||
|
Pattern sectionRegex = Pattern.compile(sectionPattern);
|
||||||
|
Matcher sectionMatcher = sectionRegex.matcher(a);
|
||||||
|
|
||||||
|
if (sectionMatcher.find()) {
|
||||||
|
System.out.println("章节号: " + sectionMatcher.group(1)); // 中文数字部分
|
||||||
|
System.out.println("章节名: " + sectionMatcher.group(2)); // 章节名称
|
||||||
|
} else {
|
||||||
|
System.out.println("没有匹配到章节信息");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
package com.guwan.backend.client;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.client.RestTemplate;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class Go2RTCClient {
|
|
||||||
|
|
||||||
private final RestTemplate restTemplate;
|
|
||||||
|
|
||||||
@Value("${go2rtc.api.url}")
|
|
||||||
private String apiUrl;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建流
|
|
||||||
*/
|
|
||||||
public void createStream(String streamId, String sourceUrl) {
|
|
||||||
String url = apiUrl + "/api/streams/" + streamId;
|
|
||||||
StreamConfig config = new StreamConfig(sourceUrl);
|
|
||||||
|
|
||||||
try {
|
|
||||||
restTemplate.postForEntity(url, config, String.class);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("创建流失败: {}", e.getMessage());
|
|
||||||
throw new RuntimeException("创建流失败", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除流
|
|
||||||
*/
|
|
||||||
public void deleteStream(String streamId) {
|
|
||||||
String url = apiUrl + "/api/streams/" + streamId;
|
|
||||||
|
|
||||||
try {
|
|
||||||
restTemplate.delete(url);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("删除流失败: {}", e.getMessage());
|
|
||||||
throw new RuntimeException("删除流失败", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取WebRTC Offer
|
|
||||||
*/
|
|
||||||
public String getOffer(String streamId, String sdp) {
|
|
||||||
String url = apiUrl + "/api/stream/" + streamId + "/webrtc";
|
|
||||||
WebRTCRequest request = new WebRTCRequest(sdp);
|
|
||||||
|
|
||||||
try {
|
|
||||||
ResponseEntity<WebRTCResponse> response =
|
|
||||||
restTemplate.postForEntity(url, request, WebRTCResponse.class);
|
|
||||||
return response.getBody().getSdp();
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("获取WebRTC Offer失败: {}", e.getMessage());
|
|
||||||
throw new RuntimeException("获取WebRTC Offer失败", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@AllArgsConstructor
|
|
||||||
static class StreamConfig {
|
|
||||||
private String input;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@AllArgsConstructor
|
|
||||||
static class WebRTCRequest {
|
|
||||||
private String sdp;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Data
|
|
||||||
static class WebRTCResponse {
|
|
||||||
private String sdp;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
//package com.guwan.backend.client;
|
|
||||||
//
|
|
||||||
//import lombok.Data;
|
|
||||||
//import lombok.RequiredArgsConstructor;
|
|
||||||
//import lombok.extern.slf4j.Slf4j;
|
|
||||||
//import org.springframework.beans.factory.annotation.Value;
|
|
||||||
//import org.springframework.http.ResponseEntity;
|
|
||||||
//import org.springframework.stereotype.Component;
|
|
||||||
//import org.springframework.web.client.RestTemplate;
|
|
||||||
//
|
|
||||||
//@Slf4j
|
|
||||||
//@Component
|
|
||||||
//@RequiredArgsConstructor
|
|
||||||
//public class SrsClient {
|
|
||||||
//
|
|
||||||
// private final RestTemplate restTemplate;
|
|
||||||
//
|
|
||||||
// @Value("${srs.server.url}")
|
|
||||||
// private String srsServerUrl;
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * 开始录制
|
|
||||||
// */
|
|
||||||
// public void startRecord(String streamKey, RecordConfig config) {
|
|
||||||
// String url = String.format("%s/api/v1/streams/%s/recording/start", srsServerUrl, streamKey);
|
|
||||||
// try {
|
|
||||||
// ResponseEntity<String> response = restTemplate.postForEntity(url, config, String.class);
|
|
||||||
// if (!response.getStatusCode().is2xxSuccessful()) {
|
|
||||||
// throw new RuntimeException("开始录制失败: " + response.getBody());
|
|
||||||
// }
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// log.error("开始录制失败", e);
|
|
||||||
// throw new RuntimeException("开始录制失败", e);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * 停止录制
|
|
||||||
// */
|
|
||||||
// public void stopRecord(String streamKey) {
|
|
||||||
// String url = String.format("%s/api/v1/streams/%s/recording/stop", srsServerUrl, streamKey);
|
|
||||||
// try {
|
|
||||||
// ResponseEntity<String> response = restTemplate.postForEntity(url, null, String.class);
|
|
||||||
// if (!response.getStatusCode().is2xxSuccessful()) {
|
|
||||||
// throw new RuntimeException("停止录制失败: " + response.getBody());
|
|
||||||
// }
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// log.error("停止录制失败", e);
|
|
||||||
// throw new RuntimeException("停止录制失败", e);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * 获取流信息
|
|
||||||
// */
|
|
||||||
// public StreamInfo getStreamInfo(String streamKey) {
|
|
||||||
// String url = String.format("%s/api/v1/streams/%s", srsServerUrl, streamKey);
|
|
||||||
// try {
|
|
||||||
// ResponseEntity<StreamInfo> response = restTemplate.getForEntity(url, StreamInfo.class);
|
|
||||||
// return response.getBody();
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// log.error("获取流信息失败", e);
|
|
||||||
// throw new RuntimeException("获取流信息失败", e);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Data
|
|
||||||
// public static class RecordConfig {
|
|
||||||
// private String format = "flv"; // 录制格式
|
|
||||||
// private String filePath; // 文件路径
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Data
|
|
||||||
// public static class StreamInfo {
|
|
||||||
// private String streamId; // 流ID
|
|
||||||
// private String clientId; // 客户端ID
|
|
||||||
// private String ip; // 客户端IP
|
|
||||||
// private Long startTime; // 开始时间
|
|
||||||
// private String status; // 状态
|
|
||||||
// private Long bytesIn; // 输入字节数
|
|
||||||
// private Long bytesOut; // 输出字节数
|
|
||||||
// }
|
|
||||||
//}
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
package com.guwan.backend.config;
|
||||||
|
|
||||||
|
import org.apache.kafka.clients.consumer.ConsumerConfig;
|
||||||
|
import org.apache.kafka.clients.producer.ProducerConfig;
|
||||||
|
import org.apache.kafka.common.serialization.StringDeserializer;
|
||||||
|
import org.apache.kafka.common.serialization.StringSerializer;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
|
||||||
|
import org.springframework.kafka.core.*;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class KafkaConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ProducerFactory<String, String> producerFactory() {
|
||||||
|
Map<String, Object> config = new HashMap<>();
|
||||||
|
|
||||||
|
config.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
|
||||||
|
config.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
|
||||||
|
config.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
|
||||||
|
|
||||||
|
return new DefaultKafkaProducerFactory<>(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ConsumerFactory<String, String> consumerFactory() {
|
||||||
|
Map<String, Object> config = new HashMap<>();
|
||||||
|
|
||||||
|
config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
|
||||||
|
config.put(ConsumerConfig.GROUP_ID_CONFIG, "book-recommendation-group");
|
||||||
|
config.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
|
||||||
|
config.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
|
||||||
|
|
||||||
|
return new DefaultKafkaConsumerFactory<>(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public KafkaTemplate<String, String> kafkaTemplate() {
|
||||||
|
return new KafkaTemplate<>(producerFactory());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ConcurrentKafkaListenerContainerFactory<String, String> kafkaListenerContainerFactory() {
|
||||||
|
ConcurrentKafkaListenerContainerFactory<String, String> factory =
|
||||||
|
new ConcurrentKafkaListenerContainerFactory<>();
|
||||||
|
factory.setConsumerFactory(consumerFactory());
|
||||||
|
return factory;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,8 @@ package com.guwan.backend.controller;
|
||||||
|
|
||||||
import com.guwan.backend.common.Result;
|
import com.guwan.backend.common.Result;
|
||||||
import com.guwan.backend.entity.BookContent;
|
import com.guwan.backend.entity.BookContent;
|
||||||
|
import com.guwan.backend.mongodb.User;
|
||||||
|
import com.guwan.backend.mongodb.MongodbUserService;
|
||||||
import com.guwan.backend.service.BookContentService;
|
import com.guwan.backend.service.BookContentService;
|
||||||
import com.guwan.backend.util.MinioUtil;
|
import com.guwan.backend.util.MinioUtil;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
@ -32,6 +34,8 @@ public class CommonController {
|
||||||
|
|
||||||
private final BookContentService bookContentService;
|
private final BookContentService bookContentService;
|
||||||
|
|
||||||
|
private final MongodbUserService mongodbUserService;
|
||||||
|
|
||||||
@PostMapping("/uploadFile")
|
@PostMapping("/uploadFile")
|
||||||
public Result<String> uploadFile(String bucketName, MultipartFile file){
|
public Result<String> uploadFile(String bucketName, MultipartFile file){
|
||||||
return Result.success(minioUtil.getUrl(minioUtil.getFileUrl
|
return Result.success(minioUtil.getUrl(minioUtil.getFileUrl
|
||||||
|
@ -40,6 +44,7 @@ public class CommonController {
|
||||||
|
|
||||||
@PostMapping("/addBookComment")
|
@PostMapping("/addBookComment")
|
||||||
public Result<String> addBookComment(String url) {
|
public Result<String> addBookComment(String url) {
|
||||||
|
log.debug(url);
|
||||||
// "http://localhost:9000/txt/8357cf6b-9637-4354-9ee6-2717141f665a.txt";
|
// "http://localhost:9000/txt/8357cf6b-9637-4354-9ee6-2717141f665a.txt";
|
||||||
OkHttpClient client = new OkHttpClient();
|
OkHttpClient client = new OkHttpClient();
|
||||||
|
|
||||||
|
@ -202,8 +207,21 @@ public class CommonController {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/testMongodb")
|
||||||
|
public Result testMongodb(){
|
||||||
|
|
||||||
|
|
||||||
|
User user = new User();
|
||||||
|
user.setId("1");
|
||||||
|
user.setName("1");
|
||||||
|
user.setAge(1L);
|
||||||
|
user.setEmail("1");
|
||||||
|
|
||||||
|
mongodbUserService.save(user);
|
||||||
|
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.guwan.backend.entity;
|
||||||
|
|
||||||
|
public class BookOfUser {
|
||||||
|
|
||||||
|
private Long UserId;
|
||||||
|
|
||||||
|
private Long bookId;
|
||||||
|
|
||||||
|
private String evaluate;
|
||||||
|
|
||||||
|
}
|
|
@ -1,16 +0,0 @@
|
||||||
package com.guwan.backend.entity;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class LiveMessage {
|
|
||||||
private String type; // 消息类型:CHAT-聊天,GIFT-礼物,LIKE-点赞,ENTER-进入,LEAVE-离开
|
|
||||||
private Long userId; // 用户ID
|
|
||||||
private String username; // 用户名
|
|
||||||
private String content; // 消息内容
|
|
||||||
private String giftType; // 礼物类型
|
|
||||||
private Integer giftCount; // 礼物数量
|
|
||||||
private LocalDateTime time; // 时间
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
package com.guwan.backend.entity;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.*;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@TableName("live_room")
|
|
||||||
public class LiveRoom {
|
|
||||||
@TableId(type = IdType.AUTO)
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
private String title; // 直播间标题
|
|
||||||
private String description; // 直播间描述
|
|
||||||
private String coverUrl; // 封面图
|
|
||||||
private Long userId; // 主播ID
|
|
||||||
private String username; // 主播名称
|
|
||||||
private String streamId; // Go2RTC流ID
|
|
||||||
private String status; // 状态:PREPARING-准备中,LIVING-直播中,ENDED-已结束
|
|
||||||
private Integer onlineCount; // 在线人数
|
|
||||||
private Integer likeCount; // 点赞数
|
|
||||||
|
|
||||||
@TableField(fill = FieldFill.INSERT)
|
|
||||||
private LocalDateTime createdTime;
|
|
||||||
|
|
||||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
|
||||||
private LocalDateTime updatedTime;
|
|
||||||
}
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.guwan.backend.kafka;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class BookEvent {
|
||||||
|
private String eventId;
|
||||||
|
private String eventType; // READ, RATE, BOOKMARK 等
|
||||||
|
private String userId;
|
||||||
|
private String bookId;
|
||||||
|
private String bookName;
|
||||||
|
private LocalDateTime timestamp;
|
||||||
|
private Map<String, Object> eventData;
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
//package com.guwan.backend.kafka;
|
||||||
|
//
|
||||||
|
//import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
//import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
//import org.springframework.kafka.annotation.KafkaListener;
|
||||||
|
//import org.springframework.stereotype.Service;
|
||||||
|
//
|
||||||
|
//import lombok.extern.slf4j.Slf4j;
|
||||||
|
//
|
||||||
|
//@Service
|
||||||
|
//@Slf4j
|
||||||
|
//public class BookEventConsumer {
|
||||||
|
//
|
||||||
|
// @Autowired
|
||||||
|
// private ObjectMapper objectMapper;
|
||||||
|
//
|
||||||
|
// @KafkaListener(topics = "book-events", groupId = "book-recommendation-group")
|
||||||
|
// public void consume(String message) {
|
||||||
|
// try {
|
||||||
|
// BookEvent event = objectMapper.readValue(message, BookEvent.class);
|
||||||
|
// processBookEvent(event);
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// log.error("Error processing book event", e);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private void processBookEvent(BookEvent event) {
|
||||||
|
// // 处理接收到的事件
|
||||||
|
// log.info("Processing book event: {}", event);
|
||||||
|
// }
|
||||||
|
//}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.guwan.backend.kafka;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.kafka.core.KafkaTemplate;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class BookEventProducer {
|
||||||
|
|
||||||
|
private static final String TOPIC = "book-events";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private KafkaTemplate<String, String> kafkaTemplate;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
public void sendBookEvent(BookEvent event) {
|
||||||
|
try {
|
||||||
|
String message = objectMapper.writeValueAsString(event);
|
||||||
|
kafkaTemplate.send(TOPIC, message);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Error sending book event", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package com.guwan.backend.kafka;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/common/v1/books")
|
||||||
|
public class BookOfKafkaController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private BookService bookService;
|
||||||
|
|
||||||
|
@PostMapping("/{bookId}/reading")
|
||||||
|
public void recordReading(
|
||||||
|
@PathVariable String bookId,
|
||||||
|
@RequestParam String userId) {
|
||||||
|
bookService.recordReadingEvent(userId, bookId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{bookId}/rating")
|
||||||
|
public void rateBook(
|
||||||
|
@PathVariable String bookId,
|
||||||
|
@RequestParam String userId,
|
||||||
|
@RequestParam int rating) {
|
||||||
|
bookService.recordBookRating(userId, bookId, rating);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{bookId}/bookmark")
|
||||||
|
public void bookmarkBook(
|
||||||
|
@PathVariable String bookId,
|
||||||
|
@RequestParam String userId) {
|
||||||
|
bookService.recordBookmarkEvent(userId, bookId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
package com.guwan.backend.kafka;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class BookService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private BookEventProducer producer;
|
||||||
|
|
||||||
|
public void recordReadingEvent(String userId, String bookId) {
|
||||||
|
BookEvent event = new BookEvent();
|
||||||
|
event.setEventId(UUID.randomUUID().toString());
|
||||||
|
event.setEventType("READ");
|
||||||
|
event.setUserId(userId);
|
||||||
|
event.setBookId(bookId);
|
||||||
|
event.setBookName("大爱仙尊");
|
||||||
|
event.setTimestamp(LocalDateTime.now());
|
||||||
|
event.setEventData(Map.of("readingTime", 30));
|
||||||
|
|
||||||
|
producer.sendBookEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recordBookRating(String userId, String bookId, int rating) {
|
||||||
|
BookEvent event = new BookEvent();
|
||||||
|
event.setEventId(UUID.randomUUID().toString());
|
||||||
|
event.setEventType("RATE");
|
||||||
|
event.setUserId(userId);
|
||||||
|
event.setBookId(bookId);
|
||||||
|
event.setTimestamp(LocalDateTime.now());
|
||||||
|
event.setEventData(Map.of("rating", rating));
|
||||||
|
|
||||||
|
producer.sendBookEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recordBookmarkEvent(String userId, String bookId) {
|
||||||
|
BookEvent event = new BookEvent();
|
||||||
|
event.setEventId(UUID.randomUUID().toString());
|
||||||
|
event.setEventType("BOOKMARK");
|
||||||
|
event.setUserId(userId);
|
||||||
|
event.setBookId(bookId);
|
||||||
|
event.setTimestamp(LocalDateTime.now());
|
||||||
|
|
||||||
|
producer.sendBookEvent(event);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.guwan.backend.kafka;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
public class EveryReadDetailOfKafka {
|
||||||
|
|
||||||
|
private Long UserId;
|
||||||
|
|
||||||
|
private Long bookId;
|
||||||
|
|
||||||
|
private LocalDateTime startTime;
|
||||||
|
|
||||||
|
private LocalDateTime endTime;
|
||||||
|
|
||||||
|
}
|
|
@ -1,9 +0,0 @@
|
||||||
package com.guwan.backend.mapper;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
|
||||||
import com.guwan.backend.entity.LiveRoom;
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
|
||||||
|
|
||||||
@Mapper
|
|
||||||
public interface LiveRoomMapper extends BaseMapper<LiveRoom> {
|
|
||||||
}
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.guwan.backend.mongodb;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
public class EveryReadDetailOfMongodb {
|
||||||
|
|
||||||
|
private Long UserId;
|
||||||
|
|
||||||
|
private Long bookId;
|
||||||
|
|
||||||
|
private LocalDateTime startTime;
|
||||||
|
|
||||||
|
private LocalDateTime endTime;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.guwan.backend.mongodb;
|
||||||
|
|
||||||
|
import com.mongoplus.service.IService;
|
||||||
|
|
||||||
|
public interface MongodbUserService extends IService<User> {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.guwan.backend.mongodb;
|
||||||
|
|
||||||
|
import com.mongoplus.service.impl.ServiceImpl;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class MongodbUserServiceImpl extends ServiceImpl<User> implements MongodbUserService {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.guwan.backend.mongodb;
|
||||||
|
|
||||||
|
import com.mongoplus.annotation.ID;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class User {
|
||||||
|
@ID //使用ID注解,标注此字段为MongoDB的_id,或者继承BaseModelID类
|
||||||
|
private String id;
|
||||||
|
private String name;
|
||||||
|
private Long age;
|
||||||
|
private String email;
|
||||||
|
}
|
|
@ -1,88 +0,0 @@
|
||||||
package com.guwan.backend.service;
|
|
||||||
|
|
||||||
import com.guwan.backend.client.Go2RTCClient;
|
|
||||||
import com.guwan.backend.entity.LiveRoom;
|
|
||||||
import com.guwan.backend.mapper.LiveRoomMapper;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class LiveStreamService {
|
|
||||||
|
|
||||||
private final Go2RTCClient go2rtcClient;
|
|
||||||
private final LiveRoomMapper liveRoomMapper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建直播间
|
|
||||||
*/
|
|
||||||
@Transactional
|
|
||||||
public LiveRoom createLiveRoom(String title, String description, Long userId) {
|
|
||||||
// 生成streamId
|
|
||||||
String streamId = UUID.randomUUID().toString();
|
|
||||||
|
|
||||||
// 创建直播间记录
|
|
||||||
LiveRoom room = new LiveRoom();
|
|
||||||
room.setTitle(title);
|
|
||||||
room.setDescription(description);
|
|
||||||
room.setUserId(userId);
|
|
||||||
room.setStreamId(streamId);
|
|
||||||
room.setStatus("PREPARING");
|
|
||||||
|
|
||||||
liveRoomMapper.insert(room);
|
|
||||||
return room;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 开始直播
|
|
||||||
*/
|
|
||||||
@Transactional
|
|
||||||
public void startLive(Long roomId, String sourceUrl) {
|
|
||||||
LiveRoom room = liveRoomMapper.selectById(roomId);
|
|
||||||
if (room == null) {
|
|
||||||
throw new IllegalArgumentException("直播间不存在");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建Go2RTC流
|
|
||||||
go2rtcClient.createStream(room.getStreamId(), sourceUrl);
|
|
||||||
|
|
||||||
// 更新状态
|
|
||||||
room.setStatus("LIVING");
|
|
||||||
liveRoomMapper.updateById(room);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 结束直播
|
|
||||||
*/
|
|
||||||
@Transactional
|
|
||||||
public void endLive(Long roomId) {
|
|
||||||
LiveRoom room = liveRoomMapper.selectById(roomId);
|
|
||||||
if (room == null) {
|
|
||||||
throw new IllegalArgumentException("直播间不存在");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除Go2RTC流
|
|
||||||
go2rtcClient.deleteStream(room.getStreamId());
|
|
||||||
|
|
||||||
// 更新状态
|
|
||||||
room.setStatus("ENDED");
|
|
||||||
liveRoomMapper.updateById(room);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取WebRTC Offer
|
|
||||||
*/
|
|
||||||
public String getWebRTCOffer(Long roomId, String sdp) {
|
|
||||||
LiveRoom room = liveRoomMapper.selectById(roomId);
|
|
||||||
if (room == null) {
|
|
||||||
throw new IllegalArgumentException("直播间不存在");
|
|
||||||
}
|
|
||||||
|
|
||||||
return go2rtcClient.getOffer(room.getStreamId(), sdp);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,6 +5,15 @@ spring:
|
||||||
application:
|
application:
|
||||||
name: backend
|
name: backend
|
||||||
|
|
||||||
|
kafka:
|
||||||
|
bootstrap-servers: localhost:9092
|
||||||
|
consumer:
|
||||||
|
group-id: book-recommendation-group
|
||||||
|
auto-offset-reset: earliest
|
||||||
|
producer:
|
||||||
|
key-serializer: org.apache.kafka.common.serialization.StringSerializer
|
||||||
|
value-serializer: org.apache.kafka.common.serialization.StringSerializer
|
||||||
|
|
||||||
# 视频上传配置
|
# 视频上传配置
|
||||||
servlet:
|
servlet:
|
||||||
multipart:
|
multipart:
|
||||||
|
@ -58,7 +67,9 @@ spring:
|
||||||
exclude:
|
exclude:
|
||||||
- org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration
|
- org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration
|
||||||
|
|
||||||
# MyBatis-Plus配置
|
|
||||||
|
|
||||||
|
# MyBatis-Plus配置
|
||||||
mybatis-plus:
|
mybatis-plus:
|
||||||
global-config:
|
global-config:
|
||||||
db-config:
|
db-config:
|
||||||
|
@ -163,3 +174,18 @@ netty:
|
||||||
go2rtc:
|
go2rtc:
|
||||||
api:
|
api:
|
||||||
url: http://localhost:1984 # Go2RTC API地址
|
url: http://localhost:1984 # Go2RTC API地址
|
||||||
|
|
||||||
|
|
||||||
|
# DataSource Config
|
||||||
|
mongo-plus:
|
||||||
|
data:
|
||||||
|
mongodb:
|
||||||
|
host: 127.0.0.1 #ip
|
||||||
|
port: 27017 #端口
|
||||||
|
database: test #数据库名
|
||||||
|
username: #用户名,没有可不填(若账号中出现@,!等等符号,不需要再进行转码!!!)
|
||||||
|
password: #密码,同上(若密码中出现@,!等等符号,不需要再进行转码!!!)
|
||||||
|
authenticationDatabase: admin #验证数据库
|
||||||
|
connectTimeoutMS: 50000 #在超时之前等待连接打开的最长时间(以毫秒为单位)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue