imAtlas
javascript、css、html等web前端的技术分享与讨论
572b438be4fe268e15072c45eb72fe71879d3e10-blog.imatlas.com
2024-02-06T14:31:00Z
老码农的小感想
2024-02-06T14:31:00Z
lao-ma-nong-de-xiao-gan-xiang
iAzrael
<p class="md_block">
<span class="md_line md_line_start">我发现,现在很多计算机和软件工程相关专业的学生,<br /></span>
<span class="md_line">都不是因为喜欢计算机这个行业或者编程才选这个专业的。<br /></span>
<span class="md_line">都不是因为喜欢计算机这个行业,或者说编程才选这个专业的。<br /></span>
<span class="md_line">临近毕业了。除了课堂作业,连一个项目都没有写过<br /></span>
<span class="md_line">当年我想学医。所以报考了纯医学类的院校。<br /></span>
<span class="md_line">谁知,被调剂到了计算机专业。<br /></span>
<span class="md_line">我也不明白校长的脑洞怎么会这么大。一个医学类院校竟然会有计算机专业?<br /></span>
<span class="md_line">当我看到录取通知书,简直都要崩溃了<br /></span>
<span class="md_line">等开学后。我发现。我还是这个学院的第二届学生<br /></span>
<span class="md_line">我更加崩溃了……<br /></span>
<span class="md_line">好不容易说服自己接受现实<br /></span>
<span class="md_line">一开始选择了C++入手。然而选错了<br /></span>
<span class="md_line">在图书馆找了一个不知名作者写的不知名的书,里面用的他写的不知名的库<br /></span>
<span class="md_line md_line_end">懵懵懂懂的搞了一个月,才写出了一个hello world。</span>
</p>
使用CSS mask 实现图片的斜线拼接
2016-02-04T03:50:00Z
use-css-mask-slash-achieve-image-stitching
iAzrael
<h2 id="toc_0" class="h16">每次必说题外话</h2>
<p class="md_block">
<span class="md_line md_line_start md_line_end">话说貌似好久没有写技术文章了,自从娃娃出来后,很少能有时间做技术研究,思考的时间也不足。不过有得必有失,世上事也就酱紫了。但是作为一个前端攻城师,不写代码,不研究技术,是会被后浪拍死在沙滩上的。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">碰巧前段时间碰到个CSS问题,一直很喜欢CSS的,能CSS解决的问题绝对不用JS,于是就抽时间整整看。</span>
</p>
<h2 id="toc_1" class="h16">什么是斜线拼接</h2>
<p class="md_block">
<span class="md_line md_line_start md_line_end">回到本文主题上,”斜线拼接“是我自创的词语,因为我也不知道怎么描述这个需求,o(╯□╰)o,实际的效果是下面所示:</span>
</p>
<p class="md_block">
<span class="md_line md_line_dom_embed md_line_start md_line_end"><a class="md_compiled" href="/uploads/2015-09-01/example.png"><img class="md_compiled " src="/uploads/2015-09-01/example.png" alt="" title="" ></a></span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">眼力好的筒子应该就能发现,上面这张图是两个帅锅拼接在一起的,看中间的斜线。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">但是呢,刚接到这个需求的时候,开发是抓狂的——第一反应就是用canvas画图,这得多累啊,只是要显示张图片而已,竟然还要动用一坨JS,O__O "…</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">不过依稀记得,CSS 貌似有个遮罩的特性,可以实现图片的部分显示的效果的。more</span>
</p>
<h2 id="toc_2" class="h16">CSS mask & linear gradient</h2>
<p class="md_block">
<span class="md_line md_line_start md_line_end">要实现这个特性,就需要用到CSS遮罩和线性渐变。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">至于这两个是什么东西,我就不班门弄斧的介绍了,毕竟这两个属性出生也挺久了的,不了解的筒子可以看这两篇文章<a class="md_compiled" href="http://www.w3cplus.com/css3/css-masking.html">CSS遮罩——如何在CSS中使用遮罩</a>和<a class="md_compiled" href="http://www.zhangxinxu.com/wordpress/2013/09/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3css3-gradient%E6%96%9C%E5%90%91%E7%BA%BF%E6%80%A7%E6%B8%90%E5%8F%98/">深入理解css3-gradient斜向线性渐变</a>。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">先看下实际的效果</span>
</p>
<p class="md_block">
<span class="md_line md_line_dom_embed md_line_start md_line_end"><a class="md_compiled" href="http://demo.imatlas.com/use-css-mask-slash-achieve-image-stitching.html"><img class="md_compiled " src="/uploads/2016-01-01/拼接效果图.png" alt="" title="" ></a></span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">大家请看妹子中间(注意表看错了,是两个妹子的中间),有一条比较明显的分界线。多说无益,我知道你们想看demo,<a class="md_compiled" href="http://demo.imatlas.com/use-css-mask-slash-achieve-image-stitching.html">用力戳这里>></a>。</span>
</p>
<h3 id="toc_3" class="h16"><strong>第一步,显示两张图</strong></h3>
<p class="md_block">
<span class="md_line md_line_start md_line_end">OK,先看代码,然后我再来解释。</span>
</p>
<div class="codehilite code_lang_html highlight"><pre><span></span> <span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"img-container"</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"img-left"</span><span class="p">></</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"img-right"</span><span class="p">></</span><span class="nt">div</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">然后是CSS</span>
</p>
<div class="codehilite code_lang_css highlight"><pre><span></span> <span class="nc">.img-container</span><span class="p">{</span>
<span class="nb">position</span><span class="o">:</span> <span class="nb">relative</span><span class="p">;</span>
<span class="nb">width</span><span class="o">:</span> <span class="m">200px</span><span class="p">;</span>
<span class="nb">height</span><span class="o">:</span> <span class="m">200px</span><span class="p">;</span>
<span class="nb">border</span><span class="o">:</span> <span class="m">5px</span> <span class="nb">solid</span> <span class="m">#40BCFF</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.img-left</span><span class="p">{</span>
<span class="nb">background</span><span class="o">:</span> <span class="sx">url(img/left.jpg)</span><span class="p">;</span>
<span class="nb">background</span><span class="o">-</span><span class="nb">size</span><span class="o">:</span> <span class="n">cover</span><span class="p">;</span>
<span class="nb">width</span><span class="o">:</span> <span class="m">100%</span><span class="p">;</span>
<span class="nb">height</span><span class="o">:</span> <span class="m">100px</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.img-right</span><span class="p">{</span>
<span class="nb">background</span><span class="o">:</span> <span class="sx">url(img/right.jpg)</span><span class="p">;</span>
<span class="nb">background</span><span class="o">-</span><span class="nb">size</span><span class="o">:</span> <span class="n">cover</span><span class="p">;</span>
<span class="nb">width</span><span class="o">:</span> <span class="m">100%</span><span class="p">;</span>
<span class="nb">height</span><span class="o">:</span> <span class="m">100px</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">OK,看下效果</span>
</p>
<p class="md_block">
<span class="md_line md_line_dom_embed md_line_start md_line_end"><a class="md_compiled" href="/uploads/2016-02-01/abcdefg.png"><img class="md_compiled " src="/uploads/2016-02-01/abcdefg.png" alt="" title="" ></a></span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">小明:尼玛,这不是坑爹么,这么简单谁不会?</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">小朋友,别急,我们两个主角还没上了。</span>
</p>
<h3 id="toc_4" class="h16"><strong>画个斜线</strong></h3>
<p class="md_block">
<span class="md_line md_line_start md_line_end">为了实现斜线拼接,你总得有个斜线吧?把img-right的背景换成一个带有“斜线”的图,这个就不用“真”图片啦,CSS渐变就能完成,如下:</span>
</p>
<div class="codehilite code_lang_css highlight"><pre><span></span> <span class="nc">.img-right</span><span class="p">{</span>
<span class="nb">background</span><span class="o">:</span> <span class="o">-</span><span class="n">webkit</span><span class="o">-</span><span class="n">linear</span><span class="o">-</span><span class="n">gradient</span><span class="p">(</span><span class="nb">left</span> <span class="nb">top</span><span class="o">,</span> <span class="nb">blue</span> <span class="m">50%</span><span class="o">,</span> <span class="nb">white</span> <span class="m">50%</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_dom_embed md_line_with_image md_line_start md_line_end"><img class="md_compiled " src="/uploads/2016-02-01/QQ截图20160204112221.png" alt="" title="" ></span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">好,把背景换成真实的美女,渐变图作为mask</span>
</p>
<div class="codehilite code_lang_css highlight"><pre><span></span><span class="nc">.img-right</span><span class="p">{</span>
<span class="nb">background</span><span class="o">:</span> <span class="sx">url(img/right.jpg)</span><span class="p">;</span>
<span class="nb">background</span><span class="o">-</span><span class="nb">size</span><span class="o">:</span> <span class="n">cover</span><span class="p">;</span>
<span class="o">-</span><span class="n">webkit</span><span class="o">-</span><span class="n">mask</span><span class="o">-</span><span class="n">image</span><span class="o">:</span> <span class="o">-</span><span class="n">webkit</span><span class="o">-</span><span class="n">linear</span><span class="o">-</span><span class="n">gradient</span><span class="p">(</span><span class="nb">left</span> <span class="nb">top</span><span class="o">,</span> <span class="nb">blue</span> <span class="m">50%</span><span class="o">,</span> <span class="nb">white</span> <span class="m">50%</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">But,如果你这么做了,会发现看到的是完整的图,并没有被遮盖,跟下图一样。</span>
</p>
<p class="md_block">
<span class="md_line md_line_dom_embed md_line_start md_line_end"><a class="md_compiled" href="/uploads/2016-02-01/abcdefg.png"><img class="md_compiled " src="/uploads/2016-02-01/abcdefg.png" alt="" title="" ></a></span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">这是因为css mask的原理是,它只会把遮罩图里透明像素所对应的原图部分进行隐藏,而我们的渐变图是完全不透明的(我们是蓝白色相间的),所以没有遮罩效果。那么把蓝色改成透明试试。</span>
</p>
<div class="codehilite code_lang_css highlight"><pre><span></span><span class="nc">.img-right</span><span class="p">{</span>
<span class="nb">background</span><span class="o">:</span> <span class="sx">url(img/right.jpg)</span><span class="p">;</span>
<span class="nb">background</span><span class="o">-</span><span class="nb">size</span><span class="o">:</span> <span class="n">cover</span><span class="p">;</span>
<span class="o">-</span><span class="n">webkit</span><span class="o">-</span><span class="n">mask</span><span class="o">-</span><span class="n">image</span><span class="o">:</span> <span class="o">-</span><span class="n">webkit</span><span class="o">-</span><span class="n">linear</span><span class="o">-</span><span class="n">gradient</span><span class="p">(</span><span class="nb">left</span> <span class="nb">top</span><span class="o">,</span> <span class="nb">transparent</span> <span class="m">50%</span><span class="o">,</span> <span class="nb">white</span> <span class="m">50%</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_dom_embed md_line_start md_line_end"><a class="md_compiled" href="/uploads/2016-02-01/QQ%E6%88%AA%E5%9B%BE20160204113645.png"><img class="md_compiled " src="/uploads/2016-02-01/QQ截图20160204113645.png" alt="" title="" ></a></span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">当当当~~美女只显示一半啦!♪(^∇^*)</span>
</p>
<h3 id="toc_5" class="h16"><strong>层叠</strong></h3>
<p class="md_block">
<span class="md_line md_line_start md_line_end">最后,把第二张图层在第一章上面,由于第二张图左边一半都是透明的,背景里的美女也能直接透过来啦。</span>
</p>
<div class="codehilite code_lang_css highlight"><pre><span></span><span class="nc">.img-right</span><span class="p">{</span>
<span class="nb">position</span><span class="o">:</span> <span class="nb">absolute</span><span class="p">;</span>
<span class="nb">left</span><span class="o">:</span> <span class="m">0</span><span class="p">;</span>
<span class="nb">top</span><span class="o">:</span> <span class="m">0</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_dom_embed md_line_start md_line_end"><a class="md_compiled" href="http://demo.imatlas.com/use-css-mask-slash-achieve-image-stitching.html"><img class="md_compiled " src="/uploads/2016-01-01/拼接效果图.png" alt="" title="" ></a></span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">看下最终img-right所需要的样式代码</span>
</p>
<div class="codehilite code_lang_css highlight"><pre><span></span><span class="nc">.img-right</span><span class="p">{</span>
<span class="nb">position</span><span class="o">:</span> <span class="nb">absolute</span><span class="p">;</span>
<span class="nb">left</span><span class="o">:</span> <span class="m">0</span><span class="p">;</span>
<span class="nb">top</span><span class="o">:</span> <span class="m">0</span><span class="p">;</span>
<span class="nb">background</span><span class="o">:</span> <span class="sx">url(img/right.jpg)</span><span class="p">;</span>
<span class="nb">background</span><span class="o">-</span><span class="nb">size</span><span class="o">:</span> <span class="n">cover</span><span class="p">;</span>
<span class="o">-</span><span class="n">webkit</span><span class="o">-</span><span class="n">mask</span><span class="o">-</span><span class="n">image</span><span class="o">:</span> <span class="o">-</span><span class="n">webkit</span><span class="o">-</span><span class="n">linear</span><span class="o">-</span><span class="n">gradient</span><span class="p">(</span><span class="nb">left</span> <span class="nb">top</span><span class="o">,</span> <span class="nb">transparent</span> <span class="m">50%</span><span class="o">,</span> <span class="nb">white</span> <span class="m">50%</span><span class="p">);</span>
<span class="nb">width</span><span class="o">:</span> <span class="m">100%</span><span class="p">;</span>
<span class="nb">height</span><span class="o">:</span> <span class="m">100%</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">怎么样,很简单是吧?</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">CSS3有很多新鲜(其实这个不新鲜了~)的特性可以实现很多有趣的应用,如果你有其他方案,欢迎留言讨论,O(∩_∩)O谢谢阅读!</span>
</p>
肿么安装Effect Game
2015-07-22T07:52:00Z
kuai-le-de-ma-nong/zhong-yao-an-zhuang-effect-game
iAzrael
<p class="md_block">
<span class="md_line md_line_start md_line_end">Effect Game的安装还是很麻烦的, 原作者用的时代比较久远, 有很多软件包在新的linux系统上都可能有兼容问题, 这里做个安装记录方便后人查阅.</span>
</p>
<h2 id="toc_0" class="h16">环境准备</h2>
<ol>
<li class="md_li"><span>fedora 21
</span></li>
<li class="md_li"><span>能翻墙的比较快的网络
</span></li>
</ol>
<p class="md_block">
<span class="md_line md_line_start md_line_end">Effect Game的需要运行在linux系统里, 理论上任何linux发行版都可以, 但是我在ubuntu上折腾了好久, 总归还是放弃了. </span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">各个发行版虽然内核一样, 但是各种软件包可能不一样, 名字也可能不一样, 包管理工具也不一样, 所以环境这里, 还是建议用 <code>fedora 21</code>, 而且不能用最新版, 最新版的fedora把 yum 给替换成了 dnf, 还是很多问题.</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">这里的安装步骤是基本按照这个E文文档的, <a class="md_compiled" href="https://github.com/jhuckaby/Effect-Games/wiki/Installation-Guide">https://github.com/jhuckaby/Effect-Games/wiki/Installation-Guide</a>, 启用能用yum安装的软件包都直接用yum了.</span>
</p>
<h2 id="toc_1" class="h16">安装各种系统依赖包</h2>
<p class="md_block">
<span class="md_line md_line_start md_line_end">作者列了yum install xxx 很多包, 但是其实可以批量安装的</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">如果是第一次用yum, 先更新下yum的版本库 <code>yum repolist</code> </span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">批量安装, <strong>安装完成后再敲入整个命令确认是否有安装失败的</strong>(已经安装了的不会重复安装)</span>
</p>
<pre><code>yum install zlib-devel libxml2-devel libgpg-error-devel libgcrypt-devel libxslt-devel expat-devel db4-devel e2fsprogs-devel krb5-devel openssl-devel aspell-devel rpm-build gcc screen sendmail "gcc-c++" bzip2-devel freetype-devel libpng-devel libtiff-devel libjpeg libjpeg-devel libstdc++-devel curl curl-devel libidn-devel krb5-devel e2fsprogs-devel libgcrypt-devel libgpg-error-devel</code></pre>
<!--block_code_end--><h2 id="toc_2" class="h16">创建 Effect Game 的安装目录</h2>
<p class="md_block">
<span class="md_line md_line_start md_line_end">这里就直接按照作者的目录来设置, 大部分东东都放到这里, 避免各种引用要修改 </span>
</p>
<pre><code>mkdir /effect
mkdir -p /effect/perl/bin/</code></pre>
<!--block_code_end--><h2 id="toc_3" class="h16">安装 perl 和 cpan</h2>
<pre><code>yum install perl
yum install cpan</code></pre>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">作者把 perl 放到了 /effect/perl 里, 这里做个软连就好</span>
</p>
<pre><code>ln -s /usr/bin/perl /effect/perl/bin/perl
ln -s /usr/bin/cpan /effect/perl/bin/cpan</code></pre>
<!--block_code_end--><h2 id="toc_4" class="h16">安装各种 perl 模块</h2>
<p class="md_block">
<span class="md_line md_line_start md_line_end">第一次使用cpan时, 直接敲入 <code>cpan</code> 运行一次, 按提示使用自动配置</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">为了避免安装时可能会遇到的下面这个提示, 烦它的话可以先装一下 <code>YAML</code>.</span>
</p>
<pre><code>>> 'YAML' not installed, will not store persistent state
cpan YAML</code></pre>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">然后批量安装各种模块, <strong>安装完成后再敲入整个命令确认是否有安装失败的</strong>(已经安装了的不会重复安装)</span>
</p>
<pre><code>cpan LWP::UserAgent Archive::Zip Archive::Tar Class::Loader Digest::SHA Digest::SHA1 Math::Pari Devel::Symdump Module::Build MIME::Lite Test::Simple Text::Wrap CGI Devel::CoreStack Cwd IO::Socket::INET Test::Harness Time::HiRes Unicode::String Date::Parse MIME::Parser Crypt::SSLeay ExtUtils::XSBuilder IO::Socket::SSL File::lockf IPC::ShareLite Syntax::Highlight::Engine::Kate Text::Aspell Net::Twitter::Lite HTTP::Daemon File::Flock</code></pre>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">这个需要等很久很久, 比很久很久还要久.</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end"><code>Text::Aspell</code> 很容易安装失败, 按如下步骤重新安装</span>
</p>
<pre><code>yum install aspell aspell-en
cpan Text::Aspell</code></pre>
<!--block_code_end--><h2 id="toc_5" class="h16">安装图片服务 ImageMagick</h2>
<p class="md_block">
<span class="md_line md_line_start md_line_end">ImageMagic不要用yum安装, 编译时需要指定很多环境变量, 直接下载下载自己编译.</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">安装jpeg和png解码库</span>
</p>
<pre><code>yum install libjpeg-devel libpng-devel</code></pre>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">作者用的ImageMagick是6.5版本, 可能会编译失败, 这里下载<strong>最新版</strong>(目前是6.9).</span>
</p>
<pre><code>wget "http://www.imagemagick.org/download/ImageMagick.tar.gz"
tar zxf ImageMagick.tar.gz
cd ImageMagick-*
ln -s /usr/include/freetype2/freetype /usr/include/freetype
export CPPFLAGS="-I/usr/include/freetype2 -I/usr/local/include"
export LDFLAGS="-L/usr/local/lib"
mkdir -p /effect/fonts
./configure --prefix=/effect/magick --enable-lzw --without-threads --without-magick-plus-plus --with-perl=perl --with-fontpath=/effect/fonts --without-x --with-quantum-depth=8 --enable-shared=yes --enable-static=no
make
make install</code></pre>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">添加库到系统</span>
</p>
<pre><code>echo "/effect/magick/lib" > /etc/ld.so.conf.d/imagemagick.conf</code></pre>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">重新加载配置</span>
</p>
<pre><code>/sbin/ldconfig -v</code></pre>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">测试是否已正常安装</span>
</p>
<pre><code>perl -MImage::Magick -e ';'</code></pre>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">没有出错就安装OK, 注意, 这里是没有什么显示</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">创建个软链</span>
</p>
<pre><code>mkdir -p /opt/local/bin
ln -s /effect/magick/bin/convert /opt/local/bin/convert</code></pre>
<!--block_code_end--><h2 id="toc_6" class="h16">安装音视频模块 MPG123 and OGG Encoder</h2>
<p class="md_block">
<span class="md_line md_line_start md_line_end">安装 MPG</span>
</p>
<pre><code>wget "http://www.effectgames.com/install/mpg123-1.10.0.tar.bz2"
tar jxf mpg123-1.10.0.tar.bz2
cd mpg123-*
./configure
make
make install</code></pre>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">安装 OGG</span>
</p>
<pre><code>yum install libvorbis libvorbis-devel vorbis-tools</code></pre>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">检查下面文件在不在, 有就安装正确了</span>
</p>
<pre><code>ls /usr/local/bin/mpg123 /usr/bin/oggenc</code></pre>
<!--block_code_end--><h2 id="toc_7" class="h16">安装 Apache</h2>
<p class="md_block">
<span class="md_line md_line_start md_line_end">先安装或更新一下openssl</span>
</p>
<pre><code>yum install openssl</code></pre>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">Apache也有很多安装选项, 自己下载来编译</span>
</p>
<pre><code>wget "http://www.effectgames.com/install/httpd-2.2.14.tar.bz2"
tar jxf httpd-2.2.14.tar.bz2
cd httpd-*
./configure --prefix=/effect/apache --with-mpm=prefork --with-ssl=openssl --with-perl=perl --enable-so --enable-expires --enable-headers --enable-mime-magic --enable-rewrite --enable-ssl --enable-mods-shared="all authn_file authn_default authz_host authz_groupfile authz_user authz_default auth_basic include filter log_config env setenvif mime status autoindex asis cgi negotiation dir actions userdir alias expires headers ssl rewrite"
make
make install</code></pre>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">之后Apache会安装到 <code>/effect/apache</code></span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">安装 mod_perl 模块, 有些系统会缺少 perl 的一些依赖, 先用 yum 安装依赖, 然后安装最新版的 mod_perl ( 目前是2.0.9 )</span>
</p>
<pre><code>yum install perl-ExtUtils-Embed
wget "http://mirror.bit.edu.cn/apache/perl/mod_perl-2.0.9.tar.gz"
tar zxf mod_perl-*.tar.gz
cd mod_perl-*
perl Makefile.PL MP_AP_PREFIX=/effect/apache
make
make install</code></pre>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">在执行<code>perl Makefile.PL MP_AP_PREFIX=/effect/apache</code> 时可能会报错</span>
</p>
<pre><code>[ error] '/effect/apache/bin/apxs -q NOTEST_CPPFLAGS' failed:
[ error] Use of assignment to $[ is deprecated at /effect/apache/bin/apxs line 86.</code></pre>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">问题原因是新版本的perl里面, <code>[</code> 不能用于变量名了, 修改 /effect/apache/bin/apxs 源码, 把<code>$[</code> 替换成 <code>$a</code>(vi 中可以用 <code>%s/$\[/\$a/g</code> 命令全局替换), 保存并重新执行 <code>perl Makefile.PL MP_AP_PREFIX=/effect/apache</code></span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">增加www用户组和用户</span>
</p>
<pre><code>/usr/sbin/groupadd www
/usr/sbin/useradd -m -g www www</code></pre>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">替换配置文件, 直接用作者的配置</span>
</p>
<pre><code>wget "http://www.effectgames.com/install/httpd.conf"
mv /effect/apache/conf/httpd.conf /effect/apache/conf/httpd.conf.bak
mv httpd.conf /effect/apache/conf/</code></pre>
<!--block_code_end--><h2 id="toc_8" class="h16">配置项目</h2>
<p class="md_block">
<span class="md_line md_line_start md_line_end">先下载项目代码下来</span>
</p>
<pre><code>wget "https://github.com/jhuckaby/Effect-Games/tarball/master"
tar zxf jhuckaby-Effect-Games-*.tar.gz
rm jhuckaby-Effect-Games-*.tar.gz
mv jhuckaby-Effect-Games-*/* /effect
ln -s /effect/htdocs /effect/apache/htdocs/effect</code></pre>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">做一些必要配置如域名等, 具体项直接参照 <a class="md_compiled" href="https://github.com/jhuckaby/Effect-Games/wiki/Installation-Guide">安装文档</a></span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">Effect Game的主要配置文件在 <code>/effect/conf/Effect.xml</code>, 基本上都不需要修改</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">启动测试一下是否正常</span>
</p>
<pre><code>/effect/apache/bin/apachectl start
/effect/apache/bin/apachectl stop</code></pre>
<!--block_code_end--><h2 id="toc_9" class="h16">初始化各种环境</h2>
<p class="md_block">
<span class="md_line md_line_start md_line_end">创建数据存储目录和配置权限</span>
</p>
<pre><code>mkdir -p /data/effect/storage
chown www:www /data/effect/storage
mkdir -p /data/effect/cleanup
chown www:www /data/effect/cleanup</code></pre>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">创建日志的目录</span>
</p>
<pre><code>mkdir -p /logs/effect
chmod 777 /logs/effect
mkdir -p /logs/apache
chmod 777 /logs/apache</code></pre>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">创建初始数据, 执行这个脚本就行, 数据的配置在 <code>/effect/conf/initial_data_setup.xml</code></span>
</p>
<pre><code>/effect/bin/setup_db.pl</code></pre>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">启动图片服务进程, Effect Game是使用了个后台进程来优化图片, 配置文件在 <code>/effect/conf/image_service.xml</code>, 用下面的命令启动</span>
</p>
<pre><code>mkdir -p /data/effect/queue
chmod 777 /data/effect/queue
/effect/bin/imageservicectl.sh start
/effect/bin/imageservicectl.sh stop</code></pre>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">配置定时任务, 这个任务用来处理日志文件和数据文件, 命令行敲入 <code>crontab -e</code>, 输入</span>
</p>
<pre><code>00 * * * * /effect/bin/maint.pl hourly
30 00 * * * /effect/bin/maint.pl daily</code></pre>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">定时任务的log输出在 <code>/logs/effect/maint.log</code></span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">过时的日志文件会被打包存储, 默认配置下存在 <code>/backup/effect/logs/CATEGORY/YYYY/MM/DD/HH.gz</code>, 路径可以在 <code>/effect/conf/Effect.xml</code> 中修改</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">创建备份目录</span>
</p>
<pre><code>mkdir -p /backup/effect
chmod 777 /backup/effect</code></pre>
<!--block_code_end--><h2 id="toc_10" class="h16">All Done</h2>
<p class="md_block">
<span class="md_line md_line_start md_line_end">现在可以启动 Effect Game 啦</span>
</p>
<pre><code>/effect/bin/imageservicectl.sh start
/effect/apache/bin/apachectl start</code></pre>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">然后访问 <code>http://127.0.0.1/effect/</code>, 默认用户名和密码都是 <code>admin</code></span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">如果要配置域名, 可以在 <code>/effect/apache/conf/httpd.conf</code> 中修改 <code>ServerName</code> </span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">So, enjoy it!</span>
</p>
谈前端工程师的职业规划
2015-04-17T08:57:50Z
talk-about-the-front-end-engineering-career-planning
iAzrael
<p class="md_block">
<span class="md_line md_line_start md_line_end">在敲下这个标题的时候,心里好虚。话说我一直不太喜欢发表这些看上去很假大空的文字,每个人的职业规划都是独有的,不具有太大的可复制性,把自己的经历放出去,容易误人子弟。只是最近很多师弟们(别问我为什么都是师弟,我想静静……也不要问我静静是谁!)问起这个,也就根据自己的经历发表一下对前端工程师的看法吧,“我说的都是错的”,仅供参考。另:本篇是纯文字,密集恐惧症换成勿入!</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">从我接收第一份前端需求开始,到现在也有五个年头了。自己也从一个愣头青变成一个快到而立之年的大叔,时间真的是哗啦哗啦的快。这五年里,其实可以分成三部分:1~2, 3~4, 5。more</span>
</p>
<h2 id="toc_0" class="h16">1~2 吸吸吸,疯狂的吸取知识</h2>
<p class="md_block">
<span class="md_line md_line_start md_line_end">刚毕业时满腔热情,一门心思只往前端事业发展。刚从学校出来,看到什么都是新鲜十足,什么都想学。不断的买书看书垫枕头,最疯狂的时候一个礼拜晚上看完正本犀牛书+做笔记,后来再也达不到这种速度了。很幸运我能加入到AlloyTeam,依靠WebQQ,使得我的编码能力、项目经验duang duang duang的上去了。同时也搞了很多奇形怪状的业余项目,基本上无论遇到什么跟JS相关的“新”技术(新是对于我自己来说的),我都想去尝一尝。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">对于刚毕业的初学者来说,头两年真的真的是非常重要,学习的激情、速度以及熬夜的能力可以发挥的淋漓尽致。在这个阶段,通过大量的编码提升JS能力,同时尝试各种JS框架和库,寻找适合自己的框架,甚至自己也写了一个JS库和构建工具。“不要重复的造轮子”这句话,初学者都应该无视。你不造轮子,怎么知道别的轮子好不好用?怎么知道造一个轮子有多难?怎么知道如何改进轮子?我不认为一个新手去看jQuery的源码能看懂,反正我当时就晕晕乎乎的。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">在这个时间点里,其实还没怎么考虑以后的发展,而且也仅认为前端工程师,学好JS/CSS/HTML就够了,其他的没兴趣也没意愿去学。</span>
</p>
<h2 id="toc_1" class="h16">3~4 大大大,扩展知识面</h2>
<p class="md_block">
<span class="md_line md_line_start md_line_end">在JS/CSS/HTML里探索了2年后,突然发现越学越不懂了。出了HTML5,看了WebSocket,想学会,结果要看网络协议、要看HTTP/TCP,还要学Server开发等。顿时感觉分身10个也不一定能学好。为了跟上潮流,也得硬着头皮上。好不容易Server、网络、前端、浏览器各种知识都多少了解的时候,移动潮流来了!OMG,Android、iOS还有WP……生命不止,学习不休。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">其实到了这个阶段,多少也算是个有经验的攻城师了。开发一般需求不在话下,偶尔还能承担个架构设计。在提升JS能力的同时,开始要往多方面发展。前端工程师远远不仅是JS而已。制作一个性能高、交互好、视觉美的页面,需要从前端框架选型、架构设计、构建工具,到后端通信机制、设计与交互、网络和浏览器优化等各方面的知识。一专多长才是前端工程师的终极目标。有个人说得对:一专是指你不可替代,多长标示你可以替代别人。这样你在团队在公司的地位才更加牢固,公司也会给你提供更多的资源。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">同时还要开始提升自己的名气,可以通过发表技术博客,提交和参与开源项目,做部门级公司级还有业界分享,参加业界会议等等。在这个信息瞬息万变的互联网时代,保持交流才会让自己不落伍。同时名气大了,能找到更多志同道合的人一起研究技术(探讨生命的起源也不是不可能的),甚至想跳槽,也是放个屁的事儿(意思是简单-_-|| 这都什么比喻)。</span>
</p>
<h2 id="toc_2" class="h16">5~ 摸摸摸,摸清前方的路</h2>
<p class="md_block">
<span class="md_line md_line_start md_line_end">这个时候,如无意外,你也应该成为高级工程师了。编码在工作中比例已经不算太高,更多的工作是承担技术评审、架构设计和项目管理等事情。工作中除了完成自己的事情,可能还需要指导新人,做新人培训,带领新人完成项目。同时还会有一个抉择摆在眼前:继续深入研究技术 or 往管理方向进发。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">技术 or 管理,这里没有对错之分,只有合不合适。有的人就不善于交流,同时喜欢专研,可以继续走技术的路,发展成专家;有的人则可能有比较强的领导力,可以带领一群人完成项目,那可以转向管理,成为Team Leader等。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">不管选哪个方向,你都已经是个优秀的人,而且应该把这种优秀传承下去。成为导师,使新人变得优秀;成为面试官,挖掘优秀的人;成为讲师,让更多人学习到优秀,等等。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">总的来说,头两年一定要打好基础,找准自己的G点,深攻下去;高潮之后,往广度发展,掌握其他相关和不相关的配套知识(这不是矛盾么?Σ( ° △ °|||)︴);然后摸到自己的目标,发售大胆的爱爱(老了,手抖打多了)吧。不仅自己爱(前端),也要让更多人一起爱(前端)哦。</span>
</p>
在浏览器端用JS创建和下载文件
2014-01-02T15:31:00Z
download-file-with-js
iAzrael
<p class="md_block">
<span class="md_line md_line_start md_line_end">前端很多项目中,都有文件下载的需求,特别是JS生成文件内容,然后让浏览器执行下载操作(例如在线图片编辑、在线代码编辑、<a class="md_compiled" href="http://www.ipresst.com">iPresst</a>等)。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">但受限于浏览器,很多情况下我们都只能给出个链接,让用户点击打开-》另存为。如下面这个链接:</span>
</p>
<div class="codehilite code_lang_html highlight"><pre><span></span><span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"file.js"</span><span class="p">></span>file.js<span class="p"></</span><span class="nt">a</span><span class="p">></span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">用户点击这个链接的时候,浏览器会打开并显示链接指向的文件内容,显然,这并没有实现我们的需求。more</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">HTML5中给a标签增加了一个download属性,只要有这个属性,点击这个链接时浏览器就不在打开链接指向的文件,而是改为下载(目前只有chrome、firefox和opera支持)。</span>
</p>
<p class="md_block">
<span class="md_line md_line_dom_embed md_line_start md_line_end"><a class="md_compiled" href="/uploads/2014-01-01/QQ20140102-2.png"><img class="md_compiled " src="/uploads/2014-01-01/QQ20140102-2.png" alt="" title="" ></a></span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">下载时会直接使用链接的名字来作为文件名,但是是可以改的,只要给download加上想要的文件名即可,如:download=“not-a-file.js”。</span>
</p>
<p class="md_block">
<span class="md_line md_line_dom_embed md_line_start md_line_end"><a class="md_compiled" href="/uploads/2014-01-01/QQ20140102-3.png"><img class="md_compiled " src="/uploads/2014-01-01/QQ20140102-3.png" alt="" title="" ></a></span>
</p>
<h2 id="toc_0" class="h16">Not enough!</h2>
<p class="md_block">
<span class="md_line md_line_start md_line_end">但是这样还不够,以上的方法只适合用在文件是在服务器上的情况。如果在浏览器端js生成的内容,想让浏览器进行下载要如何办到呢?</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">其实还是有办法办到的,相信很多人都多少听过了DataURI这个词,比较常见的就是图片的src,如:</span>
</p>
<div class="codehilite code_lang_html highlight"><pre><span></span><span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"`data:image/gif;base64,R0lGOXXXXX"</span><span class="p">></span>`
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">DataURI的解释可以移步<a class="md_compiled" href="http://sjolzy.cn/What-is-the-data-URI-scheme-and-how-to-use-the-data-URI-scheme.html">这里</a>,本人就不在解释了。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">那么,现在要将js生成的内容进行下载就有法可依了。封装成一个方法如下:</span>
</p>
<div class="codehilite code_lang_js highlight"><pre><span></span><span class="kd">function</span> <span class="nx">downloadFile</span><span class="p">(</span><span class="nx">aLink</span><span class="p">,</span> <span class="nx">fileName</span><span class="p">,</span> <span class="nx">content</span><span class="p">){</span>
<span class="nx">aLink</span><span class="p">.</span><span class="nx">download</span> <span class="o">=</span> <span class="nx">fileName</span><span class="p">;</span>
<span class="nx">aLink</span><span class="p">.</span><span class="nx">href</span> <span class="o">=</span> <span class="s2">"data:text/plain,"</span> <span class="o">+</span> <span class="nx">content</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">调用downloadFile之后,用户点击链接,就能触发浏览器下载。</span>
</p>
<h2 id="toc_1" class="h16">Not enough!</h2>
<p class="md_block md_block_as_opening md_has_block_below md_has_block_below_ol">
<span class="md_line md_line_start md_line_end">但是,还不够,上面的办法有两个硬伤,会导致流失很多懒人美眉:</span>
</p>
<ol>
<li class="md_li"><span> 下载的文件类型限制死了,美眉要下载处理后的果照怎么办?
</span></li>
<li class="md_li"><span> 下载还要再点击一下,太麻烦啦。
</span></li>
</ol>
<p class="md_block">
<span class="md_line md_line_start md_line_end">要解决文件类型的问题,可以用浏览器的新API(<a class="md_compiled" href="https://developer.mozilla.org/en-US/docs/Web/API/URL.createObjectURL">URL.createObjectURL</a>)来解决问题,URL.createObjectURL通常都是用来创建图片的DataURI用来显示图片,这里用来下载文件,让浏览器来帮我们设定好文件类型。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">URL.createObjectURL的参数是File对象或者Blob对象,File对象也就是通过input[type=file]选择的文件,Blob对象是二进制大对象,详细说明可参考<a class="md_compiled" href="https://developer.mozilla.org/en-US/docs/Web/API/Blob">这里</a>。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">现在,我们只要用content创建一个ObjectURL并赋值给aLink即可解决文件类型的限制问题。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">文件的自动下载也挺好办,自己构建一个UI点击事件,再自动触发下,就能实现自动下载啦。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">现在来看看最终代码:</span>
</p>
<div class="codehilite code_lang_js highlight"><pre><span></span><span class="kd">function</span> <span class="nx">downloadFile</span><span class="p">(</span><span class="nx">fileName</span><span class="p">,</span> <span class="nx">content</span><span class="p">){</span>
<span class="kd">var</span> <span class="nx">aLink</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s1">'a'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">blob</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Blob</span><span class="p">([</span><span class="nx">content</span><span class="p">]);</span>
<span class="kd">var</span> <span class="nx">evt</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createEvent</span><span class="p">(</span><span class="s2">"HTMLEvents"</span><span class="p">);</span>
<span class="nx">evt</span><span class="p">.</span><span class="nx">initEvent</span><span class="p">(</span><span class="s2">"click"</span><span class="p">,</span> <span class="kc">false</span><span class="p">,</span> <span class="kc">false</span><span class="p">);</span>
<span class="nx">aLink</span><span class="p">.</span><span class="nx">download</span> <span class="o">=</span> <span class="nx">fileName</span><span class="p">;</span>
<span class="nx">aLink</span><span class="p">.</span><span class="nx">href</span> <span class="o">=</span> <span class="nx">URL</span><span class="p">.</span><span class="nx">createObjectURL</span><span class="p">(</span><span class="nx">blob</span><span class="p">);</span>
<span class="nx">aLink</span><span class="p">.</span><span class="nx">dispatchEvent</span><span class="p">(</span><span class="nx">evt</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">现在,只要一调用downloadFile,文件就自动下载了,是不是很爽咧,^_^。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end"><strong>注:</strong>目前(2014-01-02)Blob和URL.createObjectURL在标准浏览器里面都不再需要加私有前缀,可以放心使用啦啦啦~~如果你不放心,可以查查<a class="md_compiled" href="http://caniuse.com/#search=Blob">Can I Use</a>。</span>
</p>
千方百计加速Web之加速DNS解析
2013-10-30T07:54:00Z
make-dns-resolve-fast-than-web-fast
iAzrael
<p class="md_block">
<span class="md_line md_line_start md_line_end">通常情况下,做移动开发时,如果要向后台请求数据,都会直接使用TCP通信。但实际上一来HTTP比TCP简单易用多了,二来有很多现有CGI如果要进行改造得花很大功夫。还是会有使用HTTP请求来拉取数据。</span>
</p>
<p class="md_block md_block_as_opening md_has_block_below md_has_block_below_ol">
<span class="md_line md_line_start md_line_end">在做Android QQ二维码时,扫描到二维码字符串,就是把该字符串用HTTP传给后台,后台解析后返回给客户端,客户端再进行下一步处理。在提交测试后,测试同事发现,在移动网络上,DNS解析会经常失败,导致二维码扫描功能不可用。功能测试不通过,导致无法发布。同时测试喜欢在清空DNS缓存和屏蔽了DNS解析的情况下,二维码解析功能仍然可用。因此这里增加了如下处理:</span>
</p>
<ol>
<li class="md_li"><span> 进入“扫一扫”的界面时,客户端就开始对CGI所在域名进行解析,并把解析结果缓存到本地文件;
</span></li>
<li class="md_li"><span> 发起CGI请求时,还是使用原域名进行请求,如果DNS解析失败,则用第一步缓存的IP替换掉CGI中的域名再发起一次请求。
</span></li>
</ol>
<p class="md_block">
<span class="md_line md_line_start">由于国内有好几个网络运营商,公司在不同的网络环境都有不一样的出口IP,因此选择最近的IP才能快速访问CGI。所以缓存域名结果时,需要区分网络分别保存。<br /></span>
<span class="md_line">more<br /></span>
<span class="md_line md_line_end">这样,当用户的手机上至少成功使用了一次二维码扫描时,CGI对应的IP就保存下来了(至少有一个出口IP)。下次访问(同一次登录或者关闭手机QQ后再打开)时,即使DNS解析失败,还是能使用上一次保存的IP进行访问,可能会相应比较慢(用户从A网络切换到了B网络),但起码保证了功能的可用性。实现起来也不难,Java都有现成的接口了。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">主动发起DNS解析只要调用InetAddress的接口即可,把获取到的结果保存到SharedPreferences供下次使用:</span>
</p>
<div class="codehilite code_lang_java highlight"><pre><span></span><span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">lookupIP</span><span class="o">(</span><span class="n">Context</span> <span class="n">context</span><span class="o">,</span> <span class="n">String</span> <span class="n">host</span><span class="o">){</span>
<span class="n">SharedPreferences</span> <span class="n">preferences</span> <span class="o">=</span> <span class="n">context</span><span class="o">.</span><span class="na">getSharedPreferences</span><span class="o">(</span><span class="s">"host"</span><span class="o">,</span> <span class="mi">0</span><span class="o">);</span>
<span class="n">String</span> <span class="n">ip</span><span class="o">;</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">InetAddress</span> <span class="n">address</span> <span class="o">=</span> <span class="n">InetAddress</span><span class="o">.</span><span class="na">getByName</span><span class="o">(</span><span class="n">host</span><span class="o">);</span>
<span class="n">ip</span> <span class="o">=</span> <span class="n">address</span><span class="o">.</span><span class="na">getHostAddress</span><span class="o">();</span>
<span class="n">SharedPreferences</span><span class="o">.</span><span class="na">Editor</span> <span class="n">editor</span> <span class="o">=</span> <span class="n">preferences</span><span class="o">.</span><span class="na">edit</span><span class="o">();</span>
<span class="n">editor</span><span class="o">.</span><span class="na">putString</span><span class="o">(</span><span class="n">host</span><span class="o">,</span> <span class="n">ip</span><span class="o">);</span>
<span class="n">editor</span><span class="o">.</span><span class="na">commit</span><span class="o">();</span>
<span class="n">QLog</span><span class="o">.</span><span class="na">d</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"lookup address: "</span> <span class="o">+</span> <span class="n">host</span> <span class="o">+</span> <span class="s">", ip: "</span> <span class="o">+</span> <span class="n">ip</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">UnknownHostException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">然后在HTTP请求出现DNS解析错误的时候,用IP替换掉URL中的域名即可:</span>
</p>
<div class="codehilite code_lang_java highlight"><pre><span></span><span class="n">HttpResponse</span> <span class="n">response</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="k">try</span><span class="o">{</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">openRequest</span><span class="o">(</span><span class="n">context</span><span class="o">,</span> <span class="n">url</span><span class="o">,</span> <span class="n">host</span><span class="o">,</span> <span class="n">method</span><span class="o">,</span> <span class="n">params</span><span class="o">,</span> <span class="n">header</span><span class="o">);</span>
<span class="o">}</span><span class="k">catch</span> <span class="o">(</span><span class="n">IOException</span> <span class="n">e</span><span class="o">){</span>
<span class="c1">//DNS错误改用ip重新发一次</span>
<span class="n">String</span> <span class="n">ip</span> <span class="o">=</span> <span class="n">getIP</span><span class="o">(</span><span class="n">context</span><span class="o">,</span> <span class="n">host</span><span class="o">);</span>
<span class="k">if</span><span class="o">(</span><span class="n">ip</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">){</span>
<span class="n">url</span> <span class="o">=</span> <span class="n">url</span><span class="o">.</span><span class="na">replace</span><span class="o">(</span><span class="n">host</span><span class="o">,</span> <span class="n">ip</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">openRequest</span><span class="o">(</span><span class="n">context</span><span class="o">,</span> <span class="n">url</span><span class="o">,</span> <span class="n">host</span><span class="o">,</span> <span class="n">method</span><span class="o">,</span> <span class="n">params</span><span class="o">,</span> <span class="n">header</span><span class="o">);</span>
<span class="o">}</span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">这里之所以不直接用上次保存的IP来替换域名进行访问,是因为在正常情况下,进入“扫一扫”的界面时,已经预先对所用域名进行了预解析,如果解析成功,调用openRequest时就不用DNS查询了;而如果预解析失败了,openRequest的时候还能再尝试一次,失败时才使用IP访问。同时,很多用户都会在移动网络和WIFI网络中切换,如果直接用IP替换域名,会出现用户当前是移动网络,而是用的域名IP是在教育网IP(上一次使用的是教育网WIFI)的情况,导致CGI响应变得更慢。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">当然,更好的解决方法是:先检测当前用户的网络环境,如果本地保存了对应网络的IP,直接使用IP请求;如果没有,再改用域名来请求。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">还有更进阶的方案:第一次登陆时,从服务器拉取一份host列表(每个域名包括各个网络环境的出口IP),把所有HTTP请求的域名都替换成相应IP,这样就能完美解决DNS不可用、DNS解析失败的情况了。之后维护host文件的更新即可。</span>
</p>
【代码分享】根据类型智能提取参数
2013-09-10T09:39:00Z
get-arguments-by-type
iAzrael
<p class="md_block">
<span class="md_line md_line_start md_line_end">如果你是个Javascript程序员,那一定经常写下面的代码:</span>
</p>
<div class="codehilite code_lang_js highlight"><pre><span></span><span class="kd">function</span> <span class="nx">funcA</span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="nx">params</span><span class="p">,</span> <span class="nx">callback</span><span class="p">,</span> <span class="nx">option</span><span class="p">){</span>
<span class="k">if</span><span class="p">(</span><span class="nx">arguments</span><span class="p">.</span><span class="nx">length</span> <span class="o">==</span> <span class="mi">2</span><span class="p">){</span>
<span class="c1">//funcA(url, callback);</span>
<span class="k">if</span><span class="p">(</span><span class="k">typeof</span> <span class="nx">params</span> <span class="o">==</span> <span class="s1">'function'</span><span class="p">){</span>
<span class="nx">callback</span> <span class="o">=</span> <span class="nx">params</span><span class="p">;</span>
<span class="nx">params</span> <span class="o">=</span> <span class="p">{};</span>
<span class="p">}</span><span class="k">else</span><span class="p">{</span>
<span class="c1">//funcA(url, params);</span>
<span class="c1">//......</span>
<span class="p">}</span>
<span class="p">}</span><span class="k">else</span> <span class="p">{</span>
<span class="c1">//......</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">当参数变化形式比较少的时候还没问题,当你的方法想对多种传参形式进行容错时,一堆的if else判断就变得很难看了。这时不妨尝试下这个 getArguments 方法。more</span>
</p>
<div class="codehilite code_lang_js highlight"><pre><span></span><span class="kd">var</span> <span class="nx">toString</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">toString</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">is</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">obj</span><span class="p">){</span>
<span class="kd">var</span> <span class="nx">type</span> <span class="o">=</span> <span class="nx">toString</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="nx">obj</span><span class="p">);</span>
<span class="nx">type</span> <span class="o">=</span> <span class="nx">type</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="nx">type</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
<span class="k">return</span> <span class="nx">type</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">var</span> <span class="nx">getArguments</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">argus</span><span class="p">,</span> <span class="nx">type1</span><span class="p">,</span> <span class="nx">type2</span><span class="p">,</span> <span class="nx">type3</span> <span class="cm">/*...*/</span><span class="p">){</span>
<span class="kd">var</span> <span class="nx">srcTypes</span> <span class="o">=</span> <span class="p">[];</span>
<span class="kd">var</span> <span class="nx">targetTypes</span> <span class="o">=</span> <span class="nb">Array</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">slice</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">arguments</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">result</span> <span class="o">=</span> <span class="p">[];</span>
<span class="k">for</span><span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">len</span> <span class="o">=</span> <span class="nx">argus</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span> <span class="o"><</span> <span class="nx">len</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">srcTypes</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">is</span><span class="p">(</span><span class="nx">argus</span><span class="p">[</span><span class="nx">i</span><span class="p">]));</span>
<span class="p">}</span>
<span class="k">for</span><span class="p">(</span><span class="kd">var</span> <span class="nx">m</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">n</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">len</span> <span class="o">=</span> <span class="nx">targetTypes</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">n</span> <span class="o"><</span> <span class="nx">len</span><span class="p">;</span> <span class="p">){</span>
<span class="k">if</span><span class="p">(</span><span class="nx">srcTypes</span><span class="p">[</span><span class="nx">m</span><span class="p">]</span> <span class="o">===</span> <span class="nx">targetTypes</span><span class="p">[</span><span class="nx">n</span><span class="p">]){</span>
<span class="nx">result</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">argus</span><span class="p">[</span><span class="nx">m</span><span class="p">]);</span>
<span class="nx">m</span><span class="o">++</span><span class="p">,</span> <span class="nx">n</span><span class="o">++</span><span class="p">;</span>
<span class="p">}</span><span class="k">else</span><span class="p">{</span>
<span class="nx">result</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="kc">null</span><span class="p">);</span>
<span class="nx">n</span><span class="o">++</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">result</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">使用方法如下:</span>
</p>
<div class="codehilite code_lang_js highlight"><pre><span></span><span class="kd">function</span> <span class="nx">funcB</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">params</span><span class="p">,</span> <span class="nx">callback</span><span class="p">,</span> <span class="nx">option</span><span class="p">){</span>
<span class="kd">var</span> <span class="nx">argus</span> <span class="o">=</span> <span class="nx">getArguments</span><span class="p">(</span><span class="nx">arguments</span><span class="p">,</span> <span class="s1">'String'</span><span class="p">,</span> <span class="s1">'Object'</span><span class="p">,</span> <span class="s1">'Function'</span><span class="p">,</span> <span class="s1">'Object'</span><span class="p">);</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">argus</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">params</span> <span class="o">=</span> <span class="nx">argus</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">||</span> <span class="p">{},</span> <span class="nx">callback</span> <span class="o">=</span> <span class="nx">argus</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="nx">option</span> <span class="o">=</span> <span class="nx">argus</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">||</span> <span class="p">{};</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">argus</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">运行结果如下:</span>
</p>
<div class="codehilite code_lang_js highlight"><pre><span></span><span class="nx">funcB</span><span class="p">(</span><span class="s1">'a'</span><span class="p">,</span><span class="kd">function</span><span class="p">(){})</span>
<span class="c1">//console: ["a", null, function, null]</span>
<span class="nx">funcB</span><span class="p">(</span><span class="s1">'a'</span><span class="p">,</span><span class="kd">function</span><span class="p">(){},</span> <span class="p">{</span><span class="nx">o</span><span class="o">:</span><span class="mi">1</span><span class="p">})</span>
<span class="c1">//console: ["a", null, function, Object]</span>
<span class="nx">funcB</span><span class="p">(</span><span class="s1">'a'</span><span class="p">,{</span><span class="nx">p</span><span class="o">:</span><span class="mi">1</span><span class="p">})</span>
<span class="c1">//console: ["a", Object, null, null]</span>
<span class="nx">funcB</span><span class="p">({</span><span class="nx">p</span><span class="o">:</span><span class="mi">1</span><span class="p">})</span>
<span class="c1">//console: [null, Object, null, null]</span>
<span class="nx">funcB</span><span class="p">(</span><span class="kd">function</span><span class="p">(){})</span>
<span class="c1">//console: [null, null, function, null]</span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">怎么样,是不是简单很多咧?^_^</span>
</p>
Compiler@NodeJS(三)- 自定义命令
2013-03-20T15:11:00Z
nodejs-compiler-custom-cmd
iAzrael
<p class="md_block">
<span class="md_line md_line_start md_line_end">_接上篇:<a class="md_compiled" href="/nodejs-compiler-pipe/" title="Compiler@NodeJS(二)- 强大的管道">Compiler@NodeJS(二)- 强大的管道</a>_</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">本来早就应该写这篇文章的,只是忙的时候忙,闲的时候懒,导致拖了这么久。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">不管内置多少命令,需求总是千变万化的,这时候内置命令就不够用了,需要使用者自己编写一些命令。现在来看看怎么做。more</span>
</p>
<h2 id="toc_0" class="h16">一、内置命令</h2>
<p class="md_block">
<span class="md_line md_line_start md_line_end">先来看看内置命令的文件结构是怎样的:</span>
</p>
<pre><code>+--- compiler
+--- cmds
+--- copy
+--- concat
--- index.js
--- README.md</code></pre>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">每个命令都是cmds下面的一个单独目录,如copy、concat等等。每个命令下面都必须有一个index.js文件,作为这个命令的入口。index.js需要export一个属性(async)和一个方法(execute),这里拿concat命令来说明,如下:</span>
</p>
<div class="codehilite code_lang_js highlight"><pre><span></span><span class="kd">var</span> <span class="nx">fs</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'fs'</span><span class="p">),</span>
<span class="nx">path</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'path'</span><span class="p">);</span>
<span class="c1">//指示该命令是异步执行的,默认为false,命令结束后会自动调用 nextTask;</span>
<span class="c1">//如果为true,则需在本命令执行完成之后主动调用 nextTask</span>
<span class="nx">exports</span><span class="p">.</span><span class="nx">async</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="c1">//命令的入口函数</span>
<span class="nx">exports</span><span class="p">.</span><span class="nx">execute</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">task</span><span class="p">,</span> <span class="nx">compileConfig</span><span class="p">,</span> <span class="nx">runOptions</span><span class="p">,</span> <span class="nx">nextTask</span><span class="p">){</span>
<span class="c1">//省略……</span>
<span class="p">}</span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">当concat命令被调用的时候,compiler会找到concat目录下的index.js,require之后执行它的execute方法,execute的参数说明如下:</span>
</p>
<table>
<thead>
<tr>
<th>参数名</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>task</td>
<td>Object,这次命令调用要执行的任务,一个task包括任务id、任务要执行的命令(cmd)、任务的输入(source)、任务执行的输出目录(target)、任务的参数(params,也就是在config.json中配置的对应的params,比如下面示例代码中的custA_html中的params)</td>
</tr>
<tr>
<td>compileConfig</td>
<td>Object,执行compiler时传入的配置,也就是config.json内容</td>
</tr>
<tr>
<td>runOptions</td>
<td>Object,执行该任务时的运行时信息,包括compiler的目录、命令的目录(concat的绝对路径)、命令的文件名(index.js的目录+名字)</td>
</tr>
<tr>
<td>nextTask</td>
<td>Function,告诉compiler继续执行下一个命令,在设置了exports.async=true时,需要该命令主动调用,如:nextTask()。</td>
</tr>
</tbody>
</table>
<h2 id="toc_1" class="h16">二、自定义命令</h2>
<p class="md_block md_block_as_opening md_has_block_below md_has_block_below_ol">
<span class="md_line md_line_start md_line_end">自定义命令的写法很简单:</span>
</p>
<ol>
<li class="md_li"><span> 只要建立一个目录,比如custA(这里我放到了项目根目录下的custom_cmds),创建index.js文件,并提供execute方法;
</span></li>
<li class="md_li"><span> 在config.json中配置该命令,让compiler知道哪里可以找到该命令。
</span></li>
</ol>
<p class="md_block">
<span class="md_line md_line_start md_line_end">有了自定义命令的config.json的样子应该是类似这样的:</span>
</p>
<div class="codehilite code_lang_json highlight"><pre><span></span><span class="p">{</span>
<span class="nt">"sourceRoot"</span><span class="p">:</span> <span class="s2">"./"</span><span class="p">,</span>
<span class="nt">"targetRoot"</span><span class="p">:</span> <span class="s2">"./build"</span><span class="p">,</span>
<span class="nt">"fileFormat"</span><span class="p">:</span> <span class="s2">"js,css,html,htm,png,gif,jpg,jpeg,wav,json"</span><span class="p">,</span>
<span class="nt">"cmds"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"custA"</span><span class="p">:</span> <span class="p">{</span><span class="err">//配置自定义命令</span>
<span class="nt">"id"</span><span class="p">:</span> <span class="s2">"custA"</span><span class="p">,</span>
<span class="nt">"root"</span><span class="p">:</span> <span class="s2">"./custom_cmds/custA/"</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="nt">"rules"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"custA_html"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"cmd"</span><span class="p">:</span> <span class="s2">"custA"</span><span class="p">,</span><span class="err">//使用自定义命令</span>
<span class="nt">"target"</span><span class="p">:</span> <span class="s2">"./"</span><span class="p">,</span>
<span class="nt">"source"</span><span class="p">:</span> <span class="s2">"./"</span><span class="p">,</span>
<span class="nt">"params"</span><span class="p">:</span> <span class="p">{}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">如代码所示,只要在cmds项中,添加一个custA的json描述,给出id和根目录(root),其他事情就不用管了。</span>
</p>
<h2 id="toc_2" class="h16">三、组合命令</h2>
<p class="md_block">
<span class="md_line md_line_start md_line_end">在<a class="md_compiled" href="/nodejs-compiler-pipe/" title="Compiler@NodeJS(二)- 强大的管道">上一篇</a>讲到,compiler最强大的是管道特性,可以用来将命令串联组合。有时候,一些任务可能需要很多个命令来组合完成,但是在每个rule里面写又不是很方便。这时候可以使用自定义命令的另外一种形式,组合命令。使用很简单,只要在config.json配置就行。</span>
</p>
<div class="codehilite code_lang_json highlight"><pre><span></span><span class="p">{</span>
<span class="nt">"sourceRoot"</span><span class="p">:</span> <span class="s2">"./"</span><span class="p">,</span>
<span class="nt">"targetRoot"</span><span class="p">:</span> <span class="s2">"./build"</span><span class="p">,</span>
<span class="nt">"fileFormat"</span><span class="p">:</span> <span class="s2">"js,css,html,htm,png,gif,jpg,jpeg,wav,json"</span><span class="p">,</span>
<span class="nt">"cmds"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"custB"</span><span class="p">:</span> <span class="s2">"translate|copy,compress"</span><span class="p">,</span>
<span class="nt">"custC"</span><span class="p">:</span> <span class="s2">"custB|ispriter"</span>
<span class="p">},</span>
<span class="nt">"rules"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"translate_html"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"cmd"</span><span class="p">:</span> <span class="s2">"custB"</span><span class="p">,</span>
<span class="nt">"parmas"</span><span class="p">:</span> <span class="p">{</span><span class="err">/*..*/</span><span class="p">}</span>
<span class="err">}</span>
<span class="err">}</span>
<span class="err">}</span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">其实组合命令就是把原有命令串、并联在一起,方便之后使用,同时组合命令还能再次被组合,是不是很神奇咧?哈哈。命令的组合原则可以看<a class="md_compiled" href="/nodejs-compiler-pipe/">上一篇</a>介绍。不过有点需要注意的,在使用组合命令时,传入的params需要一一对应,比较不顺手。如果是多次组合过的命令,params将变得更加复杂,不过暂时只能这样了。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">嗯,到这里,自定义命令的教程就结束了。如果你还是不太明白,可以到<a class="md_compiled" href="https://github.com/iazrael/compiler">github</a>中查看内置命令的实现,如:<a class="md_compiled" href="https://github.com/iazrael/compiler/blob/master/cmds/template-picker/index.js">template-picker</a>、<a class="md_compiled" href="https://github.com/iazrael/compiler/blob/master/cmds/ioffline/index.js">ioffline</a>、<a class="md_compiled" href="https://github.com/iazrael/compiler/blob/master/cmds/concat/index.js">concat</a>、<a class="md_compiled" href="https://github.com/iazrael/compiler/blob/master/cmds/copy/index.js">copy</a>等等,毕竟千言万语不及代码两行嘛,哈哈。有任何问题也可在本文留言,或者邮件给我,欢迎试用,^_^。</span>
</p>
让Java跟Javascript更加亲密
2013-02-19T08:28:00Z
make-java-communicate-with-javascript-easily
iAzrael
<p class="md_block">
<span class="md_line md_line_start md_line_end">在移动App开发中,为了快速迭代,通常都会使用Native+Web的模式开发。具体来说就是使用Java提供接口,使用WebView控件嵌套Web页面来实现UI和交互。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">在Android中,Java可以很方便的提供接口给WebView中的Js进行调用,只要以下一行代码就能搞定:</span>
</p>
<div class="codehilite code_lang_java highlight"><pre><span></span><span class="n">mWebView</span><span class="o">.</span><span class="na">addJavascriptInterface</span><span class="o">(</span><span class="k">new</span> <span class="n">JavascriptInterface</span><span class="o">(),</span> <span class="s">"custom_name"</span><span class="o">);</span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">这样,JavascriptInterface的所有声明为public的方法,都能被mWebView中的Js通过以下方式调用:</span>
</p>
<div class="codehilite code_lang_javascript highlight"><pre><span></span><span class="nb">window</span><span class="p">.</span><span class="nx">custom_name</span><span class="p">.</span><span class="nx">xxx</span><span class="p">();</span><span class="c1">//xxx为JavascriptInterface的公有方法</span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">而Java需要调用Js时,则是通过WebView实例的loadUrl方法调用:</span>
</p>
<div class="codehilite code_lang_java highlight"><pre><span></span><span class="n">mWebView</span><span class="o">.</span><span class="na">loadUrl</span><span class="o">(</span><span class="s">"javascript:xxx(yyy)"</span><span class="o">);</span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">这其实跟你在浏览器的地址栏敲下“<code>javascript:alert(1)</code>”的原理是一样的。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">一切看起来都是那么的美好,只是……</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">当Java需要传递大量字符串给Js时,URL就力不从心了。另外,从URL执行的Js,在页面没加载完成时,是有可能导致页面出现undefined错误(因为要执行的那个方法可能还没有声明呢),会引发各种奇形怪状的错误。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">more</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">那要怎么办呢?</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">再回看上面Js调用Java接口的地方,可以发现,Js是可以直接调用Java方法并取得Java给的返回值的(必须是可序列化的数据)。那么,为何不试试把Java需要执行的Js方法,保存起来,让Js来读取、执行、并把结果写回?</span>
</p>
<p class="md_block md_block_as_opening md_has_block_below md_has_block_below_ol">
<span class="md_line md_line_start md_line_end">步骤如下:</span>
</p>
<ol>
<li class="md_li"><span> Java把Js调用(命令)和回调缓存,如保存到ArrayList;
</span></li>
<li class="md_li"><span> Js定时轮询Java提供的getCommandList接口;
</span></li>
<li class="md_li"><span> Js读取到要执行命令,执行它,并把结果通过setResult写回给Java;
</span></li>
<li class="md_li"><span> Java把对应命令的回调取出并执行。
</span></li>
</ol>
<p class="md_block">
<span class="md_line md_line_start md_line_end">如此即完成了Java调用Js的流程。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">为了方便使用,简单的封装了下,名为<a class="md_compiled" href="https://github.com/iazrael/AndroidJavascriptBridge">AndroidJavascriptBridge</a>,可移步到<a class="md_compiled" href="https://github.com/iazrael/AndroidJavascriptBridge">Github</a>查看源码和示例(MainActivity.java和test.js )。</span>
</p>
<h2 id="toc_0" class="h16">使用方法</h2>
<p class="md_block">
<span class="md_line md_line_start md_line_end">Android端调用, 加入com.imatlas.jsb 和 com.imatlas.util包, 按如下步骤调用</span>
</p>
<div class="codehilite code_lang_java highlight"><pre><span></span><span class="c1">//1. 创建JavascriptBridge实例 </span>
<span class="kd">final</span> <span class="n">JavascriptBridge</span> <span class="n">jsb</span> <span class="o">=</span> <span class="k">new</span> <span class="n">JavascriptBridge</span><span class="o">(</span><span class="n">webView</span><span class="o">);</span>
<span class="c1">//2. 调用Javascript方法</span>
<span class="n">Bundle</span> <span class="n">params</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Bundle</span><span class="o">();</span>
<span class="n">params</span><span class="o">.</span><span class="na">putString</span><span class="o">(</span><span class="s">"asdfasdf"</span><span class="o">,</span> <span class="s">"123123"</span><span class="o">);</span>
<span class="n">jsb</span><span class="o">.</span><span class="na">require</span><span class="o">(</span><span class="s">"alert"</span><span class="o">,</span> <span class="n">params</span><span class="o">,</span> <span class="k">new</span> <span class="n">JavascriptBridge</span><span class="o">.</span><span class="na">Callback</span><span class="o">()</span> <span class="o">{</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onComplate</span><span class="o">(</span><span class="n">JSONObject</span> <span class="n">response</span><span class="o">,</span> <span class="n">String</span> <span class="n">cmd</span><span class="o">,</span> <span class="n">Bundle</span> <span class="n">params</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="s">"js response"</span><span class="o">,</span><span class="n">response</span><span class="o">.</span><span class="na">toString</span><span class="o">());</span>
<span class="o">}</span>
<span class="o">});</span>
<span class="c1">//3. 提供Java方法给Javascript调用</span>
<span class="c1">//添加个 messagebox 方法给js</span>
<span class="n">jsb</span><span class="o">.</span><span class="na">addJavaMethod</span><span class="o">(</span><span class="s">"messagebox"</span><span class="o">,</span> <span class="k">new</span> <span class="n">JavascriptBridge</span><span class="o">.</span><span class="na">Function</span><span class="o">()</span> <span class="o">{</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">Object</span> <span class="nf">execute</span><span class="o">(</span><span class="n">JSONObject</span> <span class="n">params</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Toast</span><span class="o">.</span><span class="na">makeText</span><span class="o">(</span><span class="n">getApplicationContext</span><span class="o">(),</span> <span class="n">params</span><span class="o">.</span><span class="na">toString</span><span class="o">(),</span> <span class="n">Toast</span><span class="o">.</span><span class="na">LENGTH_LONG</span><span class="o">)</span>
<span class="o">.</span><span class="na">show</span><span class="o">();</span>
<span class="k">return</span> <span class="s">"{\"ret\":123}"</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">});</span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">Javascript端的调用, 须先引入web/js/jsb.js, 之后按如下方式调用</span>
</p>
<div class="codehilite code_lang_javascript highlight"><pre><span></span><span class="c1">//1. 调用Java方法</span>
<span class="nx">jsb</span><span class="p">.</span><span class="nx">require</span><span class="p">(</span><span class="s1">'messagebox'</span><span class="p">,</span> <span class="p">{</span><span class="s1">'text'</span><span class="o">:</span> <span class="s1">'你好, messagebox!'</span><span class="p">},</span> <span class="kd">function</span><span class="p">(</span><span class="nx">response</span><span class="p">){</span>
<span class="nx">alert</span><span class="p">(</span><span class="s1">'调用messagebox回来啦\n'</span> <span class="o">+</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">response</span><span class="p">));</span>
<span class="p">});</span>
<span class="c1">//2. 提供Javascript方法给Java调用</span>
<span class="nx">jsb</span><span class="p">.</span><span class="nx">addJavascriptMethod</span><span class="p">(</span><span class="s1">'alert'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">params</span><span class="p">){</span>
<span class="nx">alert</span><span class="p">(</span> <span class="s1">'------\n'</span> <span class="o">+</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">params</span><span class="p">)</span> <span class="o">+</span> <span class="s1">'\n========\n'</span><span class="p">);</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'text'</span><span class="o">:</span> <span class="s1">'alert ok'</span><span class="p">};</span>
<span class="p">});</span>
</pre></div>
<!--block_code_end-->
<p class="md_block">
<span class="md_line md_line_start md_line_end">IOS的话就要反过来了,要改成由Objective-C来轮询Js,来实现Js对Native的调用。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">嗯,等改天有时间了,就把IOS也封装进来,用起来就简单多了。</span>
</p>
从网页监听Android设备的返回键
2013-02-04T09:52:00Z
monitoring-the-back-button-of-android-from-web
iAzrael
<p class="md_block">
<span class="md_line md_line_start md_line_end">最近搞Android项目的时候,遇到一个比较蛋疼的需求,需要从Client App调用系统浏览器打开一个页面,进行杂七杂八的一些交互之后,返回到App。如何打开浏览器和如何返回App这里就不说了,有兴趣的童鞋可私下交流。</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">之所以说这个需求蛋疼,是因为Android有个物理返回键啊……返回键啊……键啊……啊……</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">用户按下返回键后,预期应该跟点击页面上的返回键一样——返回App。然而这个返回键的被按下的时候网页完全不知道啊(onbeforeunload不算),找不到直接的办法去监听,愁死我们这全苦逼程序员鸟~</span>
</p>
<p class="md_block">
<span class="md_line md_line_start md_line_end">虽然啊不能直接监听,曲线救国的办法,还是有滴。more</span>
</p>
<p class="md_block md_block_as_opening md_has_block_below md_has_block_below_ol">
<span class="md_line md_line_start md_line_end">经过艰苦卓绝的寻找,发现使用HTML5的History可以稍微模拟到返回键的按下事件。原理如下:</span>
</p>
<ol>
<li class="md_li"><span> 页面加载完成时,调用history.pushState写入一个指定状态STATE,并监听window.onpopstate;
</span></li>
<li class="md_li"><span> 当onpopstate被触发时,检查event.state是否等于STATE,如果相等,表示页面发生了后退(按下返回键或者浏览器的后退按钮),则把这次行为当作是返回键被按下了(把点击浏览器的后退按钮也误算进来了,不过没啥好法子了呀)。
</span></li>
</ol>
<p class="md_block">
<span class="md_line md_line_start md_line_end">嗯,为了方便调用,把这个逻辑稍微封装了下,代码见这里(<a class="md_compiled" href="https://github.com/iazrael/xback">https://github.com/iazrael/xback</a>),使用方法如下:</span>
</p>
<div class="codehilite code_lang_javascript highlight"><pre><span></span><span class="nx">XBack</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="kd">function</span><span class="p">(){</span>
<span class="nx">alert</span><span class="p">(</span><span class="s1">'oh! you press the back button'</span><span class="p">);</span>
<span class="p">});</span>
<span class="nx">XBack</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="kd">function</span><span class="p">(){</span>
<span class="nx">alert</span><span class="p">(</span><span class="s1">'ah, press press press'</span><span class="p">);</span>
<span class="p">});</span>
</pre></div>
<!--block_code_end-->
<p class="md_block md_block_as_opening md_has_block_below md_has_block_below_ol">
<span class="md_line md_line_start md_line_end">不过这个方法有些缺陷:</span>
</p>
<ol>
<li class="md_li"><span> 如果项目本身使用了pushState,则历史记录会有瑕疵(多了一个历史);
</span></li>
<li class="md_li"><span> 浏览器的后退按钮点击以及调用history.back()也会被当成按下了返回键。
</span></li>
</ol>
<p class="md_block">
<span class="md_line md_line_start md_line_end">But anyway,对于结构和逻辑比较简单的跳转页来说(就是为了返回App用的),这个方法还是蛮实用的,对不对?嘻嘻~</span>
</p>