diff --git a/src/main/java/com/tuoheng/WvpClient.java b/src/main/java/com/tuoheng/WvpClient.java index 7f3e10e..fbef06c 100644 --- a/src/main/java/com/tuoheng/WvpClient.java +++ b/src/main/java/com/tuoheng/WvpClient.java @@ -1,4 +1,177 @@ package com.tuoheng; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; + +/** + * WVP 视频平台客户端 + * 用于调用 WVP 后端服务的 API + */ public class WvpClient { + + public static void main(String[] args) throws Exception { + + WvpTokenClient.LoginResponse loginResponse = WvpTokenClient.login("admin", "admin"); + System.out.println("登录响应结果:"); + System.out.println(loginResponse); + System.out.println("\nAccess Token: " + loginResponse.getData().getAccessToken()); + + WvpClient client = new WvpClient("http://114.67.89.4:9090",loginResponse.getData().getAccessToken()); + JsonNode result = client.getPushList(); + + } + + private final String wvpBaseUrl; + private final String accessToken; + private final HttpClient httpClient; + private final ObjectMapper objectMapper; + + /** + * 构造函数 + * + * @param wvpBaseUrl WVP 服务器地址,例如: http://114.67.89.4:9090 + * @param accessToken WVP 访问令牌 + */ + public WvpClient(String wvpBaseUrl, String accessToken) { + this.wvpBaseUrl = wvpBaseUrl; + this.accessToken = accessToken; + this.httpClient = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(10)) + .build(); + this.objectMapper = new ObjectMapper(); + } + + /** + * 获取推流列表 + * + * @param page 当前页,默认 1 + * @param count 每页数量,默认 10 + * @param query 查询内容(可选) + * @param pushing 是否只显示正在推流的,默认 true + * @param mediaServerId 流媒体服务器ID(可选) + * @return 推流列表的 JSON 响应 + * @throws Exception 请求失败时抛出异常 + */ + public JsonNode getPushList(int page, int count, String query, Boolean pushing, String mediaServerId) throws Exception { + // 构建查询参数 + Map params = new HashMap<>(); + params.put("page", String.valueOf(page)); + params.put("count", String.valueOf(count)); + + if (query != null && !query.isEmpty()) { + params.put("query", query); + } + if (pushing != null) { + params.put("pushing", pushing.toString()); + } + if (mediaServerId != null && !mediaServerId.isEmpty()) { + params.put("mediaServerId", mediaServerId); + } + + // 构建 URL + String url = buildUrl("/api/push/list", params); + + // 发送 GET 请求 + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(url)) + .header("access-token", accessToken) + .header("Content-Type", "application/json") + .GET() + .timeout(Duration.ofSeconds(30)) + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + + // 检查响应状态 + if (response.statusCode() != 200) { + throw new RuntimeException("获取推流列表失败,状态码: " + response.statusCode() + ", 响应: " + response.body()); + } + + // 解析 JSON 响应 + return objectMapper.readTree(response.body()); + } + + /** + * 获取推流列表(使用默认参数) + * + * @return 推流列表的 JSON 响应 + * @throws Exception 请求失败时抛出异常 + */ + public JsonNode getPushList() throws Exception { + return getPushList(1, 10, null, true, null); + } + + /** + * 获取播放地址 + * + * @param id 推流ID(从推流列表中获取) + * @return 播放地址的 JSON 响应,包含 FLV、HLS、WebRTC、RTMP、RTSP 等多种格式的播放地址 + * @throws Exception 请求失败时抛出异常 + */ + public JsonNode getPushStart(int id) throws Exception { + // 构建查询参数 + Map params = new HashMap<>(); + params.put("id", String.valueOf(id)); + + // 构建 URL + String url = buildUrl("/api/push/start", params); + + // 发送 GET 请求 + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(url)) + .header("access-token", accessToken) + .header("Content-Type", "application/json") + .GET() + .timeout(Duration.ofSeconds(30)) + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + + // 检查响应状态 + if (response.statusCode() != 200) { + throw new RuntimeException("获取播放地址失败,状态码: " + response.statusCode() + ", 响应: " + response.body()); + } + + // 解析 JSON 响应 + return objectMapper.readTree(response.body()); + } + + /** + * 构建带查询参数的 URL + * + * @param path API 路径 + * @param params 查询参数 + * @return 完整的 URL + */ + private String buildUrl(String path, Map params) { + StringBuilder url = new StringBuilder(wvpBaseUrl); + url.append(path); + + if (params != null && !params.isEmpty()) { + url.append("?"); + params.forEach((key, value) -> { + url.append(key).append("=").append(value).append("&"); + }); + // 移除最后一个 & + url.setLength(url.length() - 1); + } + + return url.toString(); + } + + /** + * 关闭 HTTP 客户端(如果需要) + */ + public void close() { + // HttpClient 会自动管理连接池,通常不需要手动关闭 + } } diff --git a/src/main/java/com/tuoheng/WvpTokenClient.java b/src/main/java/com/tuoheng/WvpTokenClient.java new file mode 100644 index 0000000..2d6a92b --- /dev/null +++ b/src/main/java/com/tuoheng/WvpTokenClient.java @@ -0,0 +1,289 @@ +package com.tuoheng; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import com.google.gson.Gson; + +public class WvpTokenClient { + + private static final String WVP_BASE_URL = "http://114.67.89.4:9090"; + private static final Gson gson = new Gson(); + + /** + * WVP登录响应对象 + */ + public static class LoginResponse { + private int code; + private String msg; + private LoginData data; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public LoginData getData() { + return data; + } + + public void setData(LoginData data) { + this.data = data; + } + + @Override + public String toString() { + return gson.toJson(this); + } + } + + /** + * 登录数据对象 + */ + public static class LoginData { + private String accessToken; + private String serverId; + private int id; + private boolean enabled; + private String password; + private Role role; + private String username; + private String pushKey; + private boolean accountNonExpired; + private boolean accountNonLocked; + private boolean credentialsNonExpired; + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public String getServerId() { + return serverId; + } + + public void setServerId(String serverId) { + this.serverId = serverId; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public Role getRole() { + return role; + } + + public void setRole(Role role) { + this.role = role; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPushKey() { + return pushKey; + } + + public void setPushKey(String pushKey) { + this.pushKey = pushKey; + } + + public boolean isAccountNonExpired() { + return accountNonExpired; + } + + public void setAccountNonExpired(boolean accountNonExpired) { + this.accountNonExpired = accountNonExpired; + } + + public boolean isAccountNonLocked() { + return accountNonLocked; + } + + public void setAccountNonLocked(boolean accountNonLocked) { + this.accountNonLocked = accountNonLocked; + } + + public boolean isCredentialsNonExpired() { + return credentialsNonExpired; + } + + public void setCredentialsNonExpired(boolean credentialsNonExpired) { + this.credentialsNonExpired = credentialsNonExpired; + } + } + + /** + * 角色对象 + */ + public static class Role { + private int id; + private String name; + private String authority; + private String createTime; + private String updateTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAuthority() { + return authority; + } + + public void setAuthority(String authority) { + this.authority = authority; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(String updateTime) { + this.updateTime = updateTime; + } + } + + /** + * 计算MD5哈希值 + * + * @param input 输入字符串 + * @return MD5哈希值(小写) + * @throws Exception 如果计算失败 + */ + private static String md5(String input) throws Exception { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] messageDigest = md.digest(input.getBytes(StandardCharsets.UTF_8)); + StringBuilder hexString = new StringBuilder(); + for (byte b : messageDigest) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + return hexString.toString(); + } + + /** + * WVP用户登录 + * + * @param username 用户名 + * @param password 密码(明文) + * @return 登录响应对象 + * @throws Exception 如果请求失败 + */ + public static LoginResponse login(String username, String password) throws Exception { + // 计算密码的MD5值 + String passwordMd5 = md5(password); + + // 构建 URL 参数 + StringBuilder urlBuilder = new StringBuilder(WVP_BASE_URL); + urlBuilder.append("/api/user/login?"); + urlBuilder.append("username=").append(URLEncoder.encode(username, StandardCharsets.UTF_8.name())); + urlBuilder.append("&password=").append(passwordMd5); + + // 创建 HTTP 连接 + URL url = new URL(urlBuilder.toString()); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.setConnectTimeout(10000); + connection.setReadTimeout(10000); + + // 获取响应 + int responseCode = connection.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8)); + StringBuilder response = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + response.append(line); + } + reader.close(); + + // 解析JSON响应 + return gson.fromJson(response.toString(), LoginResponse.class); + } else { + throw new Exception("HTTP 请求失败,状态码: " + responseCode); + } + } + + public static void main(String[] args) { + try { + // 调用 login 方法 + LoginResponse loginResponse = login("admin", "admin"); + System.out.println("登录响应结果:"); + System.out.println(loginResponse); + System.out.println("\nAccess Token: " + loginResponse.getData().getAccessToken()); + System.out.println("Username: " + loginResponse.getData().getUsername()); + System.out.println("Role: " + loginResponse.getData().getRole().getName()); + } catch (Exception e) { + System.err.println("登录失败: " + e.getMessage()); + e.printStackTrace(); + } + } +}