打造一个简单的视频同步网站2

打造一个简单的视频同步网站2

前面的内容将前端的部分讲完了,这里说一下后端部分。

后端

根据前面的需求,可以看出后端主要需要三个请求,/get、/update、/getupdate,所以只需要这三个controller即可,对于实体而言,需要一个视频状态的实体,以及一个封装返回信息的实体。

public class MovieSyc {
    private String roomId;
    private String roomPasswd;
    private String movieUrl;
    private Integer time = 0; //单位秒 当前播放位置
    private boolean isPlay;
public class Msg { //符合链式
    private Integer code;
    private String msg;
    private HashMap<String,Object> extend = new HashMap<>();
        public static Msg success(){
        Msg m = new Msg();
        m.setCode(100);
        m.setMsg("成功");
        return m;
    }
     public Msg add(String key,Object value){
        this.extend.put(key,value);
        return this;
    }

后端逻辑分析

之前分析过,对于我们的视频状态信息来说,也就是MovieSyc,只需要保存到webcontex即可,我们可以用roomId作为key。但是对于同步而言,我们前端会发送update请求以及get_update,这两个请求其实是应该用同步进行控制,我们的get_update应该一致处于阻塞状态,一致等到有update的时候才会释放阻塞。所以这里可以用一个阻塞队列来实现。但如果只有一个阻塞队列,会出现如下的问题:

用户1发送了update,然后用户1的get_update拿到了这个更新,那么用户2的get_update还会仍然阻塞,并不会更新,所以需要给每个用户都建立一个阻塞队列,更新的时候大家的阻塞队列都会被放入新的内容,并且在get_update里面会取出,如果取不到则阻塞。所以这里需要一个:

HashMap<String,ArrayBlockingQueue<MovieSyc> > blockingQueueHashMap = new HashMap<>();

这样的结构,其实key是roomId+username,因为这两个唯一标识一个用户。

get分析

在get里面,主要是进行一个判断和一些初始化,判断主要在如果房间存在,则需要判断密码是否正确。而初始化主要指的是创建一个新的MovieSyc和对新加入用户分配阻塞队列。

@RequestMapping("/get")
@ResponseBody
public Msg get(@RequestParam("roomId") String roomId, @RequestParam("roomPasswd") String roomPasswd,@RequestParam("userName") String userName, HttpServletRequest req){
    if(blockingQueueHashMap.get(roomId+"_"+userName)==null){
        blockingQueueHashMap.put(roomId+"_"+userName,new ArrayBlockingQueue<MovieSyc>(1));
    }
    ServletContext context  = req.getSession().getServletContext();
    MovieSyc movieSyc = (MovieSyc) context.getAttribute(roomId);
    if(movieSyc==null){
        movieSyc = new MovieSyc();
        movieSyc.setRoomId(roomId);
        movieSyc.setRoomPasswd(roomPasswd);
        context.setAttribute(roomId,movieSyc);
        return Msg.success().add("movieSyc",movieSyc);
    }else{
        if(movieSyc.getRoomPasswd().equals(roomPasswd)){
            return Msg.success().add("movieSyc",movieSyc);
        }else{
            return Msg.fail("密码错误");
        }
    }
}

update分析

这个函数里面主要是把前台的数据更新到我们的状态里面,并且放到阻塞队列里面,可以唤醒get_update.

@RequestMapping("update")
@ResponseBody
public Msg update(String roomId,String movieUrl,Integer time,Boolean play,HttpServletRequest req) throws InterruptedException {
    if(roomId==null){
        return Msg.fail("更新请提供房间号");
    }
    ServletContext context  = req.getSession().getServletContext();
    MovieSyc movieSyc = (MovieSyc) context.getAttribute(roomId);
    if(movieSyc==null){
        return Msg.fail("房间不存在");
    }
    if(movieUrl!=null && !movieUrl.equals("")){
        movieSyc.setMovieUrl(movieUrl);
    }
    if(time!=null){
        movieSyc.setTime(time);
    }
    if(movieSyc.getMovieUrl()!=null && play!=null){
        movieSyc.setPlay(play);
    }
    for (Iterator<Map.Entry<String, ArrayBlockingQueue<MovieSyc>>> it = blockingQueueHashMap.entrySet().iterator(); it.hasNext();){
        Map.Entry<String, ArrayBlockingQueue<MovieSyc>> entry = it.next();
        if(entry.getKey().split("_")[0].equals(roomId)){ //一个房间的
            if(entry.getValue().offer(movieSyc,200, TimeUnit.MILLISECONDS)){
                System.out.println(entry.getKey()+"放入");
            }else{
                System.out.println("移除用户"+entry.getKey());
                blockingQueueHashMap.remove(entry.getKey());
            }
        }
    }

    return Msg.success();
}

这里注意的是,更新阻塞队列的时候,是更新所有同房间的,而不是全部都进行了更新,所以加入了是否同房间的判断。另外可能有些用户已经离开了房间,也就是不在发送对应的get_update请求了,里面的数据不会被取出了。而我们阻塞队列的大小是1,所以放入数据会失败,所以如果放入数据失败的时候,也就是这个用户推出了,所以可以讲其对应的阻塞队列删除即可。

get_update分析

@RequestMapping("/getupdate")
@ResponseBody
public Msg getUpdate(String roomId,String userName,HttpServletRequest req) throws InterruptedException {
    MovieSyc movieSyc = blockingQueueHashMap.get(roomId+"_"+userName).take();
    System.out.println(roomId+"_"+userName+"取出");
    return Msg.success().add("movieSyc",movieSyc);
}

可以看出其主要操作就是一个take,而对于阻塞队列而言,如果没有数据,则会阻塞在这里,知道update放入数据,所以update和get_update实现了一个同步的过程,一个放入一个取出。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值