Arch-03-06-仿 facebook 底条实现聊天功能
facebook 很火,那条能聊天的底部工具条更惹眼,似乎也容易抄袭,好象还很受用,决定抄一把。
?
(1)基础框架就选 DWR,为什么,因为我讨厌写太多 JS 脚本。还有更重要的原因是 DWR3 支持多种 WEB 容器的 ?comet 特性。我喜欢这句话“Asynchronous servlet support for?Tomcat and Glassfish”。
?
那么多的 web 容器,每个都有自己的 Comet 长连接实现,自己去实现每个容器的特殊接口,不如交给 dwr 去搞定。
?
从零开始写也是不可能的,幸好 dwr.war 的包中已经有了个基础的聊天 demo,所以功能上是不成问题。
?
(2)外观要长得象 ?facebook 的底条,开源的一两个,拼凑一下。
?? ? ? ?-http://www.sohtanaka.com/web-design/examples/footer-panel/
?
?? ? ? ?-http://anantgarg.com/2009/05/13/gmail-facebook-style-jquery-chat/
?? ? ? ?-http://www.cometchat.com/?这个抄得神似一些,可惜需要美刀。
(4)如果能配上代码,就完美许多了。coming soon.
(5)还是直接拿来用比较好,这个站点几乎是最佳了,极力推荐一下下:http://code.google.com/p/ijab/
======================================================================
选择 ijab , 接下来是集成 ijab 的功能了。
一般来说,拥有注册用户的网站都有自己的用户和群组,无需要再另外注册和管理了,后台 xmpp 服务器首选 OpenFire,如何无缝集成 OpenFire+iJab+自己网站会员管理?
(1)OpenFire + iJab 比较容易,?http://code.google.com/p/ijab/wiki/iJabWithOpenfire
(2)搞了许久才测试成功,版本的选择很重要
?? ? ? ?. Openfire3.6.4
?? ? ? ?. iJab1.03
?? ? ? ?. 主系统页面和 http-bind 必须相同域名,有两种方法一是用 apache 代理,二是在 tomcat Web应用中加入代理 servlet,都测试通过
(3)apache 代理
<VirtualHost 192.168.1.100:80>ServerAdmin webmaster@plusweb.comDocumentRoot /D/WORK/SAND/JAVA/workspace/sns/ijab<Directory /D/WORK/SAND/JAVA/workspace/sns/ijab> Options +Indexes +Multiviews </Directory> ServerName ideall01.gicp.netAddDefaultCharset UTF-8 RewriteEngine on RewriteRule http-bind/ http://localhost:7070/http-bind/ [P]</VirtualHost>AddDefaultCharset UTF-8Options +MultiViews<IfModule mod_rewrite.c> RewriteEngine On RewriteRule http-bind/ http://localhost:7070/http-bind/ [P]</IfModule>?
?? ?这个单独ijab可以使用,无法和我的应用集成一起。
?
(4)加入 servlet 的方法很好,我很喜欢。
?
<servlet> <servlet-name>HttpBindServlet</servlet-name> <servlet-class>com.plus.openfire.servlet.ProxyServlet</servlet-class> <init-param> <param-name>url</param-name> <param-value>http://192.168.1.100:7070/http-bind/</param-value> </init-param> </servlet> <!--@@JSPC-SERVLETS@@--> <!-- Servlet mappings --> <servlet-mapping> <servlet-name>HttpBindServlet</servlet-name> <url-pattern>/http-bind/*</url-pattern> </servlet-mapping>
?
?
??以下代码来自于http://www.iteye.com/topic/520109
?
import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.io.UnsupportedEncodingException;import java.net.HttpURLConnection;import java.net.MalformedURLException;import java.net.URL;import java.net.URLEncoder;import java.util.Iterator;import java.util.Map;import java.util.Map.Entry;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class ProxyServlet extends HttpServlet {private String url;/** * 对servlet进行请求处理,并将结果在指定输出流中输出 * * @param os * @param servletName * @param parm * @throws IOException * @throws MalformedURLException */private void process(HttpServletRequest req, HttpServletResponse resp,String[] target) throws MalformedURLException, IOException {// 取得连接HttpURLConnection huc = (HttpURLConnection) new URL(url + target[0]).openConnection();// 设置连接属性huc.setDoOutput(true);huc.setRequestMethod("POST");huc.setUseCaches(false);huc.setInstanceFollowRedirects(true);huc.setRequestProperty("Content-Type","application/x-www-form-urlencoded");huc.connect();// 往目标servlet中提供参数OutputStream targetOS = huc.getOutputStream();targetOS.write(target[1].getBytes());targetOS.flush();targetOS.close();// 取得页面输出,并设置页面编码及缓存设置resp.setContentType(huc.getContentType());resp.setHeader("Cache-Control", huc.getHeaderField("Cache-Control"));resp.setHeader("Pragma", huc.getHeaderField("Pragma"));resp.setHeader("Expires", huc.getHeaderField("Expires"));OutputStream os = resp.getOutputStream();// 将目标servlet的输入流直接往页面输出InputStream targetIS = huc.getInputStream();int r;while ((r = targetIS.read()) != -1) {os.write(r);}targetIS.close();os.flush();os.close();huc.disconnect();}/** * 将参数中的目标分离成由目标servlet名称和参数组成的数组 * * @param queryString * @return * @throws UnsupportedEncodingException */private String[] parse(Map map) throws UnsupportedEncodingException {String[] arr = { "", "" };Iterator iter = map.entrySet().iterator();while (iter.hasNext()) {Map.Entry me = (Entry) iter.next();String[] varr = (String[]) me.getValue();if ("servletName".equals(me.getKey())) {// 取出servlet名称arr[0] = varr[0];} else {// 重新组装参数字符串for (int i = 0; i < varr.length; i++) {// 参数需要进行转码,实现字符集的统一arr[1] += "&" + me.getKey() + "="+ URLEncoder.encode(varr[i], "utf-8");}}}arr[1] = arr[1].replaceAll("^&", "");return arr;}@Overridepublic void init() throws ServletException {// 设置目标服务器地址url = this.getInitParameter("url");if (!url.endsWith("/"))url = url + "/";}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {this.doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {String[] target = parse(req.getParameterMap());process(req, resp, target);}}?
?