浏览代码

增加直播部分功能

hgw 3 年之前
父节点
当前提交
407dd73db9
共有 33 个文件被更改,包括 2035 次插入347 次删除
  1. 28 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dao/ImLiveBroadcastRoomDao.java
  2. 20 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dao/ImLiveBroadcastRoomDataDao.java
  3. 20 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dao/ImLiveBroadcastRoomMemberDao.java
  4. 154 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dto/ImLiveBroadcastRoomDto.java
  5. 217 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/entity/ImLiveBroadcastRoom.java
  6. 109 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/entity/ImLiveBroadcastRoomData.java
  7. 97 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/entity/ImLiveBroadcastRoomMember.java
  8. 196 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/vo/ImLiveBroadcastRoomVo.java
  9. 15 0
      mec-biz/src/main/java/com/ym/mec/biz/service/ImLiveBroadcastRoomDataService.java
  10. 15 0
      mec-biz/src/main/java/com/ym/mec/biz/service/ImLiveBroadcastRoomMemberService.java
  11. 34 0
      mec-biz/src/main/java/com/ym/mec/biz/service/ImLiveBroadcastRoomService.java
  12. 25 0
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/ImLiveBroadcastRoomDataServiceImpl.java
  13. 25 0
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/ImLiveBroadcastRoomMemberServiceImpl.java
  14. 193 0
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/ImLiveBroadcastRoomServiceImpl.java
  15. 30 0
      mec-biz/src/main/resources/config/mybatis/ImLiveBroadcastRoomDataMapper.xml
  16. 88 0
      mec-biz/src/main/resources/config/mybatis/ImLiveBroadcastRoomMapper.xml
  17. 27 0
      mec-biz/src/main/resources/config/mybatis/ImLiveBroadcastRoomMemberMapper.xml
  18. 133 109
      mec-client-api/src/main/java/com/ym/mec/im/ImFeignService.java
  19. 10 0
      mec-client-api/src/main/java/com/ym/mec/im/fallback/ImFeignServiceFallback.java
  20. 34 0
      mec-im/src/main/java/com/ym/controller/LiveRoomController.java
  21. 1 1
      mec-im/src/main/java/com/ym/enums/ActionEnum.java
  22. 1 1
      mec-im/src/main/java/com/ym/enums/DeviceTypeEnum.java
  23. 1 1
      mec-im/src/main/java/com/ym/enums/RoleEnum.java
  24. 52 34
      mec-im/src/main/java/com/ym/http/HttpHelper.java
  25. 81 17
      mec-im/src/main/java/com/ym/mec/im/IMHelper.java
  26. 1 0
      mec-im/src/main/java/com/ym/pojo/ControlDeviceTaskInfo.java
  27. 1 0
      mec-im/src/main/java/com/ym/pojo/UpgradeRoleTaskInfo.java
  28. 70 0
      mec-im/src/main/java/com/ym/service/Impl/LiveRoomServiceImpl.java
  29. 187 184
      mec-im/src/main/java/com/ym/service/Impl/RoomServiceImpl.java
  30. 14 0
      mec-im/src/main/java/com/ym/service/LiveRoomService.java
  31. 98 0
      mec-web/src/main/java/com/ym/mec/web/controller/ImLiveBroadcastRoomController.java
  32. 29 0
      mec-web/src/main/java/com/ym/mec/web/controller/ImLiveBroadcastRoomDataController.java
  33. 29 0
      mec-web/src/main/java/com/ym/mec/web/controller/ImLiveBroadcastRoomMemberController.java

+ 28 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dao/ImLiveBroadcastRoomDao.java

@@ -0,0 +1,28 @@
+package com.ym.mec.biz.dal.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ym.mec.biz.dal.entity.ImLiveBroadcastRoom;
+import com.ym.mec.biz.dal.vo.ImLiveBroadcastRoomVo;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 直播房间管理表(ImLiveBroadcastRoom)表数据库访问层
+ *
+ * @author hgw
+ * @since 2022-02-17 20:52:05
+ */
+public interface ImLiveBroadcastRoomDao extends BaseMapper<ImLiveBroadcastRoom> {
+
+    <T> IPage<T> queryPage(Page<T> page, @Param("param") Map<String, Object> param);
+
+    List<ImLiveBroadcastRoomVo> queryPage(@Param("param") Map<String, Object> param);
+
+    int insertBatch(@Param("entities") List<ImLiveBroadcastRoom> entities);
+
+}
+

+ 20 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dao/ImLiveBroadcastRoomDataDao.java

@@ -0,0 +1,20 @@
+package com.ym.mec.biz.dal.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ym.mec.biz.dal.entity.ImLiveBroadcastRoomData;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 直播房间数据表(ImLiveBroadcastRoomData)表数据库访问层
+ *
+ * @author hgw
+ * @since 2022-02-21 14:26:58
+ */
+public interface ImLiveBroadcastRoomDataDao extends BaseMapper<ImLiveBroadcastRoomData> {
+
+    int insertBatch(@Param("entities") List<ImLiveBroadcastRoomData> entities);
+
+}
+

+ 20 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dao/ImLiveBroadcastRoomMemberDao.java

@@ -0,0 +1,20 @@
+package com.ym.mec.biz.dal.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ym.mec.biz.dal.entity.ImLiveBroadcastRoomMember;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 直播间人员关系表(ImLiveBroadcastRoomMember)表数据库访问层
+ *
+ * @author hgw
+ * @since 2022-02-21 14:26:58
+ */
+public interface ImLiveBroadcastRoomMemberDao extends BaseMapper<ImLiveBroadcastRoomMember> {
+
+    int insertBatch(@Param("entities") List<ImLiveBroadcastRoomMember> entities);
+
+}
+

+ 154 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dto/ImLiveBroadcastRoomDto.java

@@ -0,0 +1,154 @@
+package com.ym.mec.biz.dal.dto;
+
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 直播房间管理表(ImLiveBroadcastRoom)表实体类
+ *
+ * @author hgw
+ * @since 2022-02-17 20:52:05
+ */
+@ApiModel(value = "直播房间管理")
+public class ImLiveBroadcastRoomDto implements Serializable {
+    @ApiModelProperty(value = "主键")
+    private Integer id;
+
+    @ApiModelProperty(value = "机构id")
+    private Integer tenantId;
+
+    @NotNull(message = "主讲人不能为空!")
+    @ApiModelProperty(value = "主讲人id/老师id")
+    private Integer speakerId;
+
+    @Size(max = 13, message = "房间标题最多12个字!")
+    @NotBlank(message = "房间标题不能为空")
+    @ApiModelProperty(value = "房间标题/最多12个字")
+    private String roomTitle;
+
+    @NotNull(message = "直播开始时间不能为空!")
+    @ApiModelProperty(value = "直播开始时间")
+    private Date liveStartTime;
+
+    @Size(max = 13, message = "直播内容最多200个字!")
+    @NotBlank(message = "直播内容不能为空")
+    @ApiModelProperty(value = "直播内容/最多200个字")
+    private String liveRemark;
+
+    @NotBlank(message = "预热模版不能为空")
+    @ApiModelProperty(value = "预热模版")
+    private String preTemplate;
+
+    @ApiModelProperty(value = "房间配置")
+    private RoomConfig roomConfig;
+
+    @ApiModel(value = "房间配置")
+    public static class RoomConfig implements Serializable {
+
+        @ApiModelProperty(value = "是否允许点赞 0允许 1不允许")
+        private Integer whether_like = 0;
+
+        @ApiModelProperty(value = "是否允许聊天互动  0允许 1不允许")
+        private Integer whether_chat = 0;
+
+        @ApiModelProperty(value = "是否允许保存直播回放 0允许 1不允许")
+        private Integer whether_video = 1;
+
+        public Integer getWhether_like() {
+            return whether_like;
+        }
+
+        public void setWhether_like(Integer whether_like) {
+            this.whether_like = whether_like;
+        }
+
+        public Integer getWhether_chat() {
+            return whether_chat;
+        }
+
+        public void setWhether_chat(Integer whether_chat) {
+            this.whether_chat = whether_chat;
+        }
+
+        public Integer getWhether_video() {
+            return whether_video;
+        }
+
+        public void setWhether_video(Integer whether_video) {
+            this.whether_video = whether_video;
+        }
+    }
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getTenantId() {
+        return tenantId;
+    }
+
+    public void setTenantId(Integer tenantId) {
+        this.tenantId = tenantId;
+    }
+
+    public Integer getSpeakerId() {
+        return speakerId;
+    }
+
+    public void setSpeakerId(Integer speakerId) {
+        this.speakerId = speakerId;
+    }
+
+    public String getRoomTitle() {
+        return roomTitle;
+    }
+
+    public void setRoomTitle(String roomTitle) {
+        this.roomTitle = roomTitle;
+    }
+
+    public Date getLiveStartTime() {
+        return liveStartTime;
+    }
+
+    public void setLiveStartTime(Date liveStartTime) {
+        this.liveStartTime = liveStartTime;
+    }
+
+    public String getLiveRemark() {
+        return liveRemark;
+    }
+
+    public void setLiveRemark(String liveRemark) {
+        this.liveRemark = liveRemark;
+    }
+
+    public String getPreTemplate() {
+        return preTemplate;
+    }
+
+    public void setPreTemplate(String preTemplate) {
+        this.preTemplate = preTemplate;
+    }
+
+    public RoomConfig getRoomConfig() {
+        return roomConfig;
+    }
+
+    public void setRoomConfig(RoomConfig roomConfig) {
+        this.roomConfig = roomConfig;
+    }
+
+}
+

+ 217 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/entity/ImLiveBroadcastRoom.java

@@ -0,0 +1,217 @@
+package com.ym.mec.biz.dal.entity;
+
+
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import com.baomidou.mybatisplus.annotation.TableId;
+
+import java.io.Serializable;
+
+/**
+ * 直播房间管理表(ImLiveBroadcastRoom)表实体类
+ *
+ * @author hgw
+ * @since 2022-02-17 20:52:05
+ */
+@ApiModel(value = "im_live_broadcast_room-直播房间管理表")
+public class ImLiveBroadcastRoom implements Serializable {
+    @TableId(value = "id_", type = IdType.AUTO)
+    @ApiModelProperty(value = "主键")
+    private Integer id;
+
+    @TableField("tenant_id_")
+    @ApiModelProperty(value = "机构id")
+    private Integer tenantId;
+
+    @TableField("speaker_id_")
+    @ApiModelProperty(value = "主讲人id/老师id")
+    private Integer speakerId;
+
+    @TableField("room_uid_")
+    @ApiModelProperty(value = "房间编号")
+    private String roomUid;
+
+    @TableField("room_title_")
+    @ApiModelProperty(value = "房间标题/最多12个字")
+    private String roomTitle;
+
+    @TableField("live_start_time_")
+    @ApiModelProperty(value = "直播开始时间")
+    private Date liveStartTime;
+
+    @TableField("live_end_time_")
+    @ApiModelProperty(value = "直播结束时间")
+    private Date liveEndTime;
+
+    @TableField("live_remark_")
+    @ApiModelProperty(value = "直播内容/最多200个字")
+    private String liveRemark;
+
+    @TableField("pre_template_")
+    @ApiModelProperty(value = "预热模版")
+    private String preTemplate;
+
+    @TableField("room_config_")
+    @ApiModelProperty(value = "房间配置json格式-是否允许点赞-是否允许聊天互动-是否允许保存直播回放")
+    private String roomConfig;
+
+    @TableField("live_state_")
+    @ApiModelProperty(value = "直播状态 0未开始 1开始 2已结束")
+    private Integer liveState;
+
+    @TableField("room_state_")
+    @ApiModelProperty(value = "房间状态 0正常 1已删除")
+    private Integer roomState;
+
+    @TableField("created_by_")
+    @ApiModelProperty(value = "创建人")
+    private Integer createdBy;
+
+    @TableField("created_time_")
+    @ApiModelProperty(value = "创建时间")
+    private Date createdTime;
+
+    @TableField("updated_by_")
+    @ApiModelProperty(value = "更新人")
+    private Integer updatedBy;
+
+    @TableField("updated_time_")
+    @ApiModelProperty(value = "更新时间")
+    private Date updatedTime;
+
+    private static final long serialVersionUID = 1L;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getTenantId() {
+        return tenantId;
+    }
+
+    public void setTenantId(Integer tenantId) {
+        this.tenantId = tenantId;
+    }
+
+    public Integer getSpeakerId() {
+        return speakerId;
+    }
+
+    public void setSpeakerId(Integer speakerId) {
+        this.speakerId = speakerId;
+    }
+
+    public String getRoomUid() {
+        return roomUid;
+    }
+
+    public void setRoomUid(String roomUid) {
+        this.roomUid = roomUid;
+    }
+
+    public String getRoomTitle() {
+        return roomTitle;
+    }
+
+    public void setRoomTitle(String roomTitle) {
+        this.roomTitle = roomTitle;
+    }
+
+    public Date getLiveStartTime() {
+        return liveStartTime;
+    }
+
+    public void setLiveStartTime(Date liveStartTime) {
+        this.liveStartTime = liveStartTime;
+    }
+
+    public Date getLiveEndTime() {
+        return liveEndTime;
+    }
+
+    public void setLiveEndTime(Date liveEndTime) {
+        this.liveEndTime = liveEndTime;
+    }
+
+    public String getLiveRemark() {
+        return liveRemark;
+    }
+
+    public void setLiveRemark(String liveRemark) {
+        this.liveRemark = liveRemark;
+    }
+
+    public String getPreTemplate() {
+        return preTemplate;
+    }
+
+    public void setPreTemplate(String preTemplate) {
+        this.preTemplate = preTemplate;
+    }
+
+    public String getRoomConfig() {
+        return roomConfig;
+    }
+
+    public void setRoomConfig(String roomConfig) {
+        this.roomConfig = roomConfig;
+    }
+
+    public Integer getLiveState() {
+        return liveState;
+    }
+
+    public void setLiveState(Integer liveState) {
+        this.liveState = liveState;
+    }
+
+    public Integer getRoomState() {
+        return roomState;
+    }
+
+    public void setRoomState(Integer roomState) {
+        this.roomState = roomState;
+    }
+
+    public Integer getCreatedBy() {
+        return createdBy;
+    }
+
+    public void setCreatedBy(Integer createdBy) {
+        this.createdBy = createdBy;
+    }
+
+    public Date getCreatedTime() {
+        return createdTime;
+    }
+
+    public void setCreatedTime(Date createdTime) {
+        this.createdTime = createdTime;
+    }
+
+    public Integer getUpdatedBy() {
+        return updatedBy;
+    }
+
+    public void setUpdatedBy(Integer updatedBy) {
+        this.updatedBy = updatedBy;
+    }
+
+    public Date getUpdatedTime() {
+        return updatedTime;
+    }
+
+    public void setUpdatedTime(Date updatedTime) {
+        this.updatedTime = updatedTime;
+    }
+
+}
+

+ 109 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/entity/ImLiveBroadcastRoomData.java

@@ -0,0 +1,109 @@
+package com.ym.mec.biz.dal.entity;
+
+
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import com.baomidou.mybatisplus.annotation.TableId;
+
+import java.io.Serializable;
+
+/**
+ * 直播房间数据表(ImLiveBroadcastRoomData)表实体类
+ *
+ * @author hgw
+ * @since 2022-02-21 14:26:58
+ */
+@ApiModel(value = "im_live_broadcast_room_data-直播房间数据表")
+public class ImLiveBroadcastRoomData implements Serializable {
+    @TableId(value = "id_", type = IdType.AUTO)
+    @ApiModelProperty(value = "主键")
+    private Integer id;
+
+    @TableField("tenant_id_")
+    @ApiModelProperty(value = "机构id")
+    private Integer tenantId;
+
+    @TableField("room_uid_")
+    @ApiModelProperty(value = "房间uid")
+    private Integer roomUid;
+
+    @TableField("like_num_")
+    @ApiModelProperty(value = "累计点赞数")
+    private Integer likeNum;
+
+    @TableField("look_user_num_")
+    @ApiModelProperty(value = "即时观看人员数")
+    private Integer lookUserNum;
+
+    @TableField("total_user_num_")
+    @ApiModelProperty(value = "累计观看总人员数")
+    private Integer totalUserNum;
+
+    @TableField("updated_time_")
+    @ApiModelProperty(value = "更新时间")
+    private Date updatedTime;
+
+    private static final long serialVersionUID = 1L;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getTenantId() {
+        return tenantId;
+    }
+
+    public void setTenantId(Integer tenantId) {
+        this.tenantId = tenantId;
+    }
+
+    public Integer getRoomUid() {
+        return roomUid;
+    }
+
+    public void setRoomUid(Integer roomUid) {
+        this.roomUid = roomUid;
+    }
+
+    public Integer getLikeNum() {
+        return likeNum;
+    }
+
+    public void setLikeNum(Integer likeNum) {
+        this.likeNum = likeNum;
+    }
+
+    public Integer getLookUserNum() {
+        return lookUserNum;
+    }
+
+    public void setLookUserNum(Integer lookUserNum) {
+        this.lookUserNum = lookUserNum;
+    }
+
+    public Integer getTotalUserNum() {
+        return totalUserNum;
+    }
+
+    public void setTotalUserNum(Integer totalUserNum) {
+        this.totalUserNum = totalUserNum;
+    }
+
+    public Date getUpdatedTime() {
+        return updatedTime;
+    }
+
+    public void setUpdatedTime(Date updatedTime) {
+        this.updatedTime = updatedTime;
+    }
+
+}
+

+ 97 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/entity/ImLiveBroadcastRoomMember.java

@@ -0,0 +1,97 @@
+package com.ym.mec.biz.dal.entity;
+
+
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import com.baomidou.mybatisplus.annotation.TableId;
+
+import java.io.Serializable;
+
+/**
+ * 直播间人员关系表(ImLiveBroadcastRoomMember)表实体类
+ *
+ * @author hgw
+ * @since 2022-02-21 14:26:58
+ */
+@ApiModel(value = "im_live_broadcast_room_member-直播间人员关系表")
+public class ImLiveBroadcastRoomMember implements Serializable {
+    @TableId(value = "id_", type = IdType.AUTO)
+    @ApiModelProperty(value = "主键")
+    private Integer id;
+
+    @TableField("tenant_id_")
+    @ApiModelProperty(value = "机构id")
+    private Integer tenantId;
+
+    @TableField("room_uid_")
+    @ApiModelProperty(value = "房间编号")
+    private String roomUid;
+
+    @TableField("user_id_")
+    @ApiModelProperty(value = "进入房间的人员id/学生id")
+    private Integer userId;
+
+    @TableField("join_time_")
+    @ApiModelProperty(value = "进入房间时间")
+    private Date joinTime;
+
+    @TableField("total_time_")
+    @ApiModelProperty(value = "累计观看时间/以分钟为单位")
+    private Integer totalTime;
+
+    private static final long serialVersionUID = 1L;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getTenantId() {
+        return tenantId;
+    }
+
+    public void setTenantId(Integer tenantId) {
+        this.tenantId = tenantId;
+    }
+
+    public String getRoomUid() {
+        return roomUid;
+    }
+
+    public void setRoomUid(String roomUid) {
+        this.roomUid = roomUid;
+    }
+
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    public Date getJoinTime() {
+        return joinTime;
+    }
+
+    public void setJoinTime(Date joinTime) {
+        this.joinTime = joinTime;
+    }
+
+    public Integer getTotalTime() {
+        return totalTime;
+    }
+
+    public void setTotalTime(Integer totalTime) {
+        this.totalTime = totalTime;
+    }
+
+}
+

+ 196 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/vo/ImLiveBroadcastRoomVo.java

@@ -0,0 +1,196 @@
+package com.ym.mec.biz.dal.vo;
+
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 直播房间管理表(ImLiveBroadcastRoom)表实体类
+ *
+ * @author hgw
+ * @since 2022-02-17 20:52:05
+ */
+@ApiModel(value = "im_live_broadcast_room-直播房间管理表")
+public class ImLiveBroadcastRoomVo implements Serializable {
+    @ApiModelProperty(value = "主键")
+    private Integer id;
+
+    @ApiModelProperty(value = "机构id")
+    private Integer tenantId;
+
+    @ApiModelProperty(value = "机构名称")
+    private String tenantName;
+
+    @ApiModelProperty(value = "机构logo")
+    private String tenantLogo;
+
+    @ApiModelProperty(value = "房间编号")
+    private String roomUid;
+
+    @ApiModelProperty(value = "房间标题/最多12个字")
+    private String roomTitle;
+
+    @ApiModelProperty(value = "直播内容/最多200个字")
+    private String liveRemark;
+
+    @ApiModelProperty(value = "主讲人id/老师id")
+    private Integer speakerId;
+
+    @ApiModelProperty(value = "主讲人名称")
+    private String speakerName;
+
+    @ApiModelProperty(value = "主讲人头像")
+    private String speakerPic;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty(value = "直播开始时间")
+    private Date liveStartTime;
+
+    @ApiModelProperty(value = "直播状态 0未开始 1开始 2结束")
+    private Integer liveState;
+
+    @ApiModelProperty(value = "房间状态 0正常 1已删除")
+    private Integer roomState;
+
+    @ApiModelProperty(value = "创建人")
+    private Integer createdByName;
+
+    @ApiModelProperty(value = "预热模版")
+    private String preTemplate;
+
+    @ApiModelProperty(value = "房间配置json格式-是否允许点赞-是否允许聊天互动-是否允许保存直播回放")
+    private String roomConfig;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getTenantId() {
+        return tenantId;
+    }
+
+    public void setTenantId(Integer tenantId) {
+        this.tenantId = tenantId;
+    }
+
+    public String getTenantName() {
+        return tenantName;
+    }
+
+    public void setTenantName(String tenantName) {
+        this.tenantName = tenantName;
+    }
+
+    public String getRoomUid() {
+        return roomUid;
+    }
+
+    public void setRoomUid(String roomUid) {
+        this.roomUid = roomUid;
+    }
+
+    public String getRoomTitle() {
+        return roomTitle;
+    }
+
+    public void setRoomTitle(String roomTitle) {
+        this.roomTitle = roomTitle;
+    }
+
+    public String getLiveRemark() {
+        return liveRemark;
+    }
+
+    public void setLiveRemark(String liveRemark) {
+        this.liveRemark = liveRemark;
+    }
+
+    public Integer getSpeakerId() {
+        return speakerId;
+    }
+
+    public void setSpeakerId(Integer speakerId) {
+        this.speakerId = speakerId;
+    }
+
+    public String getSpeakerName() {
+        return speakerName;
+    }
+
+    public void setSpeakerName(String speakerName) {
+        this.speakerName = speakerName;
+    }
+
+    public Date getLiveStartTime() {
+        return liveStartTime;
+    }
+
+    public void setLiveStartTime(Date liveStartTime) {
+        this.liveStartTime = liveStartTime;
+    }
+
+    public Integer getLiveState() {
+        return liveState;
+    }
+
+    public void setLiveState(Integer liveState) {
+        this.liveState = liveState;
+    }
+
+    public Integer getRoomState() {
+        return roomState;
+    }
+
+    public void setRoomState(Integer roomState) {
+        this.roomState = roomState;
+    }
+
+    public Integer getCreatedByName() {
+        return createdByName;
+    }
+
+    public void setCreatedByName(Integer createdByName) {
+        this.createdByName = createdByName;
+    }
+
+    public String getPreTemplate() {
+        return preTemplate;
+    }
+
+    public void setPreTemplate(String preTemplate) {
+        this.preTemplate = preTemplate;
+    }
+
+    public String getRoomConfig() {
+        return roomConfig;
+    }
+
+    public void setRoomConfig(String roomConfig) {
+        this.roomConfig = roomConfig;
+    }
+
+    public String getTenantLogo() {
+        return tenantLogo;
+    }
+
+    public void setTenantLogo(String tenantLogo) {
+        this.tenantLogo = tenantLogo;
+    }
+
+    public String getSpeakerPic() {
+        return speakerPic;
+    }
+
+    public void setSpeakerPic(String speakerPic) {
+        this.speakerPic = speakerPic;
+    }
+}
+

+ 15 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/ImLiveBroadcastRoomDataService.java

@@ -0,0 +1,15 @@
+package com.ym.mec.biz.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ym.mec.biz.dal.entity.ImLiveBroadcastRoomData;
+
+/**
+ * 直播房间数据表(ImLiveBroadcastRoomData)表服务接口
+ *
+ * @author hgw
+ * @since 2022-02-21 14:26:58
+ */
+public interface ImLiveBroadcastRoomDataService extends IService<ImLiveBroadcastRoomData> {
+
+}
+

+ 15 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/ImLiveBroadcastRoomMemberService.java

@@ -0,0 +1,15 @@
+package com.ym.mec.biz.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ym.mec.biz.dal.entity.ImLiveBroadcastRoomMember;
+
+/**
+ * 直播间人员关系表(ImLiveBroadcastRoomMember)表服务接口
+ *
+ * @author hgw
+ * @since 2022-02-21 14:26:59
+ */
+public interface ImLiveBroadcastRoomMemberService extends IService<ImLiveBroadcastRoomMember> {
+
+}
+

+ 34 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/ImLiveBroadcastRoomService.java

@@ -0,0 +1,34 @@
+package com.ym.mec.biz.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ym.mec.biz.dal.dto.ImLiveBroadcastRoomDto;
+import com.ym.mec.biz.dal.entity.ImLiveBroadcastRoom;
+import com.ym.mec.biz.dal.vo.ImLiveBroadcastRoomVo;
+import com.ym.mec.common.page.PageInfo;
+
+import java.util.Map;
+
+/**
+ * 直播房间管理表(ImLiveBroadcastRoom)表服务接口
+ *
+ * @author hgw
+ * @since 2022-02-17 20:52:05
+ */
+public interface ImLiveBroadcastRoomService extends IService<ImLiveBroadcastRoom> {
+
+    PageInfo<ImLiveBroadcastRoomVo> queryPage(Map<String, Object> param);
+
+    ImLiveBroadcastRoomVo queryRoom(String roomUid, Integer userId);
+
+    void add(ImLiveBroadcastRoomDto dto);
+
+    void update(ImLiveBroadcastRoomDto dto);
+
+    void delete(Integer id);
+
+    void syncLike(String roomUid, Integer likeNum);
+
+    void test();
+
+}
+

+ 25 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/impl/ImLiveBroadcastRoomDataServiceImpl.java

@@ -0,0 +1,25 @@
+package com.ym.mec.biz.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ym.mec.biz.dal.dao.ImLiveBroadcastRoomDataDao;
+import com.ym.mec.biz.dal.entity.ImLiveBroadcastRoomData;
+import com.ym.mec.biz.service.ImLiveBroadcastRoomDataService;
+import org.springframework.stereotype.Service;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 直播房间数据表(ImLiveBroadcastRoomData)表服务实现类
+ *
+ * @author hgw
+ * @since 2022-02-21 14:26:58
+ */
+@Service("imLiveBroadcastRoomDataService")
+public class ImLiveBroadcastRoomDataServiceImpl extends ServiceImpl<ImLiveBroadcastRoomDataDao, ImLiveBroadcastRoomData> implements ImLiveBroadcastRoomDataService {
+
+    private final static Logger log = LoggerFactory.getLogger(ImLiveBroadcastRoomDataServiceImpl.class);
+
+
+}
+

+ 25 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/impl/ImLiveBroadcastRoomMemberServiceImpl.java

@@ -0,0 +1,25 @@
+package com.ym.mec.biz.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ym.mec.biz.dal.dao.ImLiveBroadcastRoomMemberDao;
+import com.ym.mec.biz.dal.entity.ImLiveBroadcastRoomMember;
+import com.ym.mec.biz.service.ImLiveBroadcastRoomMemberService;
+import org.springframework.stereotype.Service;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 直播间人员关系表(ImLiveBroadcastRoomMember)表服务实现类
+ *
+ * @author hgw
+ * @since 2022-02-21 14:26:59
+ */
+@Service("imLiveBroadcastRoomMemberService")
+public class ImLiveBroadcastRoomMemberServiceImpl extends ServiceImpl<ImLiveBroadcastRoomMemberDao, ImLiveBroadcastRoomMember> implements ImLiveBroadcastRoomMemberService {
+
+    private final static Logger log = LoggerFactory.getLogger(ImLiveBroadcastRoomMemberServiceImpl.class);
+
+
+}
+

+ 193 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/impl/ImLiveBroadcastRoomServiceImpl.java

@@ -0,0 +1,193 @@
+package com.ym.mec.biz.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ym.mec.auth.api.client.SysUserFeignService;
+import com.ym.mec.auth.api.entity.SysUser;
+import com.ym.mec.biz.dal.dao.ImLiveBroadcastRoomDao;
+import com.ym.mec.biz.dal.dto.ImLiveBroadcastRoomDto;
+import com.ym.mec.biz.dal.entity.ImLiveBroadcastRoom;
+import com.ym.mec.biz.dal.vo.ImLiveBroadcastRoomVo;
+import com.ym.mec.biz.service.ImLiveBroadcastRoomService;
+import com.ym.mec.common.exception.BizException;
+import com.ym.mec.common.page.PageInfo;
+import com.ym.mec.common.page.PageUtil;
+import com.ym.mec.common.tenant.TenantContextHolder;
+import com.ym.mec.im.ImFeignService;
+import com.ym.mec.util.date.DateUtil;
+import org.redisson.api.RedissonClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.time.LocalDateTime;
+import java.util.*;
+
+/**
+ * 直播房间管理表(ImLiveBroadcastRoom)表服务实现类
+ *
+ * @author hgw
+ * @since 2022-02-17 20:52:05
+ */
+@Service("imLiveBroadcastRoomService")
+public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastRoomDao, ImLiveBroadcastRoom> implements ImLiveBroadcastRoomService {
+
+    private final static Logger log = LoggerFactory.getLogger(ImLiveBroadcastRoomServiceImpl.class);
+
+    @Autowired
+    private SysUserFeignService sysUserFeignService;
+    @Autowired
+    private ImFeignService imFeignService;
+    @Autowired
+    private RedissonClient redissonClient;
+
+    /**
+     * 进入直播间检查数据
+     *
+     * @param roomUid 房间uid
+     * @param userId  用户id
+     */
+    public ImLiveBroadcastRoomVo queryRoom(String roomUid, Integer userId) {
+        SysUser sysUser = getSysUser(userId);
+        //直播间信息校验
+        Optional<ImLiveBroadcastRoomVo> optional = Optional.ofNullable(roomUid)
+                .map(this::queryRoomInfo);
+        optional.orElseThrow(() -> new BizException("直播间不存在"));
+        optional.filter(r -> r.getTenantId().equals(sysUser.getTenantId()))
+                .orElseThrow(() -> new BizException("您不是该直播机构学员,不可观看!"));
+        optional.filter(r -> r.getRoomState() != 1).orElseThrow(() -> new BizException("直播间不存在"));
+        ImLiveBroadcastRoomVo room = optional.get();
+        String msg = "直播未开始,直播开启的时间是 " + DateUtil.format(room.getLiveStartTime(), DateUtil.EXPANDED_DATE_TIME_FORMAT);
+        if (room.getLiveState() == 0) {
+            throw new BizException(msg);
+        }
+        if (room.getLiveStartTime().getTime() < new Date().getTime()) {
+            throw new BizException(msg);
+        }
+        if (room.getLiveState() == 2) {
+            throw new BizException("直播已结束!");
+        }
+        return room;
+    }
+
+    /**
+     * 查询直播间信息
+     *
+     * @param roomUid 直播间uid
+     */
+    private ImLiveBroadcastRoomVo queryRoomInfo(String roomUid) {
+        List<ImLiveBroadcastRoomVo> list = baseMapper.queryPage(new HashMap<String, Object>() {{
+            put("roomUid", roomUid);
+        }});
+        if (CollectionUtils.isEmpty(list)) {
+            return null;
+        }
+        return list.get(0);
+    }
+
+    /**
+     * 分页查询直播间列表
+     */
+    @Override
+    public PageInfo<ImLiveBroadcastRoomVo> queryPage(Map<String, Object> param) {
+        Page<ImLiveBroadcastRoomVo> pageInfo = PageUtil.getPageInfo(param);
+        pageInfo.setDesc("a.created_time_");
+        IPage<ImLiveBroadcastRoomVo> page = baseMapper.queryPage(pageInfo, param);
+        return PageUtil.pageInfo(page);
+    }
+
+    /**
+     * 预创建直播间
+     *
+     * @param dto 直播间信息
+     */
+    @Override
+    public void add(ImLiveBroadcastRoomDto dto) {
+        SysUser sysUser = getSysUser(dto.getSpeakerId());
+        ImLiveBroadcastRoom obj = new ImLiveBroadcastRoom();
+        BeanUtils.copyProperties(dto, obj);
+        String nano = LocalDateTime.now().getNano() + "";
+        String roomUid = "LIVE-" + sysUser.getId() + "-" + nano.substring(0, 3);
+        Date now = new Date();
+        obj.setTenantId(TenantContextHolder.getTenantId());
+        obj.setRoomUid(roomUid);
+        obj.setRoomConfig(JSONObject.toJSONString(dto.getRoomConfig()));
+        obj.setLiveState(0);
+        obj.setRoomState(0);
+        obj.setCreatedBy(getUserId());
+        obj.setCreatedTime(now);
+        this.save(obj);
+    }
+
+    /**
+     * 修改直播间信息
+     *
+     * @param dto
+     */
+    @Override
+    public void update(ImLiveBroadcastRoomDto dto) {
+        ImLiveBroadcastRoom obj = new ImLiveBroadcastRoom();
+        BeanUtils.copyProperties(dto, obj);
+        log.info("update room  >>>  :{}", JSONObject.toJSONString(obj));
+        this.updateById(obj);
+    }
+
+    /**
+     * 删除直播间
+     *
+     * @param id 直播间id
+     */
+    @Override
+    public void delete(Integer id) {
+        ImLiveBroadcastRoom obj = new ImLiveBroadcastRoom();
+        obj.setId(id);
+        obj.setRoomState(1);
+        this.updateById(obj);
+    }
+
+    /**
+     * 同步点赞数量-修改房间信息
+     *
+     * @param roomUid 房间uid
+     * @param likeNum 点赞数
+     */
+    public void syncLike(String roomUid, Integer likeNum) {
+
+    }
+
+    /**
+     * 定时任务,每分钟执行
+     * 提前30分钟主动去融云注册并创建房间
+     */
+    public void createRoom() {
+        List<ImLiveBroadcastRoomVo> imLiveBroadcastRoomVos = baseMapper.queryPage(new HashMap<>());
+        imFeignService.createLiveRoom("", "");
+    }
+
+    private SysUser getSysUser(Integer userId) {
+        return Optional.ofNullable(userId)
+                .map(sysUserFeignService::queryUserById)
+                .orElseThrow(() -> new BizException("用户不存在"));
+    }
+
+    private Integer getUserId() {
+        //修改机构基础信息
+        return Optional.ofNullable(sysUserFeignService.queryUserInfo())
+                .map(SysUser::getId)
+                .orElseThrow(() -> new BizException("用户信息获取失败,请刷新页面或者重新登录!"));
+    }
+
+    /**
+     * 分享直播间
+     */
+    public void test() {
+
+    }
+
+}
+

+ 30 - 0
mec-biz/src/main/resources/config/mybatis/ImLiveBroadcastRoomDataMapper.xml

@@ -0,0 +1,30 @@
+<?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.ym.mec.biz.dal.dao.ImLiveBroadcastRoomDataDao">
+    <resultMap id="BaseResultMap" type="com.ym.mec.biz.dal.entity.ImLiveBroadcastRoomData">
+        <id column="id_" jdbcType="INTEGER" property="id"/>
+        <result column="tenant_id_" jdbcType="INTEGER" property="tenantId"/>
+        <result column="room_uid_" jdbcType="INTEGER" property="roomUid"/>
+        <result column="like_num_" jdbcType="INTEGER" property="likeNum"/>
+        <result column="look_user_num_" jdbcType="INTEGER" property="lookUserNum"/>
+        <result column="total_user_num_" jdbcType="INTEGER" property="totalUserNum"/>
+        <result column="updated_time_" jdbcType="TIMESTAMP" property="updatedTime"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id_
+        , tenant_id_, room_uid_, like_num_, look_user_num_, total_user_num_, updated_time_
+    </sql>
+
+    <insert id="insertBatch" keyColumn="id_" keyProperty="id" useGeneratedKeys="true"
+            parameterType="com.ym.mec.biz.dal.entity.ImLiveBroadcastRoomData">
+        insert into im_live_broadcast_room_data(tenant_id_, room_uid_, like_num_, look_user_num_, total_user_num_,
+        updated_time_)
+        values
+        <foreach collection="entities" item="entity" separator=",">
+            (#{entity.tenantId}, #{entity.roomUid}, #{entity.likeNum}, #{entity.lookUserNum}, #{entity.totalUserNum},
+            #{entity.updatedTime})
+        </foreach>
+    </insert>
+
+</mapper>

+ 88 - 0
mec-biz/src/main/resources/config/mybatis/ImLiveBroadcastRoomMapper.xml

@@ -0,0 +1,88 @@
+<?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.ym.mec.biz.dal.dao.ImLiveBroadcastRoomDao">
+    <resultMap id="BaseResultMap" type="com.ym.mec.biz.dal.entity.ImLiveBroadcastRoom">
+        <id column="id_" jdbcType="INTEGER" property="id"/>
+        <result column="tenant_id_" jdbcType="INTEGER" property="tenantId"/>
+        <result column="speaker_id_" jdbcType="INTEGER" property="speakerId"/>
+        <result column="room_uid_" jdbcType="VARCHAR" property="roomUid"/>
+        <result column="room_title_" jdbcType="VARCHAR" property="roomTitle"/>
+        <result column="live_start_time_" jdbcType="TIMESTAMP" property="liveStartTime"/>
+        <result column="live_end_time_" jdbcType="TIMESTAMP" property="liveEndTime"/>
+        <result column="live_remark_" jdbcType="VARCHAR" property="liveRemark"/>
+        <result column="pre_template_" jdbcType="VARCHAR" property="preTemplate"/>
+        <result column="room_config_" jdbcType="VARCHAR" property="roomConfig"/>
+        <result column="live_state_" jdbcType="INTEGER" property="liveState"/>
+        <result column="room_state_" jdbcType="INTEGER" property="roomState"/>
+        <result column="created_by_" jdbcType="INTEGER" property="createdBy"/>
+        <result column="created_time_" jdbcType="TIMESTAMP" property="createdTime"/>
+        <result column="updated_by_" jdbcType="INTEGER" property="updatedBy"/>
+        <result column="updated_time_" jdbcType="TIMESTAMP" property="updatedTime"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id_
+        , tenant_id_, speaker_id_, room_uid_, room_title_, live_start_time_, live_end_time_, live_remark_, pre_template_, room_config_, live_state_, room_state_, created_by_, created_time_, updated_by_, updated_time_
+    </sql>
+
+    <insert id="insertBatch" keyColumn="id_" keyProperty="id" useGeneratedKeys="true"
+            parameterType="com.ym.mec.biz.dal.entity.ImLiveBroadcastRoom">
+        insert into im_live_broadcast_room(tenant_id_, speaker_id_, room_uid_, room_title_, live_start_time_,
+        live_end_time_, live_remark_, pre_template_, room_config_, live_state_, room_state_, created_by_, created_time_,
+        updated_by_, updated_time_)
+        values
+        <foreach collection="entities" item="entity" separator=",">
+            (#{entity.tenantId}, #{entity.speakerId}, #{entity.roomUid}, #{entity.roomTitle}, #{entity.liveStartTime},
+            #{entity.liveEndTime}, #{entity.liveRemark}, #{entity.preTemplate}, #{entity.roomConfig},
+            #{entity.liveState}, #{entity.roomState}, #{entity.createdBy}, #{entity.createdTime}, #{entity.updatedBy},
+            #{entity.updatedTime})
+        </foreach>
+    </insert>
+
+    <select id="queryPage" resultType="com.ym.mec.biz.dal.vo.ImLiveBroadcastRoomVo">
+        select a.id_ AS id,
+        a.tenant_id_ AS tenantId,
+        t.name_ AS tenantName,
+        t.logo_ AS tenantLogo,
+        a.room_uid_ AS roomUid,
+        a.room_title_ AS roomTitle,
+        a.live_remark_ AS liveRemark,
+        a.speaker_id_ AS speakerId,
+        b.real_name_ AS speakerName,
+        b.avatar_ AS speakerPic,
+        a.live_start_time_ AS liveStartTime,
+        a.live_state_ AS liveState,
+        a.room_state_ AS roomState,
+        c.real_name_ AS createdByName,
+        a.pre_template_ AS preTemplate,
+        a.room_config_ AS roomConfig
+        from im_live_broadcast_room as a
+        left join tenant_info AS t on a.tenant_id_ = t.id_
+        left join sys_user AS b on a.speaker_id_ = b.id_
+        left join sys_user AS c on a.created_by_ = b.id_
+        <where>
+            <if test="param.search != null ">
+                AND (
+                a.`room_uid_` LIKE CONCAT('%', #{param.search},'%')
+                OR a.`room_title_` LIKE CONCAT('%', #{param.search},'%')
+                )
+            </if>
+            <if test="param.roomUid != null">
+                and  a.room_uid_ = #{param.roomUid}
+            </if>
+            <if test="param.liveState != null">
+                and a.live_state_ = #{param.liveState}
+            </if>
+            <if test="param.startTime != null">
+                <![CDATA[ AND a.live_start_time_  >= #{param.startTime} ]]>
+            </if>
+            <if test="param.endTime != null">
+                <![CDATA[ AND a.live_start_time_  <= #{param.endTime} ]]>
+            </if>
+
+        </where>
+
+
+    </select>
+
+</mapper>

+ 27 - 0
mec-biz/src/main/resources/config/mybatis/ImLiveBroadcastRoomMemberMapper.xml

@@ -0,0 +1,27 @@
+<?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.ym.mec.biz.dal.dao.ImLiveBroadcastRoomMemberDao">
+    <resultMap id="BaseResultMap" type="com.ym.mec.biz.dal.entity.ImLiveBroadcastRoomMember">
+        <id column="id_" jdbcType="INTEGER" property="id"/>
+        <result column="tenant_id_" jdbcType="INTEGER" property="tenantId"/>
+        <result column="room_uid_" jdbcType="VARCHAR" property="roomUid"/>
+        <result column="user_id_" jdbcType="INTEGER" property="userId"/>
+        <result column="join_time_" jdbcType="TIMESTAMP" property="joinTime"/>
+        <result column="total_time_" jdbcType="INTEGER" property="totalTime"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id
+        , tenant_id_, room_uid_, user_id_, join_time_, total_time_
+    </sql>
+
+    <insert id="insertBatch" keyColumn="id_" keyProperty="id" useGeneratedKeys="true"
+            parameterType="com.ym.mec.biz.dal.entity.ImLiveBroadcastRoomMember">
+        insert into im_live_broadcast_room_member(tenant_id_, room_uid_, user_id_, join_time_, total_time_)
+        values
+        <foreach collection="entities" item="entity" separator=",">
+            (#{entity.tenantId}, #{entity.roomUid}, #{entity.userId}, #{entity.joinTime}, #{entity.totalTime})
+        </foreach>
+    </insert>
+
+</mapper>

+ 133 - 109
mec-client-api/src/main/java/com/ym/mec/im/ImFeignService.java

@@ -1,121 +1,145 @@
 package com.ym.mec.im;
 
-import java.util.List;
-
+import com.ym.mec.common.config.FeignConfiguration;
+import com.ym.mec.common.entity.*;
+import com.ym.mec.im.entity.GroupModel;
+import com.ym.mec.im.fallback.ImFeignServiceFallback;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.http.MediaType;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
-
-import com.ym.mec.common.config.FeignConfiguration;
-import com.ym.mec.common.entity.ImGroupMessage;
-import com.ym.mec.common.entity.ImGroupModel;
-import com.ym.mec.common.entity.ImPrivateMessage;
-import com.ym.mec.common.entity.ImResult;
-import com.ym.mec.common.entity.ImUserModel;
-import com.ym.mec.im.entity.GroupModel;
-import com.ym.mec.im.fallback.ImFeignServiceFallback;
 import org.springframework.web.bind.annotation.RequestParam;
 
+import java.util.List;
+
 @FeignClient(name = "im-server", configuration = FeignConfiguration.class, fallback = ImFeignServiceFallback.class)
 public interface ImFeignService {
 
-	/**
-	 * 用户注册
-	 * @param userModel
-	 * @return
-	 */
-	@PostMapping(value = "user/register", consumes = MediaType.APPLICATION_JSON_VALUE)
-	ImResult register(@RequestBody ImUserModel userModel);
-
-	/**
-	 * 用户信息修改
-	 * @param userModel
-	 * @return
-	 */
-	@PostMapping(value = "user/update", consumes = MediaType.APPLICATION_JSON_VALUE)
-	void update(@RequestBody ImUserModel userModel);
-
-	/**
-	 * 创建群组
-	 * @param groupModel
-	 * @return
-	 */
-	@PostMapping(value = "group/create")
-	Object groupCreate(@RequestBody GroupModel groupModel);
-
-	/**
-	 * 批量创建群组
-	 * @param groupModels
-	 * @return
-	 */
-	@PostMapping(value = "group/batchCreate")
-	void groupBatchCreate(@RequestBody List<GroupModel> groupModels);
-
-	/**
-	 * 加入群组
-	 * @param groupModel
-	 * @return
-	 */
-	@PostMapping(value = "group/join")
-	Object groupJoin(@RequestBody GroupModel groupModel);
-
-	/**
-	 * 批量加入群组
-	 * @param groupModels
-	 * @return
-	 */
-	@PostMapping(value = "group/batchJoin")
-	Object groupBatchJoin(@RequestBody List<GroupModel> groupModels);
-
-	/**
-	 * 退出群组
-	 * @param groupModel
-	 * @return
-	 */
-	@PostMapping(value = "group/quit")
-	Object groupQuit(@RequestBody GroupModel groupModel);
-
-	/**
-	 * 解散群组
-	 * @param groupModel
-	 * @return
-	 */
-	@PostMapping(value = "group/dismiss")
-	Object groupDismiss(@RequestBody GroupModel groupModel);
-
-	/**
-	 * 批量解散群组
-	 * @param groupModels
-	 * @return
-	 */
-	@PostMapping(value = "group/batchDismiss")
-	Object groupBatchDismiss(@RequestBody List<ImGroupModel> groupModels);
-
-	/**
-	 * 批量退出群组
-	 * @param groupModels
-	 * @return
-	 */
-	@PostMapping(value = "group/batchQuit")
-	Object groupBatchQuit(@RequestBody List<GroupModel> groupModels);
-
-	/**
-	 * 发送私聊消息
-	 * @param privateMessage
-	 * @return
-	 */
-	@PostMapping(value = "private/send")
-	Object privateSend(@RequestBody ImPrivateMessage privateMessage);
-
-	@PostMapping(value = "group/send")
-	Object groupSend(@RequestBody ImGroupMessage imGroupMessage);
-
-	/**
-	 * 获取历史消息记录
-	 * @param date
-	 * @return
-	 */
-	@PostMapping(value = "history/get")
-	Object historyGet(@RequestParam("date") String date);
+    /**
+     * 用户注册
+     *
+     * @param userModel
+     * @return
+     */
+    @PostMapping(value = "user/register", consumes = MediaType.APPLICATION_JSON_VALUE)
+    ImResult register(@RequestBody ImUserModel userModel);
+
+    /**
+     * 用户信息修改
+     *
+     * @param userModel
+     * @return
+     */
+    @PostMapping(value = "user/update", consumes = MediaType.APPLICATION_JSON_VALUE)
+    void update(@RequestBody ImUserModel userModel);
+
+    /**
+     * 创建群组
+     *
+     * @param groupModel
+     * @return
+     */
+    @PostMapping(value = "group/create")
+    Object groupCreate(@RequestBody GroupModel groupModel);
+
+    /**
+     * 批量创建群组
+     *
+     * @param groupModels
+     * @return
+     */
+    @PostMapping(value = "group/batchCreate")
+    void groupBatchCreate(@RequestBody List<GroupModel> groupModels);
+
+    /**
+     * 加入群组
+     *
+     * @param groupModel
+     * @return
+     */
+    @PostMapping(value = "group/join")
+    Object groupJoin(@RequestBody GroupModel groupModel);
+
+    /**
+     * 批量加入群组
+     *
+     * @param groupModels
+     * @return
+     */
+    @PostMapping(value = "group/batchJoin")
+    Object groupBatchJoin(@RequestBody List<GroupModel> groupModels);
+
+    /**
+     * 退出群组
+     *
+     * @param groupModel
+     * @return
+     */
+    @PostMapping(value = "group/quit")
+    Object groupQuit(@RequestBody GroupModel groupModel);
+
+    /**
+     * 解散群组
+     *
+     * @param groupModel
+     * @return
+     */
+    @PostMapping(value = "group/dismiss")
+    Object groupDismiss(@RequestBody GroupModel groupModel);
+
+    /**
+     * 批量解散群组
+     *
+     * @param groupModels
+     * @return
+     */
+    @PostMapping(value = "group/batchDismiss")
+    Object groupBatchDismiss(@RequestBody List<ImGroupModel> groupModels);
+
+    /**
+     * 批量退出群组
+     *
+     * @param groupModels
+     * @return
+     */
+    @PostMapping(value = "group/batchQuit")
+    Object groupBatchQuit(@RequestBody List<GroupModel> groupModels);
+
+    /**
+     * 发送私聊消息
+     *
+     * @param privateMessage
+     * @return
+     */
+    @PostMapping(value = "private/send")
+    Object privateSend(@RequestBody ImPrivateMessage privateMessage);
+
+    @PostMapping(value = "group/send")
+    Object groupSend(@RequestBody ImGroupMessage imGroupMessage);
+
+    /**
+     * 获取历史消息记录
+     *
+     * @param date
+     * @return
+     */
+    @PostMapping(value = "history/get")
+    Object historyGet(@RequestParam("date") String date);
+
+    /**
+     * 创建直播房间
+     *
+     * @param roomId   直播间uid
+     * @param roomName 直播间名称
+     */
+    @PostMapping(value = "/liveRoom/create")
+    Object createLiveRoom(@RequestParam("roomId") String roomId, @RequestParam("roomName") String roomName);
+
+    /**
+     * 销毁直播房间
+     *
+     * @param roomId 直播间uid
+     */
+    @PostMapping(value = "/liveRoom/destroy")
+    Object destroyLiveRoom(@RequestParam("roomId") String roomId);
 }

+ 10 - 0
mec-client-api/src/main/java/com/ym/mec/im/fallback/ImFeignServiceFallback.java

@@ -80,4 +80,14 @@ public class ImFeignServiceFallback implements ImFeignService {
     public Object historyGet(String date) {
         return null;
     }
+
+    @Override
+    public Object createLiveRoom(String roomId, String roomName) {
+        return null;
+    }
+
+    @Override
+    public Object destroyLiveRoom(String roomId) {
+        return null;
+    }
 }

+ 34 - 0
mec-im/src/main/java/com/ym/controller/LiveRoomController.java

@@ -0,0 +1,34 @@
+package com.ym.controller;
+
+import com.ym.service.LiveRoomService;
+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.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author hgw
+ * Created by 2022-02-21
+ */
+@RestController
+@RequestMapping("/liveRoom")
+@Slf4j
+public class LiveRoomController {
+
+    @Autowired
+    private LiveRoomService liveRoomService;
+
+    @ApiOperation("创建直播房间")
+    @PostMapping(value = "/create")
+    public Object createLiveRoom(String roomId, String roomName) throws Exception {
+        return liveRoomService.createLiveRoom(roomId, roomName);
+    }
+
+    @ApiOperation("销毁直播房间")
+    @PostMapping(value = "/destroy")
+    public Object destroyLiveRoom(String roomId) throws Exception {
+        return liveRoomService.destroyLiveRoom(roomId);
+    }
+}

+ 1 - 1
mec-im/src/main/java/com/ym/pojo/ActionEnum.java → mec-im/src/main/java/com/ym/enums/ActionEnum.java

@@ -1,4 +1,4 @@
-package com.ym.pojo;
+package com.ym.enums;
 
 /**
  * Created by weiqinxiao on 2019/3/19.

+ 1 - 1
mec-im/src/main/java/com/ym/pojo/DeviceTypeEnum.java → mec-im/src/main/java/com/ym/enums/DeviceTypeEnum.java

@@ -1,4 +1,4 @@
-package com.ym.pojo;
+package com.ym.enums;
 
 public enum DeviceTypeEnum {
     Microphone,

+ 1 - 1
mec-im/src/main/java/com/ym/pojo/RoleEnum.java → mec-im/src/main/java/com/ym/enums/RoleEnum.java

@@ -1,4 +1,4 @@
-package com.ym.pojo;
+package com.ym.enums;
 
 import com.ym.common.ApiException;
 import com.ym.common.ErrorEnum;

+ 52 - 34
mec-im/src/main/java/com/ym/http/HttpHelper.java

@@ -2,6 +2,7 @@ package com.ym.http;
 
 import com.ym.config.IMProperties;
 import com.ym.utils.CodeUtil;
+import io.rong.util.GsonUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
@@ -12,12 +13,12 @@ import java.io.ByteArrayOutputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.ProtocolException;
-import java.net.URL;
+import java.net.*;
+import java.nio.charset.StandardCharsets;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.Map;
 
 @Slf4j
 @Component
@@ -31,7 +32,7 @@ public class HttpHelper {
 
     @Autowired
     IMProperties imProperties;
-    
+
     @PostConstruct
     private void init() {
         log.info("init HttpHelper");
@@ -69,7 +70,7 @@ public class HttpHelper {
 
     // 设置body体
     public void setBodyParameter(StringBuilder sb, HttpURLConnection conn)
-        throws IOException {
+            throws IOException {
         String str = sb.toString();
         log.info("Call server api with url: {}, data: {}", conn.getURL().toString(), str);
         DataOutputStream out = new DataOutputStream(conn.getOutputStream());
@@ -79,7 +80,7 @@ public class HttpHelper {
     }
 
     public HttpURLConnection createGetHttpConnection(String uri)
-        throws MalformedURLException, IOException {
+            throws MalformedURLException, IOException {
         URL url = new URL(uri);
         HttpURLConnection conn = (HttpURLConnection) url.openConnection();
         conn.setConnectTimeout(30000);
@@ -90,32 +91,23 @@ public class HttpHelper {
     public void setBodyParameter(String str, HttpURLConnection conn) throws IOException {
         log.info("Call IM server api with url: {}, data: {}", conn.getURL().toString(), str);
         DataOutputStream out = new DataOutputStream(conn.getOutputStream());
-        out.write(str.getBytes("utf-8"));
+        out.write(str.getBytes(StandardCharsets.UTF_8));
         out.flush();
         out.close();
     }
 
     public HttpURLConnection createWhiteBoardPostHttpConnection(String host, String uri, String contentType)
-        throws MalformedURLException, IOException, ProtocolException {
+            throws MalformedURLException, IOException, ProtocolException {
 
         URL url = new URL(host + uri);
         HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-        conn.setUseCaches(false);
-        conn.setDoInput(true);
-        conn.setDoOutput(true);
-        conn.setRequestMethod("POST");
-        conn.setInstanceFollowRedirects(true);
-        conn.setConnectTimeout(30000);
-        conn.setReadTimeout(30000);
-
-        conn.setRequestProperty("Content-Type", contentType);
-
+        setConn(conn, contentType);
         return conn;
     }
 
     public HttpURLConnection createCommonPostHttpConnection(String host, String appKey,
-        String appSecret, String uri, String contentType)
-        throws MalformedURLException, IOException, ProtocolException {
+                                                            String appSecret, String uri, String contentType)
+            throws MalformedURLException, IOException, ProtocolException {
         String nonce = String.valueOf(Math.random() * 1000000);
         String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
         StringBuilder toSign = new StringBuilder(appSecret).append(nonce).append(timestamp);
@@ -145,8 +137,7 @@ public class HttpHelper {
     }
 
     public HttpURLConnection createCommonGetHttpConnection(String host, String appKey,
-        String appSecret, String uri, String contentType)
-        throws MalformedURLException, IOException, ProtocolException {
+                                                           String appSecret, String uri, String contentType) throws IOException {
         String nonce = String.valueOf(Math.random() * 1000000);
         String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
         StringBuilder toSign = new StringBuilder(appSecret).append(nonce).append(timestamp);
@@ -175,18 +166,16 @@ public class HttpHelper {
         return conn;
     }
 
-    public HttpURLConnection createIMGetHttpConnection(String uri, String contentType)
-        throws MalformedURLException, IOException, ProtocolException {
+    public HttpURLConnection createIMGetHttpConnection(String uri, String contentType) throws IOException {
         return createCommonGetHttpConnection(imProperties.getHost(),
-            imProperties.getAppKey(), imProperties.getSecret(), uri,
-            contentType);
+                imProperties.getAppKey(), imProperties.getSecret(), uri,
+                contentType);
     }
 
-    public HttpURLConnection createIMPostHttpConnection(String uri, String contentType)
-        throws MalformedURLException, IOException, ProtocolException {
+    public HttpURLConnection createIMPostHttpConnection(String uri, String contentType) throws IOException {
         return createCommonPostHttpConnection(imProperties.getHost(),
                 imProperties.getAppKey(), imProperties.getSecret(), uri,
-            contentType);
+                contentType);
     }
 
     public byte[] readInputStream(InputStream inStream) throws Exception {
@@ -202,6 +191,34 @@ public class HttpHelper {
         return data;
     }
 
+    public String returnResult(HttpURLConnection conn) throws Exception {
+        InputStream input;
+        String result;
+        try {
+            if (conn.getResponseCode() == 200 || conn.getResponseCode() == 201) {
+                input = conn.getInputStream();
+            } else {
+                input = conn.getErrorStream();
+            }
+            result = new String(readInputStream(input), StandardCharsets.UTF_8);
+        } catch (UnknownHostException e) {
+            result = getExceptionMessage("request:" + conn.getURL() + " ,UnknownHostException:" + e.getMessage());
+        } catch (SocketTimeoutException e) {
+            result = getExceptionMessage("request:" + conn.getURL() + " ,SocketTimeoutException:" + e.getMessage());
+        } catch (IOException e) {
+            result = getExceptionMessage("request:" + conn.getURL() + " ,IOException:" + e.getMessage());
+        }
+        log.info("IM server api response:{}", result);
+        return result;
+    }
+
+    private static String getExceptionMessage(String error) {
+        Map<String, Object> result = new HashMap<>();
+        result.put("code", 400);
+        result.put("msg", error);
+        return GsonUtil.toJson(result);
+    }
+
     public String returnResult(HttpURLConnection conn, String body) throws Exception, IOException {
         InputStream input = null;
         if (conn.getResponseCode() == 200) {
@@ -214,16 +231,18 @@ public class HttpHelper {
         return result;
     }
 
-    public HttpURLConnection createPostHttpConnection(String uri, String contentType)
-        throws IOException {
-
+    public HttpURLConnection createPostHttpConnection(String uri, String contentType) throws IOException {
         URL url = new URL(uri);
         HttpURLConnection conn = (HttpURLConnection) url.openConnection();
         if (conn == null) {
             log.info("open url connection fail, url={}", uri);
             return null;
         }
+        setConn(conn, contentType);
+        return conn;
+    }
 
+    private void setConn(HttpURLConnection conn, String contentType) throws ProtocolException {
         conn.setUseCaches(false);
         conn.setDoInput(true);
         conn.setDoOutput(true);
@@ -232,6 +251,5 @@ public class HttpHelper {
         conn.setConnectTimeout(30000);
         conn.setReadTimeout(30000);
         conn.setRequestProperty("Content-Type", contentType);
-        return conn;
     }
 }

+ 81 - 17
mec-im/src/main/java/com/ym/mec/im/IMHelper.java

@@ -2,8 +2,10 @@ package com.ym.mec.im;
 
 import com.alibaba.fastjson.JSON;
 import com.ym.http.HttpHelper;
+import com.ym.mec.common.exception.BizException;
 import com.ym.pojo.IMApiResultInfo;
 import com.ym.pojo.IMTokenInfo;
+import io.rong.util.GsonUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Async;
@@ -11,6 +13,7 @@ import org.springframework.stereotype.Component;
 
 import java.net.HttpURLConnection;
 import java.net.URLEncoder;
+import java.util.List;
 
 /**
  * Created by weiqinxiao on 2019/2/28.
@@ -26,8 +29,8 @@ public class IMHelper {
     /**
      * 获取 Token 方法
      *
-     * @param userId:用户 Id,最大长度 64 字节.是用户在 App 中的唯一标识码,必须保证在同一个 App 内不重复,重复的用户 Id 将被当作是同一用户。(必传)
-     * @param name:用户名称,最大长度 128 字节.用来在 Push 推送时显示用户的名称.用户名称,最大长度 128 字节.用来在 Push 推送时显示用户的名称。(必传)
+     * @param userId:用户        Id,最大长度 64 字节.是用户在 App 中的唯一标识码,必须保证在同一个 App 内不重复,重复的用户 Id 将被当作是同一用户。(必传)
+     * @param name:用户名称,最大长度   128 字节.用来在 Push 推送时显示用户的名称.用户名称,最大长度 128 字节.用来在 Push 推送时显示用户的名称。(必传)
      * @param portraitUri:用户头像 URI,最大长度 1024 字节.用来在 Push 推送时显示用户的头像。(必传)
      * @return TokenResult
      **/
@@ -64,8 +67,8 @@ public class IMHelper {
      * 内的群组数量没有限制.注:其实本方法是加入群组方法 /group/join 的别名。)
      *
      * @param userId:要加入群的用户 Id。(必传)
-     * @param groupId:创建群组 Id。(必传)
-     * @param groupName:群组 Id 对应的名称。(必传)
+     * @param groupId:创建群组   Id。(必传)
+     * @param groupName:群组   Id 对应的名称。(必传)
      * @return CodeSuccessResult
      **/
     public IMApiResultInfo createGroup(String[] userId, String groupId, String groupName)
@@ -107,8 +110,8 @@ public class IMHelper {
     /**
      * 将用户加入指定群组,用户将可以收到该群的消息,同一用户最多可加入 500 个群,每个群最大至 3000 人。
      *
-     * @param userId:要加入群的用户 Id,可提交多个,最多不超过 1000 个。(必传)
-     * @param groupId:要加入的群 Id。(必传)
+     * @param userId:要加入群的用户  Id,可提交多个,最多不超过 1000 个。(必传)
+     * @param groupId:要加入的群   Id。(必传)
      * @param groupName:要加入的群 Id 对应的名称。(必传)
      * @return CodeSuccessResult
      **/
@@ -149,12 +152,11 @@ public class IMHelper {
     }
 
 
-
     /**
      * 退出群组方法(将用户从群中移除,不再接收该群组的消息.)
      *
      * @param userId:要退出群的用户 Id.(必传)
-     * @param groupId:要退出的群 Id.(必传)
+     * @param groupId:要退出的群  Id.(必传)
      * @return CodeSuccessResult
      **/
     public IMApiResultInfo quit(String[] userId, String groupId) throws Exception {
@@ -191,7 +193,7 @@ public class IMHelper {
      * 解散群组方法。(将该群解散,所有用户都无法再接收该群的消息。)
      *
      * @param userId:操作解散群的用户 Id。(必传)
-     * @param groupId:要解散的群 Id。(必传)
+     * @param groupId:要解散的群   Id。(必传)
      * @return CodeSuccessResult
      **/
     public IMApiResultInfo dismiss(String userId, String groupId) throws Exception {
@@ -222,15 +224,15 @@ public class IMHelper {
     /**
      * 发送群组消息方法(以一个用户身份向群组发送消息,单条消息最大 128k.每秒钟最多发送 20 条消息,每次最多向 3 个群组发送,如:一次向 3 个群组发送消息,示为 3 条消息。)
      *
-     * @param fromUserId:发送人用户 Id 。(必传)
-     * @param toGroupId:接收群Id,提供多个本参数可以实现向多群发送消息,最多不超过 3 个群组。(必传)
-     * @param pushContent:定义显示的 Push 内容,如果 objectName 为融云内置消息类型时,则发送后用户一定会收到 Push 信息. 如果为自定义消息,则
-     * pushContent 为自定义消息显示的 Push 内容,如果不传则用户不会收到 Push 通知。(可选)
-     * @param pushData:针对 iOS 平台为 Push 通知时附加到 payload 中,Android 客户端收到推送消息时对应字段名为 pushData。(可选)
-     * @param isPersisted:当前版本有新的自定义消息,而老版本没有该自定义消息时,老版本客户端收到消息后是否进行存储,0 表示为不存储、 1 表示为存储,默认为 1
-     * 存储消息。(可选)
+     * @param fromUserId:发送人用户                                             Id 。(必传)
+     * @param toGroupId:接收群Id,提供多个本参数可以实现向多群发送消息,最多不超过                     3 个群组。(必传)
+     * @param pushContent:定义显示的                                            Push 内容,如果 objectName 为融云内置消息类型时,则发送后用户一定会收到 Push 信息. 如果为自定义消息,则
+     *                                                                     pushContent 为自定义消息显示的 Push 内容,如果不传则用户不会收到 Push 通知。(可选)
+     * @param pushData:针对                                                  iOS 平台为 Push 通知时附加到 payload 中,Android 客户端收到推送消息时对应字段名为 pushData。(可选)
+     * @param isPersisted:当前版本有新的自定义消息,而老版本没有该自定义消息时,老版本客户端收到消息后是否进行存储,0   表示为不存储、 1 表示为存储,默认为 1
+     *                                                                     存储消息。(可选)
      * @param isCounted:当前版本有新的自定义消息,而老版本没有该自定义消息时,老版本客户端收到消息后是否进行未读消息计数,0 表示为不计数、 1 表示为计数,默认为 1
-     * 计数,未读消息数增加 1。(可选)
+     *                                                                     计数,未读消息数增加 1。(可选)
      * @return CodeSuccessResult
      **/
     public IMApiResultInfo publishMessage(String fromUserId, String toGroupId, BaseMessage message) throws Exception {
@@ -332,4 +334,66 @@ public class IMHelper {
 
         return JSON.parseObject(httpHelper.returnResult(conn, body), IMApiResultInfo.class);
     }
+
+    /**
+     * 创建聊天室
+     *
+     * @param chatRoomId:   要创建的聊天室 Id,长度不超过 64 字节
+     * @param chatRoomName: 聊天室的名称,每次可创建多个聊天室。
+     * @return IMApiResultInfo
+     * @throws Exception
+     */
+    public IMApiResultInfo createChatRoom(String chatRoomId, String chatRoomName) throws Exception {
+        if (chatRoomId == null) {
+            throw new BizException("房间Uid不能为空");
+        }
+
+        if (chatRoomName == null) {
+            throw new BizException("房间名称不能为空");
+        }
+
+        StringBuilder sb = new StringBuilder();
+        chatRoomId = "[" + chatRoomId + "]";
+        sb.append("&chatroom").append(URLEncoder.encode(chatRoomId, UTF8));
+        sb.append("=");
+        sb.append(URLEncoder.encode(chatRoomName, UTF8));
+        String body = sb.toString();
+        if (body.indexOf("&") == 0) {
+            body = body.substring(1);
+        }
+
+        HttpURLConnection conn = httpHelper
+                .createIMPostHttpConnection("/chatroom/create.json", "application/x-www-form-urlencoded");
+        httpHelper.setBodyParameter(body, conn);
+
+        return (IMApiResultInfo) GsonUtil.fromJson(httpHelper.returnResult(conn), IMApiResultInfo.class);
+    }
+
+
+    /**
+     * 销毁聊天室
+     *
+     * @param chatroomIds 聊天室 ID 列表(必传)
+     * @return
+     */
+    public IMApiResultInfo deleteChrm(List<String> chatroomIds)
+            throws Exception {
+        if (chatroomIds == null) {
+            throw new BizException("房间Uid不能为空");
+        }
+        StringBuilder sb = new StringBuilder();
+        for (String child : chatroomIds) {
+            sb.append("&chatroomId=").append(URLEncoder.encode(child, UTF8));
+        }
+        String body = sb.toString();
+        if (body.indexOf("&") == 0) {
+            body = body.substring(1);
+        }
+        HttpURLConnection conn = httpHelper.createIMPostHttpConnection("/chatroom/destroy.json", "application/x-www-form-urlencoded");
+        httpHelper.setBodyParameter(body, conn);
+
+        return (IMApiResultInfo) GsonUtil.fromJson(httpHelper.returnResult(conn), IMApiResultInfo.class);
+
+    }
+
 }

+ 1 - 0
mec-im/src/main/java/com/ym/pojo/ControlDeviceTaskInfo.java

@@ -1,5 +1,6 @@
 package com.ym.pojo;
 
+import com.ym.enums.DeviceTypeEnum;
 import lombok.Data;
 
 import java.io.Serializable;

+ 1 - 0
mec-im/src/main/java/com/ym/pojo/UpgradeRoleTaskInfo.java

@@ -1,5 +1,6 @@
 package com.ym.pojo;
 
+import com.ym.enums.RoleEnum;
 import lombok.Data;
 
 import java.io.Serializable;

+ 70 - 0
mec-im/src/main/java/com/ym/service/Impl/LiveRoomServiceImpl.java

@@ -0,0 +1,70 @@
+package com.ym.service.Impl;
+
+import com.ym.mec.common.exception.BizException;
+import com.ym.mec.im.IMHelper;
+import com.ym.pojo.IMApiResultInfo;
+import com.ym.service.LiveRoomService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author hgw
+ * Created by 2022-02-21
+ */
+@Slf4j
+@Service
+public class LiveRoomServiceImpl implements LiveRoomService {
+
+    @Autowired
+    private IMHelper imHelper;
+
+    /**
+     * 创建房间-聊天室
+     *
+     * @param roomId   房间Uid
+     * @param roomName 房间名称
+     */
+    public IMApiResultInfo createLiveRoom(String roomId, String roomName) {
+        IMApiResultInfo resultInfo;
+        try {
+            resultInfo = imHelper.createChatRoom(roomId, roomName);
+        } catch (Exception e) {
+            log.error("create chatRoom error >>>", e.getCause());
+            throw new BizException("创建聊天室失败!");
+        }
+        if (!resultInfo.isSuccess()) {
+            log.error("create chatRoom error: {}", resultInfo.getErrorMessage());
+            throw new BizException("创建聊天室失败!");
+        }
+        log.info("create chatRoom success: {}", roomId);
+        return resultInfo;
+    }
+
+    /**
+     * 销毁房间-聊天室
+     *
+     * @param roomId 房间Uid
+     */
+    public IMApiResultInfo destroyLiveRoom(String roomId) {
+        //删除服务器房间
+        List<String> deleteRoomIds = new ArrayList<String>() {{
+            add(roomId);
+        }};
+        IMApiResultInfo resultInfo;
+        try {
+            resultInfo = imHelper.deleteChrm(deleteRoomIds);
+        } catch (Exception e) {
+            throw new BizException("关闭聊天室失败!");
+        }
+        if (!resultInfo.isSuccess()) {
+            log.error("destroy chatRoom error: {}", resultInfo.getErrorMessage());
+            throw new BizException("关闭聊天室失败!");
+        }
+        return resultInfo;
+    }
+
+}

+ 187 - 184
mec-im/src/main/java/com/ym/service/Impl/RoomServiceImpl.java

@@ -13,6 +13,9 @@ import com.ym.dao.RoomDao;
 import com.ym.dao.RoomMemberDao;
 import com.ym.dao.UserDao;
 import com.ym.dao.WhiteboardDao;
+import com.ym.enums.ActionEnum;
+import com.ym.enums.DeviceTypeEnum;
+import com.ym.enums.RoleEnum;
 import com.ym.job.ScheduleManager;
 import com.ym.mec.auth.api.client.SysUserFeignService;
 import com.ym.mec.auth.api.entity.SysUser;
@@ -49,8 +52,8 @@ import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
-import static com.ym.pojo.RoleEnum.RoleStudent;
-import static com.ym.pojo.RoleEnum.RoleTeacher;
+import static com.ym.enums.RoleEnum.RoleStudent;
+import static com.ym.enums.RoleEnum.RoleTeacher;
 
 /**
  * Created by super_zou on 2019/11/28.
@@ -99,25 +102,25 @@ public class RoomServiceImpl implements RoomService {
     @Autowired
     private TenantAssetsInfoService tenantAssetsInfoService;
     @Autowired
-    private RedisTemplate<String,String> redisTemplate;
+    private RedisTemplate<String, String> redisTemplate;
 
     @Override
-    public Integer getCurrentCourseId(String roomId){
+    public Integer getCurrentCourseId(String roomId) {
         CourseSchedule courseSchedule = courseScheduleDao.get(Long.parseLong(roomId));
         //是否是连堂课
-        String continueCourseTime = sysTenantConfigService.getTenantConfigValue(SysConfigService.ONLINE_CONTINUE_COURSE_TIME,courseSchedule.getTenantId());
+        String continueCourseTime = sysTenantConfigService.getTenantConfigValue(SysConfigService.ONLINE_CONTINUE_COURSE_TIME, courseSchedule.getTenantId());
         if (StringUtils.isEmpty(continueCourseTime)) {
             continueCourseTime = "5";
         }
         CourseSchedule schedule = courseSchedule;
         //如果当前课程是连堂课,那么获取第一节课的课程编号
-        while (true){
+        while (true) {
             String classDate = DateUtil.format(schedule.getClassDate(), DateUtil.DEFAULT_PATTERN);
             String startClassTime = DateUtil.format(schedule.getStartClassTime(), DateUtil.EXPANDED_TIME_FORMAT);
-            schedule = courseScheduleDao.getFirstCourse(schedule.getClassGroupId(),classDate + " " + startClassTime,schedule.getActualTeacherId(),continueCourseTime);
-            if(schedule != null){
+            schedule = courseScheduleDao.getFirstCourse(schedule.getClassGroupId(), classDate + " " + startClassTime, schedule.getActualTeacherId(), continueCourseTime);
+            if (schedule != null) {
                 roomId = schedule.getId().toString();
-            }else {
+            } else {
                 break;
             }
         }
@@ -125,20 +128,20 @@ public class RoomServiceImpl implements RoomService {
     }
 
     @Transactional(rollbackFor = Exception.class)
-    public String getCloseNetworkRoomTime(CourseSchedule courseSchedule,String continueCourseTime){
-        String autoCloseNetworkRoomTime = sysTenantConfigService.getTenantConfigValue(SysConfigService.COURSE_AFTER_BUFFER_TIME,courseSchedule.getTenantId());
-        if(StringUtils.isEmpty(autoCloseNetworkRoomTime)){
+    public String getCloseNetworkRoomTime(CourseSchedule courseSchedule, String continueCourseTime) {
+        String autoCloseNetworkRoomTime = sysTenantConfigService.getTenantConfigValue(SysConfigService.COURSE_AFTER_BUFFER_TIME, courseSchedule.getTenantId());
+        if (StringUtils.isEmpty(autoCloseNetworkRoomTime)) {
             autoCloseNetworkRoomTime = "15";
         }
         CourseSchedule schedule = courseSchedule;
         //如果当前课程是连堂课,那么获取第一节课的课程编号
-        while (true){
+        while (true) {
             String classDate = DateUtil.format(schedule.getClassDate(), DateUtil.DEFAULT_PATTERN);
             String endClassTime = DateUtil.format(schedule.getEndClassTime(), DateUtil.EXPANDED_TIME_FORMAT);
-            schedule = courseScheduleDao.getLastCourse(schedule.getClassGroupId(),classDate + " " + endClassTime,schedule.getActualTeacherId(),continueCourseTime);
-            if(schedule != null){
-                autoCloseNetworkRoomTime = DateUtil.minutesBetween(new Date(),schedule.getEndClassTime()) + "";
-            }else {
+            schedule = courseScheduleDao.getLastCourse(schedule.getClassGroupId(), classDate + " " + endClassTime, schedule.getActualTeacherId(), continueCourseTime);
+            if (schedule != null) {
+                autoCloseNetworkRoomTime = DateUtil.minutesBetween(new Date(), schedule.getEndClassTime()) + "";
+            } else {
                 break;
             }
         }
@@ -155,57 +158,57 @@ public class RoomServiceImpl implements RoomService {
 
         Teacher teacher = teacherDao.get(Integer.parseInt(userId));
         CourseSchedule courseSchedule = courseScheduleDao.get(Long.parseLong(roomId));
-        if(courseSchedule.getTeachMode() == TeachModeEnum.OFFLINE){
-            return new BaseResponse(ErrorEnum.JOIN_ROOM_ERROR,ErrorEnum.JOIN_ROOM_ERROR.getErrMsg(),null);
+        if (courseSchedule.getTeachMode() == TeachModeEnum.OFFLINE) {
+            return new BaseResponse(ErrorEnum.JOIN_ROOM_ERROR, ErrorEnum.JOIN_ROOM_ERROR.getErrMsg(), null);
         }
         Date curTime = DateTimeUtils.currentUTC();
         //是否提前进入教室
-        String courseBeforeBufferTime = sysTenantConfigService.getTenantConfigValue(SysConfigService.COURSE_BEFORE_BUFFER_TIME,courseSchedule.getTenantId());
+        String courseBeforeBufferTime = sysTenantConfigService.getTenantConfigValue(SysConfigService.COURSE_BEFORE_BUFFER_TIME, courseSchedule.getTenantId());
         if (StringUtils.isEmpty(courseBeforeBufferTime)) {
             courseBeforeBufferTime = "5";
         }
         Date addMinutes = DateUtil.addMinutes(curTime, Integer.parseInt(courseBeforeBufferTime));
-        if(courseSchedule.getStartClassTime().compareTo(addMinutes) > 0 ){
-            return new BaseResponse(ErrorEnum.ROOM_NOT_START,ErrorEnum.ROOM_NOT_START.getErrMsg(),null);
+        if (courseSchedule.getStartClassTime().compareTo(addMinutes) > 0) {
+            return new BaseResponse(ErrorEnum.ROOM_NOT_START, ErrorEnum.ROOM_NOT_START.getErrMsg(), null);
 //            throw new BizException("网络教室暂未开启,请在{}分钟后进入教室",DateUtil.minutesBetween(addMinutes,courseSchedule.getStartClassTime()));
         }
         final TenantAssetsInfo one = tenantAssetsInfoService.getOne(new WrapperUtil<TenantAssetsInfo>()
                 .hasEq("tenant_id_", courseSchedule.getTenantId())
                 .queryWrapper()
                 .gt("balance_", 0));
-        if(one == null){
-            return new BaseResponse(ErrorEnum.CLOUD_BALANCE_NOT_FEE,ErrorEnum.CLOUD_BALANCE_NOT_FEE.getErrMsg(),null);
+        if (one == null) {
+            return new BaseResponse(ErrorEnum.CLOUD_BALANCE_NOT_FEE, ErrorEnum.CLOUD_BALANCE_NOT_FEE.getErrMsg(), null);
         }
 
         //是否是连堂课
-        String continueCourseTime = sysTenantConfigService.getTenantConfigValue(SysConfigService.ONLINE_CONTINUE_COURSE_TIME,courseSchedule.getTenantId());
+        String continueCourseTime = sysTenantConfigService.getTenantConfigValue(SysConfigService.ONLINE_CONTINUE_COURSE_TIME, courseSchedule.getTenantId());
         if (StringUtils.isEmpty(continueCourseTime)) {
             continueCourseTime = "5";
         }
 
         RoomResult roomResult = new RoomResult();
-        roomResult.setAutoCloseNetworkRoomTime(this.getCloseNetworkRoomTime(courseSchedule,continueCourseTime));
+        roomResult.setAutoCloseNetworkRoomTime(this.getCloseNetworkRoomTime(courseSchedule, continueCourseTime));
         CourseSchedule schedule = courseSchedule;
         //如果当前课程是连堂课,那么获取第一节课的课程编号
-        while (true){
+        while (true) {
             String classDate = DateUtil.format(schedule.getClassDate(), DateUtil.DEFAULT_PATTERN);
             String startClassTime = DateUtil.format(schedule.getStartClassTime(), DateUtil.EXPANDED_TIME_FORMAT);
-            schedule = courseScheduleDao.getFirstCourse(schedule.getClassGroupId(),classDate + " " + startClassTime,schedule.getActualTeacherId(),continueCourseTime);
-            if(schedule != null){
+            schedule = courseScheduleDao.getFirstCourse(schedule.getClassGroupId(), classDate + " " + startClassTime, schedule.getActualTeacherId(), continueCourseTime);
+            if (schedule != null) {
                 roomId = schedule.getId().toString();
 //                roomResult.setAutoCloseFlag(false);
-            }else {
+            } else {
                 break;
             }
         }
         Long courseId = Long.parseLong(roomId);
         //记录用户实际选择的房间
-        if(courseSchedule.getGroupType() == GroupType.COMM){
+        if (courseSchedule.getGroupType() == GroupType.COMM) {
             roomId = "I" + roomId;
-        }else {
+        } else {
             roomId = "S" + roomId;
         }
-        redisTemplate.opsForValue().setIfAbsent(roomId + userId,courseSchedule.getId().toString());
+        redisTemplate.opsForValue().setIfAbsent(roomId + userId, courseSchedule.getId().toString());
         log.info("joinRoom current: roomId={}, userId={}", roomId, userId);
         RoleEnum roleEnum;
 
@@ -216,13 +219,13 @@ public class RoomServiceImpl implements RoomService {
         if (member == null) {
             int count = roomMemberDao.countByRidAndExcludeRole(roomId, RoleEnum.RoleAudience.getValue());
             if (count == roomProperties.getMaxCount()) {
-                log.info("join error Over max count: roomId = {}, userId = {}", roomId,userId);
-                return new BaseResponse(ErrorEnum.ERR_OVER_MAX_COUNT,ErrorEnum.ERR_OVER_MAX_COUNT.getErrMsg(),null);
+                log.info("join error Over max count: roomId = {}, userId = {}", roomId, userId);
+                return new BaseResponse(ErrorEnum.ERR_OVER_MAX_COUNT, ErrorEnum.ERR_OVER_MAX_COUNT.getErrMsg(), null);
             }
-            if(teacher != null && teacher.getId().equals(courseSchedule.getActualTeacherId())){
+            if (teacher != null && teacher.getId().equals(courseSchedule.getActualTeacherId())) {
                 roleEnum = RoleTeacher;
                 userName = sysUser.getRealName();
-            }else {
+            } else {
                 roleEnum = RoleStudent;
                 userName = sysUser.getUsername();
             }
@@ -230,11 +233,11 @@ public class RoomServiceImpl implements RoomService {
             userResult.setCamera(true);
             userResult.setHandUpOn(false);
             userResult.setJoinTime(curTime);
-            saveRoomMember(userId,sysUser.getAvatar(), userName, roomId, roleEnum.getValue(), curTime);
+            saveRoomMember(userId, sysUser.getAvatar(), userName, roomId, roleEnum.getValue(), curTime);
         } else {
             roleEnum = RoleEnum.getEnumByValue(member.getRole());
-            if(roleEnum == RoleTeacher){
-                courseScheduleStudentPaymentDao.adjustPlayMidi(courseId,null,null);
+            if (roleEnum == RoleTeacher) {
+                courseScheduleStudentPaymentDao.adjustPlayMidi(courseId, null, null);
             }
             userName = member.getName();
             userResult.setCamera(member.isCamera());
@@ -243,7 +246,7 @@ public class RoomServiceImpl implements RoomService {
         }
         imHelper.joinGroup(new String[]{userId}, roomId, roomId);
 
-        List<CourseScheduleStudentMusicScore> scheduleStudentMusicScores = courseScheduleStudentMusicScoreDao.queryByScoreIdAndCourseId(null, courseId,null, null, null);
+        List<CourseScheduleStudentMusicScore> scheduleStudentMusicScores = courseScheduleStudentMusicScoreDao.queryByScoreIdAndCourseId(null, courseId, null, null, null);
 
         Room room = roomDao.findByRid(roomId);
         String display = "";
@@ -251,13 +254,13 @@ public class RoomServiceImpl implements RoomService {
             display = "display://type=1?userId=" + userId + "?uri=";
         } else if (roleEnum == RoleEnum.RoleAssistant && display.isEmpty()) {
             display = "display://type=0?userId=" + userId + "?uri=";
-        }else {
+        } else {
             ExamSongDownloadData examSongDownloadData;
             String json = courseScheduleStudentPaymentDao.getExamJsonByCourseIdAndUserId(courseId, sysUser.getId());
-            if(StringUtils.isEmpty(json)){
+            if (StringUtils.isEmpty(json)) {
                 examSongDownloadData = new ExamSongDownloadData();
-            }else {
-                examSongDownloadData = JSON.parseObject(json,ExamSongDownloadData.class);
+            } else {
+                examSongDownloadData = JSON.parseObject(json, ExamSongDownloadData.class);
             }
             //获取学员曲目下载状态
             userResult.setExamSongDownloadJson(examSongDownloadData);
@@ -266,7 +269,7 @@ public class RoomServiceImpl implements RoomService {
             }
         }
         //已下载的伴奏列表
-        if(scheduleStudentMusicScores != null && scheduleStudentMusicScores.size() > 0){
+        if (scheduleStudentMusicScores != null && scheduleStudentMusicScores.size() > 0) {
             List<CourseScheduleStudentMusicScore> musicScores = scheduleStudentMusicScores.stream().filter(e -> e.getUserId().equals(sysUser.getId())).collect(Collectors.toList());
             String toJSONString = JSON.toJSONString(musicScores, SerializerFeature.DisableCircularReferenceDetect);
             List<CourseScheduleStudentMusicScore> lists = JSON.parseArray(toJSONString, CourseScheduleStudentMusicScore.class);
@@ -277,24 +280,24 @@ public class RoomServiceImpl implements RoomService {
         userResult.setUserId(userId);
         userResult.setRole(roleEnum.getValue());
         //获取节拍器信息
-        String midi = courseScheduleStudentPaymentDao.getMidiByCourseIdAndUserId(courseId.toString(),userId);
-        userResult.setPlayMidiJson(JSONObject.parseObject(midi,CustomMessage.class));
+        String midi = courseScheduleStudentPaymentDao.getMidiByCourseIdAndUserId(courseId.toString(), userId);
+        userResult.setPlayMidiJson(JSONObject.parseObject(midi, CustomMessage.class));
 
         //获取当前课程剩余时长
 //        String classDate = DateUtil.format(courseSchedule.getClassDate(), DateUtil.DEFAULT_PATTERN);
 //        String endClassTime = DateUtil.format(courseSchedule.getEndClassTime(), DateUtil.EXPANDED_TIME_FORMAT);
-        roomResult.setSurplusTime(DateUtil.secondsBetween(new Date(),courseSchedule.getEndClassTime()));
+        roomResult.setSurplusTime(DateUtil.secondsBetween(new Date(), courseSchedule.getEndClassTime()));
 
         roomResult.setUserInfo(userResult);
         roomResult.setDisplay(display);
         roomResult.setRoomId(roomId);
 
         List<RoomMember> roomMemberList = roomMemberDao.findByRid(roomId);
-        if(roomMemberList != null && roomMemberList.size() > 0){
+        if (roomMemberList != null && roomMemberList.size() > 0) {
             Set<String> userIds = roomMemberList.stream().map(e -> e.getUid()).collect(Collectors.toSet());
-            Map<Integer,String> midiMap = MapUtil.convertMybatisMap(courseScheduleStudentPaymentDao.queryMidiByUserIdsAndCourseId(userIds,courseId.toString()));
-            Map<Integer,String> examSongMap = MapUtil.convertMybatisMap(courseScheduleStudentPaymentDao.queryExamSongByUserIdsAndCourseId(userIds,courseId.toString()));
-            roomResult.setMembers(roomMemberList,midiMap,examSongMap,scheduleStudentMusicScores);
+            Map<Integer, String> midiMap = MapUtil.convertMybatisMap(courseScheduleStudentPaymentDao.queryMidiByUserIdsAndCourseId(userIds, courseId.toString()));
+            Map<Integer, String> examSongMap = MapUtil.convertMybatisMap(courseScheduleStudentPaymentDao.queryExamSongByUserIdsAndCourseId(userIds, courseId.toString()));
+            roomResult.setMembers(roomMemberList, midiMap, examSongMap, scheduleStudentMusicScores);
         }
         roomResult.setWhiteboards(whiteboardDao.findByRid(roomId));
         if (room != null) {
@@ -304,7 +307,7 @@ public class RoomServiceImpl implements RoomService {
         return new BaseResponse(roomResult);
     }
 
-    public RoomMember saveRoomMember(String roomId,String userId){
+    public RoomMember saveRoomMember(String roomId, String userId) {
         SysUser sysUser = sysUserFeignService.queryUserById(Integer.parseInt(userId));
 
         Teacher teacher = teacherDao.get(Integer.parseInt(userId));
@@ -316,10 +319,10 @@ public class RoomServiceImpl implements RoomService {
         RoomMember member = roomMemberDao.findByRidAndUid(roomId, userId);
         String userName;
         if (member == null) {
-            if(teacher != null && teacher.getId().equals(courseSchedule.getActualTeacherId())){
+            if (teacher != null && teacher.getId().equals(courseSchedule.getActualTeacherId())) {
                 roleEnum = RoleTeacher;
                 userName = sysUser.getRealName();
-            }else {
+            } else {
                 roleEnum = RoleStudent;
                 userName = sysUser.getUsername();
             }
@@ -333,28 +336,28 @@ public class RoomServiceImpl implements RoomService {
     @Override
     public void joinRoomFailure(String roomId, String userId) {
         RoomMember roomMember = roomMemberDao.findByRidAndUid(roomId, userId);
-        if(roomMember == null){
-            return ;
+        if (roomMember == null) {
+            return;
         }
         log.info("joinRoomFailure : roomId={}, userId={}", roomId, userId);
         //如果加入失败,删除该用户数据
-        roomMemberDao.deleteUserByRidAndUid(roomId,userId);
+        roomMemberDao.deleteUserByRidAndUid(roomId, userId);
     }
 
     @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
     @Override
-    public void joinRoomSuccess(String roomId,String userId,String deviceNum) throws Exception {
-        log.info("joinRoomSuccess: roomId={}, userId={}, deviceNum={}", roomId,userId,deviceNum);
+    public void joinRoomSuccess(String roomId, String userId, String deviceNum) throws Exception {
+        log.info("joinRoomSuccess: roomId={}, userId={}, deviceNum={}", roomId, userId, deviceNum);
         RoomMember roomMember = roomMemberDao.findByRidAndUid(roomId, userId);
-        if(roomMember == null){
-            roomMember = saveRoomMember(roomId,userId);
+        if (roomMember == null) {
+            roomMember = saveRoomMember(roomId, userId);
         }
-        String joinSuccessKey = "joinRoomSuccess"+ roomId + userId;
+        String joinSuccessKey = "joinRoomSuccess" + roomId + userId;
         Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(joinSuccessKey, roomId, 1l, TimeUnit.SECONDS);
-        if(!aBoolean){
+        if (!aBoolean) {
             RoleEnum roleEnum = RoleEnum.getEnumByValue(roomMember.getRole());
-            if(roleEnum == RoleTeacher && StringUtils.isNotEmpty(deviceNum)){
-                teacherAttendanceService.updateDeviceNum(Integer.parseInt(roomId.substring(1)),userId,deviceNum,null);
+            if (roleEnum == RoleTeacher && StringUtils.isNotEmpty(deviceNum)) {
+                teacherAttendanceService.updateDeviceNum(Integer.parseInt(roomId.substring(1)), userId, deviceNum, null);
 //                signInSuccess(roomMember,deviceNum);
             }
             return;
@@ -364,11 +367,11 @@ public class RoomServiceImpl implements RoomService {
         CourseSchedule schedule = courseScheduleDao.getLock(Long.parseLong(roomId.substring(1)));
 
         String display = "";
-        if(roleEnum == RoleTeacher){
+        if (roleEnum == RoleTeacher) {
             //如果是老师加入房间,调整节拍器状态
-            courseScheduleStudentPaymentDao.adjustPlayMidi(schedule.getId(),null,null);
+            courseScheduleStudentPaymentDao.adjustPlayMidi(schedule.getId(), null, null);
             display = "display://type=1?userId=" + userId + "?uri=";
-        }else if (roleEnum == RoleEnum.RoleAssistant){
+        } else if (roleEnum == RoleEnum.RoleAssistant) {
             display = "display://type=0?userId=" + userId + "?uri=";
         }
         Date curTime = DateTimeUtils.currentUTC();
@@ -380,8 +383,8 @@ public class RoomServiceImpl implements RoomService {
                 log.error("joinRoomSuccess createGroup error: roomId={}, {}", roomId, resultInfo.getErrorMessage());
                 throw new ApiException(ErrorEnum.ERR_CREATE_ROOM_ERROR, resultInfo.getErrorMessage());
             }
-        }else{
-            if(roleEnum == RoleTeacher || roleEnum == RoleEnum.RoleAssistant){
+        } else {
+            if (roleEnum == RoleTeacher || roleEnum == RoleEnum.RoleAssistant) {
                 updateDisplay(roomId, userId, display, 0);
             }
         }
@@ -401,17 +404,17 @@ public class RoomServiceImpl implements RoomService {
         msg.setCamera(true);
         Boolean playMidi = false;
         Boolean examSong = false;
-        if(roleEnum == RoleStudent){
+        if (roleEnum == RoleStudent) {
             String midiByCourseIdAndUserId = courseScheduleStudentPaymentDao.getMidiByCourseIdAndUserId(schedule.getId().toString(), userId);
             //获取节拍器信息
-            if(StringUtils.isNotEmpty(midiByCourseIdAndUserId)){
+            if (StringUtils.isNotEmpty(midiByCourseIdAndUserId)) {
                 JSONObject jsonObject = JSONObject.parseObject(midiByCourseIdAndUserId);
-                if(jsonObject.get("enable") != null){
+                if (jsonObject.get("enable") != null) {
                     playMidi = Boolean.parseBoolean(jsonObject.get("enable").toString());
                 }
             }
             String examJson = courseScheduleStudentPaymentDao.getExamJsonByCourseIdAndUserId(schedule.getId(), Integer.parseInt(userId));
-            if(StringUtils.isNotEmpty(examJson)){
+            if (StringUtils.isNotEmpty(examJson)) {
                 ExamSongDownloadData examSongDownloadData = JSON.parseObject(examJson, ExamSongDownloadData.class);
                 examSong = examSongDownloadData.getEnable();
             }
@@ -421,30 +424,30 @@ public class RoomServiceImpl implements RoomService {
         msg.setExamSongSwitch(examSong);
         imHelper.publishMessage(userId, roomId, msg);
         log.info("join room success: roomId = {}, userId = {}, role = {}", roomId, userId, roleEnum);
-        signInSuccess(roomMember,deviceNum);
+        signInSuccess(roomMember, deviceNum);
     }
 
-    public void signInSuccess(RoomMember roomMember,String deviceNum) {
+    public void signInSuccess(RoomMember roomMember, String deviceNum) {
         String roomId = roomMember.getRid();
         String userId = roomMember.getUid();
         String currentRoomIdKey = roomId + userId;
 
         Long firstCourseId = Long.parseLong(roomId.substring(1));
         Long currentRoomId;
-        if(redisTemplate.hasKey(currentRoomIdKey)){
+        if (redisTemplate.hasKey(currentRoomIdKey)) {
             currentRoomId = Long.parseLong(redisTemplate.opsForValue().get(currentRoomIdKey));
-        }else {
+        } else {
             log.error("signInFailure: roomId={}, userId={}", roomId, userId);
             currentRoomId = firstCourseId;
         }
-        log.info("signInSuccess: roomId={}, userId={},currentRoomId={}", roomId, userId,currentRoomId);
+        log.info("signInSuccess: roomId={}, userId={},currentRoomId={}", roomId, userId, currentRoomId);
         Integer userIdInt = Integer.parseInt(userId);
 
         RoleEnum roleEnum = RoleEnum.getEnumByValue(roomMember.getRole());
-        if(roleEnum == RoleTeacher){
-            teacherAttendanceService.addTeacherAttendanceSignIn(firstCourseId,userIdInt,currentRoomId,deviceNum);
-        }else {
-            studentAttendanceService.addStudentAttendanceSignIn(firstCourseId,userIdInt,currentRoomId);
+        if (roleEnum == RoleTeacher) {
+            teacherAttendanceService.addTeacherAttendanceSignIn(firstCourseId, userIdInt, currentRoomId, deviceNum);
+        } else {
+            studentAttendanceService.addStudentAttendanceSignIn(firstCourseId, userIdInt, currentRoomId);
         }
         redisTemplate.delete(roomId + userId);
     }
@@ -473,30 +476,30 @@ public class RoomServiceImpl implements RoomService {
         return roomMember;
     }
 
-    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class,isolation = Isolation.READ_COMMITTED)
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
     @Override
-    public void leaveRoomSuccess(String roomId,String userId,String deviceNum) throws Exception {
-        log.info("leaveRoomSuccess: roomId={}, userId={},deviceNum={}", roomId,userId,deviceNum);
+    public void leaveRoomSuccess(String roomId, String userId, String deviceNum) throws Exception {
+        log.info("leaveRoomSuccess: roomId={}, userId={},deviceNum={}", roomId, userId, deviceNum);
         Integer firstCourseId = Integer.parseInt(roomId.substring(1));
         RoleEnum roleEnum;
         int parseInt = Integer.parseInt(userId);
         Teacher teacher = teacherDao.get(parseInt);
         CourseSchedule courseSchedule = courseScheduleDao.get(firstCourseId.longValue());
-        if(teacher != null && teacher.getId().equals(courseSchedule.getActualTeacherId())){
+        if (teacher != null && teacher.getId().equals(courseSchedule.getActualTeacherId())) {
             roleEnum = RoleTeacher;
-            courseScheduleStudentMusicScoreDao.closePlayStatus(courseSchedule.getId(),null,null);
-        }else {
+            courseScheduleStudentMusicScoreDao.closePlayStatus(courseSchedule.getId(), null, null);
+        } else {
             roleEnum = RoleStudent;
         }
 
-        String leaveSuccessKey = "leaveRoomSuccess"+ roomId + userId;
+        String leaveSuccessKey = "leaveRoomSuccess" + roomId + userId;
         Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(leaveSuccessKey, roomId, 1l, TimeUnit.SECONDS);
-        log.info("leaveRoomSuccess: roomId={}, userId={},deviceNum={},aBoolean={}", roomId,userId,deviceNum,aBoolean);
-        if(!aBoolean){
-            if (StringUtils.isNotEmpty(deviceNum)){
+        log.info("leaveRoomSuccess: roomId={}, userId={},deviceNum={},aBoolean={}", roomId, userId, deviceNum, aBoolean);
+        if (!aBoolean) {
+            if (StringUtils.isNotEmpty(deviceNum)) {
                 //如果设备号不为空,更新设备号
-                if(roleEnum == RoleTeacher){
-                    teacherAttendanceService.updateDeviceNum(firstCourseId,userId,null,deviceNum);
+                if (roleEnum == RoleTeacher) {
+                    teacherAttendanceService.updateDeviceNum(firstCourseId, userId, null, deviceNum);
 //                    teacherAttendanceService.addTeacherAttendanceSignOut(firstCourseId.longValue(),parseInt,deviceNum);
                 }
             }
@@ -505,14 +508,14 @@ public class RoomServiceImpl implements RoomService {
 
         String username;
         SysUser sysUser = sysUserFeignService.queryUserById(parseInt);
-        if(roleEnum == RoleTeacher){
+        if (roleEnum == RoleTeacher) {
             username = sysUser.getRealName();
-            courseScheduleStudentPaymentDao.adjustPlayMidi(firstCourseId,null,null);
-            courseScheduleStudentPaymentDao.adjustExamSong(firstCourseId.longValue(),null,null);
-            teacherAttendanceService.addTeacherAttendanceSignOut(firstCourseId.longValue(),parseInt,deviceNum);
-        }else {
+            courseScheduleStudentPaymentDao.adjustPlayMidi(firstCourseId, null, null);
+            courseScheduleStudentPaymentDao.adjustExamSong(firstCourseId.longValue(), null, null);
+            teacherAttendanceService.addTeacherAttendanceSignOut(firstCourseId.longValue(), parseInt, deviceNum);
+        } else {
             username = sysUser.getUsername();
-            studentAttendanceService.addStudentAttendanceSignOut(firstCourseId.longValue(),parseInt);
+            studentAttendanceService.addStudentAttendanceSignOut(firstCourseId.longValue(), parseInt);
         }
         Room room = roomDao.findByRid(roomId);
         if (room == null) {
@@ -528,15 +531,15 @@ public class RoomServiceImpl implements RoomService {
             roomDao.deleteByRid(roomId);
             deleteWhiteboardByUser(roomId, userId);
             imHelper.dismiss(userId, roomId);
-            courseScheduleStudentMusicScoreDao.closePlayStatus(courseSchedule.getId(),null,null);
-            log.info("leaveRoomSuccess dismiss the room: {},userId: {}", roomId,userId);
+            courseScheduleStudentMusicScoreDao.closePlayStatus(courseSchedule.getId(), null, null);
+            log.info("leaveRoomSuccess dismiss the room: {},userId: {}", roomId, userId);
         } else {
             roomMemberDao.deleteUserByRidAndUid(roomId, userId);
             MemberChangedMessage msg = new MemberChangedMessage(MemberChangedMessage.Action_Leave, userId, roleEnum.getValue());
             msg.setUserName(username);
             imHelper.publishMessage(userId, roomId, msg);
             imHelper.quit(new String[]{userId}, roomId);
-            log.info("leaveRoomSuccess quit group: roomId={},userId: {}", roomId,userId);
+            log.info("leaveRoomSuccess quit group: roomId={},userId: {}", roomId, userId);
         }
         userDao.deleteByUid(userId);
     }
@@ -632,7 +635,7 @@ public class RoomServiceImpl implements RoomService {
         CheckUtils.checkArgument(roomId != null, "roomId must't be null");
         log.info("kickMember: roomId={}, userId={}", roomId, userId);
         RoomMember roomMember = roomMemberDao.findByRidAndUid(roomId, userId);
-        if(roomMember == null){
+        if (roomMember == null) {
             return true;
         }
 
@@ -861,22 +864,22 @@ public class RoomServiceImpl implements RoomService {
         } else if (data.getHandUpOn() != null) {
             typeEnum = DeviceTypeEnum.HandUp;
             enable = data.getHandUpOn();
-        }else if (data.getExamSongOn() != null) {
+        } else if (data.getExamSongOn() != null) {
             typeEnum = DeviceTypeEnum.ExamSong;
             enable = data.getExamSongOn();
-        }else if (data.getMusicScoreOn() != null) {
+        } else if (data.getMusicScoreOn() != null) {
             typeEnum = DeviceTypeEnum.MusicScore;
             enable = data.getMusicScoreOn();
-            if(enable){
+            if (enable) {
                 //保存伴奏音量
-                roomDao.updateSoundVolumeById(roomId,data.getSoundVolume()==null?0:data.getSoundVolume());
+                roomDao.updateSoundVolumeById(roomId, data.getSoundVolume() == null ? 0 : data.getSoundVolume());
             }
-        }else if (data.getAccompanimentOn() != null) {
+        } else if (data.getAccompanimentOn() != null) {
             typeEnum = DeviceTypeEnum.MusicScoreAccompaniment;
             enable = data.getAccompanimentOn();
-            if(enable){
+            if (enable) {
                 //保存伴奏音量
-                roomDao.updateSoundVolumeById(roomId,data.getSoundVolume()==null?0:data.getSoundVolume());
+                roomDao.updateSoundVolumeById(roomId, data.getSoundVolume() == null ? 0 : data.getSoundVolume());
             }
         } else {
             throw new ApiException(ErrorEnum.ERR_REQUEST_PARA_ERR);
@@ -885,24 +888,24 @@ public class RoomServiceImpl implements RoomService {
         log.info("controlDevice: userId = {}, typeEnum = {}, enable = {} ,roomId = {}", userId, typeEnum, enable, roomId);
 
         if (enable) {
-            if (typeEnum.equals(DeviceTypeEnum.ExamSong)){
+            if (typeEnum.equals(DeviceTypeEnum.ExamSong)) {
                 long scheduleId = Long.parseLong(roomId.substring(1));
                 ExamSongDownloadData msg;
                 String examJson = courseScheduleStudentPaymentDao.getExamJsonByCourseIdAndUserId(scheduleId, Integer.parseInt(userId));
-                if(StringUtils.isEmpty(examJson)){
+                if (StringUtils.isEmpty(examJson)) {
                     throw new BizException("学员伴奏信息异常");
-                }else {
+                } else {
                     msg = JSON.parseObject(examJson, ExamSongDownloadData.class);
                     msg.setEnable(enable);
                 }
-                courseScheduleStudentPaymentDao.adjustExamSong(scheduleId,Integer.parseInt(userId),JSON.toJSONString(msg));
+                courseScheduleStudentPaymentDao.adjustExamSong(scheduleId, Integer.parseInt(userId), JSON.toJSONString(msg));
                 DeviceStateChangedMessage deviceResourceMessage = new DeviceStateChangedMessage(typeEnum.ordinal(), enable);
                 deviceResourceMessage.setUserId(userId);
                 imHelper.publishMessage(authUser.getId().toString(), roomId, deviceResourceMessage, 1);
-            }else if(typeEnum.equals(DeviceTypeEnum.MusicScore)){
+            } else if (typeEnum.equals(DeviceTypeEnum.MusicScore)) {
                 long scheduleId = Long.parseLong(roomId.substring(1));
                 //关闭所有曲目播放
-                courseScheduleStudentMusicScoreDao.closePlayStatus(scheduleId,Integer.parseInt(userId),null);
+                courseScheduleStudentMusicScoreDao.closePlayStatus(scheduleId, Integer.parseInt(userId), null);
                 DeviceStateChangedMessage deviceResourceMessage = new DeviceStateChangedMessage(typeEnum.ordinal(), enable);
                 deviceResourceMessage.setMusicScoreAccompanimentId(data.getMusicScoreAccompanimentId());
                 deviceResourceMessage.setUserId(userId);
@@ -910,17 +913,17 @@ public class RoomServiceImpl implements RoomService {
                 //原音
                 courseScheduleStudentMusicScoreDao.openPlayStatus(scheduleId, data.getMusicScoreAccompanimentId(), Integer.parseInt(userId));
                 imHelper.publishMessage(authUser.getId().toString(), roomId, deviceResourceMessage, 1);
-            }else if(typeEnum.equals(DeviceTypeEnum.MusicScoreAccompaniment)){
+            } else if (typeEnum.equals(DeviceTypeEnum.MusicScoreAccompaniment)) {
                 long scheduleId = Long.parseLong(roomId.substring(1));
                 //关闭所有曲目播放
-                courseScheduleStudentMusicScoreDao.closePlayStatus(scheduleId,Integer.parseInt(userId),null);
-                courseScheduleStudentMusicScoreDao.openAccompanimentPlayStatus(scheduleId,data.getMusicScoreAccompanimentId(),Integer.parseInt(userId));
+                courseScheduleStudentMusicScoreDao.closePlayStatus(scheduleId, Integer.parseInt(userId), null);
+                courseScheduleStudentMusicScoreDao.openAccompanimentPlayStatus(scheduleId, data.getMusicScoreAccompanimentId(), Integer.parseInt(userId));
                 DeviceStateChangedMessage deviceResourceMessage = new DeviceStateChangedMessage(typeEnum.ordinal(), enable);
                 deviceResourceMessage.setMusicScoreAccompanimentId(data.getMusicScoreAccompanimentId());
                 deviceResourceMessage.setUserId(userId);
                 deviceResourceMessage.setSoundVolume(data.getSoundVolume());
                 imHelper.publishMessage(authUser.getId().toString(), roomId, deviceResourceMessage, 1);
-            }else {
+            } else {
                 String ticket = IdentifierUtils.uuid();
                 ControlDeviceTaskInfo taskInfo = new ControlDeviceTaskInfo();
                 taskInfo.setRoomId(roomId);
@@ -940,30 +943,30 @@ public class RoomServiceImpl implements RoomService {
         } else {
             if (typeEnum.equals(DeviceTypeEnum.Camera)) {
                 roomMemberDao.updateCameraByRidAndUid(roomId, userId, false);
-            } else if (typeEnum.equals(DeviceTypeEnum.Microphone)){
+            } else if (typeEnum.equals(DeviceTypeEnum.Microphone)) {
                 roomMemberDao.updateMicByRidAndUid(roomId, userId, false);
-            } else if (typeEnum.equals(DeviceTypeEnum.HandUp)){
+            } else if (typeEnum.equals(DeviceTypeEnum.HandUp)) {
                 roomMemberDao.updateHandByRidAndUid(roomId, userId, false);
-            } else if (typeEnum.equals(DeviceTypeEnum.ExamSong)){
+            } else if (typeEnum.equals(DeviceTypeEnum.ExamSong)) {
                 long scheduleId = Long.parseLong(roomId.substring(1));
                 ExamSongDownloadData msg;
                 String examJson = courseScheduleStudentPaymentDao.getExamJsonByCourseIdAndUserId(scheduleId, Integer.parseInt(userId));
-                if(StringUtils.isEmpty(examJson)){
+                if (StringUtils.isEmpty(examJson)) {
                     throw new BizException("学员伴奏信息异常");
-                }else {
+                } else {
                     msg = JSON.parseObject(examJson, ExamSongDownloadData.class);
                     msg.setEnable(enable);
                 }
-                courseScheduleStudentPaymentDao.adjustExamSong(scheduleId,Integer.parseInt(userId),JSON.toJSONString(msg));
-            }else if(typeEnum.equals(DeviceTypeEnum.MusicScore)){
+                courseScheduleStudentPaymentDao.adjustExamSong(scheduleId, Integer.parseInt(userId), JSON.toJSONString(msg));
+            } else if (typeEnum.equals(DeviceTypeEnum.MusicScore)) {
                 long scheduleId = Long.parseLong(roomId.substring(1));
                 //关闭所有曲目播放
-                courseScheduleStudentMusicScoreDao.closePlayStatus(scheduleId,Integer.parseInt(userId),null);
-            }else if(typeEnum.equals(DeviceTypeEnum.MusicScoreAccompaniment)){
+                courseScheduleStudentMusicScoreDao.closePlayStatus(scheduleId, Integer.parseInt(userId), null);
+            } else if (typeEnum.equals(DeviceTypeEnum.MusicScoreAccompaniment)) {
                 long scheduleId = Long.parseLong(roomId.substring(1));
                 //关闭所有曲目播放
-                courseScheduleStudentMusicScoreDao.closePlayStatus(scheduleId,Integer.parseInt(userId),null);
-            }else {
+                courseScheduleStudentMusicScoreDao.closePlayStatus(scheduleId, Integer.parseInt(userId), null);
+            } else {
                 roomMemberDao.updateMusicByRidAndUid(roomId, userId, false);
             }
             DeviceStateChangedMessage deviceResourceMessage = new DeviceStateChangedMessage(typeEnum.ordinal(), false);
@@ -980,28 +983,28 @@ public class RoomServiceImpl implements RoomService {
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Boolean batchControlDevice(ReqDeviceControlData data) throws Exception {
-        if(data.getExamSongOn() != null || data.getMusicScoreOn() != null || data.getAccompanimentOn() != null){
+        if (data.getExamSongOn() != null || data.getMusicScoreOn() != null || data.getAccompanimentOn() != null) {
             List<BasicUserDto> students = courseScheduleStudentPaymentDao.findStudents(Long.parseLong(data.getRoomId().substring(1)));
-            for (BasicUserDto e:students) {
+            for (BasicUserDto e : students) {
                 data.setUserId(e.getUserId().toString());
                 controlDevice(data);
             }
             return true;
         }
         List<RoomMember> roomMembers;
-        if(StringUtils.isNotEmpty(data.getUserId())){
+        if (StringUtils.isNotEmpty(data.getUserId())) {
             roomMembers = new ArrayList<>();
             String[] split = data.getUserId().split(",");
             for (int i = 0; i < split.length; i++) {
                 roomMembers.add(new RoomMember(split[i]));
             }
-        }else {
+        } else {
             roomMembers = roomMemberDao.findByRidAndRole(data.getRoomId(), RoleStudent.getValue());
         }
-        if(roomMembers.size() == 0){
+        if (roomMembers.size() == 0) {
             return false;
         }
-        for (RoomMember e:roomMembers) {
+        for (RoomMember e : roomMembers) {
             data.setUserId(e.getUid());
             controlDevice(data);
         }
@@ -1020,18 +1023,18 @@ public class RoomServiceImpl implements RoomService {
         ControlDeviceTaskInfo taskInfo = (ControlDeviceTaskInfo) scheduleManager.executeTask(ticket);
         if (taskInfo.getTypeEnum().equals(DeviceTypeEnum.Camera)) {
             roomMemberDao.updateCameraByRidAndUid(roomId, userId, taskInfo.isOnOff());
-        }else if (taskInfo.getTypeEnum().equals(DeviceTypeEnum.ExamSong)) {
+        } else if (taskInfo.getTypeEnum().equals(DeviceTypeEnum.ExamSong)) {
             long scheduleId = Long.parseLong(roomId.substring(1));
             ExamSongDownloadData msg;
             String examJson = courseScheduleStudentPaymentDao.getExamJsonByCourseIdAndUserId(scheduleId, authUser.getId());
-            if(StringUtils.isEmpty(examJson)){
+            if (StringUtils.isEmpty(examJson)) {
                 throw new BizException("学员伴奏信息异常");
-            }else {
+            } else {
                 msg = JSON.parseObject(examJson, ExamSongDownloadData.class);
                 msg.setEnable(true);
             }
-            courseScheduleStudentPaymentDao.adjustExamSong(scheduleId,authUser.getId(),JSON.toJSONString(msg));
-        }else {
+            courseScheduleStudentPaymentDao.adjustExamSong(scheduleId, authUser.getId(), JSON.toJSONString(msg));
+        } else {
             roomMemberDao.updateMicByRidAndUid(roomId, userId, taskInfo.isOnOff());
         }
         ControlDeviceNotifyMessage msg = new ControlDeviceNotifyMessage(ActionEnum.Approve.ordinal());
@@ -1078,13 +1081,13 @@ public class RoomServiceImpl implements RoomService {
         } else if (data.getMusicModeOn() != null) {
             type = DeviceTypeEnum.MusicMode;
             enable = data.getMusicModeOn();
-        }  else if (data.getHandUpOn() != null) {
+        } else if (data.getHandUpOn() != null) {
             type = DeviceTypeEnum.HandUp;
             enable = data.getHandUpOn();
-        }  else if (data.getExamSongOn() != null) {
+        } else if (data.getExamSongOn() != null) {
             type = DeviceTypeEnum.ExamSong;
             enable = data.getExamSongOn();
-        }else {
+        } else {
             throw new ApiException(ErrorEnum.ERR_REQUEST_PARA_ERR);
         }
         SysUser authUser = sysUserFeignService.queryUserInfo();
@@ -1093,22 +1096,22 @@ public class RoomServiceImpl implements RoomService {
         DeviceStateChangedMessage deviceResourceMessage = new DeviceStateChangedMessage(type.ordinal(), enable);
         if (type.equals(DeviceTypeEnum.Camera)) {
             roomMemberDao.updateCameraByRidAndUid(roomId, userId, enable);
-        } else if (type.equals(DeviceTypeEnum.Microphone)){
+        } else if (type.equals(DeviceTypeEnum.Microphone)) {
             roomMemberDao.updateMicByRidAndUid(roomId, userId, enable);
-        } else if (type.equals(DeviceTypeEnum.HandUp)){
+        } else if (type.equals(DeviceTypeEnum.HandUp)) {
             roomMemberDao.updateHandByRidAndUid(roomId, userId, enable);
-        } else if (type.equals(DeviceTypeEnum.ExamSong)){
+        } else if (type.equals(DeviceTypeEnum.ExamSong)) {
             long scheduleId = Long.parseLong(roomId.substring(1));
             ExamSongDownloadData msg;
             String examJson = courseScheduleStudentPaymentDao.getExamJsonByCourseIdAndUserId(scheduleId, authUser.getId());
-            if(StringUtils.isEmpty(examJson)){
+            if (StringUtils.isEmpty(examJson)) {
                 throw new BizException("学员伴奏信息异常");
-            }else {
+            } else {
                 msg = JSON.parseObject(examJson, ExamSongDownloadData.class);
                 msg.setEnable(enable);
             }
-            courseScheduleStudentPaymentDao.adjustExamSong(scheduleId,authUser.getId(),JSON.toJSONString(msg));
-        }else {
+            courseScheduleStudentPaymentDao.adjustExamSong(scheduleId, authUser.getId(), JSON.toJSONString(msg));
+        } else {
             roomMemberDao.updateMusicByRidAndUid(roomId, userId, enable);
         }
         Room room = roomDao.findByRid(roomId);
@@ -1124,13 +1127,13 @@ public class RoomServiceImpl implements RoomService {
     public List<RoomResult.MemberResult> getMembers(String roomId) throws Exception {
         CheckUtils.checkArgument(roomId != null, "roomId must't be null");
         List<RoomMember> roomMemberList = roomMemberDao.findByRid(roomId);
-        if(roomMemberList != null && roomMemberList.size() > 0){
+        if (roomMemberList != null && roomMemberList.size() > 0) {
             List<CourseScheduleStudentMusicScore> scheduleStudentMusicScores = courseScheduleStudentMusicScoreDao.queryByScoreIdAndCourseId(null, Long.parseLong(roomId.substring(1)), null, null, null);
             RoomResult roomResult = new RoomResult();
             Set<String> userIds = roomMemberList.stream().map(e -> e.getUid()).collect(Collectors.toSet());
-            Map<Integer,String> midiMap = MapUtil.convertMybatisMap(courseScheduleStudentPaymentDao.queryMidiByUserIdsAndCourseId(userIds,roomId.substring(1)));
-            Map<Integer,String> examSongMap = MapUtil.convertMybatisMap(courseScheduleStudentPaymentDao.queryExamSongByUserIdsAndCourseId(userIds,roomId.substring(1)));
-            roomResult.setMembers(roomMemberList,midiMap,examSongMap,scheduleStudentMusicScores);
+            Map<Integer, String> midiMap = MapUtil.convertMybatisMap(courseScheduleStudentPaymentDao.queryMidiByUserIdsAndCourseId(userIds, roomId.substring(1)));
+            Map<Integer, String> examSongMap = MapUtil.convertMybatisMap(courseScheduleStudentPaymentDao.queryExamSongByUserIdsAndCourseId(userIds, roomId.substring(1)));
+            roomResult.setMembers(roomMemberList, midiMap, examSongMap, scheduleStudentMusicScores);
             return roomResult.getMembers();
         }
         return null;
@@ -1506,7 +1509,7 @@ public class RoomServiceImpl implements RoomService {
                         roomMemberDao.deleteUserByRidAndUid(member.getRid(), member.getUid());
                         roomDao.deleteByRid(member.getRid());
                         deleteWhiteboardByUser(member.getRid(), member.getUid());
-                        log.info("dismiss the room: {},userId: {}", member.getRid(),userId);
+                        log.info("dismiss the room: {},userId: {}", member.getRid(), userId);
                     } else {
                         log.error("{} exit {} room error: {}", member.getUid(), member.getRid(), apiResultInfo.getErrorMessage());
                     }
@@ -1535,17 +1538,17 @@ public class RoomServiceImpl implements RoomService {
     @Transactional(rollbackFor = Exception.class)
     public void sendImPlayMidiMessage(PlayMidiMessageData playMidiMessageData) throws Exception {
         SysUser sysUser = sysUserFeignService.queryUserInfo();
-        if(sysUser == null){
+        if (sysUser == null) {
             throw new BizException("用户信息获取失败");
         }
         String content = playMidiMessageData.getContent();
         String roomId = playMidiMessageData.getRoomId();
-        CustomMessage customMessage = JSONObject.parseObject(content,CustomMessage.class);
+        CustomMessage customMessage = JSONObject.parseObject(content, CustomMessage.class);
         String userId = sysUser.getId().toString();
         MetronomeMessageMessage displayMessage = new MetronomeMessageMessage(customMessage);
         imHelper.publishMessage(userId, roomId, displayMessage, 1);
         //记录节拍器消息
-        courseScheduleStudentPaymentDao.adjustPlayMidi(Long.parseLong(roomId.substring(1)),playMidiMessageData.getUserId(),content);
+        courseScheduleStudentPaymentDao.adjustPlayMidi(Long.parseLong(roomId.substring(1)), playMidiMessageData.getUserId(), content);
     }
 
     @Override
@@ -1556,13 +1559,13 @@ public class RoomServiceImpl implements RoomService {
         Long courseScheduleId = Long.parseLong(roomId.substring(1));
         List<CourseScheduleStudentMusicScore> scheduleStudentMusicScores =
                 courseScheduleStudentMusicScoreDao.queryByScoreIdAndCourseId(musicScoreData.getMusicScoreAccompanimentId(),
-                        courseScheduleId,null,null,0);
+                        courseScheduleId, null, null, 0);
         SysMusicScoreAccompaniment accompaniment = sysMusicScoreAccompanimentDao.get(musicScoreData.getMusicScoreAccompanimentId());
-        if(scheduleStudentMusicScores.size() == 0){
+        if (scheduleStudentMusicScores.size() == 0) {
             //第一次下载,生成数据
             List<CourseScheduleStudentPayment> courseScheduleStudentPayments = courseScheduleStudentPaymentDao.findByCourseSchedule(courseScheduleId);
             Set<Integer> studentIds = courseScheduleStudentPayments.stream().map(e -> e.getUserId()).collect(Collectors.toSet());
-            studentIds.forEach(e->{
+            studentIds.forEach(e -> {
                 CourseScheduleStudentMusicScore musicScore = new CourseScheduleStudentMusicScore();
                 musicScore.setMusicScoreAccompanimentId(accompaniment.getId());
                 musicScore.setSpeed(accompaniment.getSpeed());
@@ -1590,7 +1593,7 @@ public class RoomServiceImpl implements RoomService {
         SysUser authUser = sysUserFeignService.queryUserInfo();
 
         SysExamSong sysExamSong = sysExamSongDao.get(examSongId);
-        if(sysExamSong == null){
+        if (sysExamSong == null) {
             throw new BizException("曲目信息不存在");
         }
         //学员曲目下载状态改为未下载
@@ -1599,7 +1602,7 @@ public class RoomServiceImpl implements RoomService {
         json.setUrl(sysExamSong.getUrl());
         json.setStatus(0);
         json.setExamSongId(examSongId);
-        courseScheduleStudentPaymentDao.adjustExamSong(Long.parseLong(roomId.substring(1)),null, JSON.toJSONString(json));
+        courseScheduleStudentPaymentDao.adjustExamSong(Long.parseLong(roomId.substring(1)), null, JSON.toJSONString(json));
 
         ExamSongMessage examSongMessage = new ExamSongMessage();
         examSongMessage.setExamSongName(sysExamSong.getName());
@@ -1611,7 +1614,7 @@ public class RoomServiceImpl implements RoomService {
 
     @Override
     public List<RongyunBasicUserDto> queryNoJoinStu(String roomId) {
-        return courseScheduleStudentPaymentDao.queryNoJoinStu(roomId,roomId.substring(1));
+        return courseScheduleStudentPaymentDao.queryNoJoinStu(roomId, roomId.substring(1));
     }
 
     @Override
@@ -1622,14 +1625,14 @@ public class RoomServiceImpl implements RoomService {
         String roomId = musicScoreData.getRoomId();
         Long scheduleId = Long.parseLong(roomId.substring(1));
         Integer accompanimentId = musicScoreData.getMusicScoreAccompanimentId();
-        List<CourseScheduleStudentMusicScore> studentMusicScores = courseScheduleStudentMusicScoreDao.queryByScoreIdAndCourseId(accompanimentId,scheduleId,studentId,null,null);
-        if(accompanimentId != null){
+        List<CourseScheduleStudentMusicScore> studentMusicScores = courseScheduleStudentMusicScoreDao.queryByScoreIdAndCourseId(accompanimentId, scheduleId, studentId, null, null);
+        if (accompanimentId != null) {
             SysMusicScoreAccompaniment accompaniment = sysMusicScoreAccompanimentDao.get(accompanimentId);
-            if(accompaniment == null){
+            if (accompaniment == null) {
                 throw new BizException("曲目信息不存在");
             }
             //修改下载状态
-            if(studentMusicScores == null || studentMusicScores.size() == 0){
+            if (studentMusicScores == null || studentMusicScores.size() == 0) {
                 throw new BizException("学员不存在此下载曲目");
             }
             CourseScheduleStudentMusicScore studentMusicScore = studentMusicScores.get(0);
@@ -1638,41 +1641,41 @@ public class RoomServiceImpl implements RoomService {
         }
         //给老师发送学员曲目下载状态
         CourseSchedule courseSchedule = courseScheduleDao.get(scheduleId);
-        MusicScoreDownloadStatusMessage statusMessage = new MusicScoreDownloadStatusMessage(studentId,studentMusicScores);
-        imHelper.publishMessage(studentId.toString(),courseSchedule.getActualTeacherId().toString(), roomId,statusMessage);
+        MusicScoreDownloadStatusMessage statusMessage = new MusicScoreDownloadStatusMessage(studentId, studentMusicScores);
+        imHelper.publishMessage(studentId.toString(), courseSchedule.getActualTeacherId().toString(), roomId, statusMessage);
     }
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public void adjustExamSong(String roomId, Integer status,Integer examSongId) throws Exception {
-        if(roomId == null || status == null || examSongId == null){
+    public void adjustExamSong(String roomId, Integer status, Integer examSongId) throws Exception {
+        if (roomId == null || status == null || examSongId == null) {
             throw new BizException("参数校验失败");
         }
         SysUser authUser = sysUserFeignService.queryUserInfo();
         long scheduleId = Long.parseLong(roomId.substring(1));
 
         SysExamSong sysExamSong = sysExamSongDao.get(examSongId);
-        if(sysExamSong == null){
+        if (sysExamSong == null) {
             throw new BizException("曲目信息不存在");
         }
         ExamSongDownloadData msg;
         String examJson = courseScheduleStudentPaymentDao.getExamJsonByCourseIdAndUserId(scheduleId, authUser.getId());
-        if(StringUtils.isEmpty(examJson)){
+        if (StringUtils.isEmpty(examJson)) {
             msg = new ExamSongDownloadData();
             msg.setExamSongName(sysExamSong.getName());
             msg.setUrl(sysExamSong.getUrl());
             msg.setStatus(status);
             msg.setExamSongId(examSongId);
-        }else {
+        } else {
             msg = JSON.parseObject(examJson, ExamSongDownloadData.class);
             msg.setStatus(status);
         }
-        courseScheduleStudentPaymentDao.adjustExamSong(scheduleId,authUser.getId(),JSON.toJSONString(msg));
+        courseScheduleStudentPaymentDao.adjustExamSong(scheduleId, authUser.getId(), JSON.toJSONString(msg));
 
         //给老师发送学员曲目下载状态
         CourseSchedule courseSchedule = courseScheduleDao.get(scheduleId);
-        ExamSongDownloadStatusMessage deviceResourceMessage = new ExamSongDownloadStatusMessage(status,authUser.getId(),examSongId);
-        imHelper.publishMessage(authUser.getId().toString(),courseSchedule.getActualTeacherId().toString(), roomId, deviceResourceMessage);
+        ExamSongDownloadStatusMessage deviceResourceMessage = new ExamSongDownloadStatusMessage(status, authUser.getId(), examSongId);
+        imHelper.publishMessage(authUser.getId().toString(), courseSchedule.getActualTeacherId().toString(), roomId, deviceResourceMessage);
     }
 
     public void updateDisplay(String roomId, String senderId, String display, Integer isIncludeSender) throws Exception {

+ 14 - 0
mec-im/src/main/java/com/ym/service/LiveRoomService.java

@@ -0,0 +1,14 @@
+package com.ym.service;
+
+import com.ym.pojo.IMApiResultInfo;
+
+/**
+ * @author hgw
+ * Created by 2022-02-21
+ */
+public interface LiveRoomService {
+
+    IMApiResultInfo createLiveRoom(String roomId, String roomName) throws Exception;
+
+    IMApiResultInfo destroyLiveRoom(String roomId) throws Exception;
+}

+ 98 - 0
mec-web/src/main/java/com/ym/mec/web/controller/ImLiveBroadcastRoomController.java

@@ -0,0 +1,98 @@
+package com.ym.mec.web.controller;
+
+
+import com.ym.mec.biz.dal.dto.ImLiveBroadcastRoomDto;
+import com.ym.mec.biz.dal.vo.ImLiveBroadcastRoomVo;
+import com.ym.mec.biz.service.ImLiveBroadcastRoomService;
+import com.ym.mec.common.controller.BaseController;
+import com.ym.mec.common.entity.HttpResponseResult;
+import com.ym.mec.common.page.PageInfo;
+import com.ym.mec.common.page.WrapperUtil;
+import io.swagger.annotations.*;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.Map;
+
+/**
+ * 直播房间管理表(ImLiveBroadcastRoom)表控制层
+ *
+ * @author hgw
+ * @since 2022-02-17 20:52:04
+ */
+@Api(tags = "直播房间管理表")
+@RestController
+@RequestMapping("/imLiveBroadcastRoom")
+public class ImLiveBroadcastRoomController extends BaseController {
+    /**
+     * 服务对象
+     */
+    @Resource
+    private ImLiveBroadcastRoomService imLiveBroadcastRoomService;
+
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "search", dataType = "String", value = "模糊查询关键字"),
+            @ApiImplicitParam(name = "liveState", dataType = "Integer", value = "直播状态 0未开始 1开始 2结束"),
+            @ApiImplicitParam(name = "startTime", dataType = "String", value = "开始时间"),
+            @ApiImplicitParam(name = "endTime", dataType = "String", value = "结束时间"),
+            @ApiImplicitParam(name = "page", dataType = "Integer", value = "页数"),
+            @ApiImplicitParam(name = "rows", dataType = "Integer", value = "每页数量"),
+    })
+    @ApiOperation("分页查询直播间列表")
+    @PostMapping("/queryPage")
+    public HttpResponseResult<PageInfo<ImLiveBroadcastRoomVo>> queryPage(@RequestBody Map<String, Object> param) {
+        return succeed(imLiveBroadcastRoomService.queryPage(param));
+    }
+
+    @ApiOperation("查询房间信息")
+    @GetMapping("/queryRoom")
+    public HttpResponseResult<ImLiveBroadcastRoomVo> queryRoom(@ApiParam(value = "房间uid", required = true) String roomUid,
+                                                               @ApiParam(value = "用户id", required = true) Integer userId) {
+        return succeed(imLiveBroadcastRoomService.queryRoom(roomUid, userId));
+    }
+
+    @ApiOperation("创建直播间")
+    @PostMapping("/add")
+//    @PreAuthorize("@pcs.hasPermissions('imLiveBroadcastRoom/add')")
+    public HttpResponseResult add(@Valid @RequestBody ImLiveBroadcastRoomDto dto) {
+        imLiveBroadcastRoomService.add(dto);
+        return succeed();
+    }
+
+    @ApiOperation("修改直播间信息-已开播无法修改")
+    @PostMapping("/update")
+//    @PreAuthorize("@pcs.hasPermissions('imLiveBroadcastRoom/update')")
+    public HttpResponseResult update(@Valid @RequestBody ImLiveBroadcastRoomDto dto) {
+        imLiveBroadcastRoomService.update(dto);
+        return succeed();
+    }
+
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", dataType = "Integer", value = "房间id"),
+    })
+    @ApiOperation("删除直播间信息-已开播无法删除")
+    @PostMapping("/delete")
+//    @PreAuthorize("@pcs.hasPermissions('imLiveBroadcastRoom/delete')")
+    public HttpResponseResult delete(@RequestBody Map<String, Object> param) {
+        Integer id = WrapperUtil.toInt(param, "id", "请传入房间id");
+        imLiveBroadcastRoomService.delete(id);
+        return succeed();
+    }
+
+    @ApiOperation("同步点赞数量")
+    @GetMapping("/syncLike")
+    public HttpResponseResult syncLike(@ApiParam(value = "房间uid", required = true) String roomUid,
+                                       @ApiParam(value = "点赞数", required = true) Integer likeNum) {
+        imLiveBroadcastRoomService.syncLike(roomUid, likeNum);
+        return succeed();
+    }
+
+    @GetMapping("/shareRoom")
+    public HttpResponseResult test() {
+        imLiveBroadcastRoomService.test();
+        return succeed();
+    }
+
+}
+

+ 29 - 0
mec-web/src/main/java/com/ym/mec/web/controller/ImLiveBroadcastRoomDataController.java

@@ -0,0 +1,29 @@
+package com.ym.mec.web.controller;
+
+
+import com.ym.mec.biz.dal.entity.ImLiveBroadcastRoomData;
+import com.ym.mec.biz.service.ImLiveBroadcastRoomDataService;
+import org.springframework.web.bind.annotation.*;
+import com.ym.mec.common.controller.BaseController;
+import io.swagger.annotations.Api;
+
+import javax.annotation.Resource;
+
+/**
+ * 直播房间数据表(ImLiveBroadcastRoomData)表控制层
+ *
+ * @author hgw
+ * @since 2022-02-21 14:26:58
+ */
+@Api(tags = "直播房间数据表")
+@RestController
+@RequestMapping("/imLiveBroadcastRoomData")
+public class ImLiveBroadcastRoomDataController extends BaseController {
+    /**
+     * 服务对象
+     */
+    @Resource
+    private ImLiveBroadcastRoomDataService imLiveBroadcastRoomDataService;
+
+}
+

+ 29 - 0
mec-web/src/main/java/com/ym/mec/web/controller/ImLiveBroadcastRoomMemberController.java

@@ -0,0 +1,29 @@
+package com.ym.mec.web.controller;
+
+
+import com.ym.mec.biz.dal.entity.ImLiveBroadcastRoomMember;
+import com.ym.mec.biz.service.ImLiveBroadcastRoomMemberService;
+import org.springframework.web.bind.annotation.*;
+import com.ym.mec.common.controller.BaseController;
+import io.swagger.annotations.Api;
+
+import javax.annotation.Resource;
+
+/**
+ * 直播间人员关系表(ImLiveBroadcastRoomMember)表控制层
+ *
+ * @author hgw
+ * @since 2022-02-21 14:26:58
+ */
+@Api(tags = "直播间人员关系表")
+@RestController
+@RequestMapping("/imLiveBroadcastRoomMember")
+public class ImLiveBroadcastRoomMemberController extends BaseController {
+    /**
+     * 服务对象
+     */
+    @Resource
+    private ImLiveBroadcastRoomMemberService imLiveBroadcastRoomMemberService;
+
+}
+