parent
1551cc1263
commit
45512694b6
27
pom.xml
27
pom.xml
|
@ -278,6 +278,33 @@
|
|||
</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>
|
||||
|
||||
|
|
|
@ -13,7 +13,10 @@ import java.util.List;
|
|||
public class OkHttpExample {
|
||||
|
||||
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();
|
||||
|
||||
// 创建一个请求对象
|
||||
|
@ -24,7 +27,7 @@ public class OkHttpExample {
|
|||
// 发起同步请求
|
||||
try {
|
||||
String content = getTextUsingOkHttp(client, request);
|
||||
System.out.println("File Content:");
|
||||
// System.out.println("File Content:" + content);
|
||||
// 提取 "第几卷" 和 "第几节"
|
||||
processContent(content);
|
||||
} catch (IOException e) {
|
||||
|
@ -47,7 +50,8 @@ public class OkHttpExample {
|
|||
public static void processContent(String content) {
|
||||
// 正则表达式,提取卷和节
|
||||
String volumePattern = "第([一二三四五六七八九十]+)卷"; // 提取卷
|
||||
String sectionPattern = "第([一二三四五六七八九十零百]+)节:(.*)"; // 提取节及其节名
|
||||
// String sectionPattern = "第([一二三四五六七八九十零百]+)节:(.*)"; // 提取节及其节名
|
||||
String sectionPattern = "第([一二三四五六七八九十百千零]+)章\\s*(.*)";
|
||||
|
||||
// 提取卷
|
||||
Pattern volumeRegex = Pattern.compile(volumePattern);
|
||||
|
@ -68,11 +72,28 @@ public class OkHttpExample {
|
|||
|
||||
// 收集节的信息
|
||||
while (sectionMatcher.find()) {
|
||||
String section = "第" + sectionMatcher.group(1) + "节:" + sectionMatcher.group(2).trim(); // 这里去掉节名前后空格
|
||||
sections.add(section);
|
||||
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);
|
||||
|
||||
|
||||
// if (sectionMatcher.find()) {
|
||||
// System.out.println("章节号: " + sectionMatcher.group(1)); // 中文数字部分
|
||||
// System.out.println("章节名: " + sectionMatcher.group(2)); // 章节名称
|
||||
// } else {
|
||||
// System.out.println("没有匹配到章节信息");
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
||||
System.out.println("sections = " + sections);
|
||||
|
||||
|
||||
|
||||
boolean isFirstSection = true; // 标记是否是第一次匹配到“第一节”
|
||||
|
||||
|
|
|
@ -13,7 +13,8 @@ import java.util.List;
|
|||
public class OkHttpExample2 {
|
||||
|
||||
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();
|
||||
|
||||
// 创建一个请求对象
|
||||
|
@ -24,12 +25,14 @@ public class OkHttpExample2 {
|
|||
// 发起同步请求
|
||||
try {
|
||||
String content = getTextUsingOkHttp(client, request);
|
||||
System.out.println("File Content:");
|
||||
System.out.println("File Content:" + content);
|
||||
// 提取 "第几卷" 和 "第几节"
|
||||
processContent(content);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}*/
|
||||
|
||||
test();
|
||||
}
|
||||
|
||||
// 通过 OkHttpClient 发起同步请求获取文件内容
|
||||
|
@ -47,8 +50,8 @@ public class OkHttpExample2 {
|
|||
public static void processContent(String content) {
|
||||
// 正则表达式,提取卷和节
|
||||
String volumePattern = "第([一二三四五六七八九十]+)卷"; // 提取卷
|
||||
String sectionPattern = "第([一二三四五六七八九十零百]+)节:(.*)"; // 提取节及其节名
|
||||
|
||||
//String sectionPattern = "第([一二三四五六七八九十零百]+)章:(.*)"; // 提取节及其节名
|
||||
String sectionPattern = "第([一二三四五六七八九十百千零]+)章\\s*(.*)";
|
||||
// 提取卷
|
||||
Pattern volumeRegex = Pattern.compile(volumePattern);
|
||||
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.entity.BookContent;
|
||||
import com.guwan.backend.mongodb.User;
|
||||
import com.guwan.backend.mongodb.MongodbUserService;
|
||||
import com.guwan.backend.service.BookContentService;
|
||||
import com.guwan.backend.util.MinioUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
@ -32,6 +34,8 @@ public class CommonController {
|
|||
|
||||
private final BookContentService bookContentService;
|
||||
|
||||
private final MongodbUserService mongodbUserService;
|
||||
|
||||
@PostMapping("/uploadFile")
|
||||
public Result<String> uploadFile(String bucketName, MultipartFile file){
|
||||
return Result.success(minioUtil.getUrl(minioUtil.getFileUrl
|
||||
|
@ -40,6 +44,7 @@ public class CommonController {
|
|||
|
||||
@PostMapping("/addBookComment")
|
||||
public Result<String> addBookComment(String url) {
|
||||
log.debug(url);
|
||||
// "http://localhost:9000/txt/8357cf6b-9637-4354-9ee6-2717141f665a.txt";
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
|
||||
|
@ -186,8 +191,8 @@ public class CommonController {
|
|||
|
||||
|
||||
|
||||
@GetMapping("/getBookCommentByPath")
|
||||
public ResponseEntity<Map<String, Object>> getBookCommentByPath(@RequestParam("id") Long id) {
|
||||
@GetMapping("/getBookCommentByPath")
|
||||
public ResponseEntity<Map<String, Object>> getBookCommentByPath(@RequestParam("id") Long id) {
|
||||
// 从数据库中获取评论内容
|
||||
String comments = bookContentService.getById(id).getSectionContent();
|
||||
|
||||
|
@ -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:
|
||||
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:
|
||||
multipart:
|
||||
|
@ -58,7 +67,9 @@ spring:
|
|||
exclude:
|
||||
- org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration
|
||||
|
||||
# MyBatis-Plus配置
|
||||
|
||||
|
||||
# MyBatis-Plus配置
|
||||
mybatis-plus:
|
||||
global-config:
|
||||
db-config:
|
||||
|
@ -162,4 +173,19 @@ netty:
|
|||
|
||||
go2rtc:
|
||||
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