Browse Source

添加数据万象媒体处理接口

jiequan.bi 5 years ago
parent
commit
1e148dad19

+ 5 - 2
jeecg-boot-module-system/src/main/java/org/jeecg/JeecgApplication.java

@@ -4,6 +4,7 @@ import cn.com.ctop.common.module.utils.SpringUtils;
 import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
 import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
 import org.jeecg.common.constant.AccountReportConstants;
 import org.jeecg.common.constant.AccountReportConstants;
+import org.jeecg.modules.system.util.ExtMappingJackson2HttpMessageConverter;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.context.ConfigurableApplicationContext;
 import org.springframework.context.ConfigurableApplicationContext;
@@ -41,8 +42,10 @@ public class JeecgApplication {
     }
     }
 
 
     @Bean
     @Bean
-    public RestTemplate restTemplate() {
-        return new RestTemplate();
+    RestTemplate restTemplate(){
+        RestTemplate restTemplate = new RestTemplate();
+        restTemplate.getMessageConverters().add(new ExtMappingJackson2HttpMessageConverter());
+        return restTemplate;
     }
     }
 
 
     @Bean
     @Bean

+ 17 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/util/ExtMappingJackson2HttpMessageConverter.java

@@ -0,0 +1,17 @@
+package org.jeecg.modules.system.util;
+
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ExtMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
+    /*解决no suitable HttpMessageConverter found for response type [class com.XXX] and content type [text/plain]*/
+    public ExtMappingJackson2HttpMessageConverter(){
+        List<MediaType> mediaTypes = new ArrayList<>();
+        mediaTypes.add(MediaType.TEXT_PLAIN);
+        setSupportedMediaTypes(mediaTypes);// tag6
+    }
+
+}

+ 14 - 0
module-common/src/main/java/cn/com/ctop/common/module/constant/CosConstant.java

@@ -0,0 +1,14 @@
+package cn.com.ctop.common.module.constant;
+
+public class CosConstant {
+
+    //数据万象URL
+    public static final String URL="https://media-1301855440.ci.ap-chongqing.myqcloud.com/";
+    //jobs接口URL
+    public static final String URL_JOBS=URL+"jobs";
+    //截帧模板ID
+    public static final String TEMPLATE_ID="t11931b0daf5bf4776b612b4136ad67d00";
+    //数据万象队列ID
+    public static final String QUEUE_ID="p91b206a0462d46cda49b02063c5c42c8";
+
+}

+ 224 - 0
module-common/src/main/java/cn/com/ctop/common/module/utils/CloudVideoProcessUtil.java

@@ -0,0 +1,224 @@
+package cn.com.ctop.common.module.utils;
+
+import cn.com.ctop.common.module.constant.CosConstant;
+import cn.hutool.core.map.MapUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.qcloud.cos.auth.BasicCOSCredentials;
+import com.qcloud.cos.auth.COSCredentials;
+import com.qcloud.cos.auth.COSSigner;
+import com.qcloud.cos.http.HttpMethodName;
+import com.tencentcloudapi.common.Credential;
+import com.tencentcloudapi.common.exception.TencentCloudSDKException;
+import com.tencentcloudapi.common.profile.ClientProfile;
+import com.tencentcloudapi.common.profile.HttpProfile;
+import com.tencentcloudapi.mps.v20190612.MpsClient;
+import com.tencentcloudapi.mps.v20190612.models.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.MediaType;
+import org.springframework.web.client.RestClientException;
+import org.springframework.web.client.RestTemplate;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * Created by JQ.bi on 2020.6.28
+ */
+@Configuration
+@PropertySource("classpath:config.properties")
+public class CloudVideoProcessUtil {
+
+    private static RestTemplate restTemplate=new RestTemplate();
+
+    private static Logger logger = LoggerFactory.getLogger(CloudVideoProcessUtil.class);
+
+    private static final String SECRET_ID="AKIDE6IpMi8fJQRCg1iuWzFajjRs43kbbets";
+    private static final String SECRET_KEY="tXzuwMfplTTK3c9GFUyETilasvQfePu9";
+    private static final String ENDPOINT = "mps.tencentcloudapi.com";
+    private static final String COS_LOCATION = "ap-chongqing";
+    private static final String COS_BUCKET_MEDIA = "media-1301855440";
+    private static final String COS_BUCKET_PART = "part-1301855440";
+
+
+    public static DescribeTaskDetailResponse getTaskDetailResponse(String taskId) {
+        MpsClient client = getClient();
+        DescribeTaskDetailRequest describeTaskDetailRequest = new DescribeTaskDetailRequest();
+        describeTaskDetailRequest.setTaskId(taskId);
+        DescribeTaskDetailResponse resp = null;
+        try {
+            resp = client.DescribeTaskDetail(describeTaskDetailRequest);
+        } catch (TencentCloudSDKException e) {
+            e.printStackTrace();
+        }
+        return resp;
+    }
+
+    /**
+     * 发起视频水印处理请求
+     */
+    public static String videoWatermarkHandle(String videoPath, Long watermarkTemplateId) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        MpsClient client = getClient();
+        //发起视频处理请求
+        ProcessMediaRequest request = new ProcessMediaRequest();
+        TranscodeTaskInput transcodeTaskInput = new TranscodeTaskInput();
+        transcodeTaskInput.setOutputObjectPath("/watermark/" + sdf.format(new Date()) + "/" + UUID.randomUUID() + ".mp4");
+        //水印模板信息
+        WatermarkInput watermarkInput = new WatermarkInput();
+        watermarkInput.setDefinition(watermarkTemplateId);
+        //指定视频转码模板
+        transcodeTaskInput.setDefinition(30L);
+        transcodeTaskInput.setWatermarkSet(new WatermarkInput[]{watermarkInput});
+        MediaProcessTaskInput mediaProcessTaskInput = new MediaProcessTaskInput();
+        mediaProcessTaskInput.setTranscodeTaskSet(new TranscodeTaskInput[]{transcodeTaskInput});
+        request.setMediaProcessTask(mediaProcessTaskInput);
+        //视频输入
+        CosInputInfo cosInputInfo = new CosInputInfo();
+        cosInputInfo.setRegion(COS_LOCATION);
+        cosInputInfo.setBucket(COS_BUCKET_PART);
+        cosInputInfo.setObject(videoPath);
+        MediaInputInfo mediaInputInfo = new MediaInputInfo();
+        mediaInputInfo.setType("COS");
+        mediaInputInfo.setCosInputInfo(cosInputInfo);
+        request.setInputInfo(mediaInputInfo);
+        //加水印视频输出
+        CosOutputStorage cosOutputStorage = new CosOutputStorage();
+        cosOutputStorage.setBucket(COS_BUCKET_MEDIA);
+        cosOutputStorage.setRegion(COS_LOCATION);
+        TaskOutputStorage taskOutputStorage = new TaskOutputStorage();
+        taskOutputStorage.setType("COS");
+        taskOutputStorage.setCosOutputStorage(cosOutputStorage);
+        request.setOutputStorage(taskOutputStorage);
+        //指定输出路径
+        ProcessMediaResponse response = null;
+        String taskId = "";
+        try {
+            response = client.ProcessMedia(request);
+        } catch (TencentCloudSDKException e) {
+            logger.error(e.getMessage());
+        }
+        if (null != response) {
+            taskId = response.getTaskId();
+        }
+        return taskId;
+    }
+
+    /**
+     *  查询数据万象任务状态
+     */
+    public static Map<String,Object> getMediaJobsResponse(String jobId){
+        String auth =generateAuth(SECRET_ID,SECRET_KEY,"/jobs/"+jobId,HttpMethodName.GET);
+        if(auth.isEmpty()){
+            logger.error("腾讯云Authorization获取失败");
+        }
+        //请求media-1301855440.ci.ap-chongqing.myqcloud.com/jobs/jobId 接口
+        HttpHeaders headers = new HttpHeaders();
+        headers.set("Authorization", auth);
+        HttpEntity<String> requestEntity = new HttpEntity<>(headers);
+        String response = null;
+        try {
+            response = restTemplate.exchange(CosConstant.URL_JOBS+"/"+jobId,HttpMethod.GET,requestEntity,String.class).getBody();
+        } catch (RestClientException e) {
+            logger.error(e.getMessage());
+        }
+        Map<String,Object> mapResp= XmlToMapUtil.multilayerXmlToMap(response);
+        Map JobsDetail= (Map)((Map)mapResp.get("Response")).get("JobsDetail");
+        if(JobsDetail.get("Code").equals("Success")){
+            return JobsDetail;
+        }else {
+            return MapUtil.newHashMap();
+        }
+    }
+    /**
+     * 数据万象发起视频抽帧处理请求
+     */
+    public static Map<String,Object> videoCutFrameHandle(String videoPath, String outputPath) {
+
+        String auth =generateAuth(SECRET_ID,SECRET_KEY,"/jobs",HttpMethodName.POST);
+        if(auth.isEmpty()){
+            logger.error("腾讯云Authorization获取失败");
+        }
+        //拼接请求数据万象jobs接口的参数
+        JSONObject input = new JSONObject();
+        input.put("Object", videoPath);
+        JSONObject output = new JSONObject();
+        output.put("Region", COS_LOCATION);
+        output.put("Bucket", COS_BUCKET_MEDIA);
+        output.put("Object", outputPath);
+        JSONObject operation = new JSONObject();
+        operation.put("TemplateId", CosConstant.TEMPLATE_ID);
+        operation.put("Output", output);
+        JSONObject request = new JSONObject();
+        request.put("Tag", "Snapshot");
+        request.put("Input", input);
+        request.put("Operation", operation);
+        request.put("QueueId", CosConstant.QUEUE_ID);
+
+        //请求media-1301855440.ci.ap-chongqing.myqcloud.com/jobs 接口
+        HttpHeaders headers = new HttpHeaders();
+        headers.set("Authorization", auth);
+        headers.setContentType(MediaType.APPLICATION_JSON);
+        HttpEntity<String> requestEntity = new HttpEntity<>(request.toJSONString(), headers);
+        String response = null;
+        try {
+            response = restTemplate.exchange(CosConstant.URL_JOBS, HttpMethod.POST, requestEntity, String.class).getBody();
+        } catch (RestClientException e) {
+            logger.error(e.getMessage());
+        }
+        Map<String,Object> mapResp= XmlToMapUtil.multilayerXmlToMap(response);
+        Map JobsDetail= (Map)((Map)mapResp.get("Response")).get("JobsDetail");
+        if(JobsDetail.get("Code").equals("Success")){
+            return JobsDetail;
+        }else {
+            return MapUtil.newHashMap();
+        }
+    }
+
+    /**
+     * 获取视频处理服务 MpsClient
+     */
+    private static MpsClient getClient() {
+        MpsClient mpsClient = null;
+        try {
+            Credential cred = new Credential(SECRET_ID, SECRET_KEY);
+            HttpProfile httpProfile = new HttpProfile();
+            httpProfile.setEndpoint(ENDPOINT);
+            ClientProfile clientProfile = new ClientProfile();
+            clientProfile.setHttpProfile(httpProfile);
+            mpsClient = new MpsClient(cred, COS_LOCATION, clientProfile);
+        } catch (Exception ex) {
+            logger.error(ex.getMessage());
+        }
+        return mpsClient;
+    }
+
+    /**
+     * 获取数据万象认证Auth
+     * @param secretId
+     * @param secretKey
+     * @param path
+     * @param httpMethodName
+     * @return
+     */
+    public static String generateAuth(String secretId, String secretKey, String path, HttpMethodName httpMethodName) {
+        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
+        COSSigner signer = new COSSigner();
+        //设置过期时间为1个小时
+        Date expiredTime = new Date(System.currentTimeMillis() + 3600L * 1000L);
+        //授权的签名
+        return signer.buildAuthorizationStr(
+                httpMethodName,
+                path,
+                cred,
+                expiredTime
+        );
+    }
+}

+ 163 - 0
module-common/src/main/java/cn/com/ctop/common/module/utils/JQCOSUtils.java

@@ -0,0 +1,163 @@
+package cn.com.ctop.common.module.utils;
+
+import com.qcloud.cos.COSClient;
+import com.qcloud.cos.ClientConfig;
+import com.qcloud.cos.auth.BasicCOSCredentials;
+import com.qcloud.cos.auth.COSCredentials;
+import com.qcloud.cos.exception.CosClientException;
+import com.qcloud.cos.model.*;
+import com.qcloud.cos.region.Region;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Created by JQ.bi on 2020.6.19
+ */
+@Configuration
+@PropertySource("classpath:config.properties")
+public class JQCOSUtils {
+
+    private static Logger logger = LoggerFactory.getLogger(JQCOSUtils.class);
+
+    //腾讯云API的密钥Access Key ID
+    private static String accessKeyId;
+
+    //腾讯云API的密钥Access Key Secret
+    private static String accessKeySecret;
+
+    //腾讯云API的内或外网域名
+    private static String endpoint;
+
+    //腾讯云API的bucket名称
+    private static String bucketName;
+
+    //腾讯云API的文件夹名称
+    private static String folder;
+
+    /**
+     * 永久密钥参数初始化
+     */
+    @Value("${qcloud.accessKeyId}")
+    public void setAccessKeyId(String accessKeyId) {
+        JQCOSUtils.accessKeyId = accessKeyId;
+    }
+
+    @Value("${qcloud.accessKeySecret}")
+    public void setAccessKeySecret(String accessKeySecret) {
+        JQCOSUtils.accessKeySecret = accessKeySecret;
+    }
+
+    @Value("${qcloud.cos.endpoint}")
+    public void setEndpoint(String endpoint) {
+        JQCOSUtils.endpoint = endpoint;
+    }
+
+    @Value("${qcloud.cos.bucketName}")
+    public void setBucketName(String bucketName) {
+        JQCOSUtils.bucketName = bucketName;
+    }
+
+    @Value("${qcloud.cos.folder}")
+    public void setFolder(String folder) {
+        JQCOSUtils.folder = folder;
+    }
+
+    /**
+     * 创建COSClient实例
+     */
+    public static COSClient getCosClient() {
+        //初始化用户身份信息(secretId, secretKey)
+        COSCredentials cred = new BasicCOSCredentials(accessKeyId, accessKeySecret);
+        //设置 bucket 的区域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
+        Region region = new Region("ap-chongqing");
+        // clientConfig 中包含了设置 region, https(默认 http), 超时, 代理等 set 方法, 使用可参见源码或者常见问题 Java SDK 部分。
+        ClientConfig clientConfig = new ClientConfig(region);
+        return new COSClient(cred, clientConfig);
+    }
+
+    /**
+     * 创建桶
+     */
+    public static String createBucket(String bucketName) {
+
+        COSClient cosClient = JQCOSUtils.getCosClient();
+        CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
+        //设置 bucket 的权限为 Private(私有读写), 其他可选有公有读私有写, 公有读写
+        createBucketRequest.setCannedAcl(CannedAccessControlList.PublicReadWrite);
+        try {
+            Bucket bucketResult = cosClient.createBucket(createBucketRequest);
+            return bucketResult.getName();
+        } catch (CosClientException serverException) {
+            logger.error(serverException.getMessage());
+        }
+        return bucketName;
+    }
+
+    /**
+     * 删除桶
+     */
+    public static void deleteBucket(String bucketName) {
+
+        COSClient cosClient = JQCOSUtils.getCosClient();
+        cosClient.deleteBucket(bucketName);
+    }
+
+    /**
+     *  上传对象 文件上传
+     */
+    public static String uploadObject(File file){
+
+        String resultStr="";
+        COSClient cosClient= JQCOSUtils.getCosClient();
+        String fileName=file.getName();
+        try {
+            PutObjectResult putObjectResult = cosClient.putObject(new PutObjectRequest(bucketName, folder+fileName, file));
+            resultStr=putObjectResult.getETag();
+        }catch (CosClientException serverException){
+            logger.error(serverException.getMessage());
+        }
+        return resultStr;
+    }
+
+    /**
+     *  上传对象 流上传
+     */
+    public static String uploadObject(InputStream inputStream, String fileName){
+
+        String resultStr="";
+        COSClient cosClient= JQCOSUtils.getCosClient();
+        try {
+            ObjectMetadata metadata = new ObjectMetadata();
+            ObjectMetadata objectMetadata = new ObjectMetadata();
+            objectMetadata.setContentLength(inputStream.available());
+            objectMetadata.setCacheControl("no-cache");
+            objectMetadata.setHeader("Pragma", "no-cache");
+            objectMetadata.setContentDisposition("inline;filename=" + fileName);
+            PutObjectResult putObjectResult = cosClient.putObject(new PutObjectRequest(bucketName, folder+fileName, inputStream,metadata));
+            resultStr=putObjectResult.getETag();
+        }catch (CosClientException | IOException serverException){
+            logger.error(serverException.getMessage());
+        }
+        return resultStr;
+    }
+    /**
+     *  删除对象
+     */
+    public static void deleteObject(String dir,String fileName){
+
+        COSClient cosClient= JQCOSUtils.getCosClient();
+        try{
+            cosClient.deleteObject(bucketName, dir+fileName);
+        }catch (CosClientException serverException){
+            logger.error(serverException.getMessage());
+        }
+
+    }
+}

+ 62 - 0
module-common/src/main/java/cn/com/ctop/common/module/utils/XmlToMapUtil.java

@@ -0,0 +1,62 @@
+package cn.com.ctop.common.module.utils;
+
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.DocumentHelper;
+import org.dom4j.Element;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class XmlToMapUtil {
+
+    private static Logger logger= LoggerFactory.getLogger(XmlToMapUtil.class);
+    /**
+     * (多层)xml格式字符串转换为map
+     *
+     * @param xml xml字符串
+     * @return 第一个为Root节点,Root节点之后为Root的元素,如果为多层,可以通过key获取下一层Map
+     */
+    public static Map<String, Object> multilayerXmlToMap(String xml) {
+        Document doc = null;
+        try {
+            doc = DocumentHelper.parseText(xml);
+        } catch (DocumentException e) {
+            logger.error("xml字符串解析,失败 --> {}", e);
+        }
+        Map<String, Object> map = new HashMap<>();
+        if (null == doc) {
+            return map;
+        }
+        // 获取根元素
+        Element rootElement = doc.getRootElement();
+        recursionXmlToMap(rootElement,map);
+        return map;
+    }
+
+    /**
+     * multilayerXmlToMap核心方法,递归调用
+     *
+     * @param element 节点元素
+     * @param outmap 用于存储xml数据的map
+     */
+    @SuppressWarnings("unchecked")
+    private static void recursionXmlToMap(Element element, Map<String, Object> outmap) {
+        // 得到根元素下的子元素列表
+        List<Element> list = element.elements();
+        int size = list.size();
+        if (size == 0) {
+            // 如果没有子元素,则将其存储进map中
+            outmap.put(element.getName(), element.getTextTrim());
+        } else {
+            // innerMap
+            Map<String, Object> innerMap = new HashMap<>();
+            // 遍历子元素
+            list.forEach(childElement -> recursionXmlToMap(childElement, innerMap));
+            outmap.put(element.getName(), innerMap);
+        }
+    }
+}