从这开始有点摆烂了,有点累了写不动了,很大一部分是抄了官方的笔记,兄弟们见谅
接口文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1
(1)绑定域名
与微信分享一致
先登录微信公众平台进入“设置与开发”,“公众号设置”的“功能设置”里填写“JS接口安全域名”。
说明:因为测试号不支持支付功能,需要使用正式号才能进行测试。
(2)商户平台配置支付目录
(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到支付接口中测试
(1)trade.vue订单页面
(2)pay.vue微信支付页面
支付完毕后会得到一个序列号
我们通过这个方法把这个序列号进行测试
(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.聊天互动。
通用直播模型
如何快速开发完整直播
利用第三方SDK开发
第三方SDK好处
欢拓云直播
根据上面的综合对比和调研,我们最终选择了“欢拓与直播平台”,它为我们提供了完整的可以直接使用的示例代码,方便我们开发对接。
欢拓是一家以直播技术为核心的网络平台,旨在帮助人们通过网络也能实现真实互动通讯。从2010年开始,欢拓就专注于音频、视频的采样、编码、后处理及智能传输研究,并于2013年底正式推出了针对企业/开发者的直播云服务系统,帮助开发者轻松实现真人互动。该系统适用场景包括在线教育、游戏语音、娱乐互动、远程会议(PC、移动均可)等等。针对应用场景,采用先进技术解决方案和产品形态,让客户和客户的用户满意!
官网:https://www.talk-fun.com/
接口文档地址:http://open.talk-fun.com/docs/getstartV2/document.html
开通账号
通过官网:https://www.talk-fun.com/,联系客户或400电话开通账号,开通**“生活直播”**权限。开通后注意使用有效期,一般一周左右,可以再次申请延期。
说明:官网免费试用,功能有限制,不建议使用
创建直播
1、在直播管理创建直播
2、创建直播,选择主播模式
开始直播
1、在直播列表,点击“直播入口”
主播端下载“云直播客户端”,“频道id与密码”为直播客户端的登录账号;
下面还有管理员,主播进行直播时,助教可以在聊天时与观众互动。
2、电脑端安装后如图:
3、使用“频道id与密码”登录
4、点击“开始直播”,打开摄像头即可开始直播。
用户观看
1、在直播列表,点击“直播入口”
2、在观众一栏点击进入,即可在网页端观看直播。
体验总结
上面的体验完全能够满足我们业务的需要,硅谷课堂的需求是定期推出直播课程,方便学员与名师之间的交流互动,在直播间老师可以推荐点播课程(类似直播带货),学员可以点赞交流,购买推荐的点播课程。
直播平台只是做了直播相关的业务,不能与我们的业务进行衔接,我们期望是在硅谷课堂的管理后台管理直播相关的业务,那么怎么做呢?对接直播业务接口,直播平台有对应的直播接口,我们直接对接即可。
tml#bdpc):基于专业的跨平台视频编解码技术和大规模视频内容分发网络,提供稳定流畅、低延时、高并发的实时音视频服务,可将视频直播无缝对接到自身App.
第三方SDK好处
根据上面的综合对比和调研,我们最终选择了“欢拓与直播平台”,它为我们提供了完整的可以直接使用的示例代码,方便我们开发对接。
欢拓是一家以直播技术为核心的网络平台,旨在帮助人们通过网络也能实现真实互动通讯。从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电话开通账号,开通**“生活直播”**权限。开通后注意使用有效期,一般一周左右,可以再次申请延期。
说明:官网免费试用,功能有限制,不建议使用
创建直播
3、配置直播,可以自行查看
开始直播
1、在直播列表,点击“直播入口”
主播端下载“云直播客户端”,“频道id与密码”为直播客户端的登录账号;
下面还有管理员,主播进行直播时,助教可以在聊天时与观众互动。
2、电脑端安装后如图:
3、使用“频道id与密码”登录
4、点击“开始直播”,打开摄像头即可开始直播。
用户观看
1、在直播列表,点击“直播入口”
2、在观众一栏点击进入,即可在网页端观看直播。
体验总结
上面的体验完全能够满足我们业务的需要,硅谷课堂的需求是定期推出直播课程,方便学员与名师之间的交流互动,在直播间老师可以推荐点播课程(类似直播带货),学员可以点赞交流,购买推荐的点播课程。
直播平台只是做了直播相关的业务,不能与我们的业务进行衔接,我们期望是在硅谷课堂的管理后台管理直播相关的业务,那么怎么做呢?对接直播业务接口,直播平台有对应的直播接口,我们直接对接即可。
上面我们已经开通了“生活类直播”。
获取openId与openToken
登录进入开放后台,后台首页即可获取openId与openToken
对接说明
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
了解接口文档
根据接口文档,了解我们需要对接哪些接口
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};
直播设置最终效果:
按照课程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
<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
把SDK文件夹下的内容复制进工程
涉及的数据库
代码生成、配置文件、网关注册 之类的我就不多说了
@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);
}
下一步就该写分页查询实现类了,但是因为有教师相关信息,所以又得远程接口调用了
@ApiOperation("根据id查询")
@GetMapping("inner/getTeacher/{id}")
public Teacher getTeacherLive(@PathVariable Long id) {
Teacher teacher = teacherService.getById(id);
return teacher;
}
远程调用处理好了,就可以开始继续开发接口实现类了
先把远程调用模块的接口加上
<dependency>
<artifactId>service_clientartifactId>
<groupId>comgroupId>
<version>0.0.1-SNAPSHOTversion>
dependency>
先添加工具类对象
LiveCourseController类
LiveCourseService接口
Boolean save(LiveCourseFormVo liveCourseVo);
LiveCourseServiceImpl实现,这个挺多的,建议看看
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,"删除直播课程失败");
}
}
}
@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));
}
}
@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));
}
}
查看配置信息
(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));
}
}
(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,"修改配置信息失败");
}
}
(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>
(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路由
定义调用接口
CV页面样式
用户观看端集成
接口文档:https://open.talk-fun.com/docs/js/index.html
用户要观看直播,必须获取对应的用户access_token,通过access_token 获取观看的直播课程;
接口参数:直播id,用户id
还是在Live模块下创建LiveCourseApiController
(1)创建LiveCourseApiController
(2)LiveCourseService添加方法
JSONObject getPlayAuth(Long id, Long userId);
(3)LiveCourseServiceImpl实现方法
下载地址:https://open.talk-fun.com/docs/js/download.html
下载模板,修改token获取方式
var url = window.location.search
var token = url.split("=")[1]
(1)创建直播播放页面 live.html
观众在直播详情页面点击观看,获取通过接口获取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;
}
这个我觉得挺重要的,单独拿一篇出来讲
地址: