硅谷课堂笔记(下)

从这开始有点摆烂了,有点累了写不动了,很大一部分是抄了官方的笔记,兄弟们见谅

微信支付

微信支付

接口文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1

公众号配置

(1)绑定域名

与微信分享一致

先登录微信公众平台进入“设置与开发”,“公众号设置”的“功能设置”里填写“JS接口安全域名”。

说明:因为测试号不支持支付功能,需要使用正式号才能进行测试。

这些都是配置内网穿透的域名
硅谷课堂笔记(下)_第1张图片

(2)商户平台配置支付目录

硅谷课堂笔记(下)_第2张图片

订单支付接口

还是在订单接口
硅谷课堂笔记(下)_第3张图片

(1)创建WXPayController

@Api(tags = "微信支付接口")
@RestController
@RequestMapping("/api/order/wxPay")
public class WXPayController {

    @Autowired
    private WXPayService wxPayService;

    @ApiOperation(value = "下单 小程序支付")
    @GetMapping("/createJsapi/{orderNo}")
    public Result createJsapi(
            @ApiParam(name = "orderNo", value = "订单No", required = true)
            @PathVariable("orderNo") String orderNo) {
        return Result.ok(wxPayService.createJsapi(orderNo));
    }
}

(2)创建WXPayService

public interface WXPayService {
	Map createJsapi(String orderNo);
}

(3)service_order引入依赖

<dependency>
	<groupId>com.github.wxpaygroupId>
	<artifactId>wxpay-sdkartifactId>
	<version>0.0.3version>
dependency>

(4)创建WXPayServiceImpl

@Service
@Slf4j
public class WXPayServiceImpl implements WXPayService {

	@Autowired
	private OrderInfoService orderInfoService;
	@Resource
	private UserInfoFeignClient userInfoFeignClient;

	@Override
	public Map<String, String> createJsapi(String orderNo) {
		try {

			Map<String, String> paramMap = new HashMap();
			//1、设置参数
			paramMap.put("appid", "wxf913bfa3a2c7eeeb");
			paramMap.put("mch_id", "1481962542");
			paramMap.put("nonce_str", WXPayUtil.generateNonceStr());
			paramMap.put("body", "test");
			paramMap.put("out_trade_no", orderNo);
			paramMap.put("total_fee", "1");
			paramMap.put("spbill_create_ip", "127.0.0.1");
			paramMap.put("notify_url", "http://内网穿透隧道/api/order/wxPay/notify");
			paramMap.put("trade_type", "JSAPI");
//			paramMap.put("openid", "o1R-t5trto9c5sdYt6l1ncGmY5Y");
			//UserInfo userInfo = userInfoFeignClient.getById(paymentInfo.getUserId());
//			paramMap.put("openid", "oepf36SawvvS8Rdqva-Cy4flFFg");
			paramMap.put("openid", "oQTXC56lAy3xMOCkKCImHtHoLL");

			//2、HTTPClient来根据URL访问第三方接口并且传递参数
			HttpClientUtils client = new HttpClientUtils("https://api.mch.weixin.qq.com/pay/unifiedorder");

			//client设置参数
			client.setXmlParam(WXPayUtil.generateSignedXml(paramMap, "MXb72b9RfshXZD4FRGV5KLqmv5bx9LT9"));
			client.setHttps(true);
			client.post();
			//3、返回第三方的数据
			String xml = client.getContent();
			Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);
			if(null != resultMap.get("result_code")  && !"SUCCESS".equals(resultMap.get("result_code"))) {
				System.out.println("error1");
			}

			//4、再次封装参数
			Map<String, String> parameterMap = new HashMap<>();
			String prepayId = String.valueOf(resultMap.get("prepay_id"));
			String packages = "prepay_id=" + prepayId;
			parameterMap.put("appId", "wxf913bfa3a2c7eeeb");
			parameterMap.put("nonceStr", resultMap.get("nonce_str"));
			parameterMap.put("package", packages);
			parameterMap.put("signType", "MD5");
			parameterMap.put("timeStamp", String.valueOf(new Date().getTime()));
			String sign = WXPayUtil.generateSignature(parameterMap, "MXb72b9RfshXZD4FRGV5KLqmv5bx9LT9");

			//返回结果
			Map<String, String> result = new HashMap();
			result.put("appId", "wxf913bfa3a2c7eeeb");
			result.put("timeStamp", parameterMap.get("timeStamp"));
			result.put("nonceStr", parameterMap.get("nonceStr"));
			result.put("signType", "MD5");
			result.put("paySign", sign);
			result.put("package", packages);
			System.out.println(result);
			return result;
		} catch (Exception e) {
			e.printStackTrace();
			return new HashMap<>();
		}
	}
}

服务号测试过程

(1)修改service-user模块配置文件

wechat.mpAppId: wxf913bfa3a2c7eeeb
## 硅谷课堂微信公众平台api秘钥
wechat.mpAppSecret: cd360d429e5c8db0c638d5ef9df74f6d

(2)service-user模块创建controller

@Controller
@RequestMapping("/api/user/openid")
public class GetOpenIdController {

    @Autowired
    private WxMpService wxMpService;

    @GetMapping("/authorize")
    public String authorize(@RequestParam("returnUrl") String returnUrl, HttpServletRequest request) {
        String userInfoUrl =
                "http://内网穿透隧道/api/user/openid/userInfo";
        String redirectURL = wxMpService
                .oauth2buildAuthorizationUrl(userInfoUrl,
                                             WxConsts.OAUTH2_SCOPE_USER_INFO,
                                             URLEncoder.encode(returnUrl.replace("guiguketan", "#")));
        return "redirect:" + redirectURL;
    }

    @GetMapping("/userInfo")
    @ResponseBody
    public String userInfo(@RequestParam("code") String code,
                           @RequestParam("state") String returnUrl) throws Exception {
        WxMpOAuth2AccessToken wxMpOAuth2AccessToken = this.wxMpService.oauth2getAccessToken(code);
        String openId = wxMpOAuth2AccessToken.getOpenId();
        System.out.println("【微信网页授权】openId={}"+openId);
        return openId;
    }
}

(3)修改前端App.vue

......
if (token == '') {
    let url = window.location.href.replace('#', 'guiguketan')
    //修改认证controller路径
    window.location = 'http://内网穿透隧道路径.com/api/user/openid/authorize?returnUrl=' + url
}
......

(4)复制返回的openid到支付接口中测试

硅谷课堂笔记(下)_第4张图片

整合点播视频支付前端

(1)trade.vue订单页面

(2)pay.vue微信支付页面

硅谷课堂笔记(下)_第5张图片

订单详情接口

支付完毕后会得到一个序列号
我们通过这个方法把这个序列号进行测试

(1)OrderInfoApiController添加方法

@ApiOperation(value = "获取")
@GetMapping("getInfo/{id}")
public Result getInfo(@PathVariable Long id) {
    OrderInfoVo orderInfoVo = orderInfoService.getOrderInfoVoById(id);
    return Result.ok(orderInfoVo);
}

(2)OrderInfoServiceImpl实现方法

@Override
public OrderInfoVo getOrderInfoVoById(Long id) {
    OrderInfo orderInfo = this.getById(id);
    OrderDetail orderDetail = orderDetailService.getById(id);

    OrderInfoVo orderInfoVo = new OrderInfoVo();
    BeanUtils.copyProperties(orderInfo, orderInfoVo);
    orderInfoVo.setCourseId(orderDetail.getCourseId());
    orderInfoVo.setCourseName(orderDetail.getCourseName());
    return orderInfoVo;
}

查询支付结果

(1)WXPayController添加方法

@ApiOperation(value = "查询支付状态")
@GetMapping("/queryPayStatus/{orderNo}")
public Result queryPayStatus(
        @ApiParam(name = "orderNo", value = "订单No", required = true)
        @PathVariable("orderNo") String orderNo) {

    System.out.println("orderNo:"+orderNo);
    //调用查询接口
    Map<String, String> resultMap = wxPayService.queryPayStatus(orderNo);
    if (resultMap == null) {//出错
        return Result.fail(null).message("支付出错");
    }
    if ("SUCCESS".equals(resultMap.get("trade_state"))) {//如果成功
        //更改订单状态,处理支付结果
        String out_trade_no = resultMap.get("out_trade_no");
        System.out.println("out_trade_no:"+out_trade_no);
        orderInfoService.updateOrderStatus(out_trade_no);
        return Result.ok(null).message("支付成功");
    }
    return Result.ok(null).message("支付中");
}

(2)WXPayServiceImpl实现方法

@Override
public Map queryPayStatus(String orderNo) {
	try {
		//1、封装参数
		Map paramMap = new HashMap<>();
		paramMap.put("appid", wxPayAccountConfig.getAppId());
		paramMap.put("mch_id", wxPayAccountConfig.getMchId());
		paramMap.put("out_trade_no", orderNo);
		paramMap.put("nonce_str", WXPayUtil.generateNonceStr());

		//2、设置请求
		HttpClientUtils client = new HttpClientUtils("https://api.mch.weixin.qq.com/pay/orderquery");
		client.setXmlParam(WXPayUtil.generateSignedXml(paramMap, wxPayAccountConfig.getKey()));
		client.setHttps(true);
		client.post();
		//3、返回第三方的数据
		String xml = client.getContent();
		Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);
		//6、转成Map
		//7、返回
		return resultMap;
	} catch (Exception e) {
		e.printStackTrace();
	}
	return null;
}

(3)OrderInfoServiceImpl实现方法

@Override
public void updateOrderStatus(String out_trade_no) {
    //根据out_trade_no查询订单
    LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(OrderInfo::getOutTradeNo,out_trade_no);
    OrderInfo orderInfo = baseMapper.selectOne(wrapper);
    //更新订单状态 1 已经支付
    orderInfo.setOrderStatus("1");
    baseMapper.updateById(orderInfo);
}

直播

项目需求

硅谷课堂会定期推出直播课程,方便学员与名师之间的交流互动,在直播间老师可以推荐点播课程(类似直播带货),学员可以点赞交流,购买推荐的点播课程。

直播功能

一个完整直播实现流程:

​ 1.采集、2.滤镜处理、3.编码、4.推流、5.CDN分发、6.拉流、7.解码、8.播放、9.聊天互动。

通用直播模型

硅谷课堂笔记(下)_第6张图片

硅谷课堂笔记(下)_第7张图片

  1. 首先是主播方,它是产生视频流的源头,由一系列流程组成:第一,通过一定的设备来采集数据;第二,将采集的这些视频进行一系列的处理,比如水印、美颜和特效滤镜等处理;第三,将处理后的结果视频编码压缩成可观看可传输的视频流;第四,分发推流,即将压缩后的视频流通过网络通道传输出去。
  2. 其次是播放端,播放端功能有两个层面,第一个层面是关键性的需求;另一层面是业务层面的。先看第一个层面,它涉及到一些非常关键的指标,比如秒开,在很多场景当中都有这样的要求,然后是对于一些重要内容的版权保护。为了达到更好的效果,我们还需要配合服务端做智能解析,这在某些场景下也是关键性需求。再来看第二个层面也即业务层面的功能,对于一个社交直播产品来说,在播放端,观众希望能够实时的看到主播端推过来的视频流,并且和主播以及其他观众产生一定的互动,因此它可能包含一些像点赞、聊天和弹幕这样的功能,以及礼物这样更高级的道具。
  3. 我们知道,内容产生方和消费方一般都不是一一对应的。对于一个直播产品来讲,最直观的体现就是一个主播可能会有很多粉丝。因此,我们不能直接让主播端和所有播放端进行点对点通信,这在技术上是做不到或者很有难度。主播方播出的视频到达播放端之前,需要经过一系列的中间环节,也就是我们这里讲的直播服务器端。
  4. 直播服务器端提供的最核心功能是收集主播端的视频推流,并将其放大后推送给所有观众端。除了这个核心功能,还有很多运营级别的诉求,比如鉴权认证,视频连线和实时转码,自动鉴黄,多屏合一,以及云端录制存储等功能。另外,对于一个主播端推出的视频流,中间需要经过一些环节才能到达播放端,因此对中间环节的质量进行监控,以及根据这些监控来进行智能调度,也是非常重要的诉求。
  5. 实际上无论是主播端还是播放端,他们的诉求都不会仅仅是拍摄视频和播放视频这么简单。在这个核心诉求被满足之后,还有很多关键诉求需要被满足。比如,对于一个消费级的直播产品来说,除了这三大模块之外,还需要实现一个业务服务端来进行推流和播放控制,以及所有用户状态的维持。如此,就构成了一个消费级可用的直播产品。

如何快速开发完整直播

利用第三方SDK开发

  • 七牛云:七牛直播云是专为直播平台打造的全球化直播流服务和一站式实现SDK端到端直播场景的企业级直播云服务平台.
    ☞ 熊猫TV,龙珠TV等直播平台都是用的七牛云
  • 网易视频云:基于专业的跨平台视频编解码技术和大规模视频内容分发网络,提供稳定流畅、低延时、高并发的实时音视频服务,可将视频直播无缝对接到自身App.
  • 阿里云视频直播解决方案
    ☞ 直播推流 SDK(iOS/Android)
    ☞ 直播播放器 SDK(iOS/Android)
  • 欢拓云直播平台:欢拓是一家以直播技术为核心的网络平台,旨在帮助人们通过网络也能实现真实互动通讯。

第三方SDK好处

  • 降低成本
    ☞ 使用好的第三方企业服务,将不用再花费大量的人力物力去研发
  • 提升效率
    ☞ 第三方服务的专注与代码集成所带来的方便,所花费的时间可能仅仅是1-2个小时,节约近99%的时间,足够换取更多的时间去和竞争对手斗智斗勇,增加更大的成功可能性
  • 降低风险
    ☞ 借助专业的第三方服务,由于它的快速、专业、稳定等特点,能够极大地加强产品的竞争能力(优质服务、研发速度等),缩短试错时间,必将是创业中保命的手段之一
  • 专业的事,找专业的人来做
    ☞ 第三方服务最少是10-20人的团队专注地解决同一个问题,做同一件事情。

欢拓云直播

根据上面的综合对比和调研,我们最终选择了“欢拓与直播平台”,它为我们提供了完整的可以直接使用的示例代码,方便我们开发对接。

欢拓是一家以直播技术为核心的网络平台,旨在帮助人们通过网络也能实现真实互动通讯。从2010年开始,欢拓就专注于音频、视频的采样、编码、后处理及智能传输研究,并于2013年底正式推出了针对企业/开发者的直播云服务系统,帮助开发者轻松实现真人互动。该系统适用场景包括在线教育、游戏语音、娱乐互动、远程会议(PC、移动均可)等等。针对应用场景,采用先进技术解决方案和产品形态,让客户和客户的用户满意!

官网:https://www.talk-fun.com/

接口文档地址:http://open.talk-fun.com/docs/getstartV2/document.html

硅谷课堂笔记(下)_第8张图片

直播对接

开通账号

通过官网:https://www.talk-fun.com/,联系客户或400电话开通账号,开通**“生活直播”**权限。开通后注意使用有效期,一般一周左右,可以再次申请延期。

说明:官网免费试用,功能有限制,不建议使用

创建直播

1、在直播管理创建直播

硅谷课堂笔记(下)_第9张图片

2、创建直播,选择主播模式

硅谷课堂笔记(下)_第10张图片

3、配置直播,可以自行查看
硅谷课堂笔记(下)_第11张图片

开始直播

1、在直播列表,点击“直播入口”

硅谷课堂笔记(下)_第12张图片

主播端下载“云直播客户端”,“频道id与密码”为直播客户端的登录账号;

下面还有管理员,主播进行直播时,助教可以在聊天时与观众互动。

2、电脑端安装后如图:

硅谷课堂笔记(下)_第13张图片

3、使用“频道id与密码”登录

硅谷课堂笔记(下)_第14张图片

4、点击“开始直播”,打开摄像头即可开始直播。

用户观看

1、在直播列表,点击“直播入口”

硅谷课堂笔记(下)_第15张图片

2、在观众一栏点击进入,即可在网页端观看直播。

体验总结

上面的体验完全能够满足我们业务的需要,硅谷课堂的需求是定期推出直播课程,方便学员与名师之间的交流互动,在直播间老师可以推荐点播课程(类似直播带货),学员可以点赞交流,购买推荐的点播课程。

直播平台只是做了直播相关的业务,不能与我们的业务进行衔接,我们期望是在硅谷课堂的管理后台管理直播相关的业务,那么怎么做呢?对接直播业务接口,直播平台有对应的直播接口,我们直接对接即可。

tml#bdpc):基于专业的跨平台视频编解码技术和大规模视频内容分发网络,提供稳定流畅、低延时、高并发的实时音视频服务,可将视频直播无缝对接到自身App.

  • 阿里云视频直播解决方案
    ☞ 直播推流 SDK(iOS/Android)
    ☞ 直播播放器 SDK(iOS/Android)
  • 欢拓云直播平台:欢拓是一家以直播技术为核心的网络平台,旨在帮助人们通过网络也能实现真实互动通讯。

第三方SDK好处

  • 降低成本
    ☞ 使用好的第三方企业服务,将不用再花费大量的人力物力去研发
  • 提升效率
    ☞ 第三方服务的专注与代码集成所带来的方便,所花费的时间可能仅仅是1-2个小时,节约近99%的时间,足够换取更多的时间去和竞争对手斗智斗勇,增加更大的成功可能性
  • 降低风险
    ☞ 借助专业的第三方服务,由于它的快速、专业、稳定等特点,能够极大地加强产品的竞争能力(优质服务、研发速度等),缩短试错时间,必将是创业中保命的手段之一
  • 专业的事,找专业的人来做
    ☞ 第三方服务最少是10-20人的团队专注地解决同一个问题,做同一件事情。

欢拓云直播

根据上面的综合对比和调研,我们最终选择了“欢拓与直播平台”,它为我们提供了完整的可以直接使用的示例代码,方便我们开发对接。

欢拓是一家以直播技术为核心的网络平台,旨在帮助人们通过网络也能实现真实互动通讯。从2010年开始,欢拓就专注于音频、视频的采样、编码、后处理及智能传输研究,并于2013年底正式推出了针对企业/开发者的直播云服务系统,帮助开发者轻松实现真人互动。该系统适用场景包括在线教育、游戏语音、娱乐互动、远程会议(PC、移动均可)等等。针对应用场景,采用先进技术解决方案和产品形态,让客户和客户的用户满意!

官网:https://www.talk-fun.com/

接口文档地址:http://open.talk-fun.com/docs/getstartV2/document.html

[外链图片转存中…(img-YaTUa8hs-1658285395973)]

欢拓云直播对接

开通账号

通过官网:https://www.talk-fun.com/,联系客户或400电话开通账号,开通**“生活直播”**权限。开通后注意使用有效期,一般一周左右,可以再次申请延期。

说明:官网免费试用,功能有限制,不建议使用

创建直播

1、在直播管理创建直播
硅谷课堂笔记(下)_第16张图片

2、创建直播,选择主播模式
硅谷课堂笔记(下)_第17张图片

3、配置直播,可以自行查看

硅谷课堂笔记(下)_第18张图片

开始直播

1、在直播列表,点击“直播入口”

硅谷课堂笔记(下)_第19张图片

主播端下载“云直播客户端”,“频道id与密码”为直播客户端的登录账号;

下面还有管理员,主播进行直播时,助教可以在聊天时与观众互动。

2、电脑端安装后如图:

硅谷课堂笔记(下)_第20张图片

3、使用“频道id与密码”登录

硅谷课堂笔记(下)_第21张图片

4、点击“开始直播”,打开摄像头即可开始直播。

用户观看

1、在直播列表,点击“直播入口”

硅谷课堂笔记(下)_第22张图片

2、在观众一栏点击进入,即可在网页端观看直播。

体验总结

上面的体验完全能够满足我们业务的需要,硅谷课堂的需求是定期推出直播课程,方便学员与名师之间的交流互动,在直播间老师可以推荐点播课程(类似直播带货),学员可以点赞交流,购买推荐的点播课程。

直播平台只是做了直播相关的业务,不能与我们的业务进行衔接,我们期望是在硅谷课堂的管理后台管理直播相关的业务,那么怎么做呢?对接直播业务接口,直播平台有对应的直播接口,我们直接对接即可。

后台开发-直播管理接口

概述

上面我们已经开通了“生活类直播”。

获取openId与openToken

登录进入开放后台,后台首页即可获取openId与openToken

硅谷课堂笔记(下)_第23张图片

对接说明

1、使用HTTP协议进行信息交互,字符编码统一采用UTF-8

2、除非特殊说明,接口地址统一为:https://api.talk-fun.com/portal.php

3、除非特殊说明,同时支持GET和POST两种参数传递方式

4、除非特殊说明,返回信息支持JSON格式

5、除了sign外,其余所有请求参数值都需要进行URL编码

6、参数表中,类型一栏声明的定义为:int 代表整数类型;string 代表字符串类型,如果后面有括号,括号中的数字代表该参数的最大长度;array/object表示数组类型

7、openID、openToken参数的获取见对接流程说明

了解接口文档

接口文档地址:https://open.talk-fun.com/docs/getstartV2/api/live_dir.html

了解接口文档

根据接口文档,了解我们需要对接哪些接口

硅谷课堂笔记(下)_第24张图片
添加直播

api名称:course.add,SDK对应方法:courseAdd

添加直播是一定需要的

更新直播信息

api名称:course.update,SDK对应方法courseUpdate

删除直播信息

api名称:course.delete,SDK对应方法:courseDelete

修改生活直播相关配置

api名称:course.updateLifeConfig,SDK对应方法:updateLifeConfig

设置功能很多,但是我们只需要几个即可,这个接口我们需要做如下设置:

​ 1、界面模式:pageViewMode 界面模式 1全屏模式 0二分屏 2课件模式

​ 2、观看人数开关:number 观看人数开关;number.enable 是否开启 观看人数 0否 1是;示例:{“enable”:“1”}

​ 3、商城开关(直播推荐课程):goodsListEdit 商品列表编辑,状态goodsListEdit.status 0覆盖,1追加,不传默认为0;示例:{“status”:1};

直播设置最终效果:

硅谷课堂笔记(下)_第25张图片

按照课程ID获取访客列表

改接口在:"访客/管理员列表"下面

通过该接口统计课程观看人数信息

直播访客api名称:course.visitor.list,SDK对应方法:courseVisitorList

下载SDK

直播平台为我们准备了SDK,我们直接使用

下载地址:https://open.talk-fun.com/docs/getstartV2/api/introduce/sdkdownload.html

已下载:当前目录/MTCloud-java-sdk-1.6.zip

硅谷课堂笔记(下)_第26张图片

基础环境搭建

创建service_live模块
硅谷课堂笔记(下)_第27张图片
Pom引入相关依赖


<dependency>
    <groupId>commons-httpclientgroupId>
    <artifactId>commons-httpclientartifactId>
    <version>3.0.1version>
dependency>
<dependency>
    <groupId>net.sf.json-libgroupId>
    <artifactId>json-libartifactId>
    <version>2.4version>
    <classifier>jdk15classifier>
dependency>

刚刚在上面下载的直播SDK
硅谷课堂笔记(下)_第28张图片
把SDK文件夹下的内容复制进工程
硅谷课堂笔记(下)_第29张图片
涉及的数据库
硅谷课堂笔记(下)_第30张图片
代码生成、配置文件、网关注册 之类的我就不多说了
硅谷课堂笔记(下)_第31张图片
硅谷课堂笔记(下)_第32张图片

功能实现-直播课程列表接口

硅谷课堂笔记(下)_第33张图片
硅谷课堂笔记(下)_第34张图片
硅谷课堂笔记(下)_第35张图片
分页查询
LiveCourseController类

@RestController
@RequestMapping(value="/admin/live/liveCourse")
public class LiveCourseController {

    @Autowired
    private LiveCourseService liveCourseService;

    @Autowired
    private LiveCourseAccountService liveCourseAccountService;

    @ApiOperation(value = "获取分页列表")
    @GetMapping("{page}/{limit}")
    public Result index(
            @ApiParam(name = "page", value = "当前页码", required = true)
            @PathVariable Long page,
            @ApiParam(name = "limit", value = "每页记录数", required = true)
            @PathVariable Long limit) {
        Page<LiveCourse> pageParam = new Page<>(page, limit);
        IPage<LiveCourse> pageModel = liveCourseService.selectPage(pageParam);
        return Result.ok(pageModel);
    }
}

LiveCourseService接口

public interface LiveCourseService extends IService<LiveCourse> {
    //直播课程分页查询
    IPage<LiveCourse> selectPage(Page<LiveCourse> pageParam);
}

下一步就该写分页查询实现类了,但是因为有教师相关信息,所以又得远程接口调用了

远程调用获取教师信息

硅谷课堂笔记(下)_第36张图片
专门查询直播课程教师的

@ApiOperation("根据id查询")
@GetMapping("inner/getTeacher/{id}")
public Teacher getTeacherLive(@PathVariable Long id) {
    Teacher teacher = teacherService.getById(id);
    return teacher;
}

远程接口定义
硅谷课堂笔记(下)_第37张图片
硅谷课堂笔记(下)_第38张图片

LiveCourseService接口继续开发

远程调用处理好了,就可以开始继续开发接口实现类了
先把远程调用模块的接口加上

        
        <dependency>
            <artifactId>service_clientartifactId>
            <groupId>comgroupId>
            <version>0.0.1-SNAPSHOTversion>
        dependency>

硅谷课堂笔记(下)_第39张图片
测试
硅谷课堂笔记(下)_第40张图片

功能实现-直播课程添加接口

硅谷课堂笔记(下)_第41张图片
硅谷课堂笔记(下)_第42张图片
参数是JSON形式的对象

先添加工具类对象
硅谷课堂笔记(下)_第43张图片
LiveCourseController类
LiveCourseService接口

        Boolean save(LiveCourseFormVo liveCourseVo);

LiveCourseServiceImpl实现,这个挺多的,建议看看

功能实现-直播课程删除接口

硅谷课堂笔记(下)_第44张图片

LiveCourseController类

@ApiOperation(value = "删除")
@DeleteMapping("remove/{id}")
public Result remove(@PathVariable Long id) {
    liveCourseService.removeLive(id);
    return Result.ok(null);
}

LiveCourseService接口

//删除直播课程
void removeLive(Long id);

LiveCourseServiceImpl实现

//删除直播课程
@Override
public void removeLive(Long id) {
    //根据id查询直播课程信息
    LiveCourse liveCourse = baseMapper.selectById(id);
    if(liveCourse != null) {
        //获取直播courseid
        Long courseId = liveCourse.getCourseId();
        try {
            //调用方法删除平台直播课程
            mtCloudClient.courseDelete(courseId.toString());
            //删除表数据
            baseMapper.deleteById(id);
        } catch (Exception e) {
            e.printStackTrace();
            throw new GgktException(20001,"删除直播课程失败");
        }
    }
}

功能实现-直播课程修改接口

硅谷课堂笔记(下)_第45张图片
LiveCourseController类

@ApiOperation(value = "获取")
@GetMapping("get/{id}")
public Result<LiveCourse> get(@PathVariable Long id) {
    LiveCourse liveCourse = liveCourseService.getById(id);
    return Result.ok(liveCourse);
}

@ApiOperation(value = "获取")
@GetMapping("getInfo/{id}")
public Result<LiveCourseFormVo> getInfo(@PathVariable Long id) {
    return Result.ok(liveCourseService.getLiveCourseFormVo(id));
}

@ApiOperation(value = "修改")
@PutMapping("update")
public Result updateById(@RequestBody LiveCourseFormVo liveCourseVo) {
    liveCourseService.updateById(liveCourseVo);
    return Result.ok(null);
}

LiveCourseService接口

    //修改
    void updateById(LiveCourseFormVo liveCourseVo);

    //获取
    LiveCourseFormVo getLiveCourseFormVo(Long id);

LiveCourseServiceImpl实现

@Resource
private LiveCourseAccountService liveCourseAccountService;

@Resource
private LiveCourseDescriptionService liveCourseDescriptionService;

@Autowired
private CourseFeignClient teacherFeignClient;

@Resource
private MTCloud mtCloudClient;

//更新
@Override
public void updateById(LiveCourseFormVo liveCourseFormVo) {
    //根据id获取直播课程基本信息
    LiveCourse liveCourse = baseMapper.selectById(liveCourseFormVo.getId());
    BeanUtils.copyProperties(liveCourseFormVo,liveCourse);
    //讲师
    Teacher teacher =
            teacherFeignClient.getTeacherInfo(liveCourseFormVo.getTeacherId());

//             *   course_id 课程ID
//     *   account 发起直播课程的主播账号
//     *   course_name 课程名称
//     *   start_time 课程开始时间,格式:2015-01-01 12:00:00
//                *   end_time 课程结束时间,格式:2015-01-01 13:00:00
//                *   nickname 	主播的昵称
//                *   accountIntro 	主播的简介
//                *  options 		可选参数
    HashMap<Object, Object> options = new HashMap<>();
    try {
        String res = mtCloudClient.courseUpdate(liveCourse.getCourseId().toString(),
                teacher.getId().toString(),
                liveCourse.getCourseName(),
                new DateTime(liveCourse.getStartTime()).toString("yyyy-MM-dd HH:mm:ss"),
                new DateTime(liveCourse.getEndTime()).toString("yyyy-MM-dd HH:mm:ss"),
                teacher.getName(),
                teacher.getIntro(),
                options);
        //返回结果转换,判断是否成功
        CommonResult<JSONObject> commonResult = JSON.parseObject(res, CommonResult.class);
        if(Integer.parseInt(commonResult.getCode()) == MTCloud.CODE_SUCCESS) {
            JSONObject object = commonResult.getData();
            //更新直播课程基本信息
            liveCourse.setCourseId(object.getLong("course_id"));
            baseMapper.updateById(liveCourse);
            //直播课程描述信息更新
            LiveCourseDescription liveCourseDescription =
                    liveCourseDescriptionService.getLiveCourseById(liveCourse.getId());
            liveCourseDescription.setDescription(liveCourseFormVo.getDescription());
            liveCourseDescriptionService.updateById(liveCourseDescription);
        } else {
            throw new GgktException(20001,"修改直播课程失败");
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

@Override
public LiveCourseFormVo getLiveCourseFormVo(Long id) {
    LiveCourse liveCourse = this.getById(id);
    LiveCourseDescription liveCourseDescription = liveCourseDescriptionService.getByLiveCourseId(id);

    LiveCourseFormVo liveCourseFormVo = new LiveCourseFormVo();
    BeanUtils.copyProperties(liveCourse, liveCourseFormVo);
    liveCourseFormVo.setDescription(liveCourseDescription.getDescription());
    return liveCourseFormVo;
}

LiveCourseDescriptionService添加方法

    public interface LiveCourseDescriptionService extends IService<LiveCourseDescription> {
        LiveCourseDescription getByLiveCourseId(Long liveCourseId);
    }

LiveCourseDescriptionServiceImpl实现方法

    @Service
    public class LiveCourseDescriptionServiceImpl extends ServiceImpl<LiveCourseDescriptionMapper, LiveCourseDescription> implements LiveCourseDescriptionService {

        @Override
        public LiveCourseDescription getByLiveCourseId(Long liveCourseId) {
            return this.getOne(new LambdaQueryWrapper<LiveCourseDescription>().eq(LiveCourseDescription::getLiveCourseId, liveCourseId));
        }
    }

功能实现-查看账号接口

硅谷课堂笔记(下)_第46张图片
LiveCourseController类

@Autowired
private LiveCourseAccountService liveCourseAccountService;
	
	@ApiOperation(value = "获取")
	@GetMapping("getLiveCourseAccount/{id}")
	public Result<LiveCourseAccount> getLiveCourseAccount(@PathVariable Long id) {
	    return Result.ok(liveCourseAccountService.getByLiveCourseId(id));
	}

LiveCourseAccountService接口

public interface LiveCourseAccountService extends IService<LiveCourseAccount> {
    LiveCourseAccount getByLiveCourseId(Long liveCourseId);
}

LiveCourseAccountServiceImpl实现

@Service
public class LiveCourseAccountServiceImpl extends ServiceImpl<LiveCourseAccountMapper, LiveCourseAccount> implements LiveCourseAccountService {

    @Override
    public LiveCourseAccount getByLiveCourseId(Long liveCourseId) {
        return baseMapper.selectOne(new LambdaQueryWrapper<LiveCourseAccount>().eq(LiveCourseAccount::getLiveCourseId, liveCourseId));
    }
}

功能实现-配置和观看记录接口

硅谷课堂笔记(下)_第47张图片

查看配置信息

(1)LiveCourseController类

@ApiOperation(value = "获取")
@GetMapping("getCourseConfig/{id}")
public Result getCourseConfig(@PathVariable Long id) {
    return Result.ok(liveCourseService.getCourseConfig(id));
}

(2)LiveCourseService添加方法

//获取配置
LiveCourseConfigVo getCourseConfig(Long id);

(3)LiveCourseServiceImpl实现

@Autowired
private LiveCourseConfigService liveCourseConfigService;

@Autowired
private LiveCourseGoodsService liveCourseGoodsService;

@Override
public LiveCourseConfigVo getCourseConfig(Long id) {
    LiveCourseConfigVo liveCourseConfigVo = new LiveCourseConfigVo();
    LiveCourseConfig liveCourseConfig = liveCourseConfigService.getByLiveCourseId(id);
    if(null != liveCourseConfig) {
        List<LiveCourseGoods> liveCourseGoodsList = liveCourseGoodsService.findByLiveCourseId(id);
        BeanUtils.copyProperties(liveCourseConfig, liveCourseConfigVo);
        liveCourseConfigVo.setLiveCourseGoodsList(liveCourseGoodsList);
    }
    return liveCourseConfigVo;
}

(4)LiveCourseConfigService添加方法

public interface LiveCourseConfigService extends IService<LiveCourseConfig> {
    //查看配置信息
    LiveCourseConfig getByLiveCourseId(Long id);
}

(5)LiveCourseConfigServiceImpl实现方法

@Service
public class LiveCourseConfigServiceImpl extends ServiceImpl<LiveCourseConfigMapper, LiveCourseConfig> implements LiveCourseConfigService {

    //查看配置信息
    @Override
    public LiveCourseConfig getByLiveCourseId(Long liveCourseId) {
        return baseMapper.selectOne(new LambdaQueryWrapper<LiveCourseConfig>().eq(
                LiveCourseConfig::getLiveCourseId,
                liveCourseId));
    }
}

(6)LiveCourseGoodsService添加方法

public interface LiveCourseGoodsService extends IService<LiveCourseGoods> {
    //获取课程商品列表
    List<LiveCourseGoods> findByLiveCourseId(Long id);
}

(7)LiveCourseGoodsServiceImpl实现方法

@Service
public class LiveCourseGoodsServiceImpl extends ServiceImpl<LiveCourseGoodsMapper, LiveCourseGoods> implements LiveCourseGoodsService {

    //获取课程商品列表
    @Override
    public List<LiveCourseGoods> findByLiveCourseId(Long liveCourseId) {
        return baseMapper.selectList(new LambdaQueryWrapper<LiveCourseGoods>()
                .eq(LiveCourseGoods::getLiveCourseId, liveCourseId));
    }
}

修改直播配置信息

硅谷课堂笔记(下)_第48张图片

(1)LiveCourseController添加方法

@ApiOperation(value = "修改配置")
@PutMapping("updateConfig")
public Result updateConfig(@RequestBody LiveCourseConfigVo liveCourseConfigVo) {
    liveCourseService.updateConfig(liveCourseConfigVo);
    return Result.ok(null);
}

(2)LiveCourseService添加方法

//修改配置
void updateConfig(LiveCourseConfigVo liveCourseConfigVo);

(3)LiveCourseServiceImpl实现方法

@Override
public void updateConfig(LiveCourseConfigVo liveCourseConfigVo) {
    LiveCourseConfig liveCourseConfigUpt = new LiveCourseConfig();
    BeanUtils.copyProperties(liveCourseConfigVo, liveCourseConfigUpt);
    if(null == liveCourseConfigVo.getId()) {
        liveCourseConfigService.save(liveCourseConfigUpt);
    } else {
        liveCourseConfigService.updateById(liveCourseConfigUpt);
    }
    liveCourseGoodsService.remove(new LambdaQueryWrapper<LiveCourseGoods>().eq(LiveCourseGoods::getLiveCourseId, liveCourseConfigVo.getLiveCourseId()));
    if(!CollectionUtils.isEmpty(liveCourseConfigVo.getLiveCourseGoodsList())) {
        liveCourseGoodsService.saveBatch(liveCourseConfigVo.getLiveCourseGoodsList());
    }
    this.updateLifeConfig(liveCourseConfigVo);
}
/**
 * 上传直播配置
 * @param liveCourseConfigVo
 */
@SneakyThrows
private void updateLifeConfig(LiveCourseConfigVo liveCourseConfigVo) {
    LiveCourse liveCourse = this.getById(liveCourseConfigVo.getLiveCourseId());

    //参数设置
    HashMap<Object,Object> options = new HashMap<Object, Object>();
    //界面模式
    options.put("pageViewMode", liveCourseConfigVo.getPageViewMode());
    //观看人数开关
    JSONObject number = new JSONObject();
    number.put("enable", liveCourseConfigVo.getNumberEnable());
    options.put("number", number.toJSONString());
    //观看人数开关
    JSONObject store = new JSONObject();
    number.put("enable", liveCourseConfigVo.getStoreEnable());
    number.put("type", liveCourseConfigVo.getStoreType());
    options.put("store", number.toJSONString());
    //商城列表
    List<LiveCourseGoods> liveCourseGoodsList = liveCourseConfigVo.getLiveCourseGoodsList();
    if(!CollectionUtils.isEmpty(liveCourseGoodsList)) {
        List<LiveCourseGoodsView> liveCourseGoodsViewList = new ArrayList<>();
        for(LiveCourseGoods liveCourseGoods : liveCourseGoodsList) {
            LiveCourseGoodsView liveCourseGoodsView = new LiveCourseGoodsView();
            BeanUtils.copyProperties(liveCourseGoods, liveCourseGoodsView);
            liveCourseGoodsViewList.add(liveCourseGoodsView);
        }
        JSONObject goodsListEdit = new JSONObject();
        goodsListEdit.put("status", "0");
        options.put("goodsListEdit ", goodsListEdit.toJSONString());
        options.put("goodsList", JSON.toJSONString(liveCourseGoodsViewList));
    }
    
    String res = mtCloudClient.courseUpdateLifeConfig(liveCourse.getCourseId().toString(), options);

    CommonResult<JSONObject> commonResult = JSON.parseObject(res, CommonResult.class);
    if(Integer.parseInt(commonResult.getCode()) != MTCloud.CODE_SUCCESS) {
        throw new GgktException(20001,"修改配置信息失败");
    }
}

获取最近直播课程

硅谷课堂笔记(下)_第49张图片

(1)LiveCourseController添加方法

@ApiOperation(value = "获取最近的直播")
@GetMapping("findLatelyList")
public Result findLatelyList() {
    return Result.ok(liveCourseService.findLatelyList());
}

(2)LiveCourseService添加方法

//获取最近的直播
List<LiveCourseVo> findLatelyList();

(3)LiveCourseServiceImpl实现方法

@Override
public List<LiveCourseVo> findLatelyList() {
    List<LiveCourseVo> liveCourseVoList = baseMapper.findLatelyList();

    for(LiveCourseVo liveCourseVo : liveCourseVoList) {
        liveCourseVo.setStartTimeString(new DateTime(liveCourseVo.getStartTime()).toString("yyyy年MM月dd HH:mm"));
        liveCourseVo.setEndTimeString(new DateTime(liveCourseVo.getEndTime()).toString("HH:mm"));

        Long teacherId = liveCourseVo.getTeacherId();
        Teacher teacher = teacherFeignClient.getTeacherInfo(teacherId);
        liveCourseVo.setTeacher(teacher);

        liveCourseVo.setLiveStatus(this.getLiveStatus(liveCourseVo));
    }
    return liveCourseVoList;
}

/**
 * 直播状态 0:未开始 1:直播中 2:直播结束
 * @param liveCourse
 * @return
 */
private int getLiveStatus(LiveCourse liveCourse) {
    // 直播状态 0:未开始 1:直播中 2:直播结束
    int liveStatus = 0;
    Date curTime = new Date();
    if(DateUtil.dateCompare(curTime, liveCourse.getStartTime())) {
        liveStatus = 0;
    } else if(DateUtil.dateCompare(curTime, liveCourse.getEndTime())) {
        liveStatus = 1;
    } else {
        liveStatus = 2;
    }
    return liveStatus;
}

(4)LiveCourseMapper添加方法

public interface LiveCourseMapper extends BaseMapper<LiveCourse> {
    //获取最近直播
    List<LiveCourseVo> findLatelyList();
}

(5)LiveCourseMapper.xml编写sql语句


DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.ggkt.live.mapper.LiveCourseMapper">
    <resultMap id="liveCourseMap" type="com.atguigu.ggkt.vo.live.LiveCourseVo" autoMapping="true">
    resultMap>

    
    <sql id="columns">
id,course_id,course_name,start_time,end_time,teacher_id,cover,create_time,update_time,is_deleted
	sql>

    <select id="findLatelyList" resultMap="liveCourseMap">
        select <include refid="columns" />
        from live_course
        where date(start_time) >= curdate()
        order by id asc
        limit 5
    select>
mapper>

整合直播管理前端

service_vod添加方法

(1)CourseController添加方法

@GetMapping("findAll")
public Result findAll() {
    List<Course> list = courseService.findlist();
    return Result.ok(list);
}

(2)CourseService实现方法

@Override
public List<Course> findlist() {
    List<Course> list = baseMapper.selectList(null);
    list.stream().forEach(item -> {
        this.getTeacherAndSubjectName(item);
    });
    return list;
}

前端内容

先改路由 router->index.js路由
硅谷课堂笔记(下)_第50张图片
定义调用接口
硅谷课堂笔记(下)_第51张图片
CV页面样式
硅谷课堂笔记(下)_第52张图片

公众号直播对接

用户观看端集成

接口文档:https://open.talk-fun.com/docs/js/index.html

获取用户access_token

用户要观看直播,必须获取对应的用户access_token,通过access_token 获取观看的直播课程;

接口参数:直播id,用户id

还是在Live模块下创建LiveCourseApiController

(1)创建LiveCourseApiController
(2)LiveCourseService添加方法

JSONObject getPlayAuth(Long id, Long userId);

(3)LiveCourseServiceImpl实现方法

下载前端SDK

下载地址:https://open.talk-fun.com/docs/js/download.html

硅谷课堂笔记(下)_第53张图片
使用快捷模板

下载模板,修改token获取方式

硅谷课堂笔记(下)_第54张图片
硅谷课堂笔记(下)_第55张图片

var url  = window.location.search
var token = url.split("=")[1]

与前端项目结合

(1)创建直播播放页面 live.html
硅谷课堂笔记(下)_第56张图片
观众在直播详情页面点击观看,获取通过接口获取access_token,然后带上access_token参数跳转到直播观看页面即可,关键代码:

liveInfo.vue

play() {
  api.getPlayAuth(this.liveCourseId).then(response => {
    console.log(response.data);
    window.location = './live.html?token='+response.data.access_token;
    this.finished = true;
  });
},

http://localhost:8080/live.html为直播观看访问方式

补充接口

(1)LiveCourseApiController类

@ApiOperation("根据ID查询课程")
@GetMapping("getInfo/{courseId}")
public Result getInfo(
    @ApiParam(value = "课程ID", required = true)
    @PathVariable Long courseId){
    Map<String, Object> map = liveCourseService.getInfoById(courseId);
    return Result.ok(map);
}

(2)LiveCourseServiceImpl实现

@Override
public Map<String, Object> getInfoById(Long id) {
    LiveCourse liveCourse = this.getById(id);
    liveCourse.getParam().put("startTimeString", new DateTime(liveCourse.getStartTime()).toString("yyyy年MM月dd HH:mm"));
    liveCourse.getParam().put("endTimeString", new DateTime(liveCourse.getEndTime()).toString("yyyy年MM月dd HH:mm"));
    Teacher teacher = teacherFeignClient.get(liveCourse.getTeacherId());
    LiveCourseDescription liveCourseDescription = liveCourseDescriptionService.getByLiveCourseId(id);

    Map<String, Object> map = new HashMap<>();
    map.put("liveCourse", liveCourse);
    map.put("liveStatus", this.getLiveStatus(liveCourse));
    map.put("teacher", teacher);
    if(null != liveCourseDescription) {
        map.put("description", liveCourseDescription.getDescription());
    } else {
        map.put("description", "");
    }
    return map;
}

腾讯云部署

这个我觉得挺重要的,单独拿一篇出来讲
地址:

你可能感兴趣的:(笔记,在线课堂内容,微信)