2010年10月7日
本文的客戶端基于我們的GQT開源項目:http://cxlh.iteye.com/blog/2021463
本人拙見,如有不同意見,歡迎拍磚,同時獻給特別有對服務(wù)端跨語言需求的程序猿們!
客戶端(GQT Demo V3(服務(wù)端配套版).rar)太大請挪步到QQ群下載(群號:101189702),注明:GQT或Java,C++等;
Java工程代碼請挪步下載:http://cxlh.iteye.com/blog/2074307
總體設(shè)計思路:
- 高可用性:每個業(yè)務(wù)服務(wù)端都是獨立的個體,任何一個業(yè)務(wù)服務(wù)器Crash時,都不會影響服務(wù),并且業(yè)務(wù)服務(wù)器可以按需增加,業(yè)務(wù)服務(wù)端使用Java代碼實現(xiàn),主要是為了考慮更好的數(shù)據(jù)庫操作,更好的事務(wù)支持,更好的社區(qū)支持以及可用更多的開源服務(wù),提高開發(fā)效率;
- 自動負(fù)載均衡:當(dāng)某個接口頻繁調(diào)用,增加的響應(yīng)服務(wù)器自動分流接口調(diào)用壓力,也就說我們的異步的請求/響應(yīng)模式下,有一個Broker仲裁程序決定客戶端發(fā)來的請求交由哪個Java業(yè)務(wù)服務(wù)器來處理,這個Broker程序我們采用C++代碼實現(xiàn);
- 客戶端(包括桌面或移動端)網(wǎng)關(guān):根據(jù)策略選取遠(yuǎn)程Socket服務(wù)器連接,Socket服務(wù)器與服務(wù)器之間的消息通訊通過地址尋址遠(yuǎn)程路由,以便連在不同Socket服務(wù)器上的用戶之間可以相互通訊,典型的應(yīng)用就是聊天程序;
- Sub/Pub類消息:客戶端訂閱服務(wù)端的服務(wù),服務(wù)端有多個Pub服務(wù)器(Java編寫),交由Socket服務(wù)器將客戶端Sub的消息Push給Client,此時Socket服務(wù)只作為Proxy用;
好了,其實這里只有2個C++核心組件(Socket服務(wù)器,Broker仲裁程序)和N個Java業(yè)務(wù)服務(wù)器(請求處理服務(wù)器,Pub服務(wù)器),以下介紹用法(需要一定的客戶端編程知識和一些腳本只是):
客戶端發(fā)送請求,異步收取,編寫業(yè)務(wù)代碼步驟:
編寫Java服務(wù)端,比如我們編寫一個按關(guān)鍵字讀取股票列表等接口(依賴注入用的Spring):
@Repository @CacheNamespace(implementation = org.mybatis.caches.ehcache.EhcacheCache.class, readWrite = true) public interface StockDao { @Select("select SYMBOL,SHORT_NAME from `master`") public List<Map> listStock(); @Select("select SYMBOL,SHORT_NAME from `master` where SHORT_NAME like '%${k}%' or SPELL_NAME like '%${k}%' or SYMBOL like '%${k}%' limit 0,10") public List<Map> listStockByKeyword(Map<String,String> map); @Select("select SYMBOL,SHORT_NAME from `master` where exch_id=8") public List<Map> listAllSh(Map<String,String> map); @Select("select SYMBOL,SHORT_NAME from `master` where trade_date=#dt#") public List<Map> listStockByDate(Map<String,String> map); }
編寫Java服務(wù)就這么簡單:
package com.gqt.demo;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Properties;
import java.util.ResourceBundle;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.gqt.server.BaseReqServer;
import com.gqt.server.ReqCallBack;
public class StockServer extends BaseReqServer {
private static Logger logger = LogManager.getLogger(StockServer.class.getName());
final static Properties prop = new Properties();
static{
InputStream is = null;
try {
String c_path = StockServer.class.getResource("/").getPath();
logger.info("c_path:{}",c_path);
is = new FileInputStream(new File(c_path+"config.properties"));
prop.load(is);
} catch (Exception e) {
e.printStackTrace();
}
}
public StockServer(String ip, String port, ReqCallBack callback) {
super(ip, port, callback);
}
public static void main(String[] args) {
logger.info("=============StockServer========");
new Thread(){
@Override
public void run() {
ReqCallBack callback = new StockCallBack();
String ip = prop.getProperty("gqt-reqserver-ip");
String port = prop.getProperty("gqt-reqserver-port");
final StockServer ss = new StockServer(ip,port,callback);
ss.startServer();
}
}.start();
}
}
編寫客戶端C++或腳本:
gw.req("命令代碼"."命令代碼對應(yīng)的參數(shù)列表"); //回調(diào)函數(shù) gw.s_cb_gw.connect(function(trcode,msg){ log("-----------------------------------------------------------------"); log("<p>gqt server異步方式獲取數(shù)據(jù),回調(diào)信息:trcode=" + trcode + ",msg=" + msg+"</p>"); });
效果如下:

這樣做的好處:
- 桌面或移動的客戶端再也不用編寫繁瑣的網(wǎng)絡(luò)通信相關(guān)的程序,只需要發(fā)送請求/訂閱,處理響應(yīng)/訂閱數(shù)據(jù)包即可,也不用關(guān)心底層的數(shù)據(jù)分包合包,客戶端代理,網(wǎng)絡(luò)傳輸?shù)募咏饷芎蛪嚎s等;
- 客戶端開發(fā)人員也幾乎不用和服務(wù)端程序員溝通,通過JSON解析請求透傳給Java,Java響應(yīng)的數(shù)據(jù)帶上包頭和響應(yīng)給客戶端,客戶端解析JSON即可;
- 跨語言的服務(wù)端雖然會損失一定的性能,但似乎這點ZeroMQ已做的足夠好;
Demo程序部署步驟:
- 創(chuàng)建一個MySQL Demo數(shù)據(jù)庫,數(shù)據(jù)庫名:stock,utf-8編碼,導(dǎo)入output下的stock.sql;
- 配置output下的config.properties文件,指定機器IP,配置jdbc.properties,確保數(shù)據(jù)庫配置正確;
- 點擊runStockServer.bat,運行stock的Java Demo服務(wù)器,可以開任意個;
- 配置gqt-server-communicator(cpp)下的config_ims.ini文件,IP地址全部換成機器IP;
- 啟動ss_server.exe,ss_zserver.exe;
- 點擊客戶端GQT程序,配置config_ims.ini中的IP地址,切換到gateway的標(biāo)簽頁,enjoy it!
該項目包含的通用模塊代碼等我有時間一并剝離貢獻出來(基于WebSocket的通知引擎,工作流整合模塊,自定義表單(詳見這里),基于RBAC權(quán)限設(shè)計),最近太忙了,Web項目有一段時間沒碰,有點生疏的感覺,主要在忙GQT項目,一套基于桌面開發(fā)的框架,詳見這里,寫代碼寫的有點手酸的感覺。
基于Web的含工作流的項目看起來并不如想象的那么簡單,主要需求:
- 靈活定制工作流,并跟蹤流程進度;
- 每個Order含有歷史軌跡記錄,可在歷史中查看;
- 工作流的Action靈活,認(rèn)領(lǐng)任務(wù)不一定非要先提取表單,因為很多節(jié)點都只有幾個動作,直接按鈕操作即可;
- 待辦事宜列表在不刷新頁面情況下也能變動;
項目要求:
- 操作簡單高效;
- 權(quán)限細(xì)節(jié)到按鈕級別;
- 并發(fā)數(shù)少,不超過3000個在線用戶;
主要可能使用到技術(shù):
- 工作流引擎,我這里選用Activiti5,很靈活好用;
- 權(quán)限使用Spring Security,基于標(biāo)簽式管理權(quán)限很方便;
- 通知引擎使用WebSocket,基于Flash實時通信,基于socket.io;
- 權(quán)限粒度基于經(jīng)典的RBAC;
- 總體框架Spring MVC+Mybatis;
實現(xiàn)的WebSocket的總體思路:
- WebSocket Server獨立于Web項目,Web Server與WebSocket Server之間的局域網(wǎng)通信基于簡單的Socket通信,這樣這個組件可以完全解耦和通用;
- 當(dāng)Web項目要Push消息到Client時,通過Web Server的Socket Client向WebSocket Server的Socker Server發(fā)送消息,然后WebSocket Server收到消息后解碼,廣播到所有瀏覽器;
我們實現(xiàn)的事件通知非常簡單,設(shè)定全局變量并讓瀏覽器偵聽:
var G_WebSocket=false;
var EVENT_ORDER_CHANGE_STATUS = "orderChange";
var EVENT_ORDER_CHANGE_AMOUNT = "amountChange";
var EVENT_ORDER_CHANGE_REFUND = "refundChange";
WebSocket.init = function(callbackFunc){
socket = io.connect(connUrl, connOptions);
socket.on('connect', function() {
G_WebSocket=true;
callbackFunc("connect",null);
});
socket.on('disconnect', function() {
G_WebSocket=false;
callbackFunc("disconnect",null);
});
socket.on('clientQuit', function(obj){
G_WebSocket=false;
callbackFunc("clientQuit",obj);
});
socket.on('broadcast', function(obj) {
callbackFunc("broadcast",obj);
});
};
在需要偵聽WebSocket接受Web Server推送消息的地方加上一個函數(shù)即可:
WebSocket.init(function(command,jsonObj){
if(command=="broadcast"){
if(jsonObj.e == EVENT_ORDER_CHANGE_STATUS){
//TODO:write your code here
}else if(jsonObj.e == EVENT_ORDER_CHANGE_AMOUNT){
//TODO:write your code here
}else if(jsonObj.e == EVENT_ORDER_CHANGE_REFUND){
//TODO:write your code here
}
}
});
這樣的結(jié)構(gòu)要擴展推送服務(wù)很簡單,比如按頻道推送等,都可以很容易的擴展。
再看看看工作流,我們實現(xiàn)了activiti通用的申請?zhí)峤蝗蝿?wù)流程和自定義表單功能,提取跟蹤流程圖功能等,這樣你要設(shè)計一個新流程也變得非常簡單,只需要在eclipse里劃上工作流圖,在后臺發(fā)布,然后通過SpringMVC的RestAPI啟動實例流程,申領(lǐng)完成任務(wù)等,如下圖:

流程走到了分支的兩個節(jié)點上,這樣對后續(xù)新增的工作流提供了極大的遍歷。
最后說說Spring Security,基于RBAC的權(quán)限體系搭建好后(可以用在任何管理系統(tǒng)中),要在頁面中訪問一個資源,首先判斷一下是否有權(quán)限,如下HTML:
<sec:authorize ifAllGranted="r_pd">
<a href="#">resource access here</a>
</sec:authorize>
<sec:authorize url="/XXX/XXX/XXX.html">
<a href="XXX/XXX/XXX.html'">
<span>XXX功能</span>
</a>
</sec:authorize>
前臺由于項目比較小,沒有用到j(luò)s的MVC框架,如backbone等,這里就不再記錄了。
偶玩的版本是3.3.1,簡單而華麗的外表,界面截圖如下:

?
安裝FD,你首先需要安裝:
- JDK 1.6以上版本
- .Net運行環(huán)境
繼而你就可以一路Next完成安裝了……
安裝完成后,你必須去adobe官方網(wǎng)站下載開源的Flex SDK,我這邊下載的版本是:flex_sdk_3.5.0.12683_mpl
下載完成后,解壓到某個目錄下即可,如:F:\flex_sdk_3.5.0.12683_mpl
然后在FD中設(shè)置Flex SDK,如下圖:

?
我們這邊以O(shè)pen Flash Chart為例,導(dǎo)入項目工程,點擊運行,如下圖:

?
你可以設(shè)置斷點,運行表達式,使用起來非常方便,強烈推薦給大家使用!
已有 1 人發(fā)表留言,猛擊->>這里<<-參與討論
JavaEye推薦
10月5,6日去寧波附近的度假村旅游了一下,一家3人出發(fā)了,由于兒子還比較小,怕他累著,所以這次就去了九龍湖開元名都大酒店度假村,5星級的酒店,住了一晚,有點小貴,協(xié)議價后也得880元一晚,不過是無敵湖景房,超大陽臺,陽臺上就可以看到整個九龍湖,甚是壯觀,兒子玩的開心的不得了,在酒店的花園里滑滑板車,5日早上出發(fā),6日中午回來,在回來的路上,順便小逛了一下慈城古鎮(zhèn),到寧波吃了點飯,到家就該兒子的睡覺時間了……這個國慶節(jié)3日就簡單的陪兒子在東錢湖上座了下船,他很喜歡坐船的……其實時間都在不知不覺中度過,國慶長假結(jié)束了……
?
PS:附上酒店小圖一張,以之紀(jì)念……
?

已有 0 人發(fā)表留言,猛擊->>這里<<-參與討論
JavaEye推薦