You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
RTSPtoWeb/JAVA_INTEGRATION.md

16 KiB

Java项目集成RTSPtoWeb指南

本文档说明如何将RTSPtoWeb项目集成到Java项目中实现摄像头管理和视频流展示功能。

集成方案

方案一:嵌入式集成(推荐)

将RTSPtoWeb的前端页面嵌入到Java Web项目中通过iframe或直接集成HTML。

1. 嵌入整个管理界面

<!-- 嵌入RTSPtoWeb完整界面 -->
<iframe src="http://localhost:8083" 
        width="100%" 
        height="800px" 
        frameborder="0">
</iframe>

2. 嵌入特定功能页面

<!-- 仅嵌入摄像头管理页面 -->
<iframe src="http://localhost:8083/pages/cameras" 
        width="100%" 
        height="600px" 
        frameborder="0">
</iframe>

<!-- 仅嵌入视频流列表 -->
<iframe src="http://localhost:8083/" 
        width="100%" 
        height="600px" 
        frameborder="0">
</iframe>

方案二API集成

通过REST API调用RTSPtoWeb的功能在Java项目中实现自定义界面。

Java HTTP客户端示例

import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;

public class RTSPtoWebClient {
    private final String baseUrl;
    private final HttpClient httpClient;
    private final ObjectMapper objectMapper;
    
    public RTSPtoWebClient(String baseUrl) {
        this.baseUrl = baseUrl;
        this.httpClient = HttpClient.newHttpClient();
        this.objectMapper = new ObjectMapper();
    }
    
    // 获取所有摄像头
    public JsonNode getAllCameras() throws Exception {
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(baseUrl + "/cameras"))
            .GET()
            .build();
            
        HttpResponse<String> response = httpClient.send(request, 
            HttpResponse.BodyHandlers.ofString());
            
        if (response.statusCode() == 200) {
            return objectMapper.readTree(response.body());
        } else {
            throw new RuntimeException("Failed to get cameras: " + response.statusCode());
        }
    }
    
    // 根据单位代码获取摄像头
    public JsonNode getCamerasByUnitCode(String unitCode) throws Exception {
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(baseUrl + "/cameras/unit/" + unitCode))
            .GET()
            .build();
            
        HttpResponse<String> response = httpClient.send(request, 
            HttpResponse.BodyHandlers.ofString());
            
        if (response.statusCode() == 200) {
            return objectMapper.readTree(response.body());
        } else {
            throw new RuntimeException("Failed to get cameras by unit: " + response.statusCode());
        }
    }
    
    // 获取特定摄像头信息
    public JsonNode getCamera(String cameraId) throws Exception {
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(baseUrl + "/camera/" + cameraId))
            .GET()
            .build();
            
        HttpResponse<String> response = httpClient.send(request, 
            HttpResponse.BodyHandlers.ofString());
            
        if (response.statusCode() == 200) {
            return objectMapper.readTree(response.body());
        } else {
            throw new RuntimeException("Failed to get camera: " + response.statusCode());
        }
    }
    
    // 添加摄像头
    public JsonNode addCamera(CameraData cameraData) throws Exception {
        String jsonBody = objectMapper.writeValueAsString(cameraData);
        
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(baseUrl + "/camera/add"))
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(jsonBody))
            .build();
            
        HttpResponse<String> response = httpClient.send(request, 
            HttpResponse.BodyHandlers.ofString());
            
        if (response.statusCode() == 200) {
            return objectMapper.readTree(response.body());
        } else {
            throw new RuntimeException("Failed to add camera: " + response.statusCode());
        }
    }
    
    // 更新摄像头
    public JsonNode updateCamera(String cameraId, CameraData cameraData) throws Exception {
        String jsonBody = objectMapper.writeValueAsString(cameraData);
        
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(baseUrl + "/camera/" + cameraId))
            .header("Content-Type", "application/json")
            .PUT(HttpRequest.BodyPublishers.ofString(jsonBody))
            .build();
            
        HttpResponse<String> response = httpClient.send(request, 
            HttpResponse.BodyHandlers.ofString());
            
        if (response.statusCode() == 200) {
            return objectMapper.readTree(response.body());
        } else {
            throw new RuntimeException("Failed to update camera: " + response.statusCode());
        }
    }
    
    // 删除摄像头
    public boolean deleteCamera(String cameraId) throws Exception {
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(baseUrl + "/camera/" + cameraId))
            .DELETE()
            .build();
            
        HttpResponse<String> response = httpClient.send(request, 
            HttpResponse.BodyHandlers.ofString());
            
        return response.statusCode() == 200;
    }
    
    // 刷新摄像头状态
    public JsonNode refreshCameras() throws Exception {
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(baseUrl + "/cameras/refresh"))
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString("{}"))
            .build();
            
        HttpResponse<String> response = httpClient.send(request, 
            HttpResponse.BodyHandlers.ofString());
            
        if (response.statusCode() == 200) {
            return objectMapper.readTree(response.body());
        } else {
            throw new RuntimeException("Failed to refresh cameras: " + response.statusCode());
        }
    }
    
    // 获取视频流列表
    public JsonNode getStreams() throws Exception {
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(baseUrl + "/streams"))
            .GET()
            .build();
            
        HttpResponse<String> response = httpClient.send(request, 
            HttpResponse.BodyHandlers.ofString());
            
        if (response.statusCode() == 200) {
            return objectMapper.readTree(response.body());
        } else {
            throw new RuntimeException("Failed to get streams: " + response.statusCode());
        }
    }
    
    // 生成播放URL
    public String getPlayUrl(String cameraId, int channel, String type) {
        switch (type.toLowerCase()) {
            case "hls":
                return baseUrl + "/stream/" + cameraId + "/channel/" + channel + "/hls/live/index.m3u8";
            case "webrtc":
                return baseUrl + "/pages/player/webrtc/" + cameraId + "/" + channel;
            case "mse":
                return baseUrl + "/pages/player/mse/" + cameraId + "/" + channel;
            default:
                return baseUrl + "/pages/player/all/" + cameraId + "/" + channel;
        }
    }
}

// 摄像头数据模型
class CameraData {
    public String name;
    public String ip;
    public int port = 554;
    public String username;
    public String password;
    public String rtsp_url;
    public String camera_produce;
    public String device_type;
    public String unit_code;
    public String nvr_produce;
    public String nvr_path;
    public String play_back;
    public boolean enabled = true;
    public int user_id;
    public int dept_id;
    
    // 构造函数、getter和setter方法
    public CameraData() {}
    
    public CameraData(String name, String ip, String username, String password, String rtspUrl) {
        this.name = name;
        this.ip = ip;
        this.username = username;
        this.password = password;
        this.rtsp_url = rtspUrl;
    }
}

Spring Boot Controller示例

import org.springframework.web.bind.annotation.*;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import com.fasterxml.jackson.databind.JsonNode;

@Controller
@RequestMapping("/camera")
public class CameraController {
    
    private final RTSPtoWebClient rtspClient;
    
    public CameraController() {
        this.rtspClient = new RTSPtoWebClient("http://localhost:8083");
    }
    
    // 摄像头管理页面
    @GetMapping("/management")
    public String cameraManagement(Model model) {
        try {
            JsonNode cameras = rtspClient.getAllCameras();
            model.addAttribute("cameras", cameras);
        } catch (Exception e) {
            model.addAttribute("error", "获取摄像头列表失败: " + e.getMessage());
        }
        return "camera/management";
    }
    
    // 根据单位获取摄像头
    @GetMapping("/unit/{unitCode}")
    @ResponseBody
    public JsonNode getCamerasByUnit(@PathVariable String unitCode) {
        try {
            return rtspClient.getCamerasByUnitCode(unitCode);
        } catch (Exception e) {
            throw new RuntimeException("获取摄像头失败", e);
        }
    }
    
    // 视频监控页面
    @GetMapping("/monitor")
    public String videoMonitor(Model model) {
        try {
            JsonNode cameras = rtspClient.getAllCameras();
            model.addAttribute("cameras", cameras);
        } catch (Exception e) {
            model.addAttribute("error", "获取摄像头列表失败: " + e.getMessage());
        }
        return "camera/monitor";
    }
    
    // 添加摄像头
    @PostMapping("/add")
    @ResponseBody
    public JsonNode addCamera(@RequestBody CameraData cameraData) {
        try {
            return rtspClient.addCamera(cameraData);
        } catch (Exception e) {
            throw new RuntimeException("添加摄像头失败", e);
        }
    }
    
    // 获取播放URL
    @GetMapping("/{cameraId}/play-url")
    @ResponseBody
    public String getPlayUrl(@PathVariable String cameraId, 
                           @RequestParam(defaultValue = "0") int channel,
                           @RequestParam(defaultValue = "hls") String type) {
        return rtspClient.getPlayUrl(cameraId, channel, type);
    }
}

方案三前端JavaScript集成

在Java项目的前端页面中直接使用RTSPtoWeb提供的JavaScript API。

<!DOCTYPE html>
<html>
<head>
    <title>视频监控系统</title>
    <script src="http://localhost:8083/static/js/camera-manager.js"></script>
</head>
<body>
    <div id="camera-container"></div>
    
    <script>
        // 使用RTSPtoWeb提供的全局API
        async function loadCameras() {
            try {
                const data = await window.RTSPtoWebAPI.getCameras();
                displayCameras(data.cameras);
            } catch (error) {
                console.error('加载摄像头失败:', error);
            }
        }
        
        function displayCameras(cameras) {
            const container = document.getElementById('camera-container');
            container.innerHTML = '';
            
            cameras.forEach(camera => {
                const div = document.createElement('div');
                div.innerHTML = `
                    <h3>${camera.name}</h3>
                    <p>IP: ${camera.ip}</p>
                    <p>状态: ${camera.status}</p>
                    <button onclick="playCamera('${camera.id}', 'hls')">HLS播放</button>
                    <button onclick="playCamera('${camera.id}', 'webrtc')">WebRTC播放</button>
                `;
                container.appendChild(div);
            });
        }
        
        function playCamera(cameraId, type) {
            const url = window.RTSPtoWebAPI.getPlayUrl(cameraId, 0, type);
            window.open(url, '_blank');
        }
        
        // 页面加载时获取摄像头列表
        document.addEventListener('DOMContentLoaded', loadCameras);
    </script>
</body>
</html>

部署配置

1. RTSPtoWeb服务配置

确保RTSPtoWeb服务正常运行

# 启动RTSPtoWeb服务
cd RTSPtoWeb
go run . --config config.json

2. 跨域配置

如果Java项目和RTSPtoWeb运行在不同端口需要配置CORS

在RTSPtoWeb的apiHTTPServer.go中添加CORS中间件

func CORSMiddleware() gin.HandlerFunc {
    return gin.HandlerFunc(func(c *gin.Context) {
        c.Header("Access-Control-Allow-Origin", "*")
        c.Header("Access-Control-Allow-Credentials", "true")
        c.Header("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
        c.Header("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, DELETE")

        if c.Request.Method == "OPTIONS" {
            c.AbortWithStatus(204)
            return
        }

        c.Next()
    })
}

3. 反向代理配置

使用Nginx反向代理统一端口

server {
    listen 80;
    server_name your-domain.com;
    
    # Java应用
    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
    
    # RTSPtoWeb API
    location /rtsp-api/ {
        proxy_pass http://localhost:8083/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
    
    # WebSocket支持
    location /rtsp-api/stream/ {
        proxy_pass http://localhost:8083/stream/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
    }
}

API接口文档

摄像头管理API

方法 路径 描述
GET /cameras 获取所有摄像头列表
GET /cameras/unit/{unitcode} 根据单位代码获取摄像头
GET /camera/{id} 获取特定摄像头信息
POST /camera/add 添加新摄像头
PUT /camera/{id} 更新摄像头信息
DELETE /camera/{id} 删除摄像头
POST /cameras/refresh 刷新摄像头状态

视频流API

方法 路径 描述
GET /streams 获取所有视频流列表
GET /stream/{id}/channel/{channel}/hls/live/index.m3u8 HLS播放地址
GET /pages/player/webrtc/{id}/{channel} WebRTC播放页面
GET /pages/player/mse/{id}/{channel} MSE播放页面
GET /pages/player/all/{id}/{channel} 通用播放页面

注意事项

  1. 数据库配置确保RTSPtoWeb的数据库配置正确摄像头数据存储在数据库中。

  2. 网络配置确保Java项目能够访问RTSPtoWeb服务的端口默认8083

  3. 安全考虑:在生产环境中,建议配置认证和授权机制。

  4. 性能优化:对于大量摄像头的场景,建议实现分页和缓存机制。

  5. 错误处理:实现完善的错误处理和重试机制。

  6. 监控告警:建议添加服务健康检查和告警机制。

示例项目结构

java-rtsp-integration/
├── src/main/java/
│   ├── controller/
│   │   ├── CameraController.java
│   │   └── VideoController.java
│   ├── service/
│   │   ├── RTSPtoWebClient.java
│   │   └── CameraService.java
│   └── model/
│       └── CameraData.java
├── src/main/resources/
│   ├── templates/
│   │   ├── camera/
│   │   │   ├── management.html
│   │   │   └── monitor.html
│   │   └── layout.html
│   └── static/
│       ├── css/
│       └── js/
└── pom.xml

通过以上集成方案可以在Java项目中完整地使用RTSPtoWeb的摄像头管理和视频流功能。