<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>廖雪峰的官方网站</title>
	<atom:link href="http://www.liaoxuefeng.com/feed" rel="self" type="application/rss+xml" />
	<link>http://www.liaoxuefeng.com</link>
	<description></description>
	<lastBuildDate>Thu, 26 Jan 2012 10:39:18 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.4</generator>
		<item>
		<title>2012新年计划</title>
		<link>http://www.liaoxuefeng.com/archives/260</link>
		<comments>http://www.liaoxuefeng.com/archives/260#comments</comments>
		<pubDate>Thu, 26 Jan 2012 10:38:31 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[生活·创意]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=260</guid>
		<description><![CDATA[回顾2011，收获还是不少的： 经过1年的开发，公司产品从零开始已经基本成熟，且在若干大型机构成功部署，反馈还不错； 认识了很多在不同行业的新朋友，极大地拓展了自己的视野； 购置了一台Mac Book Pro一台，iPhone4两部，iPad2一部，App若干（花费200RMB左右）； 闺女马上4岁了！ 虽然2012也可能是地球文明的最后一个年份，但做一个新年计划仍然是很有意义的，今年计划： 继续推进公司产品的开发，为早日IPO做好准备； 继续推进跑步减肥计划，从一口气5公里提升至10公里； 升级OS X至10.7，并通过iBook Authors写一本书，在iBooks上销售； 研究iOS开发，在AppStore发布一个App。]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/260/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SAE Python如何搭建本地开发环境</title>
		<link>http://www.liaoxuefeng.com/archives/255</link>
		<comments>http://www.liaoxuefeng.com/archives/255#comments</comments>
		<pubDate>Fri, 06 Jan 2012 08:23:14 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=255</guid>
		<description><![CDATA[SAE是Sina推出的AppEngine，目前支持Python运行环境。和所有PAAS一样，服务器环境和本地开发环境总是有区别，如果在开发和部署阶段不断修改代码，会非常繁琐。本文讲述如何在本地和服务器共享同一代码版本，可以在本地调试，服务器直接部署。 首先，因为Python本身的动态特性和强大而简介的语法，我们实现这一目标非常容易（在此对Java开发人员表示遗憾）。假定我们确定用web.py框架，mysql数据库，memcache缓存，这3个组件SAE都支持，但和本地环境均有差异。 首先我们看web.py在本地和SAE是如何运行的： # 本地 app = web.application(('/(.*)', 'PageHandler'), globals()) if __name__ == "__main__": app.run() # SAE app = web.application(('/(.*)', 'PageHandler'), globals()).wsgifunc() application = sae.create_wsgi_app(app) 将两者合并，我们得到一个既可以直接在本地运行，又可以直接在SAE运行的代码： app = web.application(('/(.*)', 'PageHandler'), globals()) if __name__ == "__main__": app.run() else: import sae application <a href="http://www.liaoxuefeng.com/archives/255">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/255/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>发布新浪微博Python SDK for OAuth 2.0</title>
		<link>http://www.liaoxuefeng.com/archives/251</link>
		<comments>http://www.liaoxuefeng.com/archives/251#comments</comments>
		<pubDate>Wed, 04 Jan 2012 03:55:59 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=251</guid>
		<description><![CDATA[sinaweibopy是支持OAuth 2.0的新浪微博Python SDK，也是新浪微博官方推荐的SDK。 运行环境：Python 2.5~2.7 依赖： 2.6以前的版本需要安装simplejson，2.6及以后版本内置json，无需任何依赖。 特色： 整个SDK仅一个py文件，代码长度保持在200行以内。 项目地址：http://code.google.com/p/sinaweibopy/ 下载：http://code.google.com/p/sinaweibopy/downloads/list 源码：http://code.google.com/p/sinaweibopy/source/browse/src/weibo.py]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/251/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>为什么自然数中存在无穷多个素数</title>
		<link>http://www.liaoxuefeng.com/archives/225</link>
		<comments>http://www.liaoxuefeng.com/archives/225#comments</comments>
		<pubDate>Mon, 29 Aug 2011 08:36:39 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=225</guid>
		<description><![CDATA[素数（又称质数）是自然数中的“基本数”，但是找出自然数的素数却是无公式可循的。自然数中是否存在无穷多个素数呢？答案是肯定的。伟大的数学家欧几里得在两千多年前就给出了极其简洁的证明。以下是欧几里得的证明： 证明：自然数中存在无穷多个素数 为了证明该命题，我们需要一个预备定理： 如果A，B都是x的倍数，且A&#62;B，则A-B也是x的倍数。 证明很简单：设A=a*x, B=b*x, 则A-B=a*x-b*x=(a-b)*x是x的倍数。 欧几里得运用反证法巧妙地证明了素数的无穷性。 我们首先假定自然数中只存在有限个素数，则我们一定可以把他们都找出来，不妨用集合(A，B，C，⋯⋯，Z)表示。 考察所有素数的乘积 x ＝ A * B * C * ⋯⋯ * Z x一定是合数，且x比任何一个素数都要大 再考察x+1，因为x+1比x大，x比任何一个素数都要大，则x+1一定也是和数，否则我们就在找出所有素数的基础上又发现了一个更大的素数，与假设冲突。 由于x+1是合数，那么我们就一定能对其分解质因数，假设分解出某个质因数为C，则C也是x的质因数，因为x是所有素数之积，故x包含质因数C。 考察 x+1和x之差：(x+1) &#8211; x = 1，根据预备定理，x+1和x都是C的倍数，所以(x+1) &#8211; x = 1也是C的倍数，但这是不可能的，因为最小的素数是2，1不可能是任何素数的倍数。 故命题不成立。 所以自然数中存在无穷多个素数。 由于自然数中存在无穷多个素数，所以寻找已知的最大的素数就成了全世界数学爱好者的乐趣。现在，借助计算机的威力，可以瞬间找出一亿以内的素数。 研究素数有什么实际的应用价值呢？两千年来，研究数论的数学家一直沉醉于研究本身，他们积累了大量的理论基础，随着近代科学的发展，越来越多的领域需要应用数论的知识。一个典型的领域便是密码学。 传统的密码学使用同一个密钥加密和解密，密钥本身的传输存在很大的问题，直到非对称加密算法的出现，使得我们可以用一个公钥加密，再通过一个私钥解密，RSA算法就是一个典型的非对称加密。 RSA算法的核心思想是基于分解质因数。可以很容易地选择两个非常大的素数并得到它们的乘积，反过来，给出一个非常大的合数，要分解质因数则是非常困难的，必须使用穷举算法。 <a href="http://www.liaoxuefeng.com/archives/225">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/225/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linux配置Lighttpd+Python+web.py应用</title>
		<link>http://www.liaoxuefeng.com/archives/217</link>
		<comments>http://www.liaoxuefeng.com/archives/217#comments</comments>
		<pubDate>Tue, 19 Jul 2011 04:06:45 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=217</guid>
		<description><![CDATA[用web.py写了一个app，由于官方网站推荐Lighttpd+fastcgi模式部署，于是实践一把，在Debian Squeeze Linux上成功安装了Lighttpd和基于web.py的应用。 服务器是Debian Sequeeze Linux，首先安装Lighttpd和Python，Python默认版本是2.6： # apt-get install lighttpd python 然后安装app使用的必要的Python包： # apt-get install python-setuptools python-flup python-webpy python-mysqldb python-simplejson python-imaging 下一步是配置Lighttpd，由于web.py应用的入口是app.py，所以Lighttpd需要把请求通过fastcgi传给app.py，lighttpd.conf配置如下： server.modules = ( "mod_access", "mod_accesslog", "mod_alias", "mod_compress", "mod_fastcgi", "mod_rewrite", ) server.document-root = "/path/to/app/dir" server.upload-dirs = ( "/var/cache/lighttpd/uploads" ) <a href="http://www.liaoxuefeng.com/archives/217">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/217/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Linux命令后台执行的方法</title>
		<link>http://www.liaoxuefeng.com/archives/210</link>
		<comments>http://www.liaoxuefeng.com/archives/210#comments</comments>
		<pubDate>Fri, 01 Jul 2011 03:14:31 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=210</guid>
		<description><![CDATA[当进程不是守护进程时，不能简单地在命令行后添加一个&#38;，当终端关闭时，该进程也随之关闭。因为通常在终端起动的进程其父进程是终端进程。当终端关闭时，其所有子进程也随之关闭。使进程在后台执行需要使用nohup命令： nohup command &#62; out.log 2&#62;&#38;1 &#38; nohup的作用是将进程的父进程设置为1，即init进程，这样终端关闭时，不会影响该进程。 使用2&#62;&#38;1将标准错误输出也重定向到标准输出中，因为预定义的STDIN，STDOUT，STDERR分别是0，1，2。]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/210/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>JavaScript如何在离开页面时提示用户</title>
		<link>http://www.liaoxuefeng.com/archives/207</link>
		<comments>http://www.liaoxuefeng.com/archives/207#comments</comments>
		<pubDate>Fri, 01 Jul 2011 01:16:16 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=207</guid>
		<description><![CDATA[如果用户正在页面执行比较重要的操作，如写博客，上传文件，此时，如果点其他链接、地址栏输入新地址或刷新页面时，应该给用户提示，确认是否离开当前页面，用JavaScript可轻松完成。 以下是微软官方给出的JS示例，经测试Firefox和Chrome运行正常： var is_uploading = false; function alert_if_uploading() { if (is_uploading) return '文件正在上传中，您确定要离开当前页面？'; } window.onbeforeunload = alert_if_uploading; 核心代码就是监听window的onbeforeunload事件。]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/207/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mac OS X 10.6安装RoR</title>
		<link>http://www.liaoxuefeng.com/archives/204</link>
		<comments>http://www.liaoxuefeng.com/archives/204#comments</comments>
		<pubDate>Mon, 23 May 2011 01:41:57 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=204</guid>
		<description><![CDATA[Mac OS X 10.6自带Ruby 1.8.7，不过RubyGem版本太低，无法安装Rails 3。参考Installing Ruby 1.9 and Rails 3 on Mac OS X可快速安装Rails 3开发环境。 首先，安装XCode 3或4，以确保GCC被安装在系统里用于编译Ruby。其次，安装Git，如果安装的最新的XCode 4，则Git已经被安装了。 然后，安装RVM： $ bash < ~/.bash_profile 关闭Console并再次打开，就可以检查RVM是否已经添加到当前profile： type rvm &#124; head -1 rvm is a function 安装Ruby 1.9.2： rvm install ruby RVM会自动下载最新版Ruby源码，然后编译、安装。 <a href="http://www.liaoxuefeng.com/archives/204">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/204/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>uwsgi的多站点配置</title>
		<link>http://www.liaoxuefeng.com/archives/198</link>
		<comments>http://www.liaoxuefeng.com/archives/198#comments</comments>
		<pubDate>Sat, 07 May 2011 08:10:47 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=198</guid>
		<description><![CDATA[uwsgi似乎是目前部署python站点最方便的组件了。配置单一网站非常简单，参考Debian Lenny安装nginx+uwsgi可轻松完成。不过，同一个服务器部署多个站点就稍微复杂一点。经过一个晚上的折腾，终于配置成功。 这里的多站点是指使用同一Nginx和uwsgi主进程服务的多个站点，通常以域名区分。注意，不是使用多个uwsgi主进程实现。 首先，多站点需要Python的virtualenv支持。这个virtualenv很强大，基本作用是帮助我们隔离出一个干净的Python环境，例如，环境A安装了Django 0.9，环境B安装了Django 1.1，如果没有virtualenv，则需要自己管理这些包的路径。有了virtualenv，各个Python环境互不影响，多个站点使用各自的Python环境，同一组件的不同版本不会冲突。virtualenv的实现方式也很简单，就是复制一份完整的Python环境到单独的目录，并设置若干环境变量。一旦进入某一env，所有操作均在该目录下进行，不会影响其他env环境。所以virtualenv实乃开发必备的武器。 安装virtualenv需要root或sudo权限： # easy_install virtualenv 然后，创建一个env环境： # mkdir /srv/vpython # cd /srv/vpython # virtualenv --no-site-packages shici 现在，就创建了一个虚拟的Python环境，名为shici，加上&#45;&#45;no-site-packages是告诉virtualenv不从系统Python的site-packages下复制第三方的包。 进入虚拟shici环境： # cd /srv/vpython/shici # source bin/activate 会看到提示符前面多了一个(shici)。现在运行python，可以看到sys.path已经更改为/srv/vpython/shici目录下的各个包。 运行easy_install安装需要的包，现在安装的包将全部安装到shici环境中，不影响系统Python环境和其他env环境。 装完需要的包后，用deactivate命令退出虚拟环境。 第二步，修改/etc/init.d/uwsgi启动脚本，以vhost模式启动： #if [ -f /etc/default/uwsgi ] ; then <a href="http://www.liaoxuefeng.com/archives/198">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/198/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>安装Mac OS X 10.6 Python开发环境</title>
		<link>http://www.liaoxuefeng.com/archives/196</link>
		<comments>http://www.liaoxuefeng.com/archives/196#comments</comments>
		<pubDate>Thu, 21 Apr 2011 15:17:02 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=196</guid>
		<description><![CDATA[Mac OS X是非常优秀的系统，用惯了OSX后就再也不想切回到Windows上了。在OS X上可以搭建常用的开发环境，我的OS X 10.6已经自带Java 6，Python 2.5/2.6，Ruby 1.8.7。不过，安装一些开发环境还是跟Windows和Linux有所不一样。 默认的Python是2.6 64bit版本，如果要切回2.5，参考Apple官网给出的方法：http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/python.1.html % defaults write com.apple.versioner.python Version 2.5 以上针对当前用户生效。如果要让整个系统切到2.5版本，使用： % sudo defaults write /Library/Preferences/com.apple.versioner.python Version 2.5 安装MySQL 5.5 Server后，使用easy_install安装MySQL-python失败，提示找不到mysql_config。因为mysql_config不在默认搜索路径下。使用如下命令将其放到PATH中： $ sudo env PATH="$PATH:/usr/local/mysql/bin" easy_install MySQL-python 就可以成功安装了。不过，import MySQLdb会失败，提示Library not loaded: libmysqlclient.18.dylib。这是因为没有在PATH中找到libmysqlclient.18.dylib，该文件位于/usr/local/mysql/lib下。解决办法是创建一个软链接： $ <a href="http://www.liaoxuefeng.com/archives/196">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/196/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>中华诗词网www.shi-ci.com正式支持微博登录</title>
		<link>http://www.liaoxuefeng.com/archives/193</link>
		<comments>http://www.liaoxuefeng.com/archives/193#comments</comments>
		<pubDate>Thu, 21 Apr 2011 01:02:10 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[生活·创意]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=193</guid>
		<description><![CDATA[中华诗词网（http://www.shi-ci.com）正式支持微博登录，无需注册，您可以直接以微博账号登录，发表的诗评将直接同步到您的微博，使用更方便，欢迎访问！]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/193/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python的XML SAX解析简明教程</title>
		<link>http://www.liaoxuefeng.com/archives/189</link>
		<comments>http://www.liaoxuefeng.com/archives/189#comments</comments>
		<pubDate>Sat, 02 Apr 2011 02:08:35 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=189</guid>
		<description><![CDATA[在Python中使用SAX解析XML非常简洁，通常我们关心的事件是start element，end element和char data，准备好这3个函数，然后就可以解析xml了： import logging from xml.parsers.expat import ParserCreate class DefaultSaxHandler(object): def start_element(self, name, attrs): logging.info('sax:start_element: %s, attrs: %s' % (name, str(attrs))) def end_element(self, name): logging.info('sax:end_element: %s' % name) def char_data(self, text): logging.info('sax:char_data: %s' % text) xml = load_xml_data() <a href="http://www.liaoxuefeng.com/archives/189">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/189/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linux下查看内存</title>
		<link>http://www.liaoxuefeng.com/archives/187</link>
		<comments>http://www.liaoxuefeng.com/archives/187#comments</comments>
		<pubDate>Fri, 25 Mar 2011 05:51:32 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=187</guid>
		<description><![CDATA[在Linux下可以用free查看内存，不过，在xen环境里只能看到该domain占用的内存，如果要看整个服务器的实际物理内存，可以用dmidecode命令。 参数-t可以指定查看类型，例如查看内存： # dmidecode -t memory &#124; grep Size Size: 2048 MB Size: 2048 MB Size: 2048 MB Size: 2048 MB 以上显示共有2GB的内存条4根，总内存大小为8GB。]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/187/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SimpleJdbc: 用于简化数据库操作的Java库</title>
		<link>http://www.liaoxuefeng.com/archives/180</link>
		<comments>http://www.liaoxuefeng.com/archives/180#comments</comments>
		<pubDate>Fri, 11 Mar 2011 01:30:34 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=180</guid>
		<description><![CDATA[我不喜欢Hibernate之类的ORM，因为它会自动给你把一对多和多对一的级联记录给查出来，一级缓存没啥用，二级缓存用处不大。取出的对象还是经过CGLIB代理的，Attach/Detach的状态尤其令人讨厌。对企业应用可能ORM还适合，但Web应用就应该简洁明了，一切以简单、性能和扩展为目标。 JDBC速度最快，但代码量大。Spring的JdbcTemplate做了很好的封装，但仍旧需要RowMapper。SimpleJdbc是对Spring JdbcTemplate的进一步封装，将所有的数据库操作API全部集中在一个Db对象中，且没有任何额外的RowMapper或DAO接口。 SimpleJdbc的灵感源于web.py的db模块。借助Python的动态类型以及关键字参数，web.py的db提供了令人赞叹的简洁的API。 Java 5及其后续版本增加的唯一“动态”特性便是可变个数的参数，SimpleJdbc充分利用该特性来简化API。不幸的是，随着SUN被Oracle收购以及Oracle确认Java将继续沿企业路线发展，Java将越来越不适合web开发。 SimpleJdbc一个查询的典型用法如下： // 按ID查询： User user = db.getById(User.class, 12300); if (user==null) throw new RuntimeException("user is not exist"); // 查询单个对象： User user = db.queryForObject("select * from User where name=? and passwd=?", "Michael", "passwd"); if (user==null) throw <a href="http://www.liaoxuefeng.com/archives/180">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/180/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>双网卡机器的xen配置</title>
		<link>http://www.liaoxuefeng.com/archives/176</link>
		<comments>http://www.liaoxuefeng.com/archives/176#comments</comments>
		<pubDate>Mon, 07 Mar 2011 02:25:14 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=176</guid>
		<description><![CDATA[在为xen创建虚拟LAN一文里，配置了一个真实网卡和一个虚拟网卡作为内网的网关，通常服务器都有双网卡，如果有双线机房+双线IP，则需要充分利用双线IP。每个domU依然只分配内网IP，但是，dom0拥有3个接口： eth0：第一个物理网卡； eth1：第二个物理网卡； dummy0：虚拟网卡。 首先在/etc/network/interfaces配置文件里为lo以及eth0和eth1配置好公网IP。 当xend接管物理网卡后，将为每个网卡创建虚拟的网桥，对应的名称分别为： eth0 -&#62; peth0 -&#62; xenbr0； eth1 -&#62; peth1 -&#62; xenbr1； dummy0 -&#62; pdummy0 -&#62; xenbr2。 顺序由/etc/network/interfaces里的配置顺序确定，一般是eth0，eth1，dummy0。 因此，把自定义脚本/etc/xen/scripts/my_network_script稍作修改： #!/bin/sh dir=$(dirname "$0") "$dir/network-bridge" "$@" vifnum=0 netdev=eth0 bridge=xenbr0 "$dir/network-bridge" "$@" vifnum=1 netdev=eth1 bridge=xenbr1 "$dir/network-bridge" "$@" vifnum=2 netdev=dummy0 <a href="http://www.liaoxuefeng.com/archives/176">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/176/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL 5中文编码快速设置</title>
		<link>http://www.liaoxuefeng.com/archives/173</link>
		<comments>http://www.liaoxuefeng.com/archives/173#comments</comments>
		<pubDate>Thu, 03 Mar 2011 06:44:29 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=173</guid>
		<description><![CDATA[这里的中文编码设置实际上就是设置UTF-8编码，这样所有的语言都能正常在MySQL存储和读取。本文是针对Linux平台的，Windows平台可以直接运行配置向导，然后选择UTF-8编码即可。 在Linux平台，MySQL 5的配置文件位于/etc/my.cnf或者/etc/mysql/my.cnf，打开该文件，在[client]后添加： default-character-set=utf8 在[mysqld]后添加： default-storage-engine=INNODB character-set-server=utf8 collation-server=utf8_general_ci default-character-set=utf8 # 注：MySQL 5.5不支持该选项，应注释掉 然后重启MySQL，进入命令行模式查看： mysql> use mydatabase; mysql> show variables like '%char%'; +--------------------------+----------------------------+ &#124; Variable_name &#124; Value &#124; +--------------------------+----------------------------+ &#124; character_set_client &#124; utf8 &#124; &#124; character_set_connection &#124; utf8 &#124; &#124; character_set_database <a href="http://www.liaoxuefeng.com/archives/173">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/173/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linux安装ActiveMQ</title>
		<link>http://www.liaoxuefeng.com/archives/169</link>
		<comments>http://www.liaoxuefeng.com/archives/169#comments</comments>
		<pubDate>Mon, 28 Feb 2011 06:08:23 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=169</guid>
		<description><![CDATA[ActiveMQ是一款流行的Message服务器，在Windows开发环境下，一般可以直接运行命令行，或者在Spring中以嵌入式启动。在生产环境中，ActiveMQ需要在Linux上部署，以下是快速安装步骤。 1. 安装JDK 6： # apt-get install sun-java6-jdk 2. 下载activemq Linux二进制版本，解压： # wget http://labs.renren.com/apache-mirror//activemq/apache-activemq/5.4.2/apache-activemq-5.4.2-bin.tar.gz # tar zxvf /path/to/apache-activemq-5.4.2-bin.tar.gz /opt/ # ln -s /opt/apache-activemq-5.4.2 /opt/activemq 以上用人人网的镜像下载，然后在/opt/activemq创建了软链接。 3. 修改启动脚本/opt/activemq/bin/activemq，将开头处改为： #!/bin/sh ### BEGIN INIT INFO # Provides: activemq # Required-Start: $remote_fs $syslog # <a href="http://www.liaoxuefeng.com/archives/169">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/169/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>为xen创建虚拟LAN</title>
		<link>http://www.liaoxuefeng.com/archives/161</link>
		<comments>http://www.liaoxuefeng.com/archives/161#comments</comments>
		<pubDate>Fri, 25 Feb 2011 07:53:18 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=161</guid>
		<description><![CDATA[在Debian Squeeze上安装xen一文中，我们讨论了在局域网内部创建xen的方法，dom0和每个domU都使用相同的网段地址和网关，这种配置简单，但仅适用于局域网，因为IP数量够用，而且可以随意分配。 不过，在公网上，通常只有1个公网IP地址，domU只能分配私有IP地址，因此需要如下功能才能让domU正常服务： 1. 各个domU之间能互相通信； 2. domU能通过dom0作为网关访问Internet； 3. dom0通过NAT将某些domU的服务暴露到Internet上。 为此，首先需要为domU创建一个虚拟的局域网，例如网段设置为172.16.16.0，dom0拥有两个网络接口： eth0：公网IP； dummy0：虚拟网络接口，作为内部网络的网关，地址为172.16.16.1 因此，首先为dom0创建虚拟的网络接口： # modprobe dummy 向/etc/modules追加一行： # echo dummy &#62;&#62; /etc/modules 编辑/etc/network/interfaces，增加dummy0的配置： auto dummy0 iface dummy0 inet static address 172.16.16.1 netmask 255.255.255.0 broadcast 172.16.16.255 启动dummy0： # ifup dummy0 启用IP <a href="http://www.liaoxuefeng.com/archives/161">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/161/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Debian Linux安装NFS</title>
		<link>http://www.liaoxuefeng.com/archives/158</link>
		<comments>http://www.liaoxuefeng.com/archives/158#comments</comments>
		<pubDate>Wed, 23 Feb 2011 07:40:12 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=158</guid>
		<description><![CDATA[要在两台Linux电脑上共享一个目录，最简单的方式是使用NFS，将一台电脑的目录映射到另一台。 在Debian上实现NFS非常容易，首先，在作为服务端的电脑192.168.1.99上安装： # apt-get install nfs-common nfs-kernel-server 创建需要共享的目录： # mkdir /srv/upload # chmod a+w /srv/upload 然后修改/etc/exports文件，将需要共享的目录和客户端添加进来： /srv/upload 192.168.1.100(rw,sync) 表示允许IP为192.168.1.100的客户端以rw的模式访问。如果以只读模式访问则设置为ro。 然后启动服务： # /etc/init.d/nfs-kernel-server start 在客户端安装NFS： # apt-get install nfs-common 创建目录并挂载NFS： # mkdir /mnt/upload # mount 192.168.1.99:/srv/upload /mnt/upload 此时已经可以写入/mnt/upload，对应的服务器端可以看到创建的文件。 要在客户端每次启动时自动挂载NFS，可以编辑/etc/fstab，添加一行： 192.168.1.99:/srv/upload /mnt/upload <a href="http://www.liaoxuefeng.com/archives/158">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/158/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>web.py数据库入门</title>
		<link>http://www.liaoxuefeng.com/archives/154</link>
		<comments>http://www.liaoxuefeng.com/archives/154#comments</comments>
		<pubDate>Thu, 17 Feb 2011 06:37:13 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=154</guid>
		<description><![CDATA[web.py是一个非常精巧的web框架，不过其自带的db模块也是非常精简而高效。和Java里面复杂的JDBC和繁琐的Hibernat配置相比，使用web.db真是既简单又明了。 创建数据库对象： db = web.database(dbn=&#8217;mysql&#8217;, user=&#8217;user&#8217;, pw=&#8217;pass&#8217;, db=&#8217;dbname&#8217;) dbn指定数据库类型 查询： users = db.query(&#8216;select * from user where id&#62;$id&#8217;, vars={&#8216;id&#8217;:100}) for user in users: print user.id, user.name 查询参数用$var_name表示，查询时用vars dict中的值替换。 查询得到的是迭代对象，直接循环。 至于每个对象的具体属性，和字段名一一对应。没有任何预定义的class，没有映射和配置，一切都是约定，你需要的是自己管理好数据库字段的命名。 插入： db.insert(&#8216;user&#8217;, name=&#8217;Michael&#8217;, age=29, passwd=&#8217;passwd&#8217;, email=&#8217;abc@xyz.com&#8217;) 插入利用了python的**kw提供字段值，非常方便。 修改： db.update(&#8216;user&#8217;, where=&#8217;id=$id&#8217;, <a href="http://www.liaoxuefeng.com/archives/154">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/154/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Debian Squeeze上安装xen</title>
		<link>http://www.liaoxuefeng.com/archives/143</link>
		<comments>http://www.liaoxuefeng.com/archives/143#comments</comments>
		<pubDate>Wed, 16 Feb 2011 06:54:28 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=143</guid>
		<description><![CDATA[现在服务器虚拟化趋势越来越明显了，一方面服务器硬件越来越强大，一台服务器只跑一个系统非常浪费，另一方面虚拟机管理比物理机方便得多，而且迁移非常容易。 为了搭建测试环境，决定把一台测试服务器变为运行xen的虚拟服务器。服务器硬件配置： Intel Core 2 Quad 2.66 GHz，4核8线程，4GB 内存，500GB 硬盘 操作系统：Debian 6.0 Squeeze AMD64，因为Debian的维护和管理非常方便，而且6.0已经将xen升级到4.0版本了，在Squeeze上创建xen非常容易。 主要参考官方文档： http://wiki.debian.org/Xen 1. 安装Debian 6 Squeeze AMD64： 分区：全部分给LVM，VG：vg001 /分区：vg001-linux&#8211;root /home分区：vg001-linux&#8211;home /srv分区：vg001-linux&#8211;srv ext4格式，各10GB。 swap分区：4GB 注意：强烈推荐使用lvm，因为xen运行在lvm上的IO效率比文件高好几倍，而且便于管理。 2. 安装xen image： aptitude -P install xen-hypervisor-4.0-amd64 linux-image-xen-amd64 3. 修改grub 由于xen kernel不是默认启动的kernel，修改grub，把xen <a href="http://www.liaoxuefeng.com/archives/143">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/143/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Debian Lenny安装nginx+uwsgi</title>
		<link>http://www.liaoxuefeng.com/archives/141</link>
		<comments>http://www.liaoxuefeng.com/archives/141#comments</comments>
		<pubDate>Wed, 16 Feb 2011 02:24:45 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=141</guid>
		<description><![CDATA[已有的python web应用程序是用web.py开发的，支持wsgi。为了搭建Linux部署环境，准备采用nginx+uwsgi方式。 服务器环境：Linode VPS安装Debian Lenny 32位版本。 安装过程主要参考linode的文档： http://library.linode.com/web-servers/nginx/python-uwsgi/debian-5-lenny 不过，实际安装中还是遇到了很多问题，特记录以便备查。 问题： 安装完Python和MySQL Server后，安装MySQL-python出错，提示：EnvironmentError: mysql_config not found。 原因： 缺少mysql的dev包。 解决方案： 安装libmysqlclient-dev包：apt-get install libmysqlclient-dev。 问题： 运行uwsgi出错，提示ExtractionError: Can&#8217;t extract file(s) to egg cache。 原因： 一些包是以压缩包提供的，运行时需要解压缩，默认的解压缩目录权限对uwsgi进程用户uwsgi权限不够。 解决方案： 新建/srv/PYTHON_EGG_CACHE目录，设置权限chown uwsgi:uwsgi，在/etc/init.d/uwsgi脚本中增加： export PYTHON_EGG_CACHE=/srv/PYTHON_EGG_CACHE 问题： 运行uwsgi继续报错，提示wsgi application not <a href="http://www.liaoxuefeng.com/archives/141">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/141/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>设计REST风格的MVC框架</title>
		<link>http://www.liaoxuefeng.com/archives/138</link>
		<comments>http://www.liaoxuefeng.com/archives/138#comments</comments>
		<pubDate>Tue, 15 Feb 2011 09:09:16 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[出版·文章]]></category>
		<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=138</guid>
		<description><![CDATA[本文最早发表于IBM developerWorks： http://www.ibm.com/developerworks/cn/java/j-lo-restmvc/ 传统的JavaEE MVC框架如Struts等都是基于Action设计的后缀式映射，然而，流行的Web趋势是REST风格的架构。尽管使用Filter或者Apache mod_rewrite能够通过URL重写实现REST风格的URL，为什么不直接设计一个全新的REST风格的MVC框架呢？本文将讲述如何从头设计一个基于REST风格的Java MVC框架，配合Annotation，最大限度地简化Web应用的开发，您甚至编写一行代码就可以实现“Hello, world”。 Java开发者对MVC框架一定不陌生，从Struts到WebWork，Java MVC框架层出不穷。我们已经习惯了处理*.do或*.action风格的URL，为每一个URL编写一个控制器，并继承一个Action或者Controller接口。然而，流行的Web趋势是使用更加简单，对用户和搜索引擎更加友好的REST风格的URL。例如，来自豆瓣的一本书的链接是http://www.douban.com/subject/2129650/，而非http://www.douban.com/subject.do?id=2129650。 有经验的 Java Web 开发人员会使用 URL 重写的方式来实现类似的URL，例如，为前端Apache服务器配置mod_rewrite模块，并依次为每个需要实现URL重写的地址编写负责转换的正则表达式，或者，通过一个自定义的 RewriteFilter，使用Java Web服务器提供的Filter和请求转发（Forward）功能实现URL重写，不过，仍需要为每个地址编写正则表达式。 既然URL重写如此繁琐，为何不直接设计一个原生支持REST风格的MVC框架呢？ 要设计并实现这样一个MVC框架并不困难，下面，我们从零开始，仔细研究如何实现REST风格的URL映射，并与常见的IoC容器如Spring框架集成。这个全新的MVC框架暂命名为 WebWind。 术语 MVC：Model-View-Controller，是一种常见的UI架构模式，通过分离Model（模型）、View（视图）和Controller（控制器），可以更容易实现易于扩展的UI。在Web应用程序中，Model 指后台返回的数据；View指需要渲染的页面，通常是JSP或者其他模板页面，渲染后的结果通常是HTML；Controller 指 Web 开发人员编写的处理不同URL的控制器（在Struts中被称之为 Action），而 MVC 框架本身还有一个前置控制器，用于接收所有的 URL 请求，并根据 URL 地址分发到 Web 开发人员编写的Controller中。 IoC：Invertion-of-Control，控制反转，是目前流行的管理所有组件生命周期和复杂依赖关系的容器，例如 Spring 容器。 Template：模板，通过渲染，模板中的变量将被Model的实际数据所替换，然后，生成的内容即是用户在浏览器中看到的 <a href="http://www.liaoxuefeng.com/archives/138">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/138/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>高效使用JavaEE ORM框架</title>
		<link>http://www.liaoxuefeng.com/archives/136</link>
		<comments>http://www.liaoxuefeng.com/archives/136#comments</comments>
		<pubDate>Tue, 15 Feb 2011 09:06:05 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=136</guid>
		<description><![CDATA[虽然Java领域有无数的ORM框架，如Hibernate，iBatis，TopLink，JDO，JPA……但是这些ORM框架基本上大同小异。很多初学者对JDBC的复杂性望而却步，就简单认为使用ORM就会省时省力，结果恰恰相反，任何好的框架都是给专家准备的，任何急功近利试图偷懒的方法往往适得其反。要正确使用ORM还真不是一件简单的事情。本文仅简单整理一下ORM的原理，基本用法，以及如何避免各种陷阱的基本编程原则。 ORM的原理 先说ORM的实现原理。其实，要实现JavaBean的属性到数据库表的字段的映射，任何ORM框架不外乎是读某个配置文件把JavaBean的属性和数据库表的字段自动关联起来，当从数据库Query时，自动把字段的值塞进JavaBean的对应属性里，当做INSERT或UPDATE时，自动把JavaBean的属性值绑定到SQL语句中。但是，几乎所有的ORM都提供“按需读取”的功能，比如一个User有id，name，email和address这4个字段，但是address字段很少用，于是ORM只读取前3个字段，直到调用User的getAddress()方法时，才去数据库中读取address的值。这个功能显然不能通过User的get/set完成，因此，ORM需要采用某种方式生成一个User类的子类，并且覆写get/set方法，这样，才能在调用get方法时有机会从数据库中读取。类似的对User的修改检测也是这样实现的。 两种增强的方式 ORM为我们自己的JavaBean实现子类的方法很多，这个过程简单称之为“增强”，基本上有两种方法：Hibernate使用CGLIB在加载我们的User类时动态创建了一个子类，而JDO则要求编译完User类后再利用它提供的工具对User类进行改造，以便实现JDO需要的各种接口。请注意：就是这种极其变态的设计导致了使用JDO的极大困难，在我们编译完源码后，还需要额外执行一个增强命令，或者额外编写Ant任务，极大地影响了快速开发和单元测试，所以，凡是采用静态生成持久类的ORM，要在第一时间直接排除，切记！ 理解持久和非持久状态 所有的ORM框架都有持久和非持久的概念。简单地说，当我们new一个User实例时，它是非持久对象，当我们调用ORM的save()之类的方法后，这个实例就变成持久对象了。当我们通过ORM从数据库读取到一个User对象时，这个对象是持久对象，当关闭当前的事务后，这个对象变成非持久对象。 虽然这个过程很容易理解，但是，难点在于当我们设计一个方法时，我们必须准确地知道当前操作的对象是持久对象还是非持久对象，否则，各种灵异事件会接踵而来，比如插入了重复记录等等。举例说明，当我们需要创建一个User对象时，save(User)方法必须传入非持久对象，当我们需要更新一个User对象时，update(User)方法必须传入一个持久对象，有些ORM比如Hibernate，为了方便用户，提供了saveOrUpdate()方法，自动判断是否是持久对象，是则更新，否则创建。我的建议是永远不要使用这些看上去很简单的方法，否则将很难判断ORM到底做了什么操作，也就很难追踪到逻辑错误。 正确使用CRUD 正因为我们需要时刻区分一个对象的持久化状态，所以，编写CRUD（Create，Retrieve，Update，Delete的缩写）要严格遵循以下原则： Create：对于Create操作，传入的永远是非持久化对象，一旦调用了create方法，就变成持久化对象； Retrieve：所有通过ORM从数据库读取的对象都是持久化对象，直到当前会话结束； Update：对于Update操作，传入的必须是持久化对象，而通常需要更新的对象是从页面获得的，因此，编写Update方法要按照以下步骤： 从Web页面中获得了一个User对象（包含ID），这个对象肯定是非持久化对象； 当得到该User对象时，千万不可直接做Update操作，因为从Web页面得到的数据都是不可信任的，修改HTTP请求非常简单，有经验的开发人员利用一个FireFox插件就能完成。正确的做法是根据该User对象的ID从数据库中查询到持久化的User对象，然后把待修改的属性复制到持久化的User对象中，最后Update该持久化的User对象，简单的代码如下： void update(User u) { // 从数据库读取User： User p = load(User.class, u.getId()); // 检查当前用户有无权限修改： // TODO: ... // 复制属性： p.setName(u.getName()); p.setAddress(u.getAddress()); // 不允许修改的属性例如email就不要复制了，然后更新： update(p); } Delete：对于Delete操作，ORM通常只关心映射到主键的ID属性，不过，正确的做法仍然是根据ID先通过ORM读取，然后判断权限，最后删除。简单的代码如下： <a href="http://www.liaoxuefeng.com/archives/136">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/136/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>用Linux替代Windows</title>
		<link>http://www.liaoxuefeng.com/archives/134</link>
		<comments>http://www.liaoxuefeng.com/archives/134#comments</comments>
		<pubDate>Tue, 15 Feb 2011 09:04:18 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=134</guid>
		<description><![CDATA[Windows虽然有简单易用的特点，不过，作为一名专业的软件开发人员，使用Linux作为开发平台，还是有很大的优越性的。 首先，Windows下的软件大多是收费的，虽然网上的破解也不少，不过，在公司使用说不定哪天就有麻烦了，而Linux下的软件基本上都是免费而且开源的，虽然公开源代码对我等只用不改造的用户来说意义不大，不过，免费却是实实在在的。 其次，作为一名软件开发人员，许多服务器软件只能在Linux下运行，有的虽然已经移植到了Windows上，运行效率和稳定性却要大打折扣。 不过，和Windows用户的担心一样，使用Linux，如果不能听MP3，不能看大片，仅仅在Linux上工作也不太爽，毕竟要劳逸结合嘛。好在Linux下的多媒体软件已经今非昔比了，今天，我们就一步一步打造一个工作＋娱乐一体的Linux环境。 选择什么Linux？ Linux发行版众多，有商业公司支持的，也有开源社区支持的，不同的Linux发行版侧重也不同，有的Linux比如Gentoo，完全面向Linux发烧级用户的，从源代码编译开始。对于普通开发者而言，入门容易，安装软件快捷简便是最重要的两点。我的选择是Debian Linux，最新版本是5。相对于其他Linux版本，Debian的最大的优势就是软件众多，安装极为简单。有许多用户可能用过或听说过Red Hat的RPM软件包，不过，和Debian的DEB相比，RPM就差远了！ 另外，Debian是一个社区维护的Linux发行版，和倾向于提供傻瓜式操作的Ubuntu相比，Debian显得更加“专业”一点，动手能力要求更高一点，便于和普通的Windows用户拉开更大的差距。 安装Debian Linux 闲话少说，要安装Debian Linux，先去Debian官方网站下载刻盘，根据计算机类型选相应的ISO，通常是i386，用AMD64处理器的可以选amd64，建议以HTTP/FTP方式下载第一张ISO光盘，比如i386对应的CD： http://cdimage.debian.org/debian-cd/5.0.2a/i386/iso-cd/ 选择netinst方式的ISO虽然下载较快，但是安装过程中需要联网，毕竟麻烦。 下载后刻盘，从光盘启动，安装过程很简单，主要是分区要注意，最好手动分区，然后把引导区安装到MBR上，Debian会自动发现已安装的Windows，双系统启动没有问题。 安装时会要求输入APT源，就是将来安装软件的下载地址了，我通常选择ftp.us.debian.org，速度那是非常地快。 安装过程中可以安装桌面，也可以不装。如果没有安装，用root登录后手动安装： # apt-get install gnome 然后桌面就搞定了。 中文支持 使用Linux的第一个大问题就是要搞定中文。虽然Linux实际上完美支持各种语言，不过还是要稍微配置一下。在Debian中配置中文是相对简单的，运行命令 # dpkg-reconfigure locales 把以下的编码选中： en_US.UTF-8 UTF-8 zh_CN GB2312 zh_CN.GB18030 GB18030 zh_CN.GBK GBK zh_CN.UTF-8 UTF-8 也可以顺便把BIG5编码选上： <a href="http://www.liaoxuefeng.com/archives/134">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/134/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>将Flex集成到Java EE应用程序的最佳实践</title>
		<link>http://www.liaoxuefeng.com/archives/124</link>
		<comments>http://www.liaoxuefeng.com/archives/124#comments</comments>
		<pubDate>Tue, 15 Feb 2011 09:02:43 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[出版·文章]]></category>
		<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=124</guid>
		<description><![CDATA[本文最早发表于IBM developerWorks： http://www.ibm.com/developerworks/cn/java/j-lo-jeeflex/ 传统的Java EE应用程序通常使用某种MVC框架（例如，Struts）作为前端用户界面，随着Flex的兴起，基于RIA的客户端能够给用户带来更酷的界面，更短的响应时间，以及更接近于桌面应用程序的体验。本文将讲述如何将Flex集成至一个现有的Java EE应用程序中，以及如何应用最佳实践高效率地并行开发Java EE和Flex。 开发环境 本文的开发环境为Windows 7 Ultimate，Eclipse 3.4，Flex Builder 3。Java EE服务器使用Resin 3.2，当然，您也可以使用Tomcat等其他Java EE服务器。 现有的Java EE应用 假定我们已经拥有了一个管理雇员信息的Java EE应用，名为EmployeeMgmt-Server，结构如图所示： 这是一个典型的Java EE应用，使用了流行的Spring框架。为了简化数据库操作，我们使用了内存数据库HSQLDB。对这个简单的应用，省略了DAO，直接在Façade中通过Spring的JdbcTemplate操作数据库。最后，EmployeeMgmt应用通过Servlet和JSP页面为用户提供前端界面： 该界面为传统的HTML页面，用户每次点击某个链接都需要刷新页面。由于Employee Management系统更接近于传统的桌面应用程序，因此，用Flex重新编写界面会带来更好的用户体验。 集成BlazeDS 如何将Flex集成至该Java EE应用呢？现在，我们希望用Flex替换掉原有的Servlet和JSP页面，就需要让Flex和Java EE后端通信。Flex支持多种远程调用方式，包括HTTP，Web Services和AMF。不过，针对Java EE开发的服务器端应用，可以通过集成BlazeDS，充分利用AMF协议并能轻易与Flex前端交换数据，这种方式是JavaEE应用程序集成Flex的首选。 BlazeDS是Adobe LifeCycle Data Services的开源版本，遵循LGPL v3授权，可以免费使用。BlazeDS为Flex提供了基于AMF二进制协议的远程调用支持，其作用相当于Java的RMI。有了BlazeDS，通过简单的配置，一个Java接口就可以作为服务暴露给Flex，供其远程调用。 尽管现有的EmployeeMgmt应用程序已经有了Façade接口，但这个接口是暴露给Servlet使用的，最好能再为Flex定义另一个接口FlexService，并隐藏Java语言的特定对象： public interface FlexService <a href="http://www.liaoxuefeng.com/archives/124">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/124/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>如何卸载Eclipse中已安装的插件</title>
		<link>http://www.liaoxuefeng.com/archives/120</link>
		<comments>http://www.liaoxuefeng.com/archives/120#comments</comments>
		<pubDate>Tue, 15 Feb 2011 03:51:22 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=120</guid>
		<description><![CDATA[最近才知道原来Eclipse还可以自己卸载已经安装的插件，方法是点击菜单“Help”，“Install New Software&#8230;”，在弹出的对话框中选择那个非常隐蔽的“already installed”链接： 然后就显示已经安装的插件： 现在就可以选择要卸载的插件，然后点“Uninstall&#8230;”把它卸载掉。 这个方法对Eclipse Galileo (3.5)有效，其他版本你需要自己试一下。]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/120/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>为本地Subversion库链接外部资源库</title>
		<link>http://www.liaoxuefeng.com/archives/118</link>
		<comments>http://www.liaoxuefeng.com/archives/118#comments</comments>
		<pubDate>Tue, 15 Feb 2011 03:49:43 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=118</guid>
		<description><![CDATA[在使用Subversion进行版本管理时，有时候需要将其他资源库的一部分链接到我们自己资源库中，例如，本地已经存在的Project已经被Subversion管理了，但是，需要引入gdata等第三方库，当然可以直接将第三方发布的lib放到本地，但是，无法做到实时更新。由于Subversion支持external形式的外链，我们就可以将外部库的一部分当作本地Project的一部分。 以gdata为例，我们需要在本地的src目录下引入gdata的两个目录： atom：http://gdata-python-client.googlecode.com/svn/trunk/src/atom gdata：http://gdata-python-client.googlecode.com/svn/trunk/src/gdata 则需要通过svn命令实现。首先切换到src所在目录的父目录，新建文本文件externals.txt，内容如下： atom http://gdata-python-client.googlecode.com/svn/trunk/src/atom gdata http://gdata-python-client.googlecode.com/svn/trunk/src/gdata 给src目录加上svn:externals属性，使用以下命令： C:\projects\my_project&#62; svn propset svn:externals -F externals.txt src -F参数告诉SVN属性&#8221;svn:externals&#8221;的内容从文件externals.txt中读取，然后，对src目录做update操作，就会看到类似如下的输出： Updating external location at: C:/projects/my_project/src/atom ... Updating external location at: C:/projects/my_project/src/gdata ... 最后，在src目录下，可以看到，自动创建了引入的两个外部资源库的目录：atom和gdata。]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/118/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>在Debian上可以安装Google Chrome了</title>
		<link>http://www.liaoxuefeng.com/archives/114</link>
		<comments>http://www.liaoxuefeng.com/archives/114#comments</comments>
		<pubDate>Tue, 15 Feb 2011 03:48:22 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=114</guid>
		<description><![CDATA[现在，Google Chrome浏览器已经有了unstable的Linux版本，而且是deb格式的！ 从dev.chromium.org/getting-involved/dev-channel这里下载32位或64位版本，我选择的是32位： http://www.google.com/chrome/intl/en/eula_dev.html?dl=unstable_i386_deb 用dpkg -i xxx.deb安装，然后就可以直接启动google-chrome了： 显示的版本号是4.0.x：]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/114/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>J2ME陷阱一例</title>
		<link>http://www.liaoxuefeng.com/archives/112</link>
		<comments>http://www.liaoxuefeng.com/archives/112#comments</comments>
		<pubDate>Tue, 15 Feb 2011 03:45:58 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=112</guid>
		<description><![CDATA[用WTK 2.5开发MIDP应用时，自己写了个冒泡排序，模拟器运行正常，真机上报NoClassDefFoundError，原来是没有java.lang.Comparable这个接口，但是WTK编译居然通过了！校验器也没验出任何问题。 解决办法： 自定义一个IsComparable接口，将要排序的类实现此接口： public static void sort(Vector v) { int size = v.size(); for (int i=0; i&#60;size; i++) { for (int j=i+1; j&#60;size; j++) { IsComparable o1 = (IsComparable) v.elementAt(i); Object o2 = v.elementAt(j); if (o1.compareTo(o2) &#62; 0) { <a href="http://www.liaoxuefeng.com/archives/112">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/112/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>快速排序算法</title>
		<link>http://www.liaoxuefeng.com/archives/110</link>
		<comments>http://www.liaoxuefeng.com/archives/110#comments</comments>
		<pubDate>Tue, 15 Feb 2011 03:44:59 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=110</guid>
		<description><![CDATA[快速排序是一种基于分治的算法，其基本思想是将一个大数组按照一个基准数分成左右两份，左边的部份都不大于基准数，右边的部分都不小于基准数。然后，对这两份再分别应用快速排序，直到分到只剩2个数为止。 快速排序在通常情况下是最快的排序算法，以下是用Python实现的一个例子： ''' qsort.py Quick sort @author: Michael Liao ''' from random import Random def quick_sort(arr): if len(arr) &#62; 1: qsort(arr, 0, len(arr) - 1) def qsort(arr, start, end): base = arr[start] pl = start pr = end while pl <a href="http://www.liaoxuefeng.com/archives/110">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/110/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>在Eclipse中快速浏览源代码</title>
		<link>http://www.liaoxuefeng.com/archives/108</link>
		<comments>http://www.liaoxuefeng.com/archives/108#comments</comments>
		<pubDate>Tue, 15 Feb 2011 03:43:10 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=108</guid>
		<description><![CDATA[在Eclipse中，只需随时按住Ctrl并点击某个类名或方法名，即可跳转到相应的代码中。然而，如果引用一个开源的jar包，则会直 接打开其class的二进制码，这对于调试或研究代码内部流程颇为不便，尽管可以在Build Path中为每个jar指定源代码位置，但这样一来，对于同一个jar（例如spring.jar），每个工程都要指定，比较麻烦。 另一种更简单的方式是直接用WinZip或WinRAR之类的工具解开jar，再把源码也放进去，注意路径要正确，同一个Xxx.class和 Xxx.java应该在同一目录下，再用zip打包成jar包（jar格式其实就是zip格式），以后无论在哪个工程引用该jar包，Eclipse都可以直接从jar包中读出其对应的源代码，不必在Build Path中配置源代码位置，对于开源组件来说，大大方便了代码的跟踪和测试。]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/108/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>关于Jetty锁定静态文件的问题解决办法</title>
		<link>http://www.liaoxuefeng.com/archives/106</link>
		<comments>http://www.liaoxuefeng.com/archives/106#comments</comments>
		<pubDate>Tue, 15 Feb 2011 03:42:43 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=106</guid>
		<description><![CDATA[Jetty是一个优秀的Web服务器，最大的特点是可嵌入应用程序，因此作为调试服务器非常方便，就像跟踪普通的main()方法一样可以在Eclipse中直接调试Web应用而无需远程连接。但是使用Jetty发现一个问题，即Windows上启动后Jetty会锁定已访问的静态文件，如HTML，CSS等，这给页面设计带来了不便。 其实Jetty官方站点对此问题已有回答，锁定文件据说是为了提高性能，但我觉得缓存也不一定需要长时间锁定文件：http://docs.codehaus.org/display/JETTY/Files+locked+on+Windows 其实可以修改Jetty默认的配置文件，在jetty-6.1.5.jar中找到org/mortbay/jetty/webapp/webdefault.xml，搜索useFileMappedBuffer： &#60;init-param&#62; &#60;param-name&#62;useFileMappedBuffer&#60;/param-name&#62; &#60;param-value&#62;true&#60;/param-value&#62; &#60;/init-param&#62; 将param-value从true改为false即可。可以直接修改jar包内的这个文件，但是修改发行包毕竟不好，可以将此文件复制一份，在启动Jetty时用自己的这个webdefault.xml覆盖Jetty的设置即可。加上： WebAppContext webapp = new WebAppContext(); webapp.setDefaultsDescriptor("./webdefault.xml"); 重新启动后问题解决。]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/106/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>控制WebLogic解压war包</title>
		<link>http://www.liaoxuefeng.com/archives/104</link>
		<comments>http://www.liaoxuefeng.com/archives/104#comments</comments>
		<pubDate>Tue, 15 Feb 2011 03:41:58 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=104</guid>
		<description><![CDATA[在开发web应用时，如果通过weblogic的控制台部署war包，则weblogic默认在运行期不会解压war，这对于调试jsp颇为不便。其实，只需一个简单的设置就可以强迫weblogic解开war，并且编辑jsp后weblogic会重新加载，方便调试。 以8.1 sp4为例，打开bea/user_projects/domains/&#60;my-domain&#62;/config.xml，找到相应的war包： &#60;Application Name="test" Path="C:\java\bea\user_projects\domains\mydomain\applications\test.war" StagingMode="nostage" TwoPhase="true"&#62; 将StagingMode由nostage改为stage，重启weblogic即可。解压后的目录在myserver目录下。 需要注意的是，一旦war包需要重新部署，除了更新war包外，还要删除bea/user_projects/domains/&#60;my-domain&#62;/myserver目录下的.wlnotdelete和stage目录，以便强迫weblogic重新解开最新的war包，否则将继续使用原来已解压的目录。]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/104/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Subclipse入门指南</title>
		<link>http://www.liaoxuefeng.com/archives/98</link>
		<comments>http://www.liaoxuefeng.com/archives/98#comments</comments>
		<pubDate>Tue, 15 Feb 2011 03:41:03 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=98</guid>
		<description><![CDATA[Subversion是新一代的开源版本控制系统，和CVS相比，Subversion最大的特点是支持事务，可以确保一个提交是原子操作。此外，Subversion还支持更多的协议，包括HTTP访问。在Eclipse中，使用Subverison和CVS一样简单，只需安装Subclipse插件就可以了。 本文以Eclipse 3.3为例，安装Subclipse非常容易，打开Eclipse，选择菜单Help-&#62;Software Updates-&#62;Find and Install…，在弹出的对话框中选择“Search for new features to install”，然后点击“New Remote Site…”，填入Subclipse的在线安装的URL： 按照提示安装完毕后，我们就可以打开Subversion的资源库了。选择Eclipse菜单Window-&#62;Show View-&#62;Other…，选择SVN-&#62;SVN Repository，然后添加一个新的资源库，例如http://livebookstore.googlecode.com/svn/trunk： 添加完毕后，即可直接浏览SVN库的目录结构，然后通过右键菜单Checkout…检出为一个工程： Eclipse提示将目录检出为一个工程： 点击Finish即完成。]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/98/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Java多线程设计模式</title>
		<link>http://www.liaoxuefeng.com/archives/96</link>
		<comments>http://www.liaoxuefeng.com/archives/96#comments</comments>
		<pubDate>Tue, 15 Feb 2011 03:36:58 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=96</guid>
		<description><![CDATA[线程的创建和启动 Java语言已经内置了多线程支持，所有实现Runnable接口的类都可被启动一个新线程，新线程会执行该实例的run()方法，当run()方法执行完毕后，线程就结束了。一旦一个线程执行完毕，这个实例就不能再重新启动，只能重新生成一个新实例，再启动一个新线程。 Thread类是实现了Runnable接口的一个实例，它代表一个线程的实例，并且，启动线程的唯一方法就是通过Thread类的start()实例方法： Thread t = new Thread(); t.start(); start()方法是一个native方法，它将启动一个新线程，并执行run()方法。Thread类默认的run()方法什么也不做就退出了。注意：直接调用run()方法并不会启动一个新线程，它和调用一个普通的java方法没有什么区别。 因此，有两个方法可以实现自己的线程： 方法1：自己的类extend Thread，并复写run()方法，就可以启动新线程并执行自己定义的run()方法。例如： public class MyThread extends Thread { public run() { System.out.println("MyThread.run()"); } } 在合适的地方启动线程：new MyThread().start(); 方法2：如果自己的类已经extends另一个类，就无法直接extends Thread，此时，必须实现一个Runnable接口： public class MyThread extends OtherClass implements Runnable { public run() { <a href="http://www.liaoxuefeng.com/archives/96">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/96/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>J2ME最佳实践</title>
		<link>http://www.liaoxuefeng.com/archives/88</link>
		<comments>http://www.liaoxuefeng.com/archives/88#comments</comments>
		<pubDate>Tue, 15 Feb 2011 03:26:38 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=88</guid>
		<description><![CDATA[概述 J2ME是Sun发布的运行在小型设备上的微型版Java的一系列标准，其中，最重要的标准便是运行在手机上的MIDP应用程序了。到目前为止，MIDP一共发布了两个版本：MIDP 1.0（JSR37）和MIDP 2.0（JSR118），2.0版本可以向后兼容1.0版本，也就是说，支持MIDP 2.0的手机可以同时运行MIDP 1.0和MIDP 2.0的应用程序。本文将重点讲述开发MIDP应用程序时非常有用的一些设计模式，开发技巧以及如何调试、优化J2ME应用程序。 本文将讨论J2ME开发的以下内容： 如何自动适应用户手机配置 如何在屏幕间导航 如何实现一个灵活的联网应用 如何实现一个灵活的RMS应用 如何调试并优化J2ME程序 避免OutOfMemoryError 对于MIDP应用程序来说，由于手机设备上的资源非常有限，较弱的CPU计算能力，有限的内存（从几十KB到几百KB，虽然少数高端手机拥有超过1M的动态内存），很小的屏幕尺寸，因此，为了让一个MIDP应用程序能够不加改动地在多种不同手机上运行，程序必须有能力根据系统配置自动调整运行时的参数。比如，对于内存非常小的手机，如果从网络下载一幅较大的图像，需要分配巨大的缓冲区，就可能导致OutOfMemoryError错误，使应用程序直接终止，这会使用户感到不知所措，或者丢失用户的重要数据。因此，在试图分配一块大内存之前，首先使用System.gc()尝试让垃圾收集器释放无用对象占用的内存，然后，使用Runtime.getRuntime().freeMemory()方法获得可用的内存空间。如果可用空间太小，给用户一个“内存不足，无法完成操作”的Alert提示，从而尽可能地避免OutOfMemoryError错误。 // 示例代码： System.gc(); int max_size = 102400; // 100KB int free_size = (int)Runtime.getRuntime().freeMemory(); if(max_size&#62;free_size*2/3) { // TODO: Alert! } else { byte[] buffer = new <a href="http://www.liaoxuefeng.com/archives/88">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/88/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Amazon Kindle 2中文升级攻略</title>
		<link>http://www.liaoxuefeng.com/archives/84</link>
		<comments>http://www.liaoxuefeng.com/archives/84#comments</comments>
		<pubDate>Mon, 14 Feb 2011 13:23:10 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[生活·创意]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=84</guid>
		<description><![CDATA[托朋友从米国终于带回了Kindle 2，加上皮套一共才2000 RMB，比国内各大品牌的阅读器都要便宜很多，而且可以直接免费使用3G网络，自带的浏览器能直接浏览网站（估计是联通WCDMA信号？确实不知道为啥能免费使用）。 不过Kindle 2仍然不支持中文，需要经过hack才能支持。在国内搜索了半天，发现中文支持最后都是从Blog Kindle这个国外牛人搞出来的升级包，在Unicode Font Hack一文里有详细的升级步骤和所有升级包下载，大概读了一下，基本步骤如下： 1.首先，根据Kindle 2的型号（从Kindle机器后面的序列号看，Kindle 2是B002开头，Kindle 2国际版是B003开头，Kindle 2 DX是B004开通，Kindle 2 DX国际版是B005开头）下载对应的升级包，作者已经做了好几种字体的升级包，对于中文用户，如果你不想自己从Windows上搞微软雅黑字体，推荐直接使用Droid字体的升级包，这是Android手机默认的中文字体，显示效果很不错，完全够用。例如，Kindle 2国际版的升级包就是： http://blogkindle.com/wp-content/uploads/2009/11/update_ufh_droid_install-k2i.bin 2.把下载的update_uth_xxx.bin通过USB复制到Kindle的根目录，然后依次按Home，Menu，Settings，Menu，最后选择“Update Your Kindle”开始升级。 3.升级过程大概一分钟，然后Kindle会自动重启，重启后，复制几本中文PDF或TXT进去，能正常显示中文就大功告成！ 升级注意要点：确保下载的bin文件和你的Kindle型号对应，升级前确保电池有足够的电量，升级过程中不要做任何操作。 用Kindle看电子书效果非常出色，和普通LCD屏幕相比更有纸质书的感觉。Kindle 2最新版本已经能直接支持PDF格式，不过，由于Kindle 2的屏幕还较小（Kindle 2 DX好点），而且不支持PDF重排和字体大小调整，而一般的PDF都是按照A4纸的尺寸排版的，即使是横屏看PDF也觉得字体太小，而中文的TXT格式我发现Kindle会有乱码和不能翻页的问题，估计是一些特殊字符造成的。Kindle支持的最佳格式是AZW，也就是Amazon自家的电子书格式，不但字体可缩放，而且翻页速度极快，因此，在Kindle上看电子书最好的办法就是把PDF和TXT等格式转换为AZW格式。]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/84/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>在当前ClassPath中搜索类</title>
		<link>http://www.liaoxuefeng.com/archives/82</link>
		<comments>http://www.liaoxuefeng.com/archives/82#comments</comments>
		<pubDate>Mon, 14 Feb 2011 13:19:24 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=82</guid>
		<description><![CDATA[Spring 2.5提供了自动在当前ClassPath搜索被标注有特定注解的类，这个特性非常有用，跟踪了一下源码，发现其实核心代码就是利用ClassLoader的方法： public Enumeration&#60;URL&#62; getResources(String name) 于是自己动手，也写了一个能在ClassPath下搜索特定类的Scanner： package com.liaoxuefeng.util; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; public class ClassPathScanner { private static final String PROTOCOL_FILE = "file"; private static final String <a href="http://www.liaoxuefeng.com/archives/82">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/82/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>如何用Eclipse在Resin中调试Web应用程序</title>
		<link>http://www.liaoxuefeng.com/archives/80</link>
		<comments>http://www.liaoxuefeng.com/archives/80#comments</comments>
		<pubDate>Mon, 14 Feb 2011 13:16:45 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=80</guid>
		<description><![CDATA[本文介绍如何在Resin中调试Web应用程序。测试环境为Windows 7 / Resin 3.2 / Eclipse 3.3 在Resin的resin.conf中找到&#60;server-default&#62;并添加加以下参数： &#60;resin xmlns="http://caucho.com/ns/resin" xmlns:resin="http://caucho.com/ns/resin/core"&#62; &#60;log name="" level="info" path="stdout:"/&#62; &#60;cluster id=""&#62; &#60;root-directory&#62;.&#60;/root-directory&#62; &#60;server-default&#62; &#60;http server-id="" host="*" port="80"/&#62; &#60;jvm-arg&#62;-Xmx128m&#60;/jvm-arg&#62; &#60;jvm-arg&#62;-Xss1m&#60;/jvm-arg&#62; &#60;jvm-arg&#62;-Xdebug&#60;/jvm-arg&#62; &#60;jvm-arg&#62;-Xnoagent&#60;/jvm-arg&#62; &#60;jvm-arg&#62;-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=12345&#60;/jvm-arg&#62; 启动Resin后，打开Eclipse项目，选择 Run -&#62; Debug&#8230; -&#62; Remote Java Application -&#62; New 新建一个Remote Java <a href="http://www.liaoxuefeng.com/archives/80">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/80/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spring集成Velocity的中文解决方案</title>
		<link>http://www.liaoxuefeng.com/archives/78</link>
		<comments>http://www.liaoxuefeng.com/archives/78#comments</comments>
		<pubDate>Mon, 14 Feb 2011 13:15:34 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=78</guid>
		<description><![CDATA[在Spring framework中使用Velocity是非常方便的，只需在spring配置文件中申明： &#60;bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"&#62; &#60;/bean&#62; 即可在spring mvc框架中直接返回new ModelAndView(&#8220;velocity模板&#8221;, map)，但是中文一直为乱码。 为了解决中文问题，首先，考虑到国际化，将所有web页面都用UTF-8编码，然后在/WEB-INF/velocity.properties文件中覆盖velocity的默认编码ISO-8859-1： input.encoding = UTF-8 output.encoding = UTF-8 最后，在spring配置文件中设置： &#60;bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"&#62; &#60;property name="contentType"&#62;&#60;value&#62;text/html;charset=UTF-8&#60;/value&#62;&#60;/property&#62; &#60;/bean&#62; 启动Web服务器，可以看到中文显示正常，输入也正常。你也可以使用GBK，但是不利于多语言移植。]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/78/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>在Debian Etch上安装Windows</title>
		<link>http://www.liaoxuefeng.com/archives/74</link>
		<comments>http://www.liaoxuefeng.com/archives/74#comments</comments>
		<pubDate>Mon, 14 Feb 2011 12:43:41 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=74</guid>
		<description><![CDATA[上午通过3个小时奋战，终于成功在Debian Etch上通过xen成功安装Windows XP！ 这是安装界面： 安装成功后进入Windows的界面： 要在Linux上按装Windows，除了VMWare这种通过软件全虚拟的方式，还可以通过xen实现硬件支持的虚拟。现在，各主要发行版都内置了xen，原本打算在Redhat Enterprise 5上试试，不过配置太麻烦，最好是通过安装包一次搞定，最终决定用Debian Etch，几条apt-get就搞定了，非常方便。 安装Windows的必须条件： CPU必须支持Intel VT或AMD PT虚拟化技术，没有的话就不用考虑了。要检查CPU是否支持，用命令： grep vmx /proc/cpuinfo 如果是AMD的CPU用： grep svm /proc/cpuinfo 我的硬件配置：Intel Core2 Duo T7200 2GHz，2G RAM 先安装好Debian Etch和Gnome桌面，第一步是安装xen支持的内核，注意版本要和当前Linux内核一致。用apt-get安装： xen-linux-system-2.6.18-5-xen-686 xen-tools libc6-xen xen-ioemu-3.0.3-1 xen-hypervisor-3.0.3-1-i386-pae bridge-utils 安装完毕后重启系统，在GRUB就可以看到带xen的内核，启动后发现无线网卡不工作，需要再安装一个ipw3945-modules-2.6.18-5-686，重启后网卡工作正常。 第二步是安装准备，先创建一个4G的文件作为Windows的虚拟硬盘： dd if=/dev/zero of=/home/xuefeng/xen/winxp/winxp.img bs=1M <a href="http://www.liaoxuefeng.com/archives/74">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/74/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JSON入门指南</title>
		<link>http://www.liaoxuefeng.com/archives/70</link>
		<comments>http://www.liaoxuefeng.com/archives/70#comments</comments>
		<pubDate>Mon, 14 Feb 2011 12:38:02 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[出版·文章]]></category>
		<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=70</guid>
		<description><![CDATA[本文最早发表于IBM developerWorks： http://www.ibm.com/developerworks/cn/web/wa-lo-json/ JSON即JavaScript Object Notation，它是一种轻量级的数据交换格式，非常适合服务器与JavaScript的交互。 尽管有许多宣传关于XML如何拥有跨平台，跨语言的优势，然而，除非应用于Web Services，否则，在普通的Web应用中，开发者经常为XML的解析伤透了脑筋，无论是服务器端生成或处理XML，还是客户端用JavaScript解析XML，都常常导致复杂的代码，极低的开发效率。实际上，对于大多数Web应用来说，他们根本不需要复杂的XML来传输数据，XML的扩展性很少具有优势，许多AJAX应用甚至直接返回HTML片段来构建动态Web页面。和返回XML并解析它相比，返回HTML片段大大降低了系统的复杂性，但同时缺少了一定的灵活性。 现在，JSON为Web应用开发者提供了另一种数据交换格式。让我们来看看JSON到底是什么，同XML或HTML片段相比，JSON提供了更好的简单性和灵活性。 JSON数据格式解析 和XML一样，JSON也是基于纯文本的数据格式。由于JSON天生是为JavaScript准备的，因此，JSON的数据格式非常简单，你可以用JSON传输一个简单的String，Number，Boolean，也可以传输一个数组，或者一个复杂的Object对象。 String，Number和Boolean用JSON表示非常简单。例如，用JSON表示一个简单的String“abc”，其格式为： "abc" 除了字符&#8221;，\，/和一些控制符（\b，\f，\n，\r，\t）需要编码外，其他Unicode字符可以直接输出。下图是一个String的完整表示结构： 一个Number可以根据整型或浮点数表示如下： 这与绝大多数编程语言的表示方法一致，例如： 12345（整数） -3.9e10（浮点数） Boolean类型表示为true或false。此外，JavaScript中的null被表示为null，注意，true、false和null都没有双引号，否则将被视为一个String。 JSON还可以表示一个数组对象，使用[]包含所有元素，每个元素用逗号分隔，元素可以是任意的Value，例如，以下数组包含了一个String，Number，Boolean和一个null： ["abc",12345,false,null] Object对象在JSON中是用{}包含一系列无序的Key-Value键值对表示的，实际上此处的Object相当于Java中的Map&#60;String, Object&#62;，而不是Java的Class。注意Key只能用String表示。 例如，一个Address对象包含如下Key-Value： city:Beijing street:Chaoyang Road postcode:100025（整数） 用JSON表示如下： { "city" : "Beijing", "street" : "Chaoyang Road", "postcode" : 100025 <a href="http://www.liaoxuefeng.com/archives/70">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/70/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>将ReadWriteLock应用于缓存设计</title>
		<link>http://www.liaoxuefeng.com/archives/67</link>
		<comments>http://www.liaoxuefeng.com/archives/67#comments</comments>
		<pubDate>Mon, 14 Feb 2011 12:30:32 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[出版·文章]]></category>
		<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=67</guid>
		<description><![CDATA[本文最早发表于BEA dev2dev ——针对缓慢变化的小数据的缓存实现模型 在JavaEEdev站点的设计中，有几类数据是极少变化的，如ArticleCategory（文档分类），ResourceCategory（资源分类），Board（论坛版面）。在对应的DAO实现中，总是一次性取出所有的数据，例如： List&#60;ArticleCategory&#62; getArticleCategories(); 此类数据的特点是：数据量很小，读取非常频繁，变化却极慢（几天甚至几十天才变化一次），如果每次通过DAO从数据库获取数据，则增加了数据库服务器的压力。为了在不影响整个系统结构的情况下透明地缓存这些数据，可以在Facade一层通过Proxy模式配合ReadWriteLock实现缓存，而客户端和后台的DAO数据访问对象都不受影响： 首先，现有的中间层是由Facade接口和一个FacadeImpl具体实现构成的。对ArticleCategory的相关操作在FacadeImpl中实现如下： public class FacadeImpl implements Facade { protected CategoryDao categoryDao; public void setCategoryDao(CategoryDao categoryDao) { this.categoryDao = categoryDao; } // 读操作: public ArticleCategory queryArticleCategory(Serializable id) { return categoryDao.queryArticleCategory(id); } // 读操作: public List&#60;ArticleCategory&#62; <a href="http://www.liaoxuefeng.com/archives/67">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/67/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spring入门</title>
		<link>http://www.liaoxuefeng.com/archives/58</link>
		<comments>http://www.liaoxuefeng.com/archives/58#comments</comments>
		<pubDate>Mon, 14 Feb 2011 12:24:50 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=58</guid>
		<description><![CDATA[Spring是一个非常优秀的轻量级框架，通过Spring的IoC容器，我们的关注点便放到了需要实现的业务逻辑上。对AOP的支持则能让我们动态增强业务方法。编写普通的业务逻辑Bean是非常容易而且易于测试的，因为它能脱离J2EE容器（如Servlet，JSP环境）单独进行单元测试。最后的一步便是在Spring框架中将这些业务Bean以XML配置文件的方式组织起来，它们就按照我们预定的目标正常工作了！非常容易！ 本文将给出一个基本的Spring入门示例，并演示如何使用Spring的AOP将复杂的业务逻辑分离到每个方面中。 开发环境配置 首先，需要正确配置Java环境。推荐安装JDK1.4.2，并正确配置环境变量： JAVA_HOME=(JDK安装目录) CLASSPATH=. Path=%JAVA_HOME%\bin;... 我们将使用免费的Eclipse 3.1作为IDE。新建一个Java Project，将Spring的发布包spring.jar以及commons-logging-1.0.4.jar复制到Project目录下，并在Project &#62; Properties中配置好Java Build Path： 编写Bean接口及其实现 我们实现一个管理用户的业务Bean。首先定义一个ServiceBean接口，声明一些业务方法： package com.crackj2ee.example.spring; /** * Interface of service facade. * * @author Xuefeng */ public interface ServiceBean { void addUser(String username, String password); void deleteUser(String <a href="http://www.liaoxuefeng.com/archives/58">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/58/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>向Google博客搜索发出Ping通知</title>
		<link>http://www.liaoxuefeng.com/archives/56</link>
		<comments>http://www.liaoxuefeng.com/archives/56#comments</comments>
		<pubDate>Mon, 14 Feb 2011 12:15:02 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=56</guid>
		<description><![CDATA[通过Google“博客搜索”Ping API, 用户可以程序化的方式将博客内容的更新通知给Google“博客搜索”引擎。这对于经常更新博客内容的用户尤其有用。博客服务提供商的管理人员也可以利用此API将其平台上的博客内容变化向Google通告，以便Google“博客搜索”及时抓取来自这一服务提供商的最新内容。 Google“博客搜索”支持XML-RPC客户端和REST客户端。使用XML-RPC时，需要构造一个XML，然后将其POST到Google的指定地址，比较麻烦，而REST则既简单又方便。 使用REST时，只需构造一个如下URL： http://blogsearch.google.com/ping?name=xxx&#38;url=xxx&#38;changesURL=xxx 然后以GET发送，成功后会返回字符串“Thanks for the ping.”。 Google会根据url参数抓取blog页面并在最短的时间内索引。]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/56/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>删除Linux后如何恢复XP启动</title>
		<link>http://www.liaoxuefeng.com/archives/54</link>
		<comments>http://www.liaoxuefeng.com/archives/54#comments</comments>
		<pubDate>Mon, 14 Feb 2011 12:13:39 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=54</guid>
		<description><![CDATA[安装Linux时，如果将GRUB安装在主引导扇区，则可以正常引导Linux和Windows XP，但同时也破坏了原Windows的主引导信息。当删除Linux后，GRUB无法正常引导，因为GRUB需要读取Linux的/boot信息，但已不存在。此时，可以通过Windows XP的安装光盘恢复。 用XP安装盘启动后，选择R进入修复模式，输入管理员口令后，可以使用命令fixmbr修复主引导扇区的信息，然后重启，自动进入到Windows XP的启动菜单。 此法同样可用于Windows 2000 / 2003 / Vista等。]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/54/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>使用EasyMock使单元测试更加容易</title>
		<link>http://www.liaoxuefeng.com/archives/52</link>
		<comments>http://www.liaoxuefeng.com/archives/52#comments</comments>
		<pubDate>Mon, 14 Feb 2011 12:12:12 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=52</guid>
		<description><![CDATA[单元测试是XP极力推荐的测试驱动开发模式，是保证软件质量的重要方法。尽管如此，对许多类的单元测试仍然是极其困难的，例如，对数据库操作的类进行测试，如果不准备好数据库环境以及相关测试数据，是很难进行单元测试的；再例如，对需要运行在容器内的Servlet或EJB组件，脱离了容器也难于测试。 幸运的是，Mock Object可以用来模拟一些我们需要的类，这些对象被称之为模仿对象，在单元测试中它们特别有价值。 Mock Object用于模仿真实对象的方法调用，从而使得测试不需要真正的依赖对象。Mock Object只为某个特定的测试用例的场景提供刚好满足需要的最少功能。它们还可以模拟错误的条件，例如抛出指定的异常等。 目前，有许多可用的Mock类库可供我们选择。一些Mock库提供了常见的模仿对象，例如：HttpServletRequest，而另一些Mock库则提供了动态生成模仿对象的功能，本文将讨论使用EasyMock动态生成模仿对象以便应用于单元测试。 到目前为止，EasyMock提供了1.2版本和2.0版本，2.0版本仅支持Java SE 5.0，本例中，我们选择EasyMock 1.2 for Java 1.3版本进行测试，可以从http://www.easymock.org下载合适的版本。 我们首先来看一个用户验证的LoginServlet类： package com.javaeedev.test.mock; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String <a href="http://www.liaoxuefeng.com/archives/52">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/52/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>J2ME概念解析</title>
		<link>http://www.liaoxuefeng.com/archives/50</link>
		<comments>http://www.liaoxuefeng.com/archives/50#comments</comments>
		<pubDate>Mon, 14 Feb 2011 12:08:36 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=50</guid>
		<description><![CDATA[J2ME，即Java 2 Micro Edition，是SUN公司推出的在移动设备上运行的微型版Java平台，常见的移动设备有手机，PDA，电子词典，以及各式各样的信息终端如机顶盒等等。 由于移动终端的类型成千上万，而且计算能力差异非常大，不可能像桌面系统那样仅仅两三个版本的JVM即可满足Windows，Linux和Unix系统，因此，J2ME不是一个简单的微型版的JVM。为了满足千差万别的移动设备的需求，SUN定义了一系列的针对不同类型设备的规范，因此，J2ME平台便是由许多的规范组成的集合。 最重要的移动终端当然是手机了，因此，我们主要讨论手机相关的J2ME规范。 Configuration SUN把不同的设备按照计算能力分为CLDC（Connected Limited Device Configuration）和CDC（Connected Device Configuration）两大类，这两个Configuration是针对设备软硬件环境严格定义的，比如CLDC1.0定义了内存大小为64-512k，任何设备如果支持CLDC1.0，就必须严格满足定义，不能有可选的或者含糊的功能。 CLDC1.0是针对计算能力非常有限的设备定义的，只支持整数运算，不支持浮点运算，早期的Java手机大部分都支持CLDC1.0，如Nokia 3650，Siemens 6688i。 CLDC1.1则增加了浮点运算，因此，在支持CLDC1.1的设备上，可以使用float和double类型的变量。现在的Java手机很多都能支持CLDC1.1，如Nokia 9500，Siemens S65。 CDC则是针对计算能力比较强的设备定义的，如PPC等，CDC平台的JVM基本上和桌面的JVM很接近了，只是可以使用的Package大大少于J2SE的包。支持CDC的非常高端的Java手机也会很快上市。 Profile 和Configuration相比，Profile更多是针对软件的定义，Profile定义有必须实现的，也有可选的功能，因此，Profile更灵活。 最重要的Profile当然是MIDP（Micro Information Device Profile），MIDP定义了能在Java手机上运行的Java程序的规范，符合MIDP规范的Java小程序被称为MIDlet，可以直接通过无线网络下载到手机并运行。 早期的MIDP1.0规范使我们能在手机上运行有UI界面的Java程序，但是MIDP1.0对游戏的支持不够，必须自己实现许多必须的代码，因此，MIDP2.0规范大大加强了对游戏开发的支持，使开发者编写更少的代码来创建游戏。 MIDP规范的图形界面基本上都是独立于J2SE的AWT和Swing组件，因为目前手机的计算能力还比较有限，但是，随着手机的CPU越来越快，使得AWT和Swing移植到手机上也将成为可能，因此，最新的PBP 1.0（Personal Basic Profile）和PP 1.0（Personal Profile）规范提供了部分AWT和Swing的支持，目前，部分高端PDA已经可以运行PBP和PP的Java程序了。可以预见，将来大部分的AWT和Swing组件都能移植到手机上。 前面已经说过，和Configuration相比，Profile有许多可选包，比较实用的Profile还有在JSR135定义的MMAPI（Mobile Media API），实现多媒体播放功能；在JSR184定义的M3G API（Mobile 3D Graphics API），实现3D功能；在JSR120定义的WMA（Wireless <a href="http://www.liaoxuefeng.com/archives/50">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/50/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>3分钟安装配置Postfix邮件服务器</title>
		<link>http://www.liaoxuefeng.com/archives/48</link>
		<comments>http://www.liaoxuefeng.com/archives/48#comments</comments>
		<pubDate>Mon, 14 Feb 2011 12:07:41 +0000</pubDate>
		<dc:creator>廖雪峰</dc:creator>
				<category><![CDATA[软件·网络]]></category>

		<guid isPermaLink="false">http://www.liaoxuefeng.com/?p=48</guid>
		<description><![CDATA[Linux邮件服务器通常使用Sendmail，在网上Google了Sendmail的教程后，我决定知难而退，改用Postfix。 Postfix是用来替代Sendmail的，它的配置文件比Sendmail简单得多，配置相当容易。 在配置邮件服务器之前，先解释几个概念。 我们通常使用Email都很容易，但是Internet的邮件系统是通过几个复杂的部分连接而成的，对于最终用户而言，我们熟悉的Outlook，Foxmail等都是用来收信和发信的，称之为MUA：Mail User Agent，邮件用户代理。 MUA并非直接将邮件发送至收件人手中，而是通过MTA：Mail Transfer Agent，邮件传输代理代为传递，Sendmail和Postfix就是扮演MTA的角色。 一封邮件从MUA发出后，可能通过一个或多个MTA传递，最终到达MDA：Mail Delivery Agent，邮件投递代理，邮件到达MDA后，就存放在某个文件或特殊的数据库里，我们将这个长期保存邮件的地方称之为邮箱。 一旦邮件到达邮箱，就原地不动了，等用户再通过MUA将其取走，就是用Outlook，Foxmail等软件收信的过程。 所以一封邮件的流程是： 发件人：MUA &#8211;发送&#8211;&#62; MTA -&#62; 若干个MTA&#8230; -&#62; MTA -&#62; MDA &#60;&#8211;收取&#8211; MUA：收件人 MUA到MTA，以及MTA到MTA之间使用的协议就是SMTP协议，而收邮件时，MUA到MDA之间使用的协议最常用的是POP3或IMAP。 需要注意的是，专业邮件服务商都有大量的机器来为用户服务，所以通常MTA和MDA并不是同一台服务器，因此，在Outlook等软件里，我们需要分别填写SMTP发送服务器的地址和POP3接收服务器的地址。 下面开始用Postfix搭建Linux下的邮件服务器。目标服务器是RedHat Enterprise Linux 4，首先需要停止Sendmail： # /etc/init.d/sendmail stop 并从启动组里移除： # chkconfig sendmail off 然后，通过rpm包安装Postfix： <a href="http://www.liaoxuefeng.com/archives/48">[...]</a>]]></description>
		<wfw:commentRss>http://www.liaoxuefeng.com/archives/48/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

