应用场景:在我们的项目中我们用的是创建视频会议和预警消息通知推送这两种情况,首先创建视频会议和中途邀请人参加会议我采用的是自定义推送消息,因为此应用场景传递的参数比较多,在推送过去之后android和ios可以很方便的将参数传递过去,但是我们考虑到邀请的所有人都在登录状态的时候才可以创建会议房间,我们采用的是腾讯视频会议的sdk,因为我们采用的是别名推送,当用户在登录的时候安卓端将用户uuid设置为别名,退出时取消别名,我在服务端根据传递过来的uuid利用别名查询registration_ids的数组大小是否为空判断当前用户是否设置别名,当邀请的所有人都设置了别名之后我才调用创建会议房间的接口。而预警消息推送我采用的是通知推送,当气象预警触发的时候我会采用通知推送的方式推送给app,这种方式比较简单。
极光推送是给app推送消息的,我们首先需要在服务端集成maven依赖
<!-- 极光推送 -->
<groupId>cnjpushapi
<artifactId>jpush-client
<version>323
</dependency>
接着我们需要了解极光推送有哪些推送方式,对于安卓和ios都适用的情况,我在项目中使用的是别名推送alias,(还有标签推送tag),推送方式又分为通知推送和自定义推送,通知推送能够显示在手机提示框中,而自定义推送却不能,我看安卓他们做的能跟微信视频一样的d出一个会话框,看着挺不错的,这跟微信不同的是可以邀请多个,之前用阿里云的好像只能一对一,所以才换成腾讯视频会议的,好了,废话不多说,上我写的一个工具类,
package comjpxxhomepagehomePageserviceutils;
import cnjpushapiJPushClient;
import cnjpushapipushPushResult;
import cnjpushapipushmodelOptions;
import cnjpushapipushmodelPlatform;
import cnjpushapipushmodelPushPayload;
import cnjpushapipushmodelaudienceAudience;
import cnjpushapipushmodelnotificationNotification;
import cnjpushapipushmodelMessage;
import cnjpushapipushmodelPushPayloadBuilder;
public class SendMessageUtils {
private static StringAppKey="8a7880c6fb81ad494b224078";
/
JPush MasterSecret 极光推送平台生成的密钥
/
private static StringMasterSecret="c0fc675c4c48f9bf35269cf4";
//两个参数分别填写你申请的masterSecret和appKey
private static JPushClientjPushClient=new JPushClient(MasterSecret,AppKey);
/
通知推送
备注:推送方式不为空时,推送的值也不能为空;推送方式为空时,推送值不做要求
@param type 推送方式:1、“tag”标签推送,2、“alias”别名推送
@param value 推送的标签或别名值
@param alert 推送的内容
/
public static StringpushNotice(String type,String title,String value,String alert,int roomId,String MessageType,String name,String promoterAdavter,String meetingTitle,String sig){
Builder builder= PushPayloadnewBuilder();
buildersetPlatform(Platformall());//设置接受的平台,all为所有平台,包括安卓、ios、和微软的
//设置如果用户不在线、离线消息保存的时间
Options options=Optionssendno();
optionssetTimeToLive(86400l); //设置为86400为保存一天,如果不设置默认也是保存一天
buildersetOptions(options);
buildersetMessage(MessagenewBuilder()
setMsgContent(value)
setTitle(title)
addExtra("roomId",roomId)
addExtra("MessageType",MessageType)
addExtra("name",name)
addExtra("promoterAdavter",promoterAdavter)
addExtra("meetingTitle",meetingTitle)
addExtra("userSig",sig)
build());
//设置推送方式
if(typeequals("alias")){
buildersetAudience(Audiencealias(value));//根据别名推送
}else if(typeequals("tag")){
buildersetAudience(Audiencetag(value));//根据标签推送
}else{
buildersetAudience(Audienceall());//Audience设置为all,说明采用广播方式推送,所有用户都可以接收到
}
//设置为采用通知的方式发送消息
buildersetNotification(Notificationalert(alert));
PushPayload pushPayload=builderbuild();
Systemoutprintln("ggggggg"+pushPayload);
try{
//进行推送,实际推送就在这一步
//Systemoutprintln("zzzzzzzzz "+jPushClientsendPush(pushPayload));
PushResult pushResult=jPushClientsendPush(pushPayload);
return "success";
}catch(Exception e){
Systemoutprintln("异常 "+e);
eprintStackTrace();
return "fail";
}
}
/
自定义消息推送
备注:推送方式不为空时,推送的值也不能为空;推送方式为空时,推送值不做要求
@param type 推送方式:1、“tag”标签推送,2、“alias”别名推送
@param value 推送的标签或别名值
@param alert 推送的内容
/
public static StringpushMsg(String type,String title,String value,String alert,int roomId,String MessageType,String name,String promoterAdavter,String meetingTitle,String sig){
Builder builder= PushPayloadnewBuilder();
buildersetPlatform(Platformall());//设置接受的平台
if(typeequals("alias")){
buildersetAudience(Audiencealias(value));//别名推送
}else if(typeequals("tag")){
buildersetAudience(Audiencetag(value));//标签推送
}else{
buildersetAudience(Audienceall());//Audience设置为all,说明采用广播方式推送,所有用户都可以接收到
}
MessageBuilder newBuilder=MessagenewBuilder();
newBuildersetMsgContent(alert);//消息内容
newBuildersetTitle(title);
newBuilderaddExtra("roomId",roomId);
newBuilderaddExtra("MessageType",MessageType);
newBuilderaddExtra("name",name);
newBuilderaddExtra("promoterAdavter",promoterAdavter);
newBuilderaddExtra("meetingTitle",meetingTitle);
newBuilderaddExtra("userSig",sig);
Message message=newBuilderbuild();
buildersetMessage(message);
PushPayload pushPayload=builderbuild();
try{
PushResult pushResult=jPushClientsendPush(pushPayload);
Systemoutprintln(pushResultisResultOK());
return "success";
}catch(Exception e){
eprintStackTrace();
return "fail";
}
}
public static void main(String[] args) {
//给标签为kefu的用户进行消息推送
//SendMessageUtilspushMsg("alias","标题","5b9022746e284ea0992e3baa983035dc","你有新的任务,请及时处理",111,"meetingType","name","avater","meetingTitle","");
//sendNotificationWirhAlias_Ios("zzzzzzzzzzzz","uuid");
//String result = SendMessageUtilspushNotice("alias","标题","5b9022746e284ea0992e3baa983035dc","你有新的任务,请及时处理",111,"meetingType","name","avater","meetingTitle","");
//Systemoutprintln("返回结果"+result);
/String result = SendMessageUtilspushNotice("alias","预警标题","5b9022746e284ea0992e3baa983035dc","dddd",0,"warnType","","","",""); //userDtogetUuId()
Systemoutprintln("result "+result);/
//根据uuid查询别名信息是否存在
String result = >
楼上的不排除投机取巧(褒义)呵呵、
如果user真的有存在的房号,人不在房间的问题,不与username比较是不是也显示不出来了呢。呵呵!
select roomid,'房间号不存在'
from [user]
where roomid not in (select distinct roomid from room )
union all
select roomid,'此人不在此房间中'
from [user]
where username not in (select ausername from room a,[user] b where aroomid = broomid and ausername = busername)
and roomid not in (select roomid
from [user]
where roomid not in (select distinct roomid from room ))
这个就OK了。
下面 *** 作必须执行,要筛选人和房间的匹配哦,虽然办法垃圾,只是在外层查询筛选不存在的房间,不过也是一种办法哦。呵呵!~
第二问题我不是很明白你的意思。代替值为空可以用ISNULL。
1深拷贝与浅拷贝 拷贝即是通常所说的复制(Copy)或克隆(Clone),对象的拷贝也就是从现有对象复制一个“一模一样”的新对象出来。虽然都是复制对象,但是不同的复制方法,复制出来的新对象却并非完全一模一样,对象内部存在着一些差异。通常的拷贝方法有两种,即深拷贝和浅拷贝,那二者之间有何区别呢?MSDN里对IClone接口的Clone方法有这样的说明:在深层副本中,所有的对象都是重复的;而在浅表副本中,只有顶级对象是重复的,并且顶级以下的对象包含引用。可以看出,深拷贝和浅拷贝之间的区别在于是否复制了子对象。这如何理解呢?下面我通过带有子对象的代码来验证二者的区别。 首先定义两个类型:Student和ClassRoom,其中Student类型里包含ClassRoom,并使这两个类型都分别实现自定义的深拷贝接口(IDeepCopy)和浅拷贝接口(IShallowCopy)。 类图如下: 定义代码如下: 定义代码 /// <summary> /// 深拷贝接口 /// </summary> interface IDeepCopy { object DeepCopy(); } /// <summary> /// 浅拷贝接口 /// </summary> interface IShallowCopy { object ShallowCopy(); } /// <summary> /// 教室信息 /// </summary> class ClassRoom : IDeepCopy, IShallowCopy { public int RoomID = 1; public string RoomName = "Room1"; public override string ToString() { return "RoomID=" + RoomID + "\tRoomName=" + RoomName; } public object DeepCopy() { ClassRoom r = new ClassRoom(); rRoomID = thisRoomID; rRoomName = thisRoomName; return r; } public object ShallowCopy() { //直接使用内置的浅拷贝方法返回 return thisMemberwiseClone(); } } class Student : IDeepCopy, IShallowCopy { //为了简化,使用public 字段 public string Name; public int Age; //自定义类型,假设每个Student只拥有一个ClassRoom public ClassRoom Room = new ClassRoom(); public Student() { } public Student(string name, int age) { thisName = name; thisAge = age; } public object DeepCopy() { Student s = new Student(); sName = thisName; sAge = thisAge; sRoom = (ClassRoom)thisRoomDeepCopy(); return s; } public object ShallowCopy() { return thisMemberwiseClone(); } public override string ToString() { return "Name:" + Name + "\tAge:" + Age + "\t" + RoomToString(); } } 测试代码: 测试代码 Student s1 = new Student("Vivi", 28); ConsoleWriteLine("s1=[" + s1 + "]"); Student s2 = (Student)s1ShallowCopy(); //Student s2 = (Student)s1DeepCopy(); ConsoleWriteLine("s2=[" + s2 + "]"); //此处s2和s1内容相同 ConsoleWriteLine("-----------------------------"); //修改s2的内容 s2Name = "tianyue"; s2Age = 25; s2RoomRoomID = 2; s2RoomRoomName = "Room2"; ConsoleWriteLine("s1=[" + s1 + "]"); ConsoleWriteLine("s2=[" + s2 + "]"); //再次打印两个对象以比较 ConsoleReadLine(); 运行结果: aShallowCopy s1=[Name:Vivi Age:28 RoomID=1 RoomName=Room1] s2=[Name:Vivi Age:28 RoomID=1 RoomName=Room1] ------------------------------------------------------------- s1=[Name:Vivi Age:28 RoomID=2 RoomName=Room2] s2=[Name:tianyue Age:25 RoomID=2 RoomName=Room2] bDeepCopy s1=[Name:Vivi Age:28 RoomID=1 RoomName=Room1] s2=[Name:Vivi Age:28 RoomID=1 RoomName=Room1] ----------------------------- s1=[Name:Vivi Age:28 RoomID=1 RoomName=Room1] s2=[Name:tianyue Age:25 RoomID=2 RoomName=Room2] 从以上结果可以看出,深拷贝时两个对象是完全“分离”的,改变其中一个,不会影响到另一个对象;浅拷贝时两个对象并未完全“分离”,改变顶级对象的内容,不会对另一个对象产生影响,但改变子对象的内容,则两个对象同时被改变。这种差异的产生,即是取决于拷贝子对象时复制内存还是复制指针。深拷贝为子对象重新分配了一段内存空间,并复制其中的内容;浅拷贝仅仅将指针指向原来的子对象。 示意图如下: 2浅拷贝与赋值 *** 作 大多数面向对象语言中的赋值 *** 作都是传递引用,即改变对象的指针地址,而并没有复制内存,也没有做任何复制 *** 作。由此可知,浅拷贝与赋值 *** 作的区别是顶级对象的复制与否。当然,也有一些例外情况,比如类型定义中重载赋值 *** 作符(assignment operator),或者某些类型约定按值传递,就像C#中的结构体和枚举类型。 赋值 *** 作示意图如下: 3C++拷贝构造函数 与其它面向对象语言不同,C++允许用户选择自定义对象的传递方式:值传递和引用传递。在值传递时就要使用对象拷贝,比如说按值传递参数,编译器需要拷贝一个对象以避免原对象在函数体内被破坏。为此,C++提供了拷贝构造函数用来实现这种拷贝行为,拷贝构造函数是一种特殊的构造函数,用来完成一些基于同一类的其它对象的构造和初始化。它唯一的参数是引用类型的,而且不可改变,通常的定义为X(const X&)。在拷贝构造函数里,用户可以定义对象的拷贝行为是深拷贝还是浅拷贝,如果用户没有实现自己的拷贝构造函数,那么编译器会提供一个默认实现,该实现使用的是按位拷贝(bitwise copy),也即本文所说的浅拷贝。构造函数何时被调用呢?通常以下三种情况需要拷贝对象,此时拷贝构造函数将会被调用。 1一个对象以值传递的方式传入函数体 2一个对象以值传递的方式从函数返回 3一个对象需要通过另外一个对象进行初始化 4C# MemberwiseClone与ICloneable接口 和C++里的拷贝构造函数一样,C#也为每个对象提供了浅拷贝的默认实现,不过C#里没有拷贝构造函数,而是通过顶级类型Object里的MemberwiseClone方法。MemberwiseClone 方法创建一个浅表副本,方法是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。有没有默认的深拷贝实现呢?当然是没有,因为需要所有参与拷贝的对象定义自己的深拷贝行为。C++里需要用户实现拷贝构造函数,重写默认的浅拷贝;C#则不同,C#(确切的说是NET Framework,而非C#语言)提供了ICloneable 接口,包含一个成员 Clone,它用于支持除 MemberwiseClone 所提供的克隆之外的克隆。C++通过拷贝构造函数无法确定子对象实现的是深拷贝还是浅拷贝,而C#在“强制”实现浅拷贝的基础上,提供ICloneable 接口由用户定义深拷贝行为,通过接口来强制约束所有参与拷贝的对象,个人觉得,这也算是一小点C#对C++的改进。 5深拷贝策略与实现 深拷贝的要点就是确保所有参与拷贝的对象都要提供自己的深拷贝实现,不管是C++拷贝构造函数还是C#的ICloneable 接口,事实上都是一种拷贝的约定。有了事先的约定,才能约束实现上的统一,所以关键在于设计。 但偶尔也会在后期才想到要深拷贝,怎么办?总不能修改所有之前的实现吧。有没有办法能够通过顶级类而不关心内部的子对象直接进行深拷贝呢?能不能搞个万能的深拷贝方法,在想用的时候立即用,而不考虑前期的设计。这样“大包大揽”的方法,难点在于实现时必须自动获取子对象的信息,分别为子对象实现深拷贝。C++里比较困难,NET的反射机制使得实现容易一些。不过这样的方法虽然通用,实则破坏了封装,也不符合“每个类对自己负责”的设计原则。 基于NET的反射机制,以前写了一个通用的序列化方法,现在可以拿过来,先序列化,然后再反序列化回来,也即是一个深拷贝,示例代码如下: 深拷贝示例代码 #region ICloneable Members /// <summary> /// 此处的复制为深拷贝,在实现上,为了简化,采用序列化和反序列化。 /// </summary> /// <returns>深拷贝对象</returns> public object Clone() { Student stu = new Student(); XmlStorageHelper helper = new XmlStorageHelper(); string strXml = helperConvertToString(this); helperLoadFromString(stu, strXml); //从XML字符串来赋值 return stu; } #endregion
#include <stdioh>
#include <malloch>
#include <stringh>
typedef struct Room
{
int roomid; //房号
int roomprice; //房价
int roomflag; //房价状况
struct Room next; //上面是大写,这里是小写 改了
} RM;
RM Create_Room();
int Judge(RM ,int //);
int main()
{
// RM Create_Room();
// int Judge(RM ,int //); 不止主函数调用了它们,它们互相有调用,申明放到外面
RM head;
head=Create_Room();
return 0;
}
RM Create_Room() //创建房间函数
{
RM head=NULL, p1, p2;
int num, id, k=1;
printf("\t\t★★★★★★★★创建客房★★★★★★★★\n");
p1=(RM )malloc(sizeof(RM)); //开空间
memset(p1,0,sizeof(RM)); //应当初始化
printf("创建房间的间数: ");
scanf("%d", &num);
fflush(stdin);//getchar(); 清键盘输入缓冲区,用fflush(stdin)能清干净,getchar()只能取走1个字符 下同
printf("\n");
while(num>0)
{
printf("第%d个房间\n", k);
k++;
printf("房 号:");
scanf("%d", &p1->roomid);
fflush(stdin);//getchar();
id=p1->roomid;
while(Judge(head, /&/id)==-1)
{
printf("房 号:");
scanf("%d", &p1->roomid);
fflush(stdin);//getchar();
id=p1->roomid;
}
printf("房 价:");
scanf("%d", &p1->roomprice);
fflush(stdin);//getchar();
p1->roomflag=0;
if(head==NULL)
head = p1;
else
p2->next = p1;
p2 = p1;
p1=(RM )malloc(sizeof(RM));//出循环体后有最后一个未释放!!
memset(p1,0,sizeof(RM)); //应当初始化
num--;
printf("\n");
}
p2->next=NULL;
free(p1);//<<<最后分配了空间但未加入链表,应当释放 add
printf("!!创建结束!!\n");
printf("\n");
return head;
}
int Judge(RM temp,int //p) //判断函数
{
while(temp!=NULL)
{
//if(strcmp(temp->roomid,p)==0)//整数不需用strcmp(),如果是整数数组也只是用memcmp()
if(temp->roomid==p)
return -1;
else
temp=temp->next;
}
return 0;
}
/////已调试通过,运行结果正常
在房间被创建后,我们可以使用 edit 编辑房间的属性(例如 room description 、 secret 、 pin 、 private or not ),但不能修改一些静态的属性(例如 room ID 、 sampling rate )。
无论是静态还是动态的房间,都可以用 destroy 进行销毁。
用户可能在房间使用中销毁房间,其他观众会收到这个事件,获知房间被销毁
用于配置是否启用 token 验证,添加或移除允许进入房间的用户。
房间的管理员可以通过 kick 方法将指定参与者踢出房间。注意,只是能将他踢出房间,并不能阻止他再次进入。若想阻止他再次进入,则需要使用 allowed 对他进行限制。
用于展示公开的所有房间
在音频房间中,发布者(Publisher)是将多媒体数据发布在房间中的参与者,他们可以成为 feed 让其他用户进行订阅(subscribe)。
我们可以通过 join 请求将指定的 handle 指定为 publisher 或 subscriber 。
成功 join 入房间后,将会接收到当前房间中活跃的 publishers 的列表。
不活跃的发布者加入房间不会通知其他参与者,因为一个大房间中可能会有很多参与者,如果每一个进入离开都需要通知所有人的话会显得太过于繁琐。如果开发者它进出房间也通知所有人,那么需要将房间的 notify_joining 配置为 true 。通知的事件如下:
publish 请求必须携带着 JSEP SDP offer去协商一个新的 PeerConnection,即插件会检查编码器和码率是否是房间所支持的,之后将会回应一个 JSEP SDP acswer 来关闭循环并完成配置一个 PeerConnection。 当指定的 PeerConnection 搭建好后,该指定的 publisher 才会变成一个活跃的 publisher,之后其他参与者才可以订阅它。
Janus 会在准备好 Answer 后进行响应,该 event 中也会带着 JSEP SDP answer
publish 和 configure 在功能上时等价的,他们都有开始发布的功能。从语义上, publish 更加合适。但是 configure 可以更新发布者会话的一些属性。总的来说 configure 的功能更加强大,用它就没错了。
我们可以通过使用 joinandconfigure 在一个请求中进行加入和发布两个 *** 作。
参考 join 请求用的 body,并且携带 JSEP SDP offer
成功响应将是一个 joined 事件,并且携带 JSEP SDP answer。
当一个用户在房间中发布成功后,Janus 将会发送一个关于新对端的事件给所有参与者,事件如下:
unpublish 请求用于停止发布并且销毁相关的 PeerConnection,并且将发布者从活跃流列表中移除。
发布者停止订阅成功后,房间内的其他成员会通过下面这个通知得知此事
在 VideoRoom 中,订阅者(Subscriber)不是参与者,但是他可以准确接收指定发布者的媒体数据。通常发布者发布了媒体后,订阅者可以获取该流进行播放。当发布者取消发布后,订阅者 handle 也会随之被移除。除非给订阅者正确的信息,不然订阅者是不能单独存在的。
如果发布者对房间中的媒体进行订阅,则需要传入 private_id 。
订阅者成功加入房间并订阅指定 feed 成功后,Janus 会给予一个 attached 响应,并且在这个 event 中携带 JSEP SDP offer,用于进行媒体协商。
订阅者接收到含有 attach 的 event 后,获取里面的 JSEP SDP offer 后,将其设置为远程 SDP 后,然后发送 start 请求并携带 JSEP SDP answer。
我们可以通过 pause 和 start 请求对订阅媒体进行临时的暂停和恢复
configure 请求允许动态修改订阅者对于媒体订阅的一些属性,比如配置音频和视频的启用与禁用,灵活设置订阅内容。
switch 适用于已经与 Janus 成功建立 PeerConnection 的订阅者,通过这个请求完成订阅的切换,就像看电视切换频道一样。这样做的好处就是能复用一条连接,在切换订阅目标的时候不需要重新建立连接,消耗不必要的资源。但是他也有以下的限制:
leave 请求用于停止订阅并销毁相关的 PeerConnection,由于上下文是隐式的,所以不需要其他参数:
如何举报企业微信,现在骗子都在用企业微信诈骗,企业微信就不管吗?在使用企业微信营销时,有的时候会发现微信账号被封,但是页面没有任何解封提示,这个时候我们不要着急,应该马上寻找企业微信客服,让客服帮助解封账号。

方法有两种,都很简单,一是直接在企业微信中联系企业微信客服,二是关注公众号“企业微信”,在企业微信公众号中联系企业微信客服,公众号的路径很好找,只需在公众号右下角的功能栏中就能看到联系客服的选项。

很多用户发现自己的企业微信账号被封后,自己的个人微信账号也被封了,这是怎么回事?难道企业微信被投诉封号会影响个人微信被封号吗?那么企业微信使用影响到个人微信使用怎么办?
其实这个问题没那么复杂,明确地告诉大家,企业微信被封是不会导致个人微信被封的,如果出现两个账号都被封了的情况,应该先是你自己的个人微信账号被封,才导致的企业微信账号被封。这是因为很多时候,我们的企业微信账号是使用个人微信账号登录的,那么个人微信被封后,企业微信账号自然也就不能正常登录了。
找到根源后,这时我们只要解封了个人微信账号,企业微信账号自然就会在24小时内自动解封。
以上就是今天有关企业微信封号的全部内容了,由于企业微信还有一些营销功能不完善,不能帮助员工很好的开展运营工作,所以在使用企业微信营销的过程中,就可以使用企业微信官方服务商咚察SCRM开发的各种功能进行补充。
可能部分企业对原生的企业微信功能还不满足,小编这边特意准备了一个更加高级的SCRM系统,可以直接嵌入企业微信的一个系统-咚察SCRM系统,里面有更多高级功能,比如会话存档、渠道活码、聊天记录监管、跟进客户等这样可以大大管理好我们的企业客户。
以上就是关于极光推送总结全部的内容,包括:极光推送总结、如果查询出MySQL里某字段值最小的记录ID号、存储过程SQL语句 not in问题等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)