面试录制视频上传回调接口
This commit is contained in:
@@ -0,0 +1,15 @@
|
|||||||
|
package com.cool.store.mapper;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface TRTCVideoCallBackMapper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在面试信息表中添加面试录制视频链接
|
||||||
|
* @param roomId
|
||||||
|
* @param videoUrl
|
||||||
|
*/
|
||||||
|
void addVideoUrl(@Param("roomId") String roomId, @Param("videoUrl") String videoUrl);
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.cool.store.mapper.TRTCVideoCallBackMapper">
|
||||||
|
|
||||||
|
<update id="addVideoUrl">
|
||||||
|
UPDATE hy_partner_interview
|
||||||
|
SET process_info = IF(process_info IS NULL, #{videoUrl}, CONCAT(process_info, ',' ,#{videoUrl}))
|
||||||
|
WHERE interview_plan_id = (
|
||||||
|
SELECT id
|
||||||
|
FROM hy_partner_interview_plan
|
||||||
|
WHERE room_id = #{roomId}
|
||||||
|
)
|
||||||
|
</update>
|
||||||
|
</mapper>
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.cool.store.dto.trtc;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class TRTCVideoCallBackPayLoad {
|
||||||
|
@ApiModelProperty("参数:" +
|
||||||
|
"0:代表本录制文件正常上传至点播平台" +
|
||||||
|
"1:代表本录制文件滞留在服务器或者备份存储上" +
|
||||||
|
"2:代表本录制文件上传点播任务异常")
|
||||||
|
private String Status;
|
||||||
|
|
||||||
|
@ApiModelProperty("audio 音频 / video 纯视频 / audio_video 音视频")
|
||||||
|
private String TrackType;
|
||||||
|
|
||||||
|
@ApiModelProperty("主辅流标识,main代表主流(摄像头),aux代表辅流(屏幕分享),mix代表混流录制")
|
||||||
|
private String MediaId;
|
||||||
|
|
||||||
|
@ApiModelProperty("statue 不为0时,对应的错误信息")
|
||||||
|
private String Errmsg;
|
||||||
|
|
||||||
|
@ApiModelProperty("TencentVod")
|
||||||
|
private TRTCVideoCallBackTencentVod TencentVod;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.cool.store.dto.trtc;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class TRTCVideoCallBackTencentVod {
|
||||||
|
|
||||||
|
@ApiModelProperty("本录制文件在点播平台的播放地址")
|
||||||
|
private String VideoUrl;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.cool.store.dto.trtc;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class VideoCallBackEventInfo {
|
||||||
|
|
||||||
|
@ApiModelProperty("房间号")
|
||||||
|
private String RoomId;
|
||||||
|
|
||||||
|
@ApiModelProperty("信息参数")
|
||||||
|
private TRTCVideoCallBackPayLoad PayLoad;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.cool.store.request;
|
||||||
|
|
||||||
|
import com.cool.store.dto.trtc.VideoCallBackEventInfo;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel(description = "腾讯音视频录制文件上传回调")
|
||||||
|
public class TRTCVideoCallBackReq {
|
||||||
|
|
||||||
|
@ApiModelProperty("回调通知的事件类型,311 为音视频上传事件")
|
||||||
|
private String EventType;
|
||||||
|
|
||||||
|
@ApiModelProperty("事件信息")
|
||||||
|
private VideoCallBackEventInfo EventInfo;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.cool.store.service;
|
||||||
|
|
||||||
|
import com.cool.store.request.TRTCVideoCallBackReq;
|
||||||
|
|
||||||
|
public interface TRTCVideoService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音视频上传成功后的回调处理
|
||||||
|
*/
|
||||||
|
void handleVideoCallBack(TRTCVideoCallBackReq req);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.cool.store.service.impl;
|
||||||
|
|
||||||
|
import com.cool.store.mapper.TRTCVideoCallBackMapper;
|
||||||
|
import com.cool.store.request.TRTCVideoCallBackReq;
|
||||||
|
import com.cool.store.service.TRTCVideoService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class TRTCVideoServiceImpl implements TRTCVideoService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TRTCVideoCallBackMapper videoCallBackMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音视频上传成功后的回调处理
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void handleVideoCallBack(TRTCVideoCallBackReq req) {
|
||||||
|
//将视频播放地址拼接到对应的面试信息字段中
|
||||||
|
String videoUrl = req.getEventInfo().getPayLoad().getTencentVod().getVideoUrl();
|
||||||
|
String roomId = req.getEventInfo().getRoomId();
|
||||||
|
videoCallBackMapper.addVideoUrl(roomId, videoUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.cool.store.config;
|
||||||
|
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.servlet.*;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: JCccc
|
||||||
|
* @Date: 2022-6-12 10:35
|
||||||
|
* @Description:
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Order(2)
|
||||||
|
public class BodyWrapperFilter implements Filter {
|
||||||
|
@Override
|
||||||
|
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||||
|
ServletRequest requestWrapper = null;
|
||||||
|
if(servletRequest instanceof HttpServletRequest) {
|
||||||
|
requestWrapper = new CustomHttpServletRequestWrapper((HttpServletRequest) servletRequest);
|
||||||
|
}
|
||||||
|
if(requestWrapper == null) {
|
||||||
|
filterChain.doFilter(servletRequest, servletResponse);
|
||||||
|
} else {
|
||||||
|
filterChain.doFilter(requestWrapper, servletResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package com.cool.store.config;
|
||||||
|
|
||||||
|
import javax.servlet.ReadListener;
|
||||||
|
import javax.servlet.ServletInputStream;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletRequestWrapper;
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: JCccc
|
||||||
|
* @Date: 2022-6-12 10:36
|
||||||
|
* @Description: 重写一个自己的 RequestWrapper 拿出body给自己用
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {
|
||||||
|
private byte[] body;
|
||||||
|
public CustomHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
|
||||||
|
super(request);
|
||||||
|
BufferedReader reader = request.getReader();
|
||||||
|
try (StringWriter writer = new StringWriter()) {
|
||||||
|
int read;
|
||||||
|
char[] buf = new char[1024 * 8];
|
||||||
|
while ((read = reader.read(buf)) != -1) {
|
||||||
|
writer.write(buf, 0, read);
|
||||||
|
}
|
||||||
|
this.body = writer.getBuffer().toString().getBytes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public String getBody(){
|
||||||
|
return new String(body, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public ServletInputStream getInputStream() {
|
||||||
|
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);
|
||||||
|
return new ServletInputStream() {
|
||||||
|
@Override
|
||||||
|
public boolean isFinished() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean isReady() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setReadListener(ReadListener readListener) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() {
|
||||||
|
return byteArrayInputStream.read();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public BufferedReader getReader() {
|
||||||
|
return new BufferedReader(new InputStreamReader(this.getInputStream()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package com.cool.store.config;
|
||||||
|
|
||||||
|
import com.cool.store.utils.StringUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.crypto.Mac;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import javax.servlet.*;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对腾讯云音视频回调单独验签
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Order(4)
|
||||||
|
@Slf4j
|
||||||
|
public class TRTCCallbackFilter implements Filter {
|
||||||
|
|
||||||
|
@Value("${trtc.secretKey}")
|
||||||
|
private String secretkey;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(FilterConfig filterConfig) throws ServletException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||||
|
// HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||||
|
// String uri = request.getRequestURI();
|
||||||
|
// //不是腾讯云音视频回调请求
|
||||||
|
// if (!uri.startsWith("/partner/pc/video")) {
|
||||||
|
// filterChain.doFilter(servletRequest, servletResponse);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// if (!"POST".equals(request.getMethod())) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// String requestBody = request.getReader().lines().collect(Collectors.joining());
|
||||||
|
// //回调的签名
|
||||||
|
// String sign = request.getHeader("Sign");
|
||||||
|
// //服务器端生成的签名
|
||||||
|
// String newSign = "";
|
||||||
|
// try {
|
||||||
|
// newSign = getResultSign(secretkey, requestBody);
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// log.error("腾讯云音视频回调签名生成错误,e:\t{}", e.getMessage());
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// if (StringUtil.isEmpty(sign) || !newSign.equals(sign)) {
|
||||||
|
// log.error("腾讯云音视频回调签名错误, sign:\t{}, newSign:\t{}", sign, newSign);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
filterChain.doFilter(servletRequest, servletResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getResultSign(String key, String body) throws Exception {
|
||||||
|
Mac hmacSha256 = Mac.getInstance("HmacSHA256");
|
||||||
|
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(), "HmacSHA256");
|
||||||
|
hmacSha256.init(secret_key);
|
||||||
|
return Base64.getEncoder().encodeToString(hmacSha256.doFinal(body.getBytes()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -44,7 +44,9 @@ public class TokenValidateFilter implements Filter {
|
|||||||
|
|
||||||
Lists.newArrayList("/web/check/ok","/check/ok",
|
Lists.newArrayList("/web/check/ok","/check/ok",
|
||||||
"/partner/pc/doc.html","/partner/pc/v2/api-docs","/**/test/**","/partner/pc/feiShuLogin","/partner/pc/oss/getUploadFileConfig",
|
"/partner/pc/doc.html","/partner/pc/v2/api-docs","/**/test/**","/partner/pc/feiShuLogin","/partner/pc/oss/getUploadFileConfig",
|
||||||
"/**/swagger*/**", "/**/webjars/**");
|
"/**/swagger*/**", "/**/webjars/**",
|
||||||
|
//腾讯音视频回调,单独做验签
|
||||||
|
"/partner/pc/video/**");
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.cool.store.controller;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.cool.store.request.TRTCVideoCallBackReq;
|
||||||
|
import com.cool.store.response.ResponseResult;
|
||||||
|
import com.cool.store.service.TRTCVideoService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/video")
|
||||||
|
@Api(tags = "腾讯音视频接口")
|
||||||
|
@Slf4j
|
||||||
|
public class VideoController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TRTCVideoService videoService;
|
||||||
|
|
||||||
|
@PostMapping("/callback")
|
||||||
|
@ApiOperation("音视频回调(腾讯云回调)")
|
||||||
|
public ResponseResult videoCallback(@RequestBody String requestBody) {
|
||||||
|
//由于腾讯云恶事做尽,它的回调参数不是驼峰法,首字母是大写,导致 SpringMVC 映射不上,只能手动映射了
|
||||||
|
TRTCVideoCallBackReq req = JSONObject.parseObject(requestBody, TRTCVideoCallBackReq.class);
|
||||||
|
//不是音视频上传的回调
|
||||||
|
if (!"311".equals(req.getEventType())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!"0".equals(req.getEventInfo().getPayLoad().getStatus())) {
|
||||||
|
log.error("腾讯音视频录制视频上传错误:request:\t{}", req);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
videoService.handleVideoCallBack(req);
|
||||||
|
return new ResponseResult(0, "腾讯云回调音视频回调数据接收成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user