chore: remove java-backend test project
This commit is contained in:
parent
a1c6996fdc
commit
cc690e5c60
|
|
@ -1,126 +0,0 @@
|
|||
# 直播系统 Java 后端
|
||||
|
||||
基于 Spring Boot 3.2 + JPA + H2/MySQL 的直播系统后端服务。
|
||||
|
||||
## 技术栈
|
||||
|
||||
- Java 17
|
||||
- Spring Boot 3.2
|
||||
- Spring Data JPA
|
||||
- H2 Database (开发) / MySQL (生产)
|
||||
- Lombok
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 1. 使用 IDEA 打开项目
|
||||
|
||||
1. 打开 IntelliJ IDEA
|
||||
2. 选择 `File` -> `Open`
|
||||
3. 选择 `java-backend` 文件夹
|
||||
4. 等待 Maven 依赖下载完成
|
||||
|
||||
### 2. 运行项目
|
||||
|
||||
方式一:直接运行
|
||||
- 找到 `LivestreamingApplication.java`
|
||||
- 右键点击 -> `Run 'LivestreamingApplication'`
|
||||
|
||||
方式二:Maven 命令
|
||||
```bash
|
||||
cd java-backend
|
||||
mvn spring-boot:run
|
||||
```
|
||||
|
||||
### 3. 访问服务
|
||||
|
||||
- API 地址: http://localhost:3001/api
|
||||
- H2 控制台: http://localhost:3001/h2-console
|
||||
- JDBC URL: `jdbc:h2:file:./data/livestream`
|
||||
- 用户名: `sa`
|
||||
- 密码: (空)
|
||||
|
||||
## API 接口
|
||||
|
||||
### 直播间接口
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | /api/rooms | 获取所有直播间 |
|
||||
| GET | /api/rooms/{id} | 获取单个直播间 |
|
||||
| POST | /api/rooms | 创建直播间 |
|
||||
| DELETE | /api/rooms/{id} | 删除直播间 |
|
||||
|
||||
### 创建直播间请求示例
|
||||
|
||||
```json
|
||||
POST /api/rooms
|
||||
{
|
||||
"title": "我的直播间",
|
||||
"streamerName": "主播名称"
|
||||
}
|
||||
```
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"id": "uuid",
|
||||
"title": "我的直播间",
|
||||
"streamerName": "主播名称",
|
||||
"streamKey": "uuid",
|
||||
"isLive": false,
|
||||
"viewerCount": 0,
|
||||
"streamUrls": {
|
||||
"rtmp": "rtmp://localhost:1935/live/uuid",
|
||||
"flv": "http://localhost:8080/live/uuid.flv",
|
||||
"hls": "http://localhost:8080/live/uuid/index.m3u8"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 切换到 MySQL
|
||||
|
||||
1. 安装 MySQL 并创建数据库:
|
||||
```sql
|
||||
CREATE DATABASE livestream CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
```
|
||||
|
||||
2. 修改 `application.yml`:
|
||||
```yaml
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://localhost:3306/livestream?useSSL=false&serverTimezone=Asia/Shanghai
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
username: root
|
||||
password: your_password
|
||||
```
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
java-backend/
|
||||
├── src/main/java/com/example/livestreaming/
|
||||
│ ├── LivestreamingApplication.java # 启动类
|
||||
│ ├── config/ # 配置类
|
||||
│ ├── controller/ # 控制器
|
||||
│ ├── dto/ # 数据传输对象
|
||||
│ ├── entity/ # 实体类
|
||||
│ ├── exception/ # 异常处理
|
||||
│ ├── repository/ # 数据访问层
|
||||
│ └── service/ # 业务逻辑层
|
||||
├── src/main/resources/
|
||||
│ └── application.yml # 配置文件
|
||||
└── pom.xml # Maven 配置
|
||||
```
|
||||
|
||||
## Android App 配置
|
||||
|
||||
确保 Android App 的 API 地址指向此服务:
|
||||
|
||||
```kotlin
|
||||
// build.gradle.kts
|
||||
buildConfigField("String", "API_BASE_URL_DEVICE", "\"http://你的电脑IP:3001/api/\"")
|
||||
```
|
||||
Binary file not shown.
|
|
@ -1,88 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>livestreaming-backend</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<name>livestreaming-backend</name>
|
||||
<description>直播系统后端服务</description>
|
||||
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring Boot Web -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Data JPA -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- MySQL Driver -->
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- H2 Database (开发测试用,可选) -->
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Validation -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
package com.example.livestreaming;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class LivestreamingApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(LivestreamingApplication.class, args);
|
||||
System.out.println("========================================");
|
||||
System.out.println(" 直播系统后端服务启动成功!");
|
||||
System.out.println(" API地址: http://localhost:3001/api");
|
||||
System.out.println(" H2控制台: http://localhost:3001/h2-console");
|
||||
System.out.println("========================================");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package com.example.livestreaming.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class WebConfig implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**")
|
||||
.allowedOrigins("*")
|
||||
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||
.allowedHeaders("*")
|
||||
.maxAge(3600);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
package com.example.livestreaming.controller;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
public class HealthController {
|
||||
|
||||
@GetMapping("/health")
|
||||
public ResponseEntity<Map<String, Object>> health() {
|
||||
return ResponseEntity.ok(Map.of(
|
||||
"status", "ok",
|
||||
"timestamp", LocalDateTime.now().toString()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
package com.example.livestreaming.controller;
|
||||
|
||||
import com.example.livestreaming.dto.ApiResponse;
|
||||
import com.example.livestreaming.dto.CreateRoomRequest;
|
||||
import com.example.livestreaming.dto.RoomResponse;
|
||||
import com.example.livestreaming.service.RoomService;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/rooms")
|
||||
@RequiredArgsConstructor
|
||||
@CrossOrigin(origins = "*")
|
||||
public class RoomController {
|
||||
|
||||
private final RoomService roomService;
|
||||
|
||||
/**
|
||||
* 获取所有直播间
|
||||
* GET /api/rooms
|
||||
*/
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<List<RoomResponse>>> getAllRooms() {
|
||||
List<RoomResponse> rooms = roomService.getAllRooms();
|
||||
return ResponseEntity.ok(ApiResponse.success(rooms));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单个直播间
|
||||
* GET /api/rooms/{id}
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<RoomResponse>> getRoomById(@PathVariable String id) {
|
||||
return roomService.getRoomById(id)
|
||||
.map(room -> ResponseEntity.ok(ApiResponse.success(room)))
|
||||
.orElse(ResponseEntity.notFound().build());
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建直播间
|
||||
* POST /api/rooms
|
||||
*/
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<RoomResponse>> createRoom(@Valid @RequestBody CreateRoomRequest request) {
|
||||
RoomResponse room = roomService.createRoom(request);
|
||||
return ResponseEntity.ok(ApiResponse.success(room, "直播间创建成功"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除直播间
|
||||
* DELETE /api/rooms/{id}
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteRoom(@PathVariable String id) {
|
||||
if (roomService.deleteRoom(id)) {
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "删除成功"));
|
||||
}
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
package com.example.livestreaming.controller;
|
||||
|
||||
import com.example.livestreaming.service.RoomService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* SRS/NodeMediaServer 回调接口
|
||||
* 用于接收推流开始/结束的通知
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/srs")
|
||||
@RequiredArgsConstructor
|
||||
@CrossOrigin(origins = "*")
|
||||
public class SrsCallbackController {
|
||||
|
||||
private final RoomService roomService;
|
||||
|
||||
/**
|
||||
* 推流开始回调
|
||||
* POST /api/srs/on_publish
|
||||
*/
|
||||
@PostMapping("/on_publish")
|
||||
public ResponseEntity<Map<String, Object>> onPublish(@RequestBody Map<String, Object> body) {
|
||||
String stream = (String) body.get("stream");
|
||||
log.info("推流开始: stream={}", stream);
|
||||
|
||||
if (stream != null) {
|
||||
roomService.setLiveStatus(stream, true);
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(successResponse());
|
||||
}
|
||||
|
||||
/**
|
||||
* 推流结束回调
|
||||
* POST /api/srs/on_unpublish
|
||||
*/
|
||||
@PostMapping("/on_unpublish")
|
||||
public ResponseEntity<Map<String, Object>> onUnpublish(@RequestBody Map<String, Object> body) {
|
||||
String stream = (String) body.get("stream");
|
||||
log.info("推流结束: stream={}", stream);
|
||||
|
||||
if (stream != null) {
|
||||
roomService.setLiveStatus(stream, false);
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(successResponse());
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放开始回调
|
||||
* POST /api/srs/on_play
|
||||
*/
|
||||
@PostMapping("/on_play")
|
||||
public ResponseEntity<Map<String, Object>> onPlay(@RequestBody Map<String, Object> body) {
|
||||
String stream = (String) body.get("stream");
|
||||
log.info("观众进入: stream={}", stream);
|
||||
return ResponseEntity.ok(successResponse());
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放结束回调
|
||||
* POST /api/srs/on_stop
|
||||
*/
|
||||
@PostMapping("/on_stop")
|
||||
public ResponseEntity<Map<String, Object>> onStop(@RequestBody Map<String, Object> body) {
|
||||
String stream = (String) body.get("stream");
|
||||
log.info("观众离开: stream={}", stream);
|
||||
return ResponseEntity.ok(successResponse());
|
||||
}
|
||||
|
||||
private Map<String, Object> successResponse() {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
package com.example.livestreaming.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ApiResponse<T> {
|
||||
|
||||
private boolean success;
|
||||
private T data;
|
||||
private String message;
|
||||
|
||||
public static <T> ApiResponse<T> success(T data) {
|
||||
return new ApiResponse<>(true, data, null);
|
||||
}
|
||||
|
||||
public static <T> ApiResponse<T> success(T data, String message) {
|
||||
return new ApiResponse<>(true, data, message);
|
||||
}
|
||||
|
||||
public static <T> ApiResponse<T> error(String message) {
|
||||
return new ApiResponse<>(false, null, message);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
package com.example.livestreaming.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class CreateRoomRequest {
|
||||
|
||||
@NotBlank(message = "标题不能为空")
|
||||
private String title;
|
||||
|
||||
@NotBlank(message = "主播名称不能为空")
|
||||
private String streamerName;
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
package com.example.livestreaming.dto;
|
||||
|
||||
import com.example.livestreaming.entity.Room;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RoomResponse {
|
||||
|
||||
private String id;
|
||||
private String title;
|
||||
private String streamerName;
|
||||
private String streamKey;
|
||||
private boolean isLive;
|
||||
private int viewerCount;
|
||||
private String createdAt;
|
||||
private String startedAt;
|
||||
private StreamUrls streamUrls;
|
||||
|
||||
@Data
|
||||
public static class StreamUrls {
|
||||
private String rtmp;
|
||||
private String flv;
|
||||
private String hls;
|
||||
}
|
||||
|
||||
public static RoomResponse fromEntity(Room room, String rtmpHost, int rtmpPort, String httpHost, int httpPort) {
|
||||
RoomResponse response = new RoomResponse();
|
||||
response.setId(room.getId());
|
||||
response.setTitle(room.getTitle());
|
||||
response.setStreamerName(room.getStreamerName());
|
||||
response.setStreamKey(room.getStreamKey());
|
||||
response.setLive(room.isLive());
|
||||
response.setViewerCount(room.getViewerCount());
|
||||
response.setCreatedAt(room.getCreatedAt() != null ? room.getCreatedAt().toString() : null);
|
||||
response.setStartedAt(room.getStartedAt() != null ? room.getStartedAt().toString() : null);
|
||||
|
||||
// 构建流地址
|
||||
StreamUrls urls = new StreamUrls();
|
||||
String streamKey = room.getStreamKey();
|
||||
urls.setRtmp(String.format("rtmp://%s:%d/live/%s", rtmpHost, rtmpPort, streamKey));
|
||||
urls.setFlv(String.format("http://%s:%d/live/%s.flv", httpHost, httpPort, streamKey));
|
||||
urls.setHls(String.format("http://%s:%d/live/%s/index.m3u8", httpHost, httpPort, streamKey));
|
||||
response.setStreamUrls(urls);
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
package com.example.livestreaming.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.AllArgsConstructor;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Entity
|
||||
@Table(name = "rooms")
|
||||
public class Room {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String title;
|
||||
|
||||
@Column(name = "streamer_name", nullable = false)
|
||||
private String streamerName;
|
||||
|
||||
@Column(name = "stream_key", unique = true, nullable = false)
|
||||
private String streamKey;
|
||||
|
||||
@Column(name = "is_live")
|
||||
private boolean isLive = false;
|
||||
|
||||
@Column(name = "viewer_count")
|
||||
private int viewerCount = 0;
|
||||
|
||||
@Column(name = "created_at")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@Column(name = "started_at")
|
||||
private LocalDateTime startedAt;
|
||||
|
||||
@PrePersist
|
||||
public void prePersist() {
|
||||
if (id == null) {
|
||||
id = UUID.randomUUID().toString();
|
||||
}
|
||||
if (streamKey == null) {
|
||||
streamKey = id;
|
||||
}
|
||||
if (createdAt == null) {
|
||||
createdAt = LocalDateTime.now();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
package com.example.livestreaming.exception;
|
||||
|
||||
import com.example.livestreaming.dto.ApiResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.FieldError;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@RestControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public ResponseEntity<ApiResponse<Void>> handleValidationException(MethodArgumentNotValidException ex) {
|
||||
String message = ex.getBindingResult().getFieldErrors().stream()
|
||||
.map(FieldError::getDefaultMessage)
|
||||
.collect(Collectors.joining(", "));
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error(message));
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ResponseEntity<ApiResponse<Void>> handleException(Exception ex) {
|
||||
log.error("服务器错误", ex);
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body(ApiResponse.error("服务器内部错误"));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
package com.example.livestreaming.repository;
|
||||
|
||||
import com.example.livestreaming.entity.Room;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface RoomRepository extends JpaRepository<Room, String> {
|
||||
|
||||
Optional<Room> findByStreamKey(String streamKey);
|
||||
}
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
package com.example.livestreaming.service;
|
||||
|
||||
import com.example.livestreaming.dto.CreateRoomRequest;
|
||||
import com.example.livestreaming.dto.RoomResponse;
|
||||
import com.example.livestreaming.entity.Room;
|
||||
import com.example.livestreaming.repository.RoomRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class RoomService {
|
||||
|
||||
private final RoomRepository roomRepository;
|
||||
|
||||
@Value("${livestream.rtmp.host:localhost}")
|
||||
private String rtmpHost;
|
||||
|
||||
@Value("${livestream.rtmp.port:1935}")
|
||||
private int rtmpPort;
|
||||
|
||||
@Value("${livestream.http.host:localhost}")
|
||||
private String httpHost;
|
||||
|
||||
@Value("${livestream.http.port:8080}")
|
||||
private int httpPort;
|
||||
|
||||
/**
|
||||
* 获取所有直播间
|
||||
*/
|
||||
public List<RoomResponse> getAllRooms() {
|
||||
return roomRepository.findAll().stream()
|
||||
.map(room -> RoomResponse.fromEntity(room, rtmpHost, rtmpPort, httpHost, httpPort))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID获取直播间
|
||||
*/
|
||||
public Optional<RoomResponse> getRoomById(String id) {
|
||||
return roomRepository.findById(id)
|
||||
.map(room -> RoomResponse.fromEntity(room, rtmpHost, rtmpPort, httpHost, httpPort));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建直播间
|
||||
*/
|
||||
@Transactional
|
||||
public RoomResponse createRoom(CreateRoomRequest request) {
|
||||
Room room = new Room();
|
||||
room.setTitle(request.getTitle());
|
||||
room.setStreamerName(request.getStreamerName());
|
||||
|
||||
Room saved = roomRepository.save(room);
|
||||
return RoomResponse.fromEntity(saved, rtmpHost, rtmpPort, httpHost, httpPort);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新直播状态(供SRS回调使用)
|
||||
*/
|
||||
@Transactional
|
||||
public Optional<Room> setLiveStatus(String streamKey, boolean isLive) {
|
||||
return roomRepository.findByStreamKey(streamKey)
|
||||
.map(room -> {
|
||||
room.setLive(isLive);
|
||||
room.setStartedAt(isLive ? LocalDateTime.now() : null);
|
||||
return roomRepository.save(room);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除直播间
|
||||
*/
|
||||
@Transactional
|
||||
public boolean deleteRoom(String id) {
|
||||
if (roomRepository.existsById(id)) {
|
||||
roomRepository.deleteById(id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
server:
|
||||
port: 3001
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: livestreaming-backend
|
||||
|
||||
# 数据库配置 - 默认使用H2内存数据库(开发测试)
|
||||
# 如需使用MySQL,请取消下方注释并配置
|
||||
datasource:
|
||||
# H2 内存数据库(开发测试用,无需安装)
|
||||
url: jdbc:h2:file:./data/livestream;AUTO_SERVER=TRUE
|
||||
driver-class-name: org.h2.Driver
|
||||
username: sa
|
||||
password:
|
||||
|
||||
# MySQL 配置(生产环境使用)
|
||||
# url: jdbc:mysql://localhost:3306/livestream?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
||||
# driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
# username: root
|
||||
# password: your_password
|
||||
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
show-sql: true
|
||||
properties:
|
||||
hibernate:
|
||||
format_sql: true
|
||||
|
||||
# H2 控制台(开发时可访问 http://localhost:3001/h2-console)
|
||||
h2:
|
||||
console:
|
||||
enabled: true
|
||||
path: /h2-console
|
||||
|
||||
# 直播服务配置
|
||||
livestream:
|
||||
rtmp:
|
||||
host: localhost
|
||||
port: 1935
|
||||
http:
|
||||
host: localhost
|
||||
port: 8080
|
||||
|
||||
# 日志配置
|
||||
logging:
|
||||
level:
|
||||
com.example.livestreaming: DEBUG
|
||||
org.hibernate.SQL: DEBUG
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
server:
|
||||
port: 3001
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: livestreaming-backend
|
||||
|
||||
# 数据库配置 - 默认使用H2内存数据库(开发测试)
|
||||
# 如需使用MySQL,请取消下方注释并配置
|
||||
datasource:
|
||||
# H2 内存数据库(开发测试用,无需安装)
|
||||
url: jdbc:h2:file:./data/livestream;AUTO_SERVER=TRUE
|
||||
driver-class-name: org.h2.Driver
|
||||
username: sa
|
||||
password:
|
||||
|
||||
# MySQL 配置(生产环境使用)
|
||||
# url: jdbc:mysql://localhost:3306/livestream?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
||||
# driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
# username: root
|
||||
# password: your_password
|
||||
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
show-sql: true
|
||||
properties:
|
||||
hibernate:
|
||||
format_sql: true
|
||||
|
||||
# H2 控制台(开发时可访问 http://localhost:3001/h2-console)
|
||||
h2:
|
||||
console:
|
||||
enabled: true
|
||||
path: /h2-console
|
||||
|
||||
# 直播服务配置
|
||||
livestream:
|
||||
rtmp:
|
||||
host: localhost
|
||||
port: 1935
|
||||
http:
|
||||
host: localhost
|
||||
port: 8080
|
||||
|
||||
# 日志配置
|
||||
logging:
|
||||
level:
|
||||
com.example.livestreaming: DEBUG
|
||||
org.hibernate.SQL: DEBUG
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user