FineReport設(shè)計(jì)器有自動(dòng)的消息推送功能,可設(shè)置報(bào)表定時(shí)推送和常規(guī)的日?qǐng)?bào)周報(bào)推送。官方有自己的消息推送的接口,不過有些用戶旺旺希望自己開發(fā),符合自己需求的推送界面。
下面這個(gè)方案就從邏輯層面簡(jiǎn)單闡述一個(gè)通訊類應(yīng)該怎么實(shí)現(xiàn)。
廢話不多說直接上代碼,為了保證新手能夠看懂,這個(gè)代碼基本上只需要了解JS和JQ的常規(guī)寫法就行。
;


(function($)
{


/**//*定義一個(gè)工具對(duì)象,所有的工具以后都放進(jìn)去*/


HG =
{};


/**//*定義我們第一個(gè)基礎(chǔ)類OBJ*/


HG.OBJ = function(options)
{

//保證子類能夠繼承父類的默認(rèn)成員變量

this.options = $.extend(this._defaultOptions(), options);

//初始化對(duì)象

this._init();

};


$.extend(HG.OBJ.prototype,
{


_defaultOptions: function ()
{


return
{classType:"OBJ"};

},


_init:function()
{}

});


/**//*定義用于生成子類的方法*/


HG.extend=function(parent,options)
{


var son = $.extend(parent,
{});

son.prototype = $.extend(parent.prototype,options);

return son;

};


/**//*第一個(gè)就是要構(gòu)建我們的通訊對(duì)象*/


/**//****定義一些通訊用的私有成員和方法*****/

//發(fā)送通道的狀態(tài),為了減輕服務(wù)器壓力,采取單通道發(fā)送

var status = true;

var sendMsgList = [];

var receiveMsgList = [];

var server = null;

var sendType = null;

var dataType = null;

//最終發(fā)送消息的方法


var send=function(msg,onReceive,onComplete,onFailed)
{


if(!msg.inList)
{

msg.inList = true;

sendMsgList.push(msg);

}


if(status)
{

status = false;

var tempSendMsgList = sendMsgList;

sendMsgList = [];


FR.ajax(
{

url: server,

type: sendType,

dataType:dataType,


data:
{msgList:tempSendMsgList},


success : function(receiveMsgList)
{

status = true;

onReceive(receiveMsgList);

},


complete: function(XMLHttpRequest,textStatus)
{

status = true;

onComplete(XMLHttpRequest,textStatus);

},


error: function(XMLHttpRequest, textStatus, errorThrown)
{

status = true;

onFailed(XMLHttpRequest, textStatus, errorThrown);

}

});


}else
{


setTimeout(function()
{

send(msg,onReceive,onComplete,onFailed);

},1000);

}

};


var formatDate = function(date)
{

var d = new Date(date);

return d.getFullYear()+"-"+d.getMonth()+"-"+d.getDate()+" "+d.getHours()+":"+d.getMinutes()+":"+d.getSeconds();

};

//通訊類,可以自己重寫onReceive的方法來實(shí)現(xiàn)自己的消息工具,消息的內(nèi)容為JSON格式,自己定義就好了


HG.CommunicationClient = HG.extend(HG.OBJ,
{


_defaultOptions: function ()
{


return
{

classType:"CommunicationClient",

//默認(rèn)只跟當(dāng)前的服務(wù)器進(jìn)行聯(lián)絡(luò)

server:FR.servletURL+"?op=msgserver",

sendType:"POST",

dataType:"JSON",

//輪詢的頻率,默認(rèn)3秒1次,越快服務(wù)器和客戶端壓力越大

pollingRate:3000

};

},


_init:function()
{

server = this.options.server;

sendType = this.options.sendType;

dataType = this.options.dataType;

this.polling4Receive();

},


send:function(msg)
{

var self = this;

send(msg,self.onReceive, self.onComplete, self.onFailed);

},

//給某個(gè)用戶發(fā)文本消息


sendText:function(toUserId,text)
{


this.send(
{action:"send",userId:toUserId,time:new Date().getTime(),content:
{text:text}})

},


onReceive:function(msg)
{


if(msg.length>0)
{


for( var i=0; i<msg.length; i++ )
{

console.info(formatDate(msg[i].time)+" "+msg[i].name+" "+decodeURI("%E8%AF%B4%EF%BC%9A")+" "+msg[i].content.text);

}

}

},


onFailed:function(XMLHttpRequest, textStatus, errorThrown)
{

},


onComplete:function(XMLHttpRequest, textStatus)
{

},


/**//*向服務(wù)器輪詢,檢查是否有自己的消息*/


polling4Receive:function()
{

var self = this;


self.send(
{action:"findMessage",inList:false});


setTimeout(function()
{

self.polling4Receive();

},self.options.pollingRate);

}

});

//先生成一個(gè)對(duì)話工具

HG.Talk = new HG.CommunicationClient();

})(jQuery);


在任意一個(gè)你需要的系統(tǒng)或者界面引入這段JS,
然后最基本的文本消息發(fā)送
HG.Talk.sendText(接收者的用戶名,文本消息的內(nèi)容);
當(dāng)然,我們實(shí)際需求中需要的遠(yuǎn)遠(yuǎn)不止是發(fā)個(gè)文本這么簡(jiǎn)單,對(duì)于任意消息的發(fā)送該怎么搞呢?
有兩種方法:
繼承HG.CommunicationClient實(shí)現(xiàn)新的自己的通訊類,或者重寫 HG.Talk的方法,兩種方式都是修改onReceive方法,上面的代碼中是把消息直接顯示到控制臺(tái)當(dāng)中的。
你可以根據(jù)你自己的需要發(fā)送任意JSON格式的msg并在onReceive中去實(shí)現(xiàn)你想要的展現(xiàn)方法。當(dāng)然如果你想真正的了解它是怎么運(yùn)作的,可以花5分鐘看一遍代碼就清楚了
下面看看后臺(tái),因?yàn)闀簳r(shí)只說邏輯,所以很多東西都不考慮,后臺(tái)就會(huì)非常的簡(jiǎn)單,只需要有點(diǎn)JAVA基礎(chǔ),并且了解FineReport的service接口就應(yīng)該能看懂.
package com.hg.plugin.plate.msgutils;


import java.io.PrintWriter;

import java.util.ArrayList;

import java.util.Date;

import java.util.HashMap;

import java.util.List;

import java.util.Map;


import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import com.fr.fs.control.UserControl;

import com.fr.fs.web.service.ServiceUtils;

import com.fr.json.JSONArray;

import com.fr.json.JSONObject;

import com.fr.stable.fun.Service;

import com.fr.web.utils.WebUtils;



public class MessageServer implements Service
{



class Message
{

private long time = -1;

private String fuserId = "";

private String tuserId = "";

private JSONObject content = JSONObject.create();



public Message(String fromUserId,String toUserId,JSONObject content)
{

this.fuserId = fromUserId;

this.tuserId = toUserId;

this.content = content;

time = new Date().getTime();

}



public JSONObject toJSON() throws Exception
{

JSONObject jo = JSONObject.create();

jo.put("userId", fuserId);

jo.put("name", UserControl.getInstance().getByUserName(fuserId).getRealname());

jo.put("content", content);

jo.put("time", time);

return jo;

}

}


private static Map<String,List<Message>> messageStore = new HashMap<String,List<Message>>();


@Override


public String actionOP()
{

return "msgserver";

}


@Override


public void process(HttpServletRequest req, HttpServletResponse res,String op, String sessionID) throws Exception
{

String msgListStr = WebUtils.getHTTPRequestParameter(req, "msgList");

JSONArray msgListJa = new JSONArray(msgListStr);

List<JSONObject> msgList = sortMessageList(msgListJa);

String fromUserId = ServiceUtils.getCurrentUserName(req);

//投遞給別人的信件


for(JSONObject msg : msgList)
{

String tuserId = msg.getString("userId");


if(!messageStore.containsKey(tuserId))
{

messageStore.put(tuserId, new ArrayList<Message>());

}

messageStore.get(tuserId).add(new Message(fromUserId,tuserId,msg.getJSONObject("content")));

}

//查看是否有自己的信件


if(!messageStore.containsKey(fromUserId))
{

messageStore.put(fromUserId, new ArrayList<Message>());

}

List<Message> sendList = messageStore.get(fromUserId);

JSONArray result = JSONArray.create();


for(Message msg : sendList)
{

result.put(msg.toJSON());

}

messageStore.put(fromUserId, new ArrayList<Message>());

res.setContentType("text/html;charset=UTF-8");

res.setCharacterEncoding("UTF-8");

PrintWriter write = res.getWriter();

write.write(result.toString());

write.flush();

write.close();

}



private static List<JSONObject> sortMessageList(JSONArray msgListJa) throws Exception
{

List<JSONObject> result = new ArrayList<JSONObject>();


for(int i=0; i<msgListJa.length(); i++)
{

JSONObject msgJo = msgListJa.getJSONObject(i);

//去除輪詢的請(qǐng)求


if("findMessage".equals(msgJo.getString("action")))
{

continue;

}


if(result.size()==0)
{

result.add(msgJo);


}else
{

boolean add = false;


for(int j=0;j<result.size();j++)
{

JSONObject tempMsgJo = result.get(j);


if(tempMsgJo.getLong("time")>=msgJo.getLong("time"))
{

result.add(j, msgJo);

add = true;

break;

}

}


if(!add)
{

result.add(msgJo);

}

}

}

return result;

}

}


邏輯是什么呢?這么說你就懂了,在還是寫信通訊的年代,負(fù)責(zé)通訊的就是郵局,郵局是怎么處理事務(wù)的呢?
發(fā)件人把信投遞到郵局,郵局根據(jù)收件人地址進(jìn)行分類,然后由不同的郵遞員分別送到各個(gè)收件人的家里,
這里情況比較特殊,就是當(dāng)某些地方郵局不派送信件的地方,當(dāng)?shù)厝嗽趺慈⌒拍兀慨?dāng)有同村的進(jìn)城的時(shí)候就拜托他到郵局看看有沒有自己的信件有的話就帶回來。
我們上面的代碼就是類似后面這種特俗情況。
每個(gè)客戶端,每隔一段時(shí)間都發(fā)送一個(gè)請(qǐng)求到服務(wù)器詢問有沒有自己的信件,有的話就打包全部接收進(jìn)來。
每次發(fā)送信件出去也是一樣,可能有多個(gè)信息同時(shí)被投遞,交給服務(wù)器去分類保存。
這個(gè)代碼實(shí)在沒啥說的~基本上邏輯一目了然~
然后怎么用呢?編譯后注冊(cè)成為插件就可以使用了~當(dāng)然要用到項(xiàng)目中需要自己對(duì)消息隊(duì)列進(jìn)行持久化和線程同步互斥的管理,不然并發(fā)多了隊(duì)列可能就會(huì)混亂的喲~~