openmeetings二次开发日志(四) 4.0.2及openmeetings工具类

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zoroduyu/article/details/79431749

过年事情太多,一个多月没写博客了。今天来补一篇openmeetings的。话说在我上次写完openmeetings4.0.0的安装后,Apache又陆续更新了4.0.1和4.0.2版本,两个版本都进行一些优化和改动。我两个版本都简单体验了以下,总体感觉4.0.1版本不是很好,在进行过登录或注册时出现过非常明显的延迟现象。18年2月23日发布了4.0.2版,这一般感觉优化还不错,运行比之前流畅的多。贴一张官网的更新说明:

这里写图片描述

优化和改进的功能中有很大一部分是聊天,房间中感觉最好的就是修复了重复用户这一bug,用户体验性得到了极大的改善。

新版本linux版安装和部署同4.0.0版本一样,没有区别,不知道怎么安装和部署的同学可以参考以下我的这篇博客linux下安装Openmeetings4.0.0

好了,新版本的简介暂时聊到这里,接下来我会用一个现实遇到的需求做例子,讲一讲实际开发中怎么利用openmeetings去实现我们的业务,展示一些我自己封装的openmeetings的工具类给各位做实现业务的一些参考。先来看看目录结构:

这里写图片描述

图中,om文件夹下存放与openmeetings的相关的所有类,fileWebService,roomWebService,userWebService这三个文件夹是存放openmeetings的webservice生成的文件,剩下两个类OpenmeetingsConstants是个接口,主要用于存放常量,OpenmeetingsServiceUtil是我封装的工具类,来看看这个类的代码:

package com.avie.ltd.om;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import com.avie.ltd.om.fileWebService.FileExplorerObject;
import com.avie.ltd.om.fileWebService.FileItemDTO;
import com.avie.ltd.om.fileWebService.FileWebService;
import com.avie.ltd.om.fileWebService.OrgApacheOpenmeetingsWebserviceFileWebService;
import com.avie.ltd.om.roomWebService.OrgApacheOpenmeetingsWebserviceRoomWebService;
import com.avie.ltd.om.roomWebService.RoomDTO;
import com.avie.ltd.om.roomWebService.RoomWebService;
import com.avie.ltd.om.roomWebService.Type;
import com.avie.ltd.om.userWebService.ExternalUserDTO;
import com.avie.ltd.om.userWebService.OrgApacheOpenmeetingsWebserviceUserWebService;
import com.avie.ltd.om.userWebService.RoomOptionsDTO;
import com.avie.ltd.om.userWebService.ServiceResult;
import com.avie.ltd.om.userWebService.UserWebService;

/**
 * openmeetings的专用工具类
 * 
 * @author duyu
 *
 */
public class OpenmeetingsServiceUtil {

    /**
     * 线程安全的map对象。存放sid
     */
    private static ConcurrentHashMap<String, String> sidMap = new ConcurrentHashMap<>();

    private static OrgApacheOpenmeetingsWebserviceRoomWebService orgRoom = new OrgApacheOpenmeetingsWebserviceRoomWebService();
    private static OrgApacheOpenmeetingsWebserviceUserWebService orgUser = new OrgApacheOpenmeetingsWebserviceUserWebService();
    private static OrgApacheOpenmeetingsWebserviceFileWebService orgFile = new OrgApacheOpenmeetingsWebserviceFileWebService();
    private static RoomWebService roomService;
    private static UserWebService userWebService;
    private static FileWebService fileWebService;

    /**
     * 得到RoomWebService 基于双检锁的单例模式
     * 
     * @return
     */
    private static RoomWebService getRoomWebService() {
        if (roomService == null) {
            synchronized (RoomWebService.class) {
                if (roomService == null) {
                    try {
                        roomService = orgRoom.getRoomWebServicePort();
                    } catch (Exception e) {
                        // TODO: handle exception
                    }
                }
            }
        }
        return roomService;
    }

    /**
     * 得到fileWebService
     * 
     * @return
     */
    private static FileWebService getFileWebService() {
        if (fileWebService == null) {
            synchronized (RoomWebService.class) {
                if (fileWebService == null) {
                    try {
                        fileWebService = orgFile.getFileWebServicePort();
                    } catch (Exception e) {
                        // TODO: handle exception
                    }
                }
            }
        }
        return fileWebService;
    }

    /**
     * 得到RoomWebService 基于双检锁的单例模式
     * 
     * @return
     */
    private static UserWebService getUserWebService() {
        if (userWebService == null) {
            synchronized (UserWebService.class) {
                if (userWebService == null) {
                    try {
                        userWebService = orgUser.getUserService();
                    } catch (Exception e) {
                        // TODO: handle exception
                    }
                }
            }
        }
        return userWebService;
    }

    /**
     * 得到某个登录用户的sid
     */
    public static String getSid() {

        if (!sidMap.isEmpty()) {
            String time = sidMap.get("time");
            // 假如没超过10分钟
            if (Long.valueOf(time) + 1000 * 60 * 10 <= System.currentTimeMillis()) {
                return sidMap.get("sid");
            }
        }
        userWebService = getUserWebService();
        if (userWebService == null) {
            return null;
        }
        try {
            ServiceResult rs = userWebService.login(OpenmeetingsConstants.USERNAME, OpenmeetingsConstants.PASSWORD);
            String sid = rs.getMessage();
            sidMap.put("sid", sid);
            sidMap.put("time", String.valueOf(System.currentTimeMillis()));
            return sid;
        } catch (Exception e) {
            // TODO: handle exception
            return null;
        }
    }

    public static Long addRoom(String roomType, Long capacity, boolean allowRecording, boolean allowUserQuestions) {
        RoomDTO room = new RoomDTO();
        room.setType(Type.fromValue(roomType));
        room.setCapacity(capacity);
        room.setAllowRecording(allowRecording);
        room.setAllowUserQuestions(allowUserQuestions);
        RoomWebService roomService = getRoomWebService();
        // 如果roomService没拿到,说明openmeetings的服务没起,进不去,返回-1表示异常
        if (roomService == null) {
            return -1L;
        }
        String sid = getSid();
        if(sid == null ) {
            return -1L;
        }
        room = roomService.add(sid, room);
        return room.getId();
    }

    public static String getIntoRoom(Long roomId,boolean showAudioVideoTest,boolean moderator,boolean allowSameURLMultipleTimes,boolean allowRecording,ExternalUserDTO user) {
        RoomOptionsDTO options = new RoomOptionsDTO();
        options.setRoomId(roomId);
        options.setShowAudioVideoTest(showAudioVideoTest);
        options.setModerator(moderator);
        options.setAllowSameURLMultipleTimes(allowSameURLMultipleTimes);
        options.setAllowRecording(allowRecording);
        UserWebService userWebService = getUserWebService();
        if(userWebService == null) {
            return null;
        }
        String sid = getSid();
        if(sid == null ) {
            return null;
        }
        ServiceResult serviceRs = userWebService.getRoomHash(sid, user, options);
        return serviceRs.getMessage();
    }

//  public static void getRoomFile() {
//      FileWebService fileWebService = getFileWebService();
//      FileExplorerObject ex = fileWebService.getRoom(getSid(), 6);
//      List<FileItemDTO> files = ex.getRoomHome();
//      for(FileItemDTO dto : files) {
////            dto.getha
//      }
//  }
}

我简单的讲一下这段代码,说一下我的实现思路,从最上面的变量开始讲:

这里写图片描述

最开始的sidMap是一个ConcurrentHashMap的实例。ConcurrentHashMap是一个线程安全的map实现类,在这里使用也是出于线程安全的考虑,因为sidMap中我主要存放了登录所需的sid(之前的博客中讲过sid主要是和我们平时登录的token类似的东西。),待会儿我会详细讲这个。往下走,orgRoom,orgUser,orgFile这三个东西主要是用于得到下面的roomService,userWebService,fileWebService这三个业务相关类的实例,用于实现openmeetings的相关业务。
往下走,是实例化三个业务类的方法;

/**
     * 得到RoomWebService 基于双检锁的单例模式
     * 
     * @return
     */
    private static RoomWebService getRoomWebService() {
        if (roomService == null) {
            synchronized (RoomWebService.class) {
                if (roomService == null) {
                    try {
                        roomService = orgRoom.getRoomWebServicePort();
                    } catch (Exception e) {
                        // TODO: handle exception
                    }
                }
            }
        }
        return roomService;
    }

    /**
     * 得到fileWebService
     * 
     * @return
     */
    private static FileWebService getFileWebService() {
        if (fileWebService == null) {
            synchronized (RoomWebService.class) {
                if (fileWebService == null) {
                    try {
                        fileWebService = orgFile.getFileWebServicePort();
                    } catch (Exception e) {
                        // TODO: handle exception
                    }
                }
            }
        }
        return fileWebService;
    }

    /**
     * 得到UserWebService 基于双检锁的单例模式
     * 
     * @return
     */
    private static UserWebService getUserWebService() {
        if (userWebService == null) {
            synchronized (UserWebService.class) {
                if (userWebService == null) {
                    try {
                        userWebService = orgUser.getUserService();
                    } catch (Exception e) {
                        // TODO: handle exception
                    }
                }
            }
        }
        return userWebService;
    }

这里使用双检锁来保证这几个业务实体类为单例,用双检锁实现的单例模式好处在于延迟加载且有较好的性能。这里不采用饿汉式的单例实现方法还有一种考虑,就是这几个service的实例并不一定拿得到且有可能抛出错误。因为你在执行roomService = orgRoom.getRoomWebServicePort();这一句代码时,是会发起一次对openmeetings的请求的,假如这时候openmeetings的服务没有起起来,会导致这里出现异常。如果用饿汉式的单例实现方法,直接RoomWebService roomService = orgRoom.getRoomWebServicePort();就有可能导致该类初始化失败,进而导致整个服务器启动失败。而对于我们的业务而言,openmeetings的服务起不起不应该影响到我们这边的业务服务,所以我采用这种方式来初始化几个service类的实例。

这里写图片描述

接下来是一个静态方法,主要用于得到sid并存入上面提到过的ConcurrentHashMap中。这里,sid其实是你调用userWebService的登录方法后这句代码后得到的值,这个值是你调用其他WebService接口的必传的一个值,可以看做登录的token。这里要拿到这个值你必须要传入一个具有soap权限的内部用户名和密码。怎么知道该用户有没有soap权限楠?用最开始你创建openmeetings的时设置的超级管理员登上去,选择用户管理即可查看是否有soap权限,如下图:

这里写图片描述

这里用一个map来存sid,而不用一个String类型的变量来指向sid,是因为sid是有时间限制的,openmeetings里面好像是默认(之前在哪里看到过,记不清楚了)一个sid只有15分钟的生存时间,过了15分钟之后就会自动失效,这时你需要重新登录重新拿一次sid。所以我这里就考虑把sid存在map中,并记录下它的存入时间,当下次需要用到时,拿到他上次的存入时间进行比对,如果没超过10分钟,则返回当前值,如果超过,则重新请求一次登录方法,拿到一个新的sid存入并返回。

代码继续往下走:

这里写图片描述

一个封装的创建房间的方法,需要传入roomType(房间类型),capacity(房间最大人数),allowRecording(是否允许记录),创建一个RoomDTO的对象,设置它的参数,然后得到roomService的实例,判断一下非空,拿到sid,调用roomService的add方法进行添加,然后拿到添加后room对象的id值进行返回,这个方法用于创建一个自定义的房间。

再往下走:

这里写图片描述

这个方法是进入房间的方法,跟上面那个方法大同小异,该方法传入进入房间需要的一些参数,诸如房间id,是否为主持人等参数,然后得到userWebService,调用getRoomHash这个方法得到进入的房间的密钥返回。

到这里,一个基本的openmeetings的工具类就实现了,我们来看它实际的调用情况。
先说一说我的具体需求:老师和学生在我们现有的系统中注册账号,然后在我们的系统中点击进入课堂,跳转到openmeetings的房间中进行视频通话并用白板进行授课。
下面是业务代码的一部分:

这里写图片描述

getStudentUrl这个方法主要用于拿到跳转openmeetings房间的url,从外面传入三个参数,user为学生的实体对象,classSystem可以看做房间的最大限制人数,teacher是老师的实体对象。进入方法先判断该老师有roomId,也就是之前是否为该老师创建过房间,如果没有,调用OpenmeetingsServiceUtil我的openmeetings工具类创建一个房间,将得到的roomId存数据库中,然后调用 OpenmeetingsServiceUtil的getIntoRoom方法得到进入该房间的密钥,拼接成url返回,前台拿到这个url跳转就可以进入房间了。
业务层的调用我就暂时讲到这,大家做个参考就行了。毕竟每个公司的业务都不一样,讲多了也没意义。

这些代码总体基于我之前博客中利用webService调用openmeetings的实现,照自己的理解进行了一些封装和解耦。目前我给公司开发的这套系统还属于一个测试版,后面还会进行不断的完善并增强功能(比如修改openmeetings的页面,拿到openmeetings的文件之内的),所以后面应该会在其他博客中掺杂一些openmeetings最新进度的博客。喜欢的可以跟进一下。

猜你喜欢

转载自blog.csdn.net/zoroduyu/article/details/79431749