做个备份。
原文地址:http://erning.net/blog/2012/06/18/the-architect-of-anjuke-inc/
private String encrypt(String encodeString) { //空字符串不加密 if (StringUtil.isEmpty(encodeString)) { return ""; } try { byte[] modulusBytes = new BASE64Decoder().decodeBuffer(PropertiesHelp.getProperty( configPath, "encrypt.modulus")); byte[] exponentBytes = new BASE64Decoder().decodeBuffer(PropertiesHelp.getProperty( configPath, "encrypt.exponent")); BigInteger modulus = new BigInteger(1, modulusBytes); BigInteger exponent = new BigInteger(1, exponentBytes); RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, exponent); KeyFactory fact = KeyFactory.getInstance("RSA"); PublicKey pubKey = fact.generatePublic(rsaPubKey); Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, pubKey); byte[] bytes = encodeString.getBytes(); byte[] encodedByteArray = new byte[] {}; for (int i = 0; i < bytes.length; i += 102) { byte[] subarray = ArrayUtils.subarray(bytes, i, i + 102); byte[] doFinal = cipher.doFinal(subarray); encodedByteArray = ArrayUtils.addAll(encodedByteArray, doFinal); } return new BASE64Encoder().encode(encodedByteArray); } catch (Exception e) { logger.error(e.getMessage()); } return null; }
今天终于把AC权限管理系统“上线”了
内部项目,取名AC,即access control 一个权限授权及管理服务。
百度最近蛋疼的搞出了“百度网盘” 分享分享。大家一起用用。
http://pan.baidu.com/netdisk/beinvited?invite_code=4a71de09a323e92f473702bd3e908a9f
http://pan.baidu.com/netdisk/beinvited?invite_code=91d92483f8016a39c0ac3681881ce6a3
http://pan.baidu.com/netdisk/beinvited?invite_code=eece5a656f35811e329acd4b92012195
http://pan.baidu.com/netdisk/beinvited?invite_code=0d1b7588022472d479fb185cd3926cd1
http://pan.baidu.com/netdisk/beinvited?invite_code=562e1bbcffe5374290682a9204d2fc66
http://pan.baidu.com/netdisk/beinvited?invite_code=f5e51e22680ba945431d462b3d9bd46d
http://pan.baidu.com/netdisk/beinvited?invite_code=0a8387a03876e7215d49d62a7548eb3b
http://pan.baidu.com/netdisk/beinvited?invite_code=39cd3b2cc1e003b602e5edd22cd1db99
http://pan.baidu.com/netdisk/beinvited?invite_code=a2a6ad4aaa5631b14a6f0075d9707e46
http://pan.baidu.com/netdisk/beinvited?invite_code=429b7611de758873f39d4fc278e7b310
webbit是基于netty扩展的websocket工具。可以大大简化websocket开发。
项目地址:https://github.com/webbit/webbit
使用说明:https://github.com/webbit/webbit/blob/master/README.md
本文权当翻译,高手直接进上面链接。
一些题外话:
Maven配置
<dependency> <groupId>org.webbitserver</groupId> <artifactId>webbit</artifactId> <version>0.4.7</version> </dependency>
配置端口8080.并配置websocket路径/socket的handler
public class WebSocketServer{ public static void main(String[] args) { WebServer webServer = WebServers.createWebServer(8080) .add(new StaticFileHandler("/socket")); webServer.start(); } }
编写/socket handler
public class WebSocketHandler extends BaseWebSocketHandler{ private int connectionCount; public void onOpen(WebSocketConnection connection) { connection.send("Hello! There are " + connectionCount + " other connections active"); connectionCount++; } public void onClose(WebSocketConnection connection) { connectionCount--; } public void onMessage(WebSocketConnection connection, String message) { connection.send(message.toUpperCase()); // echo back message in upper case } }
到此为止。基本代码已经都好了。感觉更写个servlet一样方便。
下面是客户端代码:
<html> <body> <!-- Send text to websocket --> <input id="userInput" type="text"> <button onclick="ws.send(document.getElementById('userInput').value)">Send</button> <!-- Results --> <div id="message"></div> <script> function showMessage(text) { document.getElementById('message').innerHTML = text; } var ws = new WebSocket('ws://' + document.location.host + '/hellowebsocket'); showMessage('Connecting...'); ws.onopen = function() { showMessage('Connected!'); }; ws.onclose = function() { showMessage('Lost connection'); }; ws.onmessage = function(msg) { showMessage(msg.data); }; </script> </body> </html>
到此为止。websocket基本功能都已经实现。
这几天公司做了个简单的web im聊天室。麦包包晒包频道 右下角的“包打听”。
采用netty 做socket server + flash client. 通讯采用自定义的JSON文本。
在线IM初步的探索,现阶段做的比较简单。
目前就部署1台服务器。没有考虑多机通信。没有涉及通信队列。
总共代码不到1000行。netty的确强大。
关键代码分享:
无话可说的代码,netty通用设置。
public class ChatRoomNioServer { private static final Logger logger = Logger.getLogger(ChatRoomNioServer.class); private static final Integer SERVER_PORT = Integer.parseInt(PropertiesHelp .getProperty("chat.server.port")); public void start() { logger.info("chatroom init..."); ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); bootstrap.setPipelineFactory(new ChatRoomServerPipelineFactory()); bootstrap.setOption("child.tcpNoDelay", true); bootstrap.setOption("child.keepAlive", true); bootstrap.setOption("reuseAddress", true); bootstrap.bind(new InetSocketAddress(SERVER_PORT)); logger.info("chatroom running..."); } }
由于采用JSON协议。
上行通道:
下行通道:
public class ChatRoomServerPipelineFactory implements ChannelPipelineFactory { @Override public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = Channels.pipeline(); pipeline .addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.zeroDelimiter())); pipeline.addLast("stringDecoder", new StringDecoder(CharsetUtil.UTF_8)); pipeline.addLast("stringEncoder", new StringEncoder(CharsetUtil.UTF_8)); pipeline.addLast("messageHandler", new MessageHandler()); pipeline.addLast("encoder", new MessageEncoder()); return pipeline; } }
netty没有提供\0截取。不过重写部分代码即可。
public class Delimiters { public static ChannelBuffer[] zeroDelimiter() { return new ChannelBuffer[] { ChannelBuffers.wrappedBuffer(new byte[] { '\0' }), ChannelBuffers.wrappedBuffer(new byte[] { '\r', '\n' }) }; } private Delimiters() { } }
逻辑处理:
public class MessageHandler extends SimpleChannelUpstreamHandler { private static final Logger logger = Logger.getLogger(MessageHandler.class); private static final String POLICY_REQUEST = "<policy-file-request/>"; private static final String POLICY_XML = "<?xml version=\"1.0\"?><cross-domain-policy><site-control permitted-cross-domain-policies=\"master-only\"/><allow-access-from domain=\"*\" to-ports=\"*\" /></cross-domain-policy>"; @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { super.channelConnected(ctx, e); ChatService.initConnection(e.getChannel()); logger.info("one user connection server, left " + ChatUserService.getOnlineUserCount() + " users"); } @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { super.channelConnected(ctx, e); ChatService.closedConnection(e.getChannel()); logger .info("one user left server, left " + ChatUserService.getOnlineUserCount() + " users"); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { String msg = (String) e.getMessage(); if (msg.equalsIgnoreCase(POLICY_REQUEST)) { e.getChannel().write(POLICY_XML + "\0"); e.getChannel().close(); } else { try { MessageDispatchHandler messageDispatchHandler = new MessageDispatchHandler(e); messageDispatchHandler.setListener(new ChatRoomListenerImpl()); messageDispatchHandler.dispatch(); } catch (Exception ex) { logger.error("message handler error", ex); } } } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { logger.warn("Unexpected exception from downstream.", e.getCause()); e.getChannel().close(); } }
具体业务在 MessageDispatchHandler 处理一些业务逻辑即可。
public class MessageDispatchHandler { private static final Logger logger = Logger.getLogger(MessageDispatchHandler.class); private ChatData chatData; private ChatConnection connection; //事件监听器 private ChatRoomListener listener; public MessageDispatchHandler(ChatConnection connection, Object message) { this.chatData = ChatPackageUtil.unpackage(message); this.connection = connection; } public void dispatch() { logger.debug("current chatdata :" + chatData); if (listener == null) { throw new RuntimeException("监听器不能为空!"); } try { switch (chatData.getMethod()) { case C_CONN: listener.connChatRoom(connection, chatData); break; case C_JOIN: listener.loginChatRoom(connection, chatData); break; case C_PUBLISH_MSG: listener.broadcastMsg(connection, chatData); break; case C_SEND_ADMIN: listener.sendAdminMsg(connection, chatData); break; case C_SEND_NORMAL: listener.sendNormalMsg(connection, chatData); break; case C_GET_USERS: listener.getOnlineUserList(connection, chatData); break; default: throw new BusinessException("错误指令:" + chatData.getMethod()); } } catch (BusinessException e) { logger.info("error msg:" + e.getMessage()); ChatService.pushErrorMsg(e.getCode(), e.getMessage(), connection); } } public void setListener(ChatRoomListener listener) { this.listener = listener; } }
总结下遇到的问题:
<cross-domain-policy> <allow-access-from domain="*" to-ports="80-9000" /> </cross-domain-policy>
之前写过一点飞信相关的小程序。很久没关心了。发现现在飞信协议都改掉了。强制了验证码。基本上原来的第三方库都不能使用了。
下面就是现在的飞信验证码。看上去破解难度不大。就一根干扰线。有哪位可以破解的网友贡献下代码to me<me[???]fengsage.com> 替换[???]你懂得。
废话不多说,开始进入正文。
最近发现飞信官网出了webim版的飞信。而且因为年底工作不多。有点无聊。花了几周无聊时间写写代码。给自己发发短信神马的。没多大意义。
项目地址:http://code.google.com/p/fetionim/
值得注意的地方:
目前实现的功能:
未来要实现的功能:
本来不打算发布这个。个人感觉这玩意不能算是什么好的作品。不过以我个性,如果不发布这玩意。估计后面也懒得去维护了。索性发布。代码写的不好。看到的朋友请口水少喷。多提点实在点的意见。
java和ruby都有基于webim的类似实现。
java参见:litefetion
ruby参见:fetion-robot
python的应该算是独一无二的。我没看过这些现有的代码是如何实现的。纯粹自己编写边想。思路和方式和他们应该都存在较多的不同。算是给python初学者提供一些例子吧。
每年都给自己写个总结。写给将来的自己看。
不太会写文章,分几个方面总结下2011过去的一年。
生活
离开了生活了5年多的杭州。其实说是5年。但里面有3年大学生活,只有2年的工作。虽然是爸妈的意思,但我知道,其实是我自己的软弱。我害怕孤单的一直生活下去。每天上班下班。不知道前面的路在哪里。回嘉兴的这一年来感觉非常的放松,再也没有了那种漂泊孤单感觉,有着家人的关爱,重新滋润了我那干枯的心床。我不后悔!感谢小龚老师、小王老师、老蒋童鞋。曾经的照顾和关怀~
工作
告别了曾经共同奋斗过得同事们,告别了我最尊敬的王总。感谢你2年前给我一个走出大学的学生机会,让我不至于在茫茫的毕业潮中失去方向。在公司的这段日子是我毕生难忘的日子。你教会了我如何学习,如何沟通,如何写文档……感谢震宇,我的好兄弟,好朋友。感谢所有曾经给我过帮助的同事朋友们。
这1年找了2份工作,这在我以前看来是十分反常的。我很反感经常换工作的人,频繁的换工作即是对公司的不负责任也是对自己的懈怠。然而我犯了这个错误。
回嘉兴的第一份工作是在浙江衣派网络科技公司,一家不上进的公司。从刚开始给人一种勃勃生机的兴奋,到最后给人一种日落黄昏的伤感。不想过于主观的评价一家公司,这里感谢强哥,老陆,小朱,老吴,小彭。感谢技术部同事们给我的帮助和照顾。感谢你们包容我的缺点,祝愿新的一年,你们在各自的岗位上取得新的成就。
第二家公司就是现在的嘉兴麦包包网络科技公司。说实话我刚回嘉兴之前从来没听说过。虽然麦包包在电商领域已经较有名气。来麦包包的理由就简单,一是上一家公司的确经营不善,面临裁员的风险,其次就是这里有我非常感兴趣的项目,搭建自己的支付系统。前面这半年,基本快打磨掉我的积极性,整天准点下班,做些没有挑战的事情。人都懒散了。然而这个项目给了我兴奋的感觉。我太渴望有所提升。感谢我的胖师傅银鲨,二师弟银鲈.(呵呵,麦包包的企业文化的确做得不错,有意思的花名文化,虽然山寨但不错)。你们给了我太多太多的帮助。银鲨师傅的“苛刻”灭了偷懒的借口,重新点燃了我的斗志。银鲈童鞋的固执,坚持,避免了我很多bug的出现。然而好事多磨,年前的1个月,银鲨师傅的突然离职,让我感到希望的破灭,没有领路人的感觉真的不好受。随后项目的暂停和转移,让我有了离开麦包包的想法。12月被安排到日本项目组,我有种被打入冷宫的感觉。为了总监给我的希望,坚持了1个月。回头想来这1个月同样精彩。跟新的同事打了交道,虽然已经来了2个多月,但是除了跟银鲨和银鲈,没有和太多的同事沟通,想来有点可悲。感谢滕枣童鞋,很高兴与你的合作。这个月是轻松愉快的。感谢下糯米同学,你是我见过最有才华和实力的应届毕业生了。希望你在新一年里,新的公司取得更多的成就。年初之际总监重启了支付项目,今年这个将是我努力的目标和方向。
感谢下卷丹童鞋、木虱童鞋、戎麦童鞋、巴叶童鞋、灵猫童鞋、角蒿童鞋、银鲈童鞋、章木童鞋、腾枣童鞋、铁阕童鞋、青柠童鞋、戟天童鞋、白鱼童鞋、翠雀童鞋、戎草童鞋、海椒童鞋、蜂虎童鞋、蝎虎童鞋、龙猫童鞋、简草童鞋、洋姜童鞋、白鲩童鞋、蓝天童鞋、白苏童鞋、西柚童鞋、毛尖童鞋…..(排名按我座位的远近,方便我回想。并且在职的同事。保佑我都记全了)
感情
感情方面一直是我的弱项,25年来就没真正谈过一场恋爱。大学里我不想谈,更不敢谈。承担不起责任的我,没资格谈恋爱。所以我不后悔。这方面今年是可悲一年。一是曾经很喜欢的女生结婚了,我从头到尾都没有勇气去追求过,伤悔。二是好不容易相亲到一个比较中意的女生,准备踏踏实实一起走下去。但对方一句从来没有喜欢过我,把我打落了谷底。我不怪她,如果我能多关心关心她,也许结局会不一样。感情方面一直都是我很回避的方面,但2012年我会改正这一点。遇到喜欢的就尽力去追,”放开”的去追。不想以后来了有后悔。
财产
左边是全年的支出图,总体感觉每一笔钱都是有价值的。
理财方面非常的糟糕。今年基本亏损10%左右。还在坚持定存的习惯,投入财产的资金不多。总体亏损在1-2K之前。但和我2011年初制定的理财计划已经相差太多了。2011理财计划。感觉今年的亏损主要原因还是投机心太重,没有真正的肯去学习理财知识。以为读几本理财方面的书,就能理到财。其次今年全球的经济的确不景气。黄金大大起大落,给人当年中国股市崩盘的感觉。
2012的展望
工作上,把东西做好,做漂亮。努力工作,早日升值加薪。
生活上,多做点力所能及的事情,少让爸妈操心。周末多学点菜,为将来做准备。
感情上,希望今年能找到心仪的女朋友,早日踏上婚姻的”坟墓”。
理财上,有空,踏踏实实学点经济常识,少点投机心,多点主观意念。
学习上,今年要好好学好英语。踏踏实实。把阅读和听力提升一个台阶。
身体上,有时间好好锻炼下自己,瘦巴巴的,像柴火一样。我是女人也不会喜欢。
历经几次换域名,以及从GAE-wordpress造成不少历史遗留的图片分布在不同域名或gae目录下。
主要分布
http://oldres.fengsage.com
http://www.fengsage.com
http://fensageblog.appspot.com
原来使用代码实现图片代理访问。但自己越看越不爽。索性写个脚本一次性把原来的图片下载到wordpress本地。并且更新数据库。主要是圣诞节闲的蛋疼。
代码有不少问题:
wordpress插件实现:
http://wordpress.org/extend/plugins/velvet-blues-update-urls/ 等发现的时候脚本已经写好了。悲哀~~
脚本笔记简单。分享下。
#!/usr/bin/env python # --*-- encoding:utf-8 --*-- ''' Created on 2011-12-25 @author: fred''' import MySQLdb import re import urllib import time import os WP_POST_CONTENT = u"wp_posts" SIMPLE_IMG_URL = r'' NEW_IMG_URL = u'' DOWNLOAD_PATH = u'wp-content/uploads/%s'%(time.strftime('%m/%d', time.localtime(time.time()))) REPLACE_LIST = ['http://oldres.fengsage.com','../media','http://www.fengsage.com'] conn = MySQLdb.connect(host="localhost", user="root", passwd="zhufeng", db="wordpress", charset='utf8') def get_post_list(): cursor = conn.cursor() cursor.execute("SET NAMES utf8") cursor.execute("select * from %s"%WP_POST_CONTENT); return cursor.fetchall() def find_img_urls(str): pattern = re.compile(SIMPLE_IMG_URL) match = pattern.findall(str) if match: return match return None def process_imgs(img_urls,replace): result = {} for img in img_urls: for rp in replace: if img.find(rp)>=0: print "\tdownload picture" new_img_ath = download_img(img) result.update({img:new_img_ath}) return result def download_img(img_url): IMG_NAME_REG = r'([^./]*).(png|jpg|gif|jpeg|bmp)' m = re.findall(IMG_NAME_REG, img_url) if m: name,suf = m[0] if os.path.isdir(DOWNLOAD_PATH) == False: os.makedirs(DOWNLOAD_PATH) file_path = u'%s/%s.%s'%(DOWNLOAD_PATH,name,suf) downloaded_image = file(file_path.encode('utf-8'), "wb") try: image_on_web = urllib.urlopen(img_url.encode('utf-8')) while True: buf = image_on_web.read(65536) if len(buf) == 0: break downloaded_image.write(buf) downloaded_image.close() image_on_web.close() return file_path except: print '\tdownload img failture:%s'%img_url def refresh_content(post_content,result): for k in result.keys(): post_content = post_content.replace(k,'%s/%s'%(NEW_IMG_URL,result[k])) return post_content def update_content(post_id,post_content): sql = "update "+WP_POST_CONTENT+" set post_content=%s where ID=%s" cursor = conn.cursor() cursor.execute("SET NAMES utf8") cursor.execute(sql,(post_content,post_id)) def go(): post_list = get_post_list() for post in post_list: post_id = post[0] post_content = post[4] post_title = post[5] if post_id and post_content and post_title: print "process article ID:%s"%(post_id) img_urls = find_img_urls(post_content) if img_urls: result = process_imgs(img_urls,REPLACE_LIST) if result and len(result)>0: post_content = refresh_content(post_content,result) try: update_content(post_id,post_content) except Exception, e: print 'update database failture:%s'%e if __name__ == '__main__': print go()
John Resig 开发的一个简易模板引擎,配合json非常的实用。
// Simple JavaScript Templating // John Resig - http://ejohn.org/ - MIT Licensed (function(){ var cache = {}; this.tmpl = function tmpl(str, data){ // Figure out if we're getting a template, or if we need to // load the template - and be sure to cache the result. var fn = !/\W/.test(str) ? cache[str] = cache[str] || tmpl(document.getElementById(str).innerHTML) : // Generate a reusable function that will serve as a template // generator (and which will be cached). new Function("obj", "var p=[],print=function(){p.push.apply(p,arguments);};" + // Introduce the data as local variables using with(){} "with(obj){p.push('" + // Convert the template into pure JavaScript str .replace(/[\r\t\n]/g, " ") .split("<%").join("\t") .replace(/((^|%>)[^\t]*)'/g, "$1\r") .replace(/\t=(.*?)%>/g, "',$1,'") .split("\t").join("');") .split("%>").join("p.push('") .split("\r").join("\\'") + "');}return p.join('');"); // Provide some basic currying to the user return data ? fn( data ) : fn; }; })();
很少的一点代码。但功能非常实用。
准备json和一个模板即可
近期评论