package com.fzzy.igds.camera.impl; import com.alibaba.fastjson.JSONObject; import com.fzzy.igds.camera.AbstractApiCameraService; import com.fzzy.igds.camera.data.*; import com.fzzy.igds.camera.data.ydqly.YdQlyCamera; import com.fzzy.igds.camera.data.ydqly.YdQlyDto; import com.fzzy.igds.camera.data.ydqly.YdQlyResp; import com.fzzy.igds.constant.CameraPlayType; import com.fzzy.igds.constant.Constant; import com.fzzy.igds.constant.RedisConst; import com.fzzy.igds.domain.Camera; import com.fzzy.igds.domain.CameraMedia; import com.fzzy.igds.service.CameraMediaService; import com.fzzy.igds.service.SecCameraService; import com.fzzy.igds.utils.ContextUtil; import com.fzzy.igds.utils.HttpUtils; import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.utils.StringUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.*; import java.util.concurrent.TimeUnit; import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.digest.DigestUtils; import java.security.*; import java.security.spec.PKCS8EncodedKeySpec; /** * @Desc 移动千里眼播放 * @Author CZT * @Date 2026/01/04 16:09 */ @Slf4j @Component public class ApiPlayYdQlyService extends AbstractApiCameraService { /** * 获取accessToken接口路径 */ private static final String URL_ACCESS_TOKEN = "https://open.qly.cmviot.cn/v3/open/api/token"; private static final String URL_PLAY_LIVE = "https://open.qly.cmviot.cn/v3/open/api/websdk/live"; private static final String URL_CAMERA_LIST = "https://open.qly.cmviot.cn/v3/open/api/node/tree"; @Resource private CameraMediaService cameraMediaService; @Resource private SecCameraService cameraService; @Resource private RedisCache redisCache; @Override public String getType() { return CameraPlayType.PLAY_TYPE_YD_QLY.getCode(); } @Override public ApiCameraResp getPlayAddr(ApiCameraData apiCameraDto) { if (StringUtils.isBlank(apiCameraDto.getCameraId())) { log.error("获取摄像头信息失败,监控ID为空!"); return null; } if (StringUtils.isBlank(apiCameraDto.getDeptId())) { log.error("获取摄像头信息失败,库区编码为空!"); return null; } //查询库区流媒体配置,获取库区节点 CameraMedia cameraMedia = cameraMediaService.getByDeptId(apiCameraDto.getDeptId(), apiCameraDto.getCompanyId()); if(null == cameraMedia || StringUtils.isBlank(cameraMedia.getYdStoreId())){ log.error("获取摄像头信息失败,库区节点未配置!"); return null; } //接口获取播放地址 YdQlyResp resp = getPlayUrl(cameraMedia, apiCameraDto.getCameraId()); if(!"000000".equals(resp.getResultCode())){ return new ApiCameraResp(ApiCameraResp.CODE_ERROR, resp.getResultMsg()); } YdQlyDto dto = JSONObject.parseObject(resp.getData(), YdQlyDto.class); if (null == dto || StringUtils.isBlank(dto.getUrl())) { return new ApiCameraResp(ApiCameraResp.CODE_ERROR, "未获取到摄像头播放地址!"); } return new ApiCameraResp(dto.getUrl()); } @Override public List searchCamera(ApiCameraData apiCameraDto) { if (StringUtils.isEmpty(apiCameraDto.getDeptId())) { log.error("获取摄像头信息失败,库区编码为空!"); return null; } //查询库区流媒体配置,获取库区节点 CameraMedia cameraMedia = cameraMediaService.getByDeptId(apiCameraDto.getDeptId(), apiCameraDto.getCompanyId()); if(null == cameraMedia || StringUtils.isEmpty(cameraMedia.getYdStoreId())){ log.error("获取摄像头信息失败,库区节点未配置!"); return null; } String str = getCameraList(cameraMedia); if(null== str){ log.error("获取摄像头信息失败,库区节点未配置!"); return null; } YdQlyDto ydQlyDto = JSONObject.parseObject(str, YdQlyDto.class); if(null== ydQlyDto || null == ydQlyDto.getDevice()){ log.error("获取摄像头信息失败,库区节点未配置!"); return null; } //持久化 List listCamera = new ArrayList<>(); Camera camera; for (YdQlyCamera dto : ydQlyDto.getDevice()) { camera = new Camera(); camera.setId(dto.getDeviceId()); camera.setCompanyId(cameraMedia.getCompanyId()); camera.setDeptId(cameraMedia.getDeptId()); camera.setSn(dto.getDeviceId()); camera.setName(dto.getDeviceName()); camera.setType("01"); camera.setPlayType(CameraPlayType.PLAY_TYPE_YD_QLY.getCode()); cameraService.pullUpdateCamera(camera); } return listCamera; } /** * 获取accessToken * * @param cameraMedia * @return */ private String getAccessToken(CameraMedia cameraMedia) { //默认先从缓存获取 String key = RedisConst.buildKey(ContextUtil.getCompanyId(), Constant.KEY_ACCESS_TOKEN_YD_QLY); String accessToken = (String) redisCache.getCacheObject(key); //若缓存获取为空,则通过接口请求获取 if (null == accessToken) { String result = getAccessTokenApi(cameraMedia); YdQlyDto dto = JSONObject.parseObject(result, YdQlyDto.class); if (null == dto) { return null; } accessToken = dto.getToken(); Integer expiresIn = dto.getExpires_in(); //将token存入缓存,默认7天 redisCache.setCacheObject(key, accessToken, 7*60*24, TimeUnit.MINUTES); } return accessToken; } /** * 接口获取授权accessToken * @param cameraMedia * @return */ private String getAccessTokenApi(CameraMedia cameraMedia) { try { String timestamp = String.valueOf(System.currentTimeMillis()); String sig = Hex.encodeHexString(MessageDigest.getInstance("MD5").digest(StringUtils.getBytes(cameraMedia.getYdAppKey()+cameraMedia.getYdAppSecret(),"UTF-8"))); JSONObject requestBody = new JSONObject(); requestBody.put("operatorType", 1); requestBody.put("sig", sig); String requestBodyStr = requestBody.toString(); // 2. 计算请求体MD5 String md5 = DigestUtils.md5Hex(String.valueOf(requestBody)); // 3. 构建签名字符串 LinkedHashMap herderParams = new LinkedHashMap<>(); herderParams.put("appid", cameraMedia.getYdAppKey()); herderParams.put("md5", md5); herderParams.put("timestamp", timestamp); herderParams.put("version", "1.0.0"); String jsonString = JSONObject.toJSONString(herderParams); // 4. RSA签名 byte[] keyBytes = Base64.getDecoder().decode(cameraMedia.getYdRsa()); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); PrivateKey priKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec); Signature signature = Signature.getInstance("SHA1WithRSA"); signature.initSign(priKey); signature.update(jsonString.getBytes("UTF-8")); String signatureString = Base64.getEncoder().encodeToString(signature.sign()); herderParams.put("signature", signatureString); herderParams.put("content-type", "application/json"); // 5. 发送请求 String response = HttpUtils.doPost(URL_ACCESS_TOKEN, herderParams, requestBodyStr); YdQlyResp ydQlyResp = JSONObject.parseObject(response, YdQlyResp.class); if(!"000000".equals(ydQlyResp.getResultCode())){ return null; } return ydQlyResp.getData(); } catch (Exception e) { log.error("-----获取身份认证异常-----,原因={}", e.toString()); return null; } } /** * 接口获取播放地址 * @param cameraMedia * @param cameraId * @return */ private YdQlyResp getPlayUrl(CameraMedia cameraMedia, String cameraId) { try { String timestamp = String.valueOf(System.currentTimeMillis()); JSONObject requestBody = new JSONObject(); requestBody.put("deviceId", cameraId); String requestBodyStr = requestBody.toString(); // 2. 计算请求体MD5 String md5 = DigestUtils.md5Hex(String.valueOf(requestBody)); // 3. 构建签名字符串 LinkedHashMap herderParams = new LinkedHashMap<>(); herderParams.put("appid", cameraMedia.getYdAppKey()); herderParams.put("md5", md5); herderParams.put("timestamp", timestamp); herderParams.put("token", getAccessToken(cameraMedia)); herderParams.put("version", "1.0.0"); String jsonString = JSONObject.toJSONString(herderParams); // 4. RSA签名 byte[] keyBytes = Base64.getDecoder().decode(PRIVATE_KEY); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); PrivateKey priKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec); Signature signature = Signature.getInstance("SHA1WithRSA"); signature.initSign(priKey); signature.update(jsonString.getBytes("UTF-8")); String signatureString = Base64.getEncoder().encodeToString(signature.sign()); herderParams.put("signature", signatureString); herderParams.put("content-type", "application/json"); // 5. 发送请求 String response = HttpUtils.doPost(URL_PLAY_LIVE, herderParams, requestBodyStr); YdQlyResp ydQlyResp = JSONObject.parseObject(response, YdQlyResp.class); return ydQlyResp; } catch (Exception e) { return null; } } /** * 接口获取播放地址 * @param cameraMedia * @return */ private String getCameraList(CameraMedia cameraMedia) { try { String timestamp = String.valueOf(System.currentTimeMillis()); JSONObject requestBody = new JSONObject(); requestBody.put("queryType", 0); requestBody.put("page", 1); requestBody.put("pageSize", 100); requestBody.put("nodeId", cameraMedia.getYdStoreId()); String requestBodyStr = requestBody.toString(); // 2. 计算请求体MD5 String md5 = DigestUtils.md5Hex(String.valueOf(requestBody)); // 3. 构建签名字符串 LinkedHashMap herderParams = new LinkedHashMap<>(); herderParams.put("appid", cameraMedia.getYdAppKey()); herderParams.put("md5", md5); herderParams.put("timestamp", timestamp); herderParams.put("token", getAccessToken(cameraMedia)); herderParams.put("version", "1.0.0"); String jsonString = JSONObject.toJSONString(herderParams); // 4. RSA签名 byte[] keyBytes = Base64.getDecoder().decode(PRIVATE_KEY); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); PrivateKey priKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec); Signature signature = Signature.getInstance("SHA1WithRSA"); signature.initSign(priKey); signature.update(jsonString.getBytes("UTF-8")); String signatureString = Base64.getEncoder().encodeToString(signature.sign()); herderParams.put("signature", signatureString); herderParams.put("content-type", "application/json"); // 5. 发送请求 String response = HttpUtils.doPost(URL_CAMERA_LIST, herderParams, requestBodyStr); YdQlyResp ydQlyResp = JSONObject.parseObject(response, YdQlyResp.class); if(!"000000".equals(ydQlyResp.getResultCode())){ return null; } return ydQlyResp.getData(); } catch (Exception e) { return null; } } private static final String TOKEN = "eyJhbGciOiJIUzI1NiJ9.eyJwcm9mZXNzaW9uIjoxLCJhcHBpZCI6ImUwYTFhNDIwZjU1YTRmOWRiYTBkNjM4MmRmNTlkYjY2Iiwib3BlcmF0b3JUeXBlIjoxLCJvcGVyYXRvciI6ImUwYTFhNDIwZjU1YTRmOWRiYTBkNjM4MmRmNTlkYjY2IiwianRpIjoiMjE4Nzk0MzMzMTE4NDM1NzM4NyIsImlhdCI6MTc2NzYxMDM3Mywic3ViIjoiZTBhMWE0MjBmNTVhNGY5ZGJhMGQ2MzgyZGY1OWRiNjYiLCJleHAiOjE3NjgyMTUxNzN9.Tot-yYsNLbY9YH2AYgV_Fggb7PCNrUR0PDi0Ear1s5w"; private static final String APP_ID = "e0a1a420f55a4f9dba0d6382df59db66"; private static final String SECRET = "OuLsvFL9nqxeeltu"; private static final String URL = "https://open.qly.cmviot.cn/v3/open/api/token"; private static final String URL_PLAY = "https://open.qly.cmviot.cn/v3/open/api/websdk/live"; private static final String URL_LIST = "https://open.qly.cmviot.cn/v3/open/api/node/tree"; private static final String PRIVATE_KEY = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAI7iA0WASV8pekjHVcsYV3ycZR2/+XK7O6BZpybAw/cauEzHRKsrDknErFxdNFca1OlVbPljBOfXjIrhS1CpAWez3Ff2+XaAaFE3fFer9LTxQ5GMXJSIAGQ4ntq/7y57ucwdVjL9+4B4WT8Yfea1DLa/fv+I0Gm7haVQj75JVYhBAgMBAAECgYAfvBs16JRjSncaiwuHHFTyHFppDSZ+UQ+hQchaVx4vWAPvKaMa0WlPARu3OAxT/GWlnY+ipFeGlt1kSz3LIH5rERYd5sNPOFmK7Nzih1VK6r/y1XobM4cLqLrP2UW2c3V36A77xz1xpaa9CP5l6gFjYAdZ1vnGS7HyjolWvzjUAQJBAMB6OTwrHcxOUJiLRJSK697LMIziBi1p5cR4NdSoQjQ4/enUqzAalwi6ZODuGSYai5VKhH9xkxFASWMT8waTOxECQQC+CbWK4Igx8Uh5qPpBIiFuA6ReAuFoRDMvKlzPUi8FGFkvF/CDx5IUFvYUd7FFX4l6Wtu5vf+VF3OydmzFr5oxAkB96Xa3nZ0IodKnd7ONWLOkM1e3UcSowLXGKL1OOCPW9dFkvfKerUZQN172pctd2c+mAfFbTXjfuCZJ4isBCh+BAkA8+ZiKaujIPYbnolRJuc3IItsGXx47+kYCCDGnQ9NaaymSdrfxUIOKdqOWhaEXhUPzQlvmCRSMne29gUn9VA7BAkBLvhtfSuANFSDt942GAY0Q25bJBM01yrRjtTEVCnGDxztexksPKaWGnJxk0Zk0xp4PkJCZvVuxFZ1Dw7F9yg6X"; public static void main(String[] args) { // String accessToken = getAccessTokenTest(); // System.out.println("accessToken: " + accessToken); // String playUrl = getPlayUrlTest(); // System.out.println("playUrl: " + playUrl); String cameraList = getCameraListTest(); System.out.println("cameraList: " + cameraList); } private static String getCameraListTest() { try { String timestamp = String.valueOf(System.currentTimeMillis()); JSONObject requestBody = new JSONObject(); requestBody.put("queryType", 0); requestBody.put("nodeId", "1346024619493187584"); String requestBodyStr = requestBody.toString(); // 2. 计算请求体MD5 String md5 = DigestUtils.md5Hex(String.valueOf(requestBody)); // 3. 构建签名字符串 Map signParams = new LinkedHashMap(); signParams.put("appid", APP_ID); signParams.put("md5", md5); signParams.put("timestamp", timestamp); signParams.put("token", TOKEN); signParams.put("version", "1.0.0"); String jsonString = JSONObject.toJSONString(signParams); // 4. RSA签名 byte[] keyBytes = Base64.getDecoder().decode(PRIVATE_KEY); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); PrivateKey priKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec); Signature signature = Signature.getInstance("SHA1WithRSA"); signature.initSign(priKey); signature.update(jsonString.getBytes("UTF-8")); String signatureString = Base64.getEncoder().encodeToString(signature.sign()); LinkedHashMap herderParams = new LinkedHashMap<>(); herderParams.put("content-type", "application/json"); herderParams.put("appid", APP_ID); herderParams.put("md5", md5); herderParams.put("timestamp", timestamp); herderParams.put("token", TOKEN); herderParams.put("version", "1.0.0"); herderParams.put("signature", signatureString); // 5. 发送请求 String response = HttpUtils.doPost(URL_LIST, herderParams, requestBodyStr); return response; } catch (Exception e) { e.printStackTrace(); return null; } } private static String getPlayUrlTest() { try { String timestamp = String.valueOf(System.currentTimeMillis()); JSONObject requestBody = new JSONObject(); requestBody.put("deviceId", "gb_26236371771319266195"); String requestBodyStr = requestBody.toString(); // 2. 计算请求体MD5 String md5 = DigestUtils.md5Hex(String.valueOf(requestBody)); // 3. 构建签名字符串 Map signParams = new LinkedHashMap(); signParams.put("appid", APP_ID); signParams.put("md5", md5); signParams.put("timestamp", timestamp); signParams.put("token", TOKEN); signParams.put("version", "1.0.0"); String jsonString = JSONObject.toJSONString(signParams); // 4. RSA签名 byte[] keyBytes = Base64.getDecoder().decode(PRIVATE_KEY); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); PrivateKey priKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec); Signature signature = Signature.getInstance("SHA1WithRSA"); signature.initSign(priKey); signature.update(jsonString.getBytes("UTF-8")); String signatureString = Base64.getEncoder().encodeToString(signature.sign()); LinkedHashMap herderParams = new LinkedHashMap<>(); herderParams.put("content-type", "application/json"); herderParams.put("appid", APP_ID); herderParams.put("md5", md5); herderParams.put("timestamp", timestamp); herderParams.put("token", TOKEN); herderParams.put("version", "1.0.0"); herderParams.put("signature", signatureString); // 5. 发送请求 String response = HttpUtils.doPost(URL_PLAY, herderParams, requestBodyStr); return response; } catch (Exception e) { e.printStackTrace(); return null; } } private static String getAccessTokenTest() { try { String timestamp = String.valueOf(System.currentTimeMillis()); String sig = Hex.encodeHexString(MessageDigest.getInstance("MD5").digest(StringUtils.getBytes(APP_ID+SECRET,"UTF-8"))); JSONObject requestBody = new JSONObject(); requestBody.put("operatorType", 1); requestBody.put("sig", sig); String requestBodyStr = requestBody.toString(); // 2. 计算请求体MD5 String md5 = DigestUtils.md5Hex(String.valueOf(requestBody)); // 3. 构建签名字符串 Map signParams = new LinkedHashMap(); signParams.put("appid", APP_ID); signParams.put("md5", md5); signParams.put("timestamp", timestamp); signParams.put("version", "1.0.0"); String jsonString = JSONObject.toJSONString(signParams); // 4. RSA签名 byte[] keyBytes = Base64.getDecoder().decode(PRIVATE_KEY); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); PrivateKey priKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec); Signature signature = Signature.getInstance("SHA1WithRSA"); signature.initSign(priKey); signature.update(jsonString.getBytes("UTF-8")); String signatureString = Base64.getEncoder().encodeToString(signature.sign()); LinkedHashMap herderParams = new LinkedHashMap<>(); herderParams.put("content-type", "application/json"); herderParams.put("appid", APP_ID); herderParams.put("md5", md5); herderParams.put("timestamp", timestamp); herderParams.put("version", "1.0.0"); herderParams.put("signature", signatureString); // 5. 发送请求 String response = HttpUtils.doPost(URL, herderParams, requestBodyStr); return response; } catch (Exception e) { e.printStackTrace(); return null; } } }