FineReport設計器有自動的消息推送功能,可設置報表定時推送和常規的日報週報推送。官方有自己的消息推送的接口,不過有些用戶旺旺希望自己開發,符合自己需求的推送界面。
下面這個方案就從邏輯層面簡單闡述一個通訊類應該怎麼實現。
廢話不多說直接上代碼,爲了保證新手能夠看懂,這個代碼基本上只需要瞭解JS和JQ的常規寫法就行。
;
(function($){
/*定義一個工具對象,所有的工具以後都放進去*/
HG = {};
/*定義我們第一個基礎類OBJ*/
HG.OBJ = function(options){
//保證子類能夠繼承父類的默認成員變量
this.options = $.extend(this._defaultOptions(), options);
//初始化對象
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;
};
/*第一個就是要構建我們的通訊對象*/
/****定義一些通訊用的私有成員和方法*****/
//發送通道的狀態,爲了減輕服務器壓力,採取單通道發送
var status = true;
var sendMsgList = [];
var receiveMsgList = [];
var server = null;
var sendType = null;
var dataType = null;
//最終發送消息的方法
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的方法來實現自己的消息工具,消息的內容爲JSON格式,自己定義就好了
HG.CommunicationClient = HG.extend(HG.OBJ,{
_defaultOptions: function () {
return {
classType:"CommunicationClient",
//默認只跟當前的服務器進行聯絡
server:FR.servletURL+"?op=msgserver",
sendType:"POST",
dataType:"JSON",
//輪詢的頻率,默認3秒1次,越快服務器和客戶端壓力越大
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);
},
//給某個用戶發文本消息
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){
},
/*向服務器輪詢,檢查是否有自己的消息*/
polling4Receive:function(){
var self = this;
self.send({action:"findMessage",inList:false});
setTimeout(function(){
self.polling4Receive();
},self.options.pollingRate);
}
});
//先生成一個對話工具
HG.Talk = new HG.CommunicationClient();
})(jQuery);
在任意一個你需要的系統或者界面引入這段JS,
然後最基本的文本消息發送
HG.Talk.sendText(接收者的用戶名,文本消息的內容);
當然,我們實際需求中需要的遠遠不止是發個文本這麼簡單,對於任意消息的發送該怎麼搞呢?
有兩種方法:
繼承HG.CommunicationClient實現新的自己的通訊類,或者重寫 HG.Talk的方法,兩種方式都是修改onReceive方法,上面的代碼中是把消息直接顯示到控制檯當中的。
你可以根據你自己的需要發送任意JSON格式的msg並在onReceive中去實現你想要的展現方法。當然如果你想真正的瞭解它是怎麼運作的,可以花5分鐘看一遍代碼就清楚了
下面看看後臺,因爲暫時只說邏輯,所以很多東西都不考慮,後臺就會非常的簡單,只需要有點JAVA基礎,並且瞭解FineReport的service接口就應該能看懂.
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);
//去除輪詢的請求
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;
}
}
邏輯是什麼呢?這麼說你就懂了,在還是寫信通訊的年代,負責通訊的就是郵局,郵局是怎麼處理事務的呢?
發件人把信投遞到郵局,郵局根據收件人地址進行分類,然後由不同的郵遞員分別送到各個收件人的家裏,
這裏情況比較特殊,就是當某些地方郵局不派送信件的地方,當地人怎麼取信呢?當有同村的進城的時候就拜託他到郵局看看有沒有自己的信件有的話就帶回來。
我們上面的代碼就是類似後面這種特俗情況。
每個客戶端,每隔一段時間都發送一個請求到服務器詢問有沒有自己的信件,有的話就打包全部接收進來。
每次發送信件出去也是一樣,可能有多個信息同時被投遞,交給服務器去分類保存。
這個代碼實在沒啥說的~基本上邏輯一目瞭然~
然後怎麼用呢?編譯後註冊成爲插件就可以使用了~當然要用到項目中需要自己對消息隊列進行持久化和線程同步互斥的管理,不然併發多了隊列可能就會混亂的喲~~