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;
}
}
逻辑是什么呢?这么说你就懂了,在还是写信通讯的年代,负责通讯的就是邮局,邮局是怎么处理事务的呢?
发件人把信投递到邮局,邮局根据收件人地址进行分类,然后由不同的邮递员分别送到各个收件人的家里,
这里情况比较特殊,就是当某些地方邮局不派送信件的地方,当地人怎么取信呢?当有同村的进城的时候就拜托他到邮局看看有没有自己的信件有的话就带回来。
我们上面的代码就是类似后面这种特俗情况。
每个客户端,每隔一段时间都发送一个请求到服务器询问有没有自己的信件,有的话就打包全部接收进来。
每次发送信件出去也是一样,可能有多个信息同时被投递,交给服务器去分类保存。
这个代码实在没啥说的~基本上逻辑一目了然~
然后怎么用呢?编译后注册成为插件就可以使用了~当然要用到项目中需要自己对消息队列进行持久化和线程同步互斥的管理,不然并发多了队列可能就会混乱的哟~~