DIY 消息工具

楼主
我是社区第55902位番薯,欢迎点我头像关注我哦~
本帖最后由 迈达斯之手 于 2016-12-3 14:37 编辑

周末闲着也是闲着,写个小工具打发一下时间吧~
FR官方有自己的消息推送的接口,不过我相信是不是大部分新手(跟撸主一样菜的)第一次看那个接口都有些云里雾里摸不着头脑~既然看不懂!那咱就自己写一个吧~下面这个方案仅仅是从逻辑层面取简单的阐述了一个通讯类应该怎么实现,至于线程同步,持久化,并发等等问题就不哔哔了~那样会把问题搞复杂掉。
废话不多说直接上代码,为了保证新手能够看懂,这个代码基本上能不用FR的就没有用FR的~只需要了解js和JQ的常规写法就行。
如果没兴趣看,OK,跳过这段代码,直接说用法!

  1. ;
  2. (function($){
  3.         /*定义一个工具对象,所有的工具以后都放进去*/
  4.         HG = {};
  5.         /*定义我们第一个基础类OBJ*/
  6.         HG.OBJ = function(options){
  7.                 //保证子类能够继承父类的默认成员变量
  8.                 this.options = $.extend(this._defaultOptions(), options);
  9.                 //初始化对象
  10.                 this._init();
  11.         };
  12.         $.extend(HG.OBJ.prototype, {
  13.                 _defaultOptions: function () {
  14.                         return {classType:"OBJ"};
  15.                 },
  16.                 _init:function(){}
  17.         });
  18.         /*定义用于生成子类的方法*/
  19.         HG.extend=function(parent,options){
  20.                 var son = $.extend(parent,{});
  21.                 son.prototype = $.extend(parent.prototype,options);
  22.                 return son;
  23.         };
  24.         /*第一个就是要构建我们的通讯对象*/
  25.         /****定义一些通讯用的私有成员和方法*****/
  26.         //发送通道的状态,为了减轻服务器压力,采取单通道发送
  27.         var status = true;
  28.         var sendMsgList = [];
  29.         var receiveMsgList = [];
  30.         var server = null;
  31.         var sendType = null;
  32.         var dataType = null;
  33.         //最终发送消息的方法
  34.         var send=function(msg,onReceive,onComplete,onFailed){
  35.                 if(!msg.inList){
  36.                         msg.inList = true;
  37.                         sendMsgList.push(msg);
  38.                 }
  39.                 if(status){
  40.                         status = false;
  41.                         var tempSendMsgList = sendMsgList;
  42.                         sendMsgList = [];
  43.                         FR.ajax({  
  44.                                 url: server,  
  45.                                 type: sendType,
  46.                                 dataType:dataType,
  47.                                 data:{msgList:tempSendMsgList},
  48.                                 success : function(receiveMsgList){
  49.                                         status = true;
  50.                                         onReceive(receiveMsgList);
  51.                                 },
  52.                                 complete: function(XMLHttpRequest,textStatus){
  53.                                         status = true;
  54.                                         onComplete(XMLHttpRequest,textStatus);
  55.                                 },
  56.                                 error: function(XMLHttpRequest, textStatus, errorThrown){
  57.                                         status = true;
  58.                                         onFailed(XMLHttpRequest, textStatus, errorThrown);
  59.                                 }
  60.                         });
  61.                 }else{
  62.                         setTimeout(function(){
  63.                                 send(msg,onReceive,onComplete,onFailed);
  64.                         },1000);
  65.                 }
  66.         };
  67.         var formatDate = function(date){
  68.                 var d = new Date(date);
  69.                 return d.getFullYear()+"-"+d.getMonth()+"-"+d.getDate()+"  "+d.getHours()+":"+d.getMinutes()+":"+d.getSeconds();
  70.         };
  71.         //通讯类,可以自己重写onReceive的方法来实现自己的消息工具,消息的内容为JSON格式,自己定义就好了
  72.         HG.CommunicationClient = HG.extend(HG.OBJ,{
  73.                 _defaultOptions: function () {
  74.                         return {
  75.                                 classType:"CommunicationClient",
  76.                                 //默认只跟当前的服务器进行联络
  77.                                 server:FR.servletURL+"?op=msgserver",
  78.                                 sendType:"POST",
  79.                                 dataType:"JSON",
  80.                                 //轮询的频率,默认3秒1次,越快服务器和客户端压力越大
  81.                                 pollingRate:3000
  82.                         };
  83.                 },
  84.                 _init:function(){
  85.                         server = this.options.server;
  86.                         sendType = this.options.sendType;
  87.                         dataType = this.options.dataType;
  88.                         this.polling4Receive();
  89.                 },
  90.                 send:function(msg){
  91.                         var self = this;
  92.                         send(msg,self.onReceive, self.onComplete, self.onFailed);
  93.                 },
  94.                 //给某个用户发文本消息
  95.                 sendText:function(toUserId,text){
  96.                         this.send({action:"send",userId:toUserId,time:new Date().getTime(),content:{text:text}})
  97.                 },
  98.                 onReceive:function(msg){
  99.                         if(msg.length>0){
  100.                                 for( var i=0; i<msg.length; i++ ){
  101.                                         console.info(formatDate(msg[i].time)+"  "+msg[i].name+" "+decodeURI("%E8%AF%B4%EF%BC%9A")+" "+msg[i].content.text);
  102.                                 }
  103.                         }
  104.                 },
  105.                 onFailed:function(XMLHttpRequest, textStatus, errorThrown){
  106.                 },
  107.                 onComplete:function(XMLHttpRequest, textStatus){
  108.                 },
  109.                 /*向服务器轮询,检查是否有自己的消息*/
  110.                 polling4Receive:function(){
  111.                         var self = this;
  112.                         self.send({action:"findMessage",inList:false});
  113.                         setTimeout(function(){
  114.                                 self.polling4Receive();
  115.                         },self.options.pollingRate);
  116.                 }
  117.         });
  118.         //先生成一个对话工具
  119.         HG.Talk = new HG.CommunicationClient();
  120. })(jQuery);
复制代码
在任意一个你需要的系统或者界面引入这段JS,
然后最基本的文本消息发送

                                                HG.Talk.sendText(接收者的用户名,文本消息的内容);
当然,我们实际需求中需要的远远不止是发个文本这么简单,对于任意消息的发送该怎么搞呢?
有两种方法:
继承
HG.CommunicationClient实现新的自己的通讯类,或者重写 HG.Talk的方法,两种方式都是修改onReceive方法,上面的代码中是把消息直接显示到控制台当中的。
你可以根据你自己的需要发送任意JSON格式的msg并在onReceive中去实现你想要的展现方法。当然如果你想真正的了解它是怎么运作的,可以花5分钟看一遍代码就清楚了

下面看看后台,因为暂时只说逻辑,所以很多东西都不考虑,后台就会非常的简单,只需要有点JAVA基础,并且了解FR的service接口就应该能看懂
  1. package com.hg.plugin.plate.msgutils;

  2. import java.io.PrintWriter;
  3. import java.util.ArrayList;
  4. import java.util.Date;
  5. import java.util.HashMap;
  6. import java.util.List;
  7. import java.util.Map;

  8. import javax.servlet.http.HttpServletRequest;
  9. import javax.servlet.http.HttpServletResponse;

  10. import com.fr.fs.control.UserControl;
  11. import com.fr.fs.web.service.ServiceUtils;
  12. import com.fr.json.JSONArray;
  13. import com.fr.json.JSONObject;
  14. import com.fr.stable.fun.Service;
  15. import com.fr.web.utils.WebUtils;

  16. public class MessageServer implements Service {
  17.        
  18.         class Message{
  19.                 private long time = -1;
  20.                 private String fuserId = "";
  21.                 private String tuserId = "";
  22.                 private JSONObject content = JSONObject.create();
  23.                
  24.                 public Message(String fromUserId,String toUserId,JSONObject content){
  25.                         this.fuserId = fromUserId;
  26.                         this.tuserId = toUserId;
  27.                         this.content = content;
  28.                         time = new Date().getTime();
  29.                 }
  30.                
  31.                 public JSONObject toJSON() throws Exception{
  32.                         JSONObject jo = JSONObject.create();
  33.                         jo.put("userId", fuserId);
  34.                         jo.put("name", UserControl.getInstance().getByUserName(fuserId).getRealname());
  35.                         jo.put("content", content);
  36.                         jo.put("time", time);
  37.                         return jo;
  38.                 }
  39.         }
  40.        
  41.         private static Map<String,List<Message>> messageStore = new HashMap<String,List<Message>>();
  42.        
  43.         @Override
  44.         public String actionOP() {
  45.                 return "msgserver";
  46.         }
  47.        
  48.         @Override
  49.         public void process(HttpServletRequest req, HttpServletResponse res,String op, String sessionID) throws Exception {
  50.                 String msgListStr = WebUtils.getHTTPRequestParameter(req, "msgList");
  51.                 JSONArray msgListJa = new JSONArray(msgListStr);
  52.                 List<JSONObject> msgList = sortMessageList(msgListJa);
  53.                 String fromUserId = ServiceUtils.getCurrentUserName(req);
  54.                 //投递给别人的信件
  55.                 for(JSONObject msg : msgList){
  56.                         String tuserId = msg.getString("userId");
  57.                         if(!messageStore.containsKey(tuserId)){
  58.                                 messageStore.put(tuserId, new ArrayList<Message>());
  59.                         }
  60.                         messageStore.get(tuserId).add(new Message(fromUserId,tuserId,msg.getJSONObject("content")));
  61.                 }
  62.                 //查看是否有自己的信件
  63.                 if(!messageStore.containsKey(fromUserId)){
  64.                         messageStore.put(fromUserId, new ArrayList<Message>());
  65.                 }
  66.                 List<Message> sendList = messageStore.get(fromUserId);
  67.                 JSONArray result = JSONArray.create();
  68.                 for(Message msg : sendList){
  69.                         result.put(msg.toJSON());
  70.                 }
  71.                 messageStore.put(fromUserId, new ArrayList<Message>());
  72.                 res.setContentType("text/html;charset=UTF-8");
  73.                 res.setCharacterEncoding("UTF-8");
  74.                 PrintWriter  write = res.getWriter();
  75.                 write.write(result.toString());
  76.                 write.flush();
  77.                 write.close();
  78.         }
  79.        
  80.         private static List<JSONObject> sortMessageList(JSONArray msgListJa) throws Exception{
  81.                 List<JSONObject> result = new ArrayList<JSONObject>();
  82.                 for(int i=0; i<msgListJa.length(); i++){
  83.                         JSONObject msgJo = msgListJa.getJSONObject(i);
  84.                         //去除轮询的请求
  85.                         if("findMessage".equals(msgJo.getString("action"))){
  86.                                 continue;
  87.                         }
  88.                         if(result.size()==0){
  89.                                 result.add(msgJo);
  90.                         }else{
  91.                                 boolean add = false;
  92.                                 for(int j=0;j<result.size();j++){
  93.                                         JSONObject tempMsgJo = result.get(j);
  94.                                         if(tempMsgJo.getLong("time")>=msgJo.getLong("time")){
  95.                                                 result.add(j, msgJo);
  96.                                                 add = true;
  97.                                                 break;
  98.                                         }
  99.                                 }
  100.                                 if(!add){
  101.                                         result.add(msgJo);
  102.                                 }
  103.                         }
  104.                 }
  105.                 return result;
  106.         }
  107. }
复制代码
逻辑是什么呢?这么说你就懂了,在还是写信通讯的年代,负责通讯的就是邮局,邮局是怎么处理事务的呢?
发件人把信投递到邮局,邮局根据收件人地址进行分类,然后由不同的邮递员分别送到各个收件人的家里,
这里情况比较特殊,就是当某些地方邮局不派送信件的地方,当地人怎么取信呢?当有同村的进城的时候就拜托他到邮局看看有没有自己的信件有的话就带回来。

我们上面的代码就是类似后面这种特俗情况。
每个客户端,每隔一段时间都发送一个请求到服务器询问有没有自己的信件,有的话就打包全部接收进来。
每次发送信件出去也是一样,可能有多个信息同时被投递,交给服务器去分类保存。

这个代码实在没啥说的~基本上逻辑一目了然~


然后怎么用呢?编译后注册成为插件就可以使用了~当然要用到项目中需要自己对消息队列进行持久化和线程同步互斥的管理,不然并发多了队列可能就会混乱的哟~~
好了~时间打发了~出去看电影去了~{:5_147:}
分享扩散:
参与人数 +2 F豆 +89 理由
windy_gui + 1 赞一个!
星痕 + 88

查看全部评分

沙发
发表于 2016-12-3 14:41:29

这个是用两个浏览器来做得基本测试~闲得蛋疼的同志可以扩展做一个什么即时通信或者代办提醒定时任务什么的~

参与人数 +1 F豆 +66 理由
孤陌 + 66 感谢分享

查看全部评分

板凳
发表于 2016-12-3 23:14:26
大神666虽然看不懂
地板
发表于 2016-12-4 00:57:46
大神就是牛,打发时间靠写代码。。
5楼
发表于 2016-12-9 01:29:00
哥你总是这么任性
6楼
发表于 2016-12-20 23:28:43
7楼
发表于 2017-4-22 12:10:37
太复杂了
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

7回帖数 1关注人数 3276浏览人数
最后回复于:2017-4-22 12:10

返回顶部 返回列表