﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-马航的博客</title><link>http://www.blogjava.net/mahang/</link><description /><language>zh-cn</language><lastBuildDate>Sat, 09 May 2026 20:11:38 GMT</lastBuildDate><pubDate>Sat, 09 May 2026 20:11:38 GMT</pubDate><ttl>60</ttl><item><title>Struts、Ajax、Restful、Web Service 狂想曲框架实现篇（三）</title><link>http://www.blogjava.net/mahang/archive/2011/11/25/365019.html</link><dc:creator>马航</dc:creator><author>马航</author><pubDate>Fri, 25 Nov 2011 10:18:00 GMT</pubDate><guid>http://www.blogjava.net/mahang/archive/2011/11/25/365019.html</guid><wfw:comment>http://www.blogjava.net/mahang/comments/365019.html</wfw:comment><comments>http://www.blogjava.net/mahang/archive/2011/11/25/365019.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mahang/comments/commentRss/365019.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mahang/services/trackbacks/365019.html</trackback:ping><description><![CDATA[<p class="p0"><span style="font-size: 16px;">&nbsp; &nbsp; &nbsp; 在第一篇时就说过框架要在<span style="font-family: 'Times New Roman';">URL</span><span style="font-family: 宋体;">上作文章，是的，本文就框架怎样充分利用</span><span style="font-family: 'Times New Roman';">url</span><span style="font-family: 宋体;">上作尽可能详细的说明。</span></span></p>
<p class="p0"><span style="font-size: 16px;">&nbsp; &nbsp; &nbsp; 做<span style="font-family: 'Times New Roman';">web</span><span style="font-family: 宋体;">开发的不可能对</span><span style="font-family: 'Times New Roman';">url</span><span style="font-family: 宋体;">陌生，早在</span><span style="font-family: 'Times New Roman';">web1.0</span><span style="font-family: 宋体;">时代，</span><span style="font-family: 'Times New Roman';">url</span><span style="font-family: 宋体;">作为统一资源定位符，在对</span><span style="font-family: 'Times New Roman';">web</span><span style="font-family: 宋体;">中资源的如何获得上起到巨大作用。不论用户请求的时静态页面或者是各种图片、脚本文件，通过</span><span style="font-family: 'Times New Roman';">url</span><span style="font-family: 宋体;">总能从</span><span style="font-family: 'Times New Roman';">web</span><span style="font-family: 宋体;">网站获取要访问的资源。</span><span style="font-family: 'Times New Roman';">Web2.0</span><span style="font-family: 宋体;">更是常常使用</span><span style="font-family: 'Times New Roman';">url</span><span style="font-family: 宋体;">作为</span><span style="font-family: 'Times New Roman';">get</span><span style="font-family: 宋体;">请求时参数的传递，如</span><span style="font-family: 'Times New Roman';">http://xxx.xxx.xxx/xxx.jsp?user=admin</span><span style="font-family: 宋体;">。以及近几年很火</span><span style="font-family: 'Times New Roman';">restful&nbsp;web&nbsp;service&nbsp;</span><span style="font-family: 宋体;">摒弃</span><span style="font-family: 'Times New Roman';">soap</span><span style="font-family: 宋体;">而使用</span><span style="font-family: 'Times New Roman';">url</span><span style="font-family: 宋体;">传递请求参数&nbsp;都说明合理利用</span><span style="font-family: 'Times New Roman';">url</span><span style="font-family: 宋体;">的可行和流行。</span></span></p>
<p class="p0"><span style="font-size: 16px;">&nbsp; &nbsp; &nbsp; 当然不止是使用了<span style="font-family: 'Times New Roman';">url</span><span style="font-family: 宋体;">就算好的实践，而是能够做到优雅的使用，保证层次分明和整体的简洁，这才算是好的方式，这也正是本框架对使用</span><span style="font-family: 'Times New Roman';">url&nbsp;</span><span style="font-family: 宋体;">所追求的目标。</span></span></p>
<p class="p0"><span style="font-size: 16px;">&nbsp; &nbsp; &nbsp; 首先来看几个例子：</span></p>
<div class="cnblogs_code">
<pre><span style="font-size: 16px;">http://www.cnblogs.com/p2</span><br /><span style="font-size: 16px;">http://www.xxx.com/index.do?page=2</span><br /><br /><span style="font-size: 16px;">http://www.xxx.com/product/</span><br /><span style="font-size: 16px;">http://www.xxx.com/channel.do?channel=product</span><br /><br /><span style="font-size: 16px;">http://www.xxx.com/product/mobile</span><br /><span style="font-size: 16px;">http://www.xxx.com/channel.do?channel=product&amp;<span style="color: #ff0000;">&amp;subChannel</span>=mobile</span></pre>
</div>
<p class="p0"><span style="font-size: 16px;">&nbsp; &nbsp; &nbsp; 相信各位看官不用我说也能明白，这几组的实现肯定第一种实现的方式更佳。抛开它能屏蔽服务器端使用的技术这一特性不说，它还能够更好地说明动态网站的层次结构，让用户在访问时能明确知道在网站的什么位置，而不会觉得是陷入了一个迷宫。</span></p>
<p class="p0"><span style="font-size: 16px;">&nbsp; &nbsp; &nbsp; 当然上面列举的例子是网站前端所使用的<span style="font-family: 'Times New Roman';">url</span><span style="font-family: 宋体;">表现方式，因为表现方式可以多种多样，个人喜好不同，本框架在设计时没有给指定前端</span><span style="font-family: 'Times New Roman';">url</span><span style="font-family: 宋体;">的表现方式，而是定义接口，把这个权利留给使用的用户。框架将考虑更多&nbsp;通用性的东西而不是&nbsp;个性&nbsp;自由的东西。</span></span></p>
<p class="p0">&nbsp;</p>
<p class="p0"><span style="font-size: 16px;">&nbsp; &nbsp; &nbsp; 下面对框架里默认使用的<span style="font-family: 'Times New Roman';">url&nbsp;Router&nbsp;AMPPathRouter</span><span style="font-family: 宋体;">做详细的介绍，包括设计的思想和实现的方式。首先</span><span style="font-family: 'Times New Roman';">AMPPathRouter</span><span style="font-family: 宋体;">的用途定位为后台使用。为了理解快速的理解它的工作原理，先来和</span><span style="font-family: 'Times New Roman';">struts</span><span style="font-family: 宋体;">做一下对比。</span></span></p>
<p class="p0"><span style="font-size: 16px;">&nbsp; &nbsp; &nbsp; Struts<span style="font-family: 宋体;">关于请求的配置：</span></span></p>
<p class="p0">&nbsp;</p>
<div class="cnblogs_code">
<pre><span style="font-size: 16px;"><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">action </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="login"</span><span style="color: #ff0000;"> class</span><span style="color: #0000ff;">="com.lscmjx.action.LoginAction"</span><span style="color: #ff0000;"> method</span><span style="color: #0000ff;">="login"</span><span style="color: #0000ff;">&gt;</span></span><br /><span style="font-size: 16px;">      <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">result </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="success"</span><span style="color: #0000ff;">&gt;</span></span><br /><span style="font-size: 16px;">            main.jsp</span><br /><span style="font-size: 16px;">      <span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">result</span><span style="color: #0000ff;">&gt;</span></span><br /><span style="font-size: 16px;">      <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">result </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="failure"</span><span style="color: #0000ff;">&gt;</span></span><br /><span style="font-size: 16px;">            login.jsp</span><br /><span style="font-size: 16px;">      <span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">result</span><span style="color: #0000ff;">&gt;</span></span><br /><span style="font-size: 16px;"><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">action</span><span style="color: #0000ff;">&gt;</span></span></pre>
</div>
<p class="p0"><span style="font-family: 宋体; font-size: 16px;"><span style="font-family: 宋体;">&nbsp; &nbsp; 它提交的</span><span style="font-family: 'Times New Roman';">url</span>会是<span style="font-family: 'Times New Roman';">http://xxx.xxx.xxx/login</span>，访问<span style="font-family: 'Times New Roman';">web</span>服务器时会把此<span style="font-family: 'Times New Roman';">url</span>传递到<span style="font-family: 'Times New Roman';">struts</span>框架交给它处理，之后<span style="font-family: 'Times New Roman';">struts</span>会在<span style="font-family: 'Times New Roman';">struts.xml</span>中寻找<span style="font-family: 'Times New Roman';">login</span>的相关的配置，像上面例子，<span style="font-family: 'Times New Roman';">struts</span>会找到<span style="font-family: 'Times New Roman';">LoginAction</span>的类，并且调用其<span style="font-family: 'Times New Roman';">login</span>的方法。</span></p>
<p class="p0"><span style="font-size: 16px;">&nbsp; &nbsp; &nbsp; 写到这里，我请问这是最好的方式吗？当然不是，至少我在使用<span style="font-family: 'Times New Roman';">struts</span><span style="font-family: 宋体;">时就认为这是相当撇脚的设计。上面例子只是列举一个</span><span style="font-family: 'Times New Roman';">login</span><span style="font-family: 宋体;">方法，假如一个系统中要对后台调用的方法是</span><span style="font-family: 'Times New Roman';">100</span><span style="font-family: 宋体;">个，那岂不是就需要在</span><span style="font-family: 'Times New Roman';">struts.xml</span><span style="font-family: 宋体;">中写</span><span style="font-family: 'Times New Roman';">100</span><span style="font-family: 宋体;">个与之类似的配置。想想都头大，这样繁琐的工作，应该是由框架自己去处理，而不是人工给配置。</span></span></p>
<p class="p0">&nbsp;</p>
<p class="p0"><span style="font-size: 16px;">&nbsp; &nbsp; &nbsp; 再来看实现相同功能的<span style="font-family: 'Times New Roman';">Unicorn&nbsp;web</span><span style="font-family: 宋体;">框架的配置。</span></span></p>
<p class="p0">&nbsp;</p>
<div class="cnblogs_code">
<pre><span style="font-size: 16px;"><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">action </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="com.mh.action.UserAction"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">action</span><span style="color: #0000ff;">&gt;</span></span></pre>
</div>
<p class="p0"><span style="font-size: 16px;">&nbsp; &nbsp; &nbsp; 当然提交的<span style="font-family: 'Times New Roman';">url</span><span style="font-family: 宋体;">肯定需要包含多一些的信息，来保证能通过</span><span style="font-family: 'Times New Roman';">url</span><span style="font-family: 宋体;">正确调用框架</span><span style="font-family: 'Times New Roman';">Action</span><span style="font-family: 宋体;">里的方法。这里提交的</span><span style="font-family: 'Times New Roman';">url</span><span style="font-family: 宋体;">方式：</span><a href="http://xxx.xxx.xxx/UserAction/login/">http://xxx.xxx.xxx/UserAction/login/</a></span></p>
<p class="p0"><span style="font-size: 16px;">&nbsp; &nbsp; &nbsp; 通过在<span style="font-family: 'Times New Roman';">url</span><span style="font-family: 宋体;">里附加调用的</span><span style="font-family: 'Times New Roman';">Action</span><span style="font-family: 宋体;">类的信息，可以省略为不同的方法都在</span><span style="font-family: 'Times New Roman';">xml</span><span style="font-family: 宋体;">里配置的麻烦。假如</span><span style="font-family: 'Times New Roman';">UserAction</span><span style="font-family: 宋体;">里有</span><span style="font-family: 'Times New Roman';">100</span><span style="font-family: 宋体;">个方法，框架也只需这一行的配置。</span></span></p>
<p class="p0"><span style="font-size: 16px;">&nbsp; &nbsp; &nbsp; 有了大体的认识之后，来看框架的核心部分<span style="font-family: 'Times New Roman';">AMPPathRouter</span><span style="font-family: 宋体;">的具体实现。</span></span></p>
<p class="p0">&nbsp;</p>
<div class="cnblogs_code">
<pre><span style="color: #008000;">　　/**</span><span style="color: #008000;"><br />     * 检查url是否是此Router类要处理的，/Action/Method/Param 格式的将会被检查合格，返回true<br />     * </span><span style="color: #808080;">@param</span><span style="color: #008000;"> relativeUri<br />     * </span><span style="color: #808080;">@param</span><span style="color: #008000;"> actionMap<br />     * </span><span style="color: #808080;">@return</span><span style="color: #008000;"><br />     </span><span style="color: #008000;">*/</span><br />    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">boolean</span> checkUrl(String relativeUri, Map&lt;String, ActionSupport&gt; actionMap) {<br />        Pattern pattern = Pattern.compile("^/\\w+/\\w+/\\S*");<br />        Matcher matcher = pattern.matcher(relativeUri);<br />        <span style="color: #0000ff;">if</span>(matcher.matches()) {<br />            String actionName = relativeUri.split("/")[1];<br />            ActionSupport actionSupport = actionMap.get(actionName);<br />            <span style="color: #0000ff;">if</span>(<span style="color: #0000ff;">null</span> != actionSupport) {<br />                String actionMethodName = relativeUri.split("/")[2];<br />                Class&lt;?&gt; actionClass = actionSupport.getClass();<br />                Method[] methods = actionClass.getMethods();<br />                <span style="color: #0000ff;">for</span>(<span style="color: #0000ff;">int</span> i = 0; i &lt; methods.length; i++) {<br />                    Method method = methods[i];<br />                    String methodName = method.getName();<br />                    <span style="color: #0000ff;">if</span>(methodName.equals(actionMethodName)) {<br />                        <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">true</span>;<br />                    }<br />                }<br />            } <span style="color: #0000ff;">else</span> {<br />                <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">false</span>;<br />            }<br />        }<br />        <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">false</span>;<br />    }<br />    <span style="color: #008000;">/**</span><span style="color: #008000;"><br />     * 匹配规则为：<br />     * 1、符合/Action/method/param格式，<br />     * 2、并且Action在actionMap中的确存在<br />     * 3、method在此Action中存在<br />     </span><span style="color: #008000;">*/</span><br />    @Override<br />    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">boolean</span> route(String relativeUri, UrlFilter urlFilter) {<br />        Map&lt;String, ActionSupport&gt; actionMap = urlFilter.getActionMap();<br />        <span style="color: #0000ff;">if</span>(!<span style="color: #0000ff;">this</span>.checkUrl(relativeUri, actionMap)) {<br />            <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">false</span>;<br />        }<br />        <span style="color: #008000;">//</span><span style="color: #008000;"> 拦截Action/Method/Param方式的请求，并构建ActionSupport类的属性</span><span style="color: #008000;"><br /></span>        String[] params = relativeUri.split("/");<br />        <span style="color: #0000ff;">try</span> {<br />            ActionSupport actionSupport = actionMap.get(params[1]);<br />            Class&lt;?&gt; action = actionSupport.getClass();<br />            Method method = action.getMethod(params[2], <span style="color: #0000ff;">new</span> Class[] {});<br />            <span style="color: #0000ff;">if</span>(params.length &gt; 3) {<br />                <span style="color: #0000ff;">this</span>.boxingRequest(urlFilter.getRequest(), params[3]);<br />            }<br />            <span style="color: #008000;">//</span><span style="color: #008000;"> 只要找到ActionSupport的子类，则初始化其所具有的属性</span><span style="color: #008000;"><br /></span>            Object newInstance = action.newInstance();<br />            <span style="color: #0000ff;">this</span>.initActionSupport(newInstance, urlFilter);<br />            String result = (String) method.invoke(newInstance, <span style="color: #0000ff;">new</span> Object[] {});<br />            <span style="color: #0000ff;">if</span> (<span style="color: #0000ff;">null</span> == result || ActionSupport.AJAX.equals(result) || ActionSupport.FORWARD.equals(result) || ActionSupport.WEB_SERVICE.equals(result)) {<br />                <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">true</span>;<br />            } <br />            <span style="color: #0000ff;">if</span>(ActionSupport.REDIRECT.equals(result)) {<br />                urlFilter.getResponse().sendRedirect(result);<br />                <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">true</span>;<br />            }<br />        } <span style="color: #0000ff;">catch</span> (NoSuchMethodException e) {<br />            e.printStackTrace();<br />        } <span style="color: #0000ff;">catch</span> (SecurityException e) {<br />            e.printStackTrace();<br />        } <span style="color: #0000ff;">catch</span> (IllegalAccessException e) {<br />            e.printStackTrace();<br />        } <span style="color: #0000ff;">catch</span> (IllegalArgumentException e) {<br />            e.printStackTrace();<br />        } <span style="color: #0000ff;">catch</span> (InvocationTargetException e) {<br />            e.printStackTrace();<br />        } <span style="color: #0000ff;">catch</span> (InstantiationException e) {<br />            e.printStackTrace();<br />        } <span style="color: #0000ff;">catch</span> (Exception e) {<br />            e.printStackTrace();<br />        }<br />        <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">false</span>;<br />    }<br />    <span style="color: #008000;">/**</span><span style="color: #008000;"><br />     * 把url中得param加入到request的attribute里<br />     * </span><span style="color: #808080;">@param</span><span style="color: #008000;"> request<br />     * </span><span style="color: #808080;">@param</span><span style="color: #008000;"> parameter<br />     </span><span style="color: #008000;">*/</span><br />    <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> boxingRequest(HttpServletRequest request, String parameter) {<br />        String[] parameters = parameter.split("&amp;");<br />        <span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i &lt; parameters.length; i++) {<br />            String param = parameters[i];<br />            String[] key_value = param.split("=");<br />            <span style="color: #0000ff;">if</span>(key_value.length == 2) {<br />                request.setAttribute(key_value[0], key_value[1]);<br />            }<br />        }<br />    }<br />    <span style="color: #008000;">/**</span><span style="color: #008000;"><br />     * 初始化ActionSupport类中所需的request、response、session、application等对象<br />     * </span><span style="color: #808080;">@param</span><span style="color: #008000;"> obj<br />     * </span><span style="color: #808080;">@param</span><span style="color: #008000;"> urlFilter<br />     </span><span style="color: #008000;">*/</span><br />    <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> initActionSupport(Object obj, UrlFilter urlFilter) {<br />        ActionSupport action = (ActionSupport) obj;<br />        action.setRequest(urlFilter.getRequest());<br />        action.setResponse(urlFilter.getResponse());<br />        action.setSession(urlFilter.getSession());<br />        action.setApplication(urlFilter.getApplication());<br />    }</pre>
</div>
<p class="p0">&nbsp;</p>
<p>&nbsp; &nbsp; &nbsp; 这便是AMPPathRouter的全部内容，其中在把请求分发到ActionSupport的子类 并调用相关方法时 是通过反射实现，其他地方地方都是相当容易理解的。</p>
<p>&nbsp; &nbsp; &nbsp; 空说无凭，把框架应用到实战中才是硬道理：</p>
<p><img src="http://pic002.cnblogs.com/images/2011/324517/2011112518265470.jpg" alt="" /></p>
<p>&nbsp;</p>
<p class="p0"><span style="font-family: 宋体;">&nbsp; &nbsp; &nbsp; 好了，下一篇介绍Action 和 json。</span></p><img src ="http://www.blogjava.net/mahang/aggbug/365019.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mahang/" target="_blank">马航</a> 2011-11-25 18:18 <a href="http://www.blogjava.net/mahang/archive/2011/11/25/365019.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts、Ajax、Restful、Web Service 狂想曲框架实现篇（二）</title><link>http://www.blogjava.net/mahang/archive/2011/11/25/365020.html</link><dc:creator>马航</dc:creator><author>马航</author><pubDate>Fri, 25 Nov 2011 04:35:00 GMT</pubDate><guid>http://www.blogjava.net/mahang/archive/2011/11/25/365020.html</guid><wfw:comment>http://www.blogjava.net/mahang/comments/365020.html</wfw:comment><comments>http://www.blogjava.net/mahang/archive/2011/11/25/365020.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mahang/comments/commentRss/365020.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mahang/services/trackbacks/365020.html</trackback:ping><description><![CDATA[<div class="Section0">
<p class="p0">&nbsp; &nbsp; &nbsp; 上篇说过，所有提交到web<span style="font-family: 宋体;">程序的</span><span style="font-family: 'Times New Roman';">url</span><span style="font-family: 宋体;">都被此</span><span style="font-family: 'Times New Roman';">UrlFilter</span><span style="font-family: 宋体;">拦截。拦截到请求后，</span><span style="font-family: 'Times New Roman';">UrlFilter</span><span style="font-family: 宋体;">则召集它的好多个得力干将</span><span style="font-family: 'Times New Roman';">Router&nbsp;</span><span style="font-family: 宋体;">们，&nbsp;询问他们：&ldquo;谁能处理此</span><span style="font-family: 'Times New Roman';">URL</span><span style="font-family: 宋体;">啊&nbsp;？&rdquo;</span></p>
<p class="p0">这时一位叫做<span style="font-family: 'Times New Roman';">AMP</span><span style="font-family: 宋体;">的</span><span style="font-family: 'Times New Roman';">Router&nbsp;</span><span style="font-family: 宋体;">首当其冲&nbsp;说：&ldquo;这个</span><span style="font-family: 'Times New Roman';">url</span><span style="font-family: 宋体;">交给我了&rdquo;。这时</span><span style="font-family: 'Times New Roman';">filter</span><span style="font-family: 宋体;">就会把此</span><span style="font-family: 'Times New Roman';">url</span><span style="font-family: 宋体;">全权交给</span><span style="font-family: 'Times New Roman';">AMPRouter</span><span style="font-family: 宋体;">来办，至于如何去处理，</span><span style="font-family: 'Times New Roman';">filter</span><span style="font-family: 宋体;">也不再过问，它觉得：&ldquo;我把任务都交给你了，怎么解决是你的事&rdquo;。</span></p>
<p class="p0">&nbsp; &nbsp; &nbsp; 根据单一职责的原则，<span style="font-family: 'Times New Roman';">UrlFilter</span><span style="font-family: 宋体;">就负责上面情景中的分发</span><span style="font-family: 'Times New Roman';">url</span><span style="font-family: 宋体;">到</span><span style="font-family: 'Times New Roman';">Router</span><span style="font-family: 宋体;">中的差事，</span><span style="font-family: 'Times New Roman';">url</span><span style="font-family: 宋体;">如何分发交给</span><span style="font-family: 'Times New Roman';">Router</span><span style="font-family: 宋体;">处理。并且</span><span style="font-family: 'Times New Roman';">Router</span><span style="font-family: 宋体;">实际是一个接口，使用框架的用户完全可以自己实现</span><span style="font-family: 'Times New Roman';">Router</span><span style="font-family: 宋体;">，这样用户可以自主定义的</span><span style="font-family: 'Times New Roman';">url</span><span style="font-family: 宋体;">分发的策略。另外呢，框架初始化的一些操作它也是&nbsp;推脱不掉的，像根据</span><span style="font-family: 'Times New Roman';">unicorn-config.xml</span><span style="font-family: 宋体;">初始化系统中的</span><span style="font-family: 'Times New Roman';">Router</span><span style="font-family: 宋体;">和</span><span style="font-family: 'Times New Roman';">Action'</span><span style="font-family: 宋体;">。下面是具体的代码：</span></p>
<p class="p0">&nbsp;</p>
<div class="cnblogs_Highlighter">
<pre class="brush:java;gutter:false;">@Override
public void init(FilterConfig config) throws ServletException {
	application = config.getServletContext();
	String loadPath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
	String classPath = loadPath.substring(1, loadPath.length());
	ArrayList&lt;String&gt; actions = XMLReader.getNodeValues(classPath + "unicorn-config.xml", "actions");
	this.initActions(actions);
	ArrayList&lt;String&gt; routers = XMLReader.getNodeValues(classPath + "unicorn-config.xml", "routers");
	this.initRouters(routers);
}</pre>
</div>
<p class="p0">&nbsp;</p>
<div class="cnblogs_Highlighter">
<pre class="brush:java;gutter:false;">@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
			throws IOException, ServletException {
	HttpServletRequest request = (HttpServletRequest) servletRequest;
	String path = request.getContextPath();
	String uri = request.getRequestURI();
	String relativeUri = uri.substring(path.length(), uri.length());
	this.request = request;
	this.session = request.getSession();
	this.response = (HttpServletResponse) servletResponse;
	// 用户自定义的Router优先级最高，url先通过用户定义的
	Iterator&lt;IPathRouter&gt; iterator = routerList.iterator();
	while(iterator.hasNext()) {
		IPathRouter router = iterator.next();
		if(router.route(relativeUri, this)) {
			return ;
		}
	}
	// 拦截不到的继续访问
	filterChain.doFilter(servletRequest, servletResponse);
}
</pre>
</div>
<p>　　 &nbsp; &nbsp; &nbsp;其中Router类的初始化，Action类的初始化于这个类似：</p>
<div class="cnblogs_Highlighter">
<pre class="brush:java;gutter:false;">private void initRouters(ArrayList&lt;String&gt; routers) {
	routerList = new ArrayList&lt;IPathRouter&gt;();
	for (int i = 0; i &lt; routers.size(); i++) {
		String routerName = routers.get(i);
		try {
			Class&lt;?&gt; clz = Class.forName(routers.get(i));
			// 单例模式通过方法获取对象实例
			IPathRouter router = (IPathRouter) clz.newInstance();
			routerList.add(router);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		}
	}
	// 最后把框架默认的Router加入进来
	routerList.add(new AMPPathRouter());
}
</pre>
</div>
<p>　　 &nbsp; &nbsp; &nbsp;其中unicorn-config.xml文件的编写，拿其中我一个项目里的这个文件来举例：</p>
<div class="cnblogs_code">
<pre><span style="color: #0000ff;">&lt;?</span><span style="color: #ff00ff;">xml version="1.0" encoding="UTF-8" </span><span style="color: #0000ff;">?&gt;</span><br /><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">config</span><span style="color: #0000ff;">&gt;</span><br />    <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">routers</span><span style="color: #0000ff;">&gt;</span><br />        <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">router </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="com.mh.router.MySessionCheckRouter"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">router</span><span style="color: #0000ff;">&gt;</span><br />    <span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">routers</span><span style="color: #0000ff;">&gt;</span><br />    <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">actions</span><span style="color: #0000ff;">&gt;</span><br />        <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">action </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="com.mh.action.UserAction"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">action</span><span style="color: #0000ff;">&gt;</span><br />        <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">action </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="com.mh.action.InformationAction"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">action</span><span style="color: #0000ff;">&gt;</span><br />        <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">action </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="com.mh.action.UploadInformationIconAction"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">action</span><span style="color: #0000ff;">&gt;</span><br />        <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">action </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="com.mh.action.TempPicAction"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">action</span><span style="color: #0000ff;">&gt;</span><br />        <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">action </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="com.mh.action.MobileAction"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">action</span><span style="color: #0000ff;">&gt;</span><br />    <span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">actions</span><span style="color: #0000ff;">&gt;</span><br /><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">config</span><span style="color: #0000ff;">&gt;</span></pre>
</div>
<p>&nbsp; &nbsp; &nbsp; 这里即定义了Action，也定义了自己的Router，并且从名称上可以看出，这个SessionCheckRouter是要判断所有提交到服务器的指定url的请求 是否已经登录过，没有登录，可能会把此请求遣送会登录页。以及初始化所有的Action，在Router处理完请求，分发给action时，可以从filter里面去取。</p>
<p>&nbsp;<br /><br /></p>
<p class="p0"><span style="font-family: 宋体;"><br /></span></p>
</div><img src ="http://www.blogjava.net/mahang/aggbug/365020.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mahang/" target="_blank">马航</a> 2011-11-25 12:35 <a href="http://www.blogjava.net/mahang/archive/2011/11/25/365020.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts、Ajax、Restful、Web Service 狂想曲框架实现篇（一）</title><link>http://www.blogjava.net/mahang/archive/2011/11/25/365021.html</link><dc:creator>马航</dc:creator><author>马航</author><pubDate>Fri, 25 Nov 2011 03:43:00 GMT</pubDate><guid>http://www.blogjava.net/mahang/archive/2011/11/25/365021.html</guid><wfw:comment>http://www.blogjava.net/mahang/comments/365021.html</wfw:comment><comments>http://www.blogjava.net/mahang/archive/2011/11/25/365021.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mahang/comments/commentRss/365021.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mahang/services/trackbacks/365021.html</trackback:ping><description><![CDATA[<div class="Section0">
<p class="p0">&nbsp; &nbsp; &nbsp; 承接上篇的简单介绍，下面详细介绍整个框架的大致结构。</p>
<p class="p0">&nbsp; &nbsp; &nbsp; 先来看一下整个框架包的结构：</p>
<p class="p0">&nbsp;</p>
<p><img src="http://pic002.cnblogs.com/images/2011/324517/2011112511422324.png" alt="" /></p>
<p class="p0">&nbsp; &nbsp; &nbsp; 可以看出框架包含的包很少，包的结构也超简单。这里&nbsp;涉及<span style="font-family: 'Times New Roman';">Filter</span><span style="font-family: 宋体;">、</span><span style="font-family: 'Times New Roman';">ActionSupport</span><span style="font-family: 宋体;">、</span><span style="font-family: 'Times New Roman';">Router</span><span style="font-family: 宋体;">等三个概念，他们之间的关系，通过下图来表示：</span></p>
<p class="p0">&nbsp;</p>
<p><img src="http://pic002.cnblogs.com/images/2011/324517/2011112511440742.png" alt="" /></p>
<p class="p0">&nbsp; &nbsp; &nbsp; 图也不规范，说不上来是哪个UML<span style="font-family: 宋体;">图，不过通过它也能看出一个请求到达时，框架基本的处理流程。首先由</span><span style="font-family: 'Times New Roman';">Filter</span><span style="font-family: 宋体;">拦截到所有请求，然后把请求交给所有注册的</span><span style="font-family: 'Times New Roman';">Router</span><span style="font-family: 宋体;">类，如果请求的</span><span style="font-family: 'Times New Roman';">Url</span><span style="font-family: 宋体;">正好是一个</span><span style="font-family: 'Times New Roman';">Router</span><span style="font-family: 宋体;">要拦截的，则把此请求交给这个</span><span style="font-family: 'Times New Roman';">Router</span><span style="font-family: 宋体;">，框架不再把请求向下传递。</span><span style="font-family: 'Times New Roman';">Router</span><span style="font-family: 宋体;">得到请求后，分析</span><span style="font-family: 'Times New Roman';">Url</span><span style="font-family: 宋体;">，通过</span><span style="font-family: 'Times New Roman';">Url</span><span style="font-family: 宋体;">里的信息把请求交给对应的</span><span style="font-family: 'Times New Roman';">ActionSupport</span><span style="font-family: 宋体;">的子类来处理。</span></p>
<p class="p0">&nbsp; &nbsp; &nbsp; 这里拦截采用<span style="font-family: 'Times New Roman';">Filter</span><span style="font-family: 宋体;">来处理，这跟多数的</span><span style="font-family: 'Times New Roman';">web</span><span style="font-family: 宋体;">框架一样，使用</span><span style="font-family: 'Times New Roman';">Filter</span><span style="font-family: 宋体;">比</span><span style="font-family: 'Times New Roman';">Servlet</span><span style="font-family: 宋体;">有更多的能力进行请求的分发。首先在一个</span><span style="font-family: 'Times New Roman';">web</span><span style="font-family: 宋体;">工程的</span><span style="font-family: 'Times New Roman';">web.xml</span><span style="font-family: 宋体;">文件中配置框架的</span><span style="font-family: 'Times New Roman';">UrlFilter</span><span style="font-family: 宋体;">类来拦截所有的请求。需要注意的一点是</span>dispatcher&nbsp;要设置为<span style="font-family: Consolas;">request</span><span style="font-family: 宋体;">，如果设置了</span><span style="font-family: Consolas;">forward</span><span style="font-family: 宋体;">的话，由框架内部进行的</span><span style="font-family: Consolas;">forward</span><span style="font-family: 宋体;">又会被框架拦截，从而造成无限的循环。</span><span style="font-family: Consolas;">Url-pattern</span><span style="font-family: 宋体;">设置为</span><span style="font-family: Consolas;">/*</span><span style="font-family: 宋体;">，表示所有的请求都会拦截，从而把对</span><span style="font-family: Consolas;">url</span><span style="font-family: 宋体;">分发的权利交由框架本身，而不是采用</span><span style="font-family: Consolas;">jsp</span><span style="font-family: 宋体;">规范里的</span><span style="font-family: Consolas;">url</span><span style="font-family: 宋体;">分发策略。框架在处理所有请求的</span><span style="font-family: Consolas;">url&nbsp;</span><span style="font-family: 宋体;">时，依次交给各个</span><span style="font-family: Consolas;">Router</span><span style="font-family: 宋体;">类来处理，如果</span><span style="font-family: Consolas;">Router</span><span style="font-family: 宋体;">类判断是符合自己的</span><span style="font-family: Consolas;">url</span><span style="font-family: 宋体;">格式，则分发给&nbsp;</span><span style="font-family: Consolas;">action&nbsp;</span><span style="font-family: 宋体;">处理。如果不能处理再交给下一级的</span><span style="font-family: Consolas;">Router</span><span style="font-family: 宋体;">，最后</span><span style="font-family: Consolas;">url</span><span style="font-family: 宋体;">经由所有</span><span style="font-family: Consolas;">Router</span><span style="font-family: 宋体;">处理完，剩下的资源文件的</span><span style="font-family: Consolas;">url</span><span style="font-family: 宋体;">，如</span><span style="font-family: Consolas;">http://xxx.xxx.xxx.jpg</span><span style="font-family: 宋体;">，则框架调用</span><span style="font-family: Consolas;">filter</span><span style="font-family: 宋体;">的</span><span style="font-family: Consolas;">doChain()</span><span style="font-family: 宋体;">方法，通过</span><span style="font-family: Consolas;">filter的过滤</span><span style="font-family: 宋体;">去访问</span><span style="font-family: Consolas;">web</span><span style="font-family: 宋体;">里的资源。</span></p>
<table>
<tbody>
<tr>
<td valign="top" width="568">
<p class="p0">&lt;filter&gt;</p>
<p class="p0">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;filter-name&gt;unicornWeb&lt;/filter-name&gt;</p>
<p class="p0">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;filter-class&gt;com.mh.mvc.filter.UrlFilter&lt;/filter-class&gt;</p>
<p class="p0">&lt;/filter&gt;</p>
<p class="p0">&lt;filter-mapping&gt;</p>
<p class="p0">&nbsp;&nbsp;&nbsp;&nbsp;&lt;filter-name&gt;unicornWeb&lt;/filter-name&gt;</p>
<p class="p0">&nbsp;&nbsp;&nbsp;&nbsp;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;</p>
<p class="p0">&nbsp;&nbsp;&nbsp;&nbsp;&lt;dispatcher&gt;REQUEST&lt;/dispatcher&gt;</p>
<p class="p0">&lt;/filter-mapping&gt;</p>
</td>
</tr>
</tbody>
</table>
<p class="p0">&nbsp; &nbsp; &nbsp; 大致的原理就是这样，在下篇介绍框架的详细实现。</p>
</div><img src ="http://www.blogjava.net/mahang/aggbug/365021.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mahang/" target="_blank">马航</a> 2011-11-25 11:43 <a href="http://www.blogjava.net/mahang/archive/2011/11/25/365021.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts、Ajax、Restful、Web Service 狂想曲</title><link>http://www.blogjava.net/mahang/archive/2011/11/22/365022.html</link><dc:creator>马航</dc:creator><author>马航</author><pubDate>Tue, 22 Nov 2011 08:22:00 GMT</pubDate><guid>http://www.blogjava.net/mahang/archive/2011/11/22/365022.html</guid><wfw:comment>http://www.blogjava.net/mahang/comments/365022.html</wfw:comment><comments>http://www.blogjava.net/mahang/archive/2011/11/22/365022.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mahang/comments/commentRss/365022.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mahang/services/trackbacks/365022.html</trackback:ping><description><![CDATA[<p>&nbsp; &nbsp; &nbsp; 我承认有点标题党了，不过题目中所说的几项技术确实有其相似之处，欲知事情原委，且听我详细道来。</p>
<p>&nbsp; &nbsp; &nbsp; 项目一开始只是不满 struts 庞大的体积，于是想自己根据其原理实现一个tiny 版。后来的开发中觉得，完全可以把上述的ajax、Restuful web service的一些思想加入进来。经过几周的努力，便开发出了一个基本成型的web 框架，暂且起名为unicorn（独角兽，吼吼）。下文开始便对这个自编写的框架做一些列的介绍，并且初步打算是将其开源，希望能一起交流和完善它。</p>
<p>&nbsp; &nbsp; &nbsp; 首先，为了能快速了解它是什么，先来看一下配置文件：</p>
<div class="cnblogs_code">
<pre><span style="color: #0000ff;">&lt;?</span><span style="color: #ff00ff;">xml version="1.0" encoding="UTF-8" </span><span style="color: #0000ff;">?&gt;</span><br /><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">config</span><span style="color: #0000ff;">&gt;</span><br />    <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">routers</span><span style="color: #0000ff;">&gt;</span><br />        <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">router </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="com.mh.router.MySessionCheckRouter"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">router</span><span style="color: #0000ff;">&gt;</span><br />    <span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">routers</span><span style="color: #0000ff;">&gt;</span><br />    <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">actions</span><span style="color: #0000ff;">&gt;</span><br />        <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">action </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="com.mh.action.UserAction"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">action</span><span style="color: #0000ff;">&gt;</span><br />        <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">action </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="com.mh.action.InformationAction"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">action</span><span style="color: #0000ff;">&gt;</span><br />        <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">action </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="com.mh.action.MobileAction"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">action</span><span style="color: #0000ff;">&gt;</span><br />    <span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">actions</span><span style="color: #0000ff;">&gt;</span><br /><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">config</span><span style="color: #0000ff;">&gt;</span></pre>
</div>
<p>&nbsp; &nbsp; &nbsp; 上面就是整个工程的配置文件，可以看出需要配置的东西非常少，只需要制定action类 和 router类有哪些就Ok。框架奉行约定大于配置的思想，至于请求如何分发，这个不需要人工配置，框架自动解决。这里要介绍两个概念Action 和 Router，熟悉Struts的肯定都知道Action，Action替代Servlet、JSP时代的Servlet，所有提交的请求由struts分发给不同的Action来处理。这里道理也是一样的，Action就是经过框架处理后的请求接受者。再来说一下Router，字面意思路由器，学过计算机网络的都知道，ip数据包在网络上之所以能够顺利到达，就是因为路由器根据路由表来来确定出来传输的途径。这里Router也是这个作用，根据访问服务器的URL来制定分发策略。Router是完全可以自定义的，用户可以定义自己的Router来制定URL分发的策略，并且用户自定义的Router比系统默认的Router有更高的优先权。</p>
<p>二、URL上做文章</p>
<p><span style="background-color: #ff9900;">/UserAction/login/username=admin&amp;&amp;password=admin</span></p>
<p>&nbsp; &nbsp; &nbsp; 先来介绍系统MethodRouter的处理方式。上面的url根据"/"分为三个部分，第一部分是请求的Action类，第二部分是类中的方法Method，第三部分是提交的参数Param。这一点受上篇文章优酷的架构里URL设计的启发。</p>
<p>&nbsp; &nbsp; &nbsp; 经过这样的设计，就明白在上述配置文件中为何可以如此简单了。</p>
<p>&nbsp; &nbsp; &nbsp; 当然也可以不以这样的方式，框架提供自定义Router的支持。比如你想这样处理URL：<span style="background-color: #ff9900;">/前台页面/子栏目/子栏目</span></p>
<p>&nbsp; &nbsp; &nbsp; 想实现上面的方式，就可以自己定义Router，在Router里面获取上述的URL，然后做处理、forward到相应的jsp页面。</p>
<p>三、使用Json传输数据</p>
<p>&nbsp; &nbsp; &nbsp; Ajax请求很容易处理json数据，ajax可以与系统轻松交互。</p>
<p>&nbsp; &nbsp; &nbsp; 当初Web Service使用SOAP的xml格式传输数据，如今也有人指责这是大费周折。Restful方式提倡遵循HTTP语义，完全使用URL结合GET、POST、PUT、DELETE来传输请求，结果在roil阵营里广泛使用，认为是web service更优雅的方式。所以本框架也吸取他们的优点，也完全可以通过url传输请求的数据，如上述URL中的Param部分。不过没有遵循Restful强调的Http语义，全部使用Get和POST的请求方式，当然也可以制定为其他，这完全看你的心情，因为这对功能实现无关紧要。而且我觉得统一使用一种，更避免了需要指定请求方式的麻烦。</p>
<p>&nbsp; &nbsp; &nbsp; 数据的返回使用json格式，比SOAP更为轻量简洁和优雅，而且有更多的平台直接支持。如在android平台，本身就支持json格式的处理， 如果使用web service 的SOAP，你可能还要导入KSOAP的第三方库。</p>
<p>&nbsp; &nbsp; &nbsp; 在非浏览器的客户端，可以借助编写的工具类，来完成web service方式的操作，</p>
<div class="cnblogs_Highlighter">
<pre class="brush:java;gutter:false;">public interface IWebService {
	public List&lt;LiteInformationDTO&gt; getInformationsOfOwnerApp(String ownerApp, int start, int limit) throws SocketTimeoutException;
}
</pre>
</div>
<p>&nbsp; &nbsp; &nbsp; 经过这样的封装，已经与使用web service毫无差别，而且还会更加高效，因为处理json总比处理SOAP的xml要容易。</p>
<p>&nbsp;</p>
<p>&nbsp; &nbsp; &nbsp; 先简单写这么多，之后的续篇详细介绍。</p><img src ="http://www.blogjava.net/mahang/aggbug/365022.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mahang/" target="_blank">马航</a> 2011-11-22 16:22 <a href="http://www.blogjava.net/mahang/archive/2011/11/22/365022.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>优酷网架构学习笔记</title><link>http://www.blogjava.net/mahang/archive/2011/11/02/365023.html</link><dc:creator>马航</dc:creator><author>马航</author><pubDate>Wed, 02 Nov 2011 03:23:00 GMT</pubDate><guid>http://www.blogjava.net/mahang/archive/2011/11/02/365023.html</guid><wfw:comment>http://www.blogjava.net/mahang/comments/365023.html</wfw:comment><comments>http://www.blogjava.net/mahang/archive/2011/11/02/365023.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mahang/comments/commentRss/365023.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mahang/services/trackbacks/365023.html</trackback:ping><description><![CDATA[<p>记得以前给大家介绍过视频网站龙头老大<a href="http://www.itivy.com/ivy/archive/2011/3/6/634350416046298451.html" target="_blank">YouTube的技术架构</a>，相信大家看了都会有不少的感触，互联网就是这么一个神奇的东西。今天我突然想到，优酷网在国内也算是视频网站的老大了，不知道他的架构相对于YouTube是怎么样的，于是带着这个好奇心去网上找了优酷网架构的各方面资料，虽然谈得没有YouTube那么详细，但多少还是挖掘了一点，现在总结一下，希望对喜欢架构的朋友有所帮助。</p>
<p><span>一、网站基本数据概览</span></p>
<ul>
<li>据2010年统计，优酷网日均独立访问人数（uv)达到了8900万，日均访问量（pv）更是达到了17亿，优酷凭借这一数据成为google榜单中国内视频网站排名最高的厂商。</li>
<li>硬件方面，优酷网引进的戴尔服务器主要以 PowerEdge 1950与PowerEdge 860为主，存储阵列以戴尔MD1000为主，2007的数据表明，优酷网已有1000多台服务器遍布在全国各大省市，现在应该更多了吧。</li>
</ul>
<p><span>二、网站前端框架</span></p>
<p>从一开始，优酷网就自建了一套CMS来解决前端的页面显示，各个模块之间分离得比较恰当，前端可扩展性很好，UI的分离，让开发与维护变得十分简单和灵活，下图是优酷前端的模块调用关系：</p>
<p><img src="http://www.itivy.com/Upload/EditorImage/20110910151338_0929.jpg" alt="" border="0" /></p>
<p>这样，就根据module、method及params来确定调用相对独立的模块，显得非常简洁。下面附一张优酷的前端局部架构图：</p>
<p><img src="http://www.itivy.com/Upload/EditorImage/20111020120723_5812.jpg" alt="" border="0" /></p>
<p>&nbsp;</p>
<p><span>三、数据库架构</span></p>
<p>应该说优酷的数据库架构也是经历了许多波折，从一开始的单台MySQL服务器（Just Running）到简单的MySQL主从复制、SSD优化、垂直分库、水平sharding分库，这一系列过程只有经历过才会有更深的体会吧，就像<a href="http://www.itivy.com/ivy/archive/2011/3/7/634351257301504864.html" target="_blank">MySpace的架构经历</a>一样，架构也是一步步慢慢成长和成熟的。</p>
<p>1、简单的MySQL主从复制:</p>
<p>MySQL的主从复制解决了数据库的读写分离，并很好的提升了读的性能，其原来图如下：</p>
<p><img src="http://www.itivy.com/Upload/EditorImage/20110910151549_5879.jpg" alt="" border="0" /></p>
<p>其主从复制的过程如下图所示：</p>
<p><img src="http://www.itivy.com/Upload/EditorImage/20110910151641_1001.jpg" alt="" border="0" /></p>
<p>但是，主从复制也带来其他一系列性能瓶颈问题：</p>
<ol>
<li>写入无法扩展</li>
<li>写入无法缓存</li>
<li>复制延时</li>
<li>锁表率上升</li>
<li>表变大，缓存率下降</li>
</ol>
<p>那问题产生总得解决的，这就产生下面的优化方案，一起来看看。</p>
<p>&nbsp;</p>
<p>2、MySQL垂直分区</p>
<p>如果把业务切割得足够独立，那把不同业务的数据放到不同的数据库服务器将是一个不错的方案，而且万一其中一个业务崩溃了也不会影响其他业务的正常进行，并且也起到了负载分流的作用，大大提升了数据库的吞吐能力。经过垂直分区后的数据库架构图如下：</p>
<p><img src="http://www.itivy.com/Upload/EditorImage/20110910151747_8225.jpg" alt="" border="0" /></p>
<p>然而，尽管业务之间已经足够独立了，但是有些业务之间或多或少总会有点联系，如用户，基本上都会和每个业务相关联，况且这种分区方式，也不能解决单张表数据量暴涨的问题，因此为何不试试水平sharding呢？</p>
<p>&nbsp;</p>
<p>3、MySQL水平分片（Sharding）</p>
<p>这是一个非常好的思路，将用户按一定规则（按id哈希）分组，并把该组用户的数据存储到一个数据库分片中，即一个sharding，这样随着用户数量的增加，只要简单地配置一台服务器即可，原理图如下：</p>
<p><img src="http://www.itivy.com/Upload/EditorImage/20110910151842_9228.jpg" alt="" border="0" /></p>
<p>如何来确定某个用户所在的shard呢，可以建一张用户和shard对应的数据表，每次请求先从这张表找用户的shard id，再从对应shard中查询相关数据，如下图所示：</p>
<p><img src="http://www.itivy.com/Upload/EditorImage/20110910152117_6934.jpg" alt="" border="0" /></p>
<p>但是，优酷是如何解决跨shard的查询呢，这个是个难点，据介绍优酷是尽量不跨shard查询，实在不行通过多维分片索引、分布式搜索引擎，下策是分布式数据库查询（这个非常麻烦而且耗性能）</p>
<p>&nbsp;</p>
<p><span>四、缓存策略</span></p>
<p>貌似大的系统都对&ldquo;缓存&rdquo;情有独钟，从http缓存到memcached内存数据缓存，但优酷表示没有用内存缓存，理由如下：</p>
<ol>
<li>避免内存拷贝，避免内存锁</li>
<li>如接到老大哥通知要把某个视频撤下来，如果在缓存里是比较麻烦的</li>
</ol>
<p>而且Squid 的 write() 用户进程空间有消耗，Lighttpd 1.5 的 AIO(异步I/O) 读取文件到用户内存导致效率也比较低下。</p>
<p>但为何我们访问优酷会如此流畅，与土豆相比优酷的视频加载速度略胜一筹？这个要归功于优酷建立的比较完善的内容分发网络（CDN），<span>它通过多种方式保证分布在全国各地的用户进行就近访问&mdash;&mdash;用户点击视频请求后，优酷网将根据用户所处地区位置，将离用户最近、服务状况最好的视频服务器地址传送给用户，从而保证用户可以得到快速的视频体验。这就是CDN带来的优势，就近访问，有关CDN的更多内容，请大家Google一下。</span></p>
<p>好了，就总结这么多了，有兴趣的同学接着补充，虽然很多资料图片都来自网络，但整理也不容易，欢迎转载，转载留个出处：<a href="http://www.itivy.com/ivy" target="_blank">青藤屋</a>&nbsp;<a href="http://www.itivy.com/ivy/archive/2011/8/13/the-architecture-of-youku.html" target="_blank">原文链接</a></p><img src ="http://www.blogjava.net/mahang/aggbug/365023.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mahang/" target="_blank">马航</a> 2011-11-02 11:23 <a href="http://www.blogjava.net/mahang/archive/2011/11/02/365023.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows 下 SVN 服务器配置</title><link>http://www.blogjava.net/mahang/archive/2011/10/12/365024.html</link><dc:creator>马航</dc:creator><author>马航</author><pubDate>Wed, 12 Oct 2011 09:26:00 GMT</pubDate><guid>http://www.blogjava.net/mahang/archive/2011/10/12/365024.html</guid><wfw:comment>http://www.blogjava.net/mahang/comments/365024.html</wfw:comment><comments>http://www.blogjava.net/mahang/archive/2011/10/12/365024.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mahang/comments/commentRss/365024.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mahang/services/trackbacks/365024.html</trackback:ping><description><![CDATA[<p>windows系统使我们经常使用的操作系统怎么才能使用我们现在经常使用的操作系统不变的情况下继续我们的SVN之旅，我们在综合了好动种方法的同时感觉这些内容非常贴近我们SVN在Windows种的应用与配置.</p>
<p>1.下载文件，</p>
<p>下载最新版本subversion,我这里选择svn-1.4.5-setup.exe</p>
<p>下载 "Subversion Windows Service" 软件包</p>
<p>下载 TortoiseSVN shell integration utility</p>
<p>2.安装Subversion 服务器</p>
<p>由于我下载的是setup.exe版本,安装程序安装后会自动设置系统变量.如果你下载的是zip版就需要手动设置系统变量.</p>
<p>setup.exe版直接安装就可以了.安装到D:/Program Files/Subversion</p>
<p>首先创建SVN储存库(repository)</p>
<p>svnadmin create F:/svn/</p>
<p>repository创建完毕后会在目录下生成若干个文件和文件夹，dav目录是提供给Apache与mod_dav_svn使用的目录，让它们存储内部数据；db目录就是所有版本控制的数据文件；hooks目录放置hook脚本文件的目录；locks用来放置Subversion文件库锁定数据的目录，用来追踪存取文件库的客户端；format文件是一个文本文件，里面只放了一个整数，表示当前文件库配置的版本号；</p>
<p>3.配置SVN服务器</p>
<p>（这个位置就是在你建储存库的地方F:/svn）</p>
<p>打开/conf/目录，打开svnserve.conf找到一下两句：</p>
<p># [general]</p>
<p># password-db = passwd</p>
<p># anon-access = none</p>
<p># auth-access = write</p>
<p>去之每行开头的#，其中第二行是指定身份验证的文件名，即passwd文件.anon-access = none 是匿名用户不能访问，必须要有用户名和密码。（注意：问题就出在这，一定要注意格式去掉注释后要顶格不能有空）</p>
<p>同样打开passwd文件，将</p>
<p># [users]</p>
<p># harry = harryssecret</p>
<p># sally = sallyssecret</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 格式为&ldquo;用户名 = 密码&rdquo;，如可插入一行：admin = admin888，即为系统添加一个用户名为admin，密码为admin888的用户</p>
<p>4.运行SVN服务器</p>
<p>运行SVN服务</p>
<p>在命令行执行</p>
<p>svnserve --daemon --root F:/svn</p>
<p>服务启动，--daemon可简写为-d，--root可简写为-r，可以建立一个批处理文件并放在windows启动组中便于开机就运行SVN服务（注意：这是临时打开的服务，命令执行后不能关闭窗口）</p>
<p>也可以制定subversion工作的端口：svnserve -d -r f:/svn --listen-port 9999</p>
<p>用后台服务的方式可以设置开机自动执行。</p>
<p>D:/Program Files/Subversion/bin&gt;sc create svnservice binpath= "C:/Program Files/Subversion/bin/svnserve.exe --service -r f:/svn &nbsp;--listen-port 9999"</p>
<p>就可以用net svnservice stop 或者start来启动服务了 也可以在Sevices.msc来启动了。</p>
<p>5、用客户端访问</p>
<p>格式：svn://服务器IP</p>
<p>&nbsp;</p>
<p>---------------------------------------------------------------------------------------------------------</p>
<p>&nbsp;</p>
<p>基于svnserve的服务器，权限文件authz配置的常见问题及解答&nbsp;&nbsp;<br />&nbsp;最近在我用Subversion论坛(<a href="http://www.iusesvn.com/bbs" style="color: #336699; text-decoration: none;">http://www.iUseSVN.com/bbs</a>)经常有人提到这样的问题：&nbsp;<br />为什么我的客户端没有写权限？&nbsp;<br />为什么我的权限没有起作用？</p>
<p>总结他们的配置，发现&nbsp;<br />都是用svnserve作为服务器，&nbsp;<br />都在svnserve.conf中使用了authz-db选项</p>
<p>原因可能如下：</p>
<p>1，配置authz时，没有注意svnserve启动参数-r所指定的目录。&nbsp;<br />这里有两种情况：&nbsp;<br />A:-r直接指定到版本库(称之为单库svnserve方式)&nbsp;<br />比如，有一个库project1，位于D:/svn/project1&nbsp;<br />使用以下命令启动svnserve</p>
<p>[Copy to clipboard] [ - ]CODE:&nbsp;<br />svnserve -d -r D:/svn/project1&nbsp;<br />在这种情况下，一个svnserve只能为一个版本库工作&nbsp;<br />authz文件如果配置成下面这样就是错的，</p>
<p>[Copy to clipboard] [ - ]CODE:&nbsp;<br />[groups]&nbsp;<br />admin=user1&nbsp;<br />dev=user2&nbsp;<br />[project1:/]&nbsp;<br />@admin=rw&nbsp;<br />@doc=r&nbsp;<br />应该配置成</p>
<p>[Copy to clipboard] [ - ]CODE:&nbsp;<br />[groups]&nbsp;<br />admin=user1&nbsp;<br />dev=user2&nbsp;<br />[/]&nbsp;<br />@admin=rw&nbsp;<br />@doc=r&nbsp;<br />因为[project1:/]表示库project1的根目录，而按上面的启动参数，是没有库的概念的。&nbsp;<br />使用类似这样的URL：svn://192.168.0.1/　即可访问project1</p>
<p>B:-r指定到版本库的上级目录(称之为多库svnserve方式)&nbsp;<br />同样，有一个库project1，位于D:/svn/project1&nbsp;<br />如果使用以下命令启动svnserve</p>
<p>[Copy to clipboard] [ - ]CODE:&nbsp;<br />svnserve -d -r D:/svn&nbsp;<br />这种情况，一个svnserve可以为多个版本库工作，&nbsp;<br />这时如果想限制指定库的指定目录，就应该指定具体的库，像这样</p>
<p>[Copy to clipboard] [ - ]CODE:&nbsp;<br />[groups]&nbsp;<br />admin=user1&nbsp;<br />dev=user2&nbsp;<br />[project1:/]&nbsp;<br />@admin=rw&nbsp;<br />@doc=r&nbsp;<br />如果此时你还用[/]，则表示所有库的根目录，同理，[/src]表示所有库的根目录下的src目录&nbsp;<br />使用类似这样的URL：svn://192.168.0.1/project1　即可访问project1&nbsp;<br />这样的URL：svn://192.168.0.1/project2　即可访问project2</p>
<p>2，对中文目录进行权限控制时，没有将权限文件authz改为utf-8格式。</p>
<p>svn对于非英文文件名和目录名使用utf-8格式编码处理，要对中文目录进行正确控制，&nbsp;<br />应该使用无BOM的utf-8格式，如何将默认的文件转为utf-8，&nbsp;<br />我使用的是UltraEdit的菜单"ASCII to UTF-8 (Unicode Editing)"。在UltraEdit的配置中，可以设置有无BOM&nbsp;&nbsp;</p><img src ="http://www.blogjava.net/mahang/aggbug/365024.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mahang/" target="_blank">马航</a> 2011-10-12 17:26 <a href="http://www.blogjava.net/mahang/archive/2011/10/12/365024.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SIP资料汇总</title><link>http://www.blogjava.net/mahang/archive/2011/10/07/365025.html</link><dc:creator>马航</dc:creator><author>马航</author><pubDate>Fri, 07 Oct 2011 12:31:00 GMT</pubDate><guid>http://www.blogjava.net/mahang/archive/2011/10/07/365025.html</guid><wfw:comment>http://www.blogjava.net/mahang/comments/365025.html</wfw:comment><comments>http://www.blogjava.net/mahang/archive/2011/10/07/365025.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mahang/comments/commentRss/365025.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mahang/services/trackbacks/365025.html</trackback:ping><description><![CDATA[<p style="padding: 0px; margin: 0px;"><strong style="font-weight: bold;">SIP协议</strong></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="SIP协议过程概念及分析" href="http://www.docin.com/p-163183484.html" target="_blank" style="color: #108ac6; text-decoration: underline;">SIP协议过程概念及分析</a></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="SIP入门开发之路(含SIP开发需要学习的资源及网址)" href="http://www.docin.com/p-163183482.html" target="_blank" style="color: #108ac6; text-decoration: underline;">SIP入门开发之路(含SIP开发需要学习的资源及网址)</a></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="SIP揭密（中文版）" href="http://www.docin.com/p-163183483.html" target="_blank" style="color: #108ac6; text-decoration: underline;">SIP揭密（中文版）</a></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	</span><a title="使用Java的SIP Servlet进行SIP开发" href="http://www.docin.com/p-54504229.html" target="_blank" style="color: #108ac6; text-decoration: underline;">使用Java的SIP Servlet进行SIP开发</a></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span><span><strong style="font-weight: bold;">Asterisk:</strong></span></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="Asterisk安装" href="http://www.docin.com/p-56495135.html" target="_blank" style="color: #108ac6; text-decoration: underline;">Asterisk安装及测试</a></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="Asterisk十问十答" href="http://www.docin.com/p-164770966.html" target="_blank" style="color: #108ac6; text-decoration: underline;">Asterisk十问十答</a></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	</span><a title="Asterisk入门教程" href="http://www.docin.com/p-164770963.html" target="_blank" style="color: #108ac6; text-decoration: underline;">Asterisk入门教程</a></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	</span><a title="Asterisk介绍" href="http://www.docin.com/p-163196430.html" target="_blank" style="color: #108ac6; text-decoration: underline;">Asterisk介绍-Asterisk RealTime SIP</a></p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	</span></p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="asterisk配置文件列表及常用指令" href="http://www.docin.com/p-177421282.html" target="_blank" style="color: #108ac6; text-decoration: underline;">asterisk配置文件列表及常用指令</a></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="asterisk 官方文档" href="http://www.docin.com/p-56205626.html" target="_blank" style="color: #108ac6; text-decoration: underline;">asterisk 官方文档</a></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="asterisk目录及配置说明" href="http://www.docin.com/p-164770964.html" target="_blank" style="color: #108ac6; text-decoration: underline;">asterisk目录及配置说明</a></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="Asterisk功能整理" href="http://www.docin.com/p-164770961.html" target="_blank" style="color: #108ac6; text-decoration: underline;">Asterisk功能整理</a></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="Asterisk使用ODBC实现语音信箱" href="http://www.docin.com/p-163196431.html" target="_blank" style="color: #108ac6; text-decoration: underline;">Asterisk使用ODBC实现语音信箱</a></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	</span><a title="使用Asterisk实现可视的语音交换" href="http://www.docin.com/p-164770960.html" target="_blank" style="color: #108ac6; text-decoration: underline;">使用Asterisk实现可视的语音交换</a></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><strong style="font-weight: bold;">OpenSIPS</strong></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="开源SIP服务器OpenSIPS应用介绍" href="http://www.docin.com/p-163183479.html" target="_blank" style="color: #108ac6; text-decoration: underline;">开源SIP服务器OpenSIPS应用介绍</a></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="Opensips 安装" href="http://www.docin.com/p-154358866.html" target="_blank" style="color: #108ac6; text-decoration: underline;">Opensips 安装</a></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="Opensips 配置文件" href="http://www.docin.com/p-154393877.html" target="_blank" style="color: #108ac6; text-decoration: underline;">Opensips 配置文件</a></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="Mediaproxy的安装及其在OpenSIPS中的配置" href="http://www.docin.com/p-163183480.html" target="_blank" style="color: #108ac6; text-decoration: underline;">Mediaproxy的安装及其在OpenSIPS中的配置</a></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="Opensips文档之MediaProxy模块" href="http://www.docin.com/p-154354628.html" target="_blank" style="color: #108ac6; text-decoration: underline;">Opensips文档之MediaProxy模块</a></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="使用OpenSIPS构建电话通信系统-8媒体服务整合" href="http://www.docin.com/p-163183477.html" target="_blank" style="color: #108ac6; text-decoration: underline;">使用OpenSIPS构建电话通信系统-8媒体服务整合</a></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="使用OpenSIPS构建电话通信系统-4脚本及路由基础" href="http://www.docin.com/p-163183478.html" target="_blank" style="color: #108ac6; text-decoration: underline;">使用OpenSIPS构建电话通信系统-4脚本及路由基础</a></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="Opensips文档之TM模块" href="http://www.docin.com/p-154354956.html" target="_blank" style="color: #108ac6; text-decoration: underline;">Opensips文档之TM模块</a></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="Opensips文档之RR模块" href="http://www.docin.com/p-154354812.html" target="_blank" style="color: #108ac6; text-decoration: underline;">Opensips文档之RR模块</a></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="Opensips文档之TEXTOPS 模块" href="http://www.docin.com/p-154355145.html" target="_blank" style="color: #108ac6; text-decoration: underline;">Opensips文档之TEXTOPS 模块</a></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="Opensips文档之AVPOPS模块" href="http://www.docin.com/p-154353896.html" target="_blank" style="color: #108ac6; text-decoration: underline;">Opensips文档之AVPOPS模块</a></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;">NAT穿透(即SIP打洞)</p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="使用OpenSIPS构建电话通信系统-9SIP穿透NAT" href="http://www.docin.com/p-163183476.html" target="_blank" style="color: #108ac6; text-decoration: underline;">使用OpenSIPS构建电话通信系统-SIP穿透NAT</a></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	</span><a title="NAT穿透问题探讨" href="http://www.docin.com/p-163196435.html" target="_blank" style="color: #108ac6; text-decoration: underline;">NAT穿透问题探讨</a></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="完美的NAT穿透技术ICE介绍" href="http://www.docin.com/p-163183485.html" target="_blank" style="color: #108ac6; text-decoration: underline;">完美的NAT穿透技术ICE介绍</a></span></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	</span><a title="ICE-SIP穿透NAT问题的终极解决方案" href="http://www.docin.com/p-163196433.html" target="_blank" style="color: #108ac6; text-decoration: underline;">ICE-SIP穿透NAT问题的终极解决方案</a></p>
<p style="padding: 0px; margin: 0px;">&nbsp;</p>
<p style="padding: 0px; margin: 0px;"><span style="white-space: pre;">	<a title="NAT穿透技术ICE基础教程" href="http://www.docin.com/p-163196432.html" target="_blank" style="color: #108ac6; text-decoration: underline;">NAT穿透技术ICE基础教程</a></span></p><img src ="http://www.blogjava.net/mahang/aggbug/365025.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mahang/" target="_blank">马航</a> 2011-10-07 20:31 <a href="http://www.blogjava.net/mahang/archive/2011/10/07/365025.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Android 自定义 ExpandableListView</title><link>http://www.blogjava.net/mahang/archive/2011/10/06/365026.html</link><dc:creator>马航</dc:creator><author>马航</author><pubDate>Thu, 06 Oct 2011 01:37:00 GMT</pubDate><guid>http://www.blogjava.net/mahang/archive/2011/10/06/365026.html</guid><wfw:comment>http://www.blogjava.net/mahang/comments/365026.html</wfw:comment><comments>http://www.blogjava.net/mahang/archive/2011/10/06/365026.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mahang/comments/commentRss/365026.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mahang/services/trackbacks/365026.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Android中有一控件是ExpandableListView，比ListView更高级，ExpandableListView的效果很实用，比如因为需要查看一堆文件的目录结构或者开发像QQ好友那样的界面，就应该使用Expandablelistview。本文最终效果如下：首先是Activity代码，实际开发中数据（包括父item，子item及图片，Expandablelistview...&nbsp;&nbsp;<a href='http://www.blogjava.net/mahang/archive/2011/10/06/365026.html'>阅读全文</a><img src ="http://www.blogjava.net/mahang/aggbug/365026.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mahang/" target="_blank">马航</a> 2011-10-06 09:37 <a href="http://www.blogjava.net/mahang/archive/2011/10/06/365026.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>手机视频文件格式解析之 3GP/MP4</title><link>http://www.blogjava.net/mahang/archive/2011/10/03/365027.html</link><dc:creator>马航</dc:creator><author>马航</author><pubDate>Mon, 03 Oct 2011 02:54:00 GMT</pubDate><guid>http://www.blogjava.net/mahang/archive/2011/10/03/365027.html</guid><wfw:comment>http://www.blogjava.net/mahang/comments/365027.html</wfw:comment><comments>http://www.blogjava.net/mahang/archive/2011/10/03/365027.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mahang/comments/commentRss/365027.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mahang/services/trackbacks/365027.html</trackback:ping><description><![CDATA[<p></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">前言：做完了手机全能播放器的项目，&nbsp;又要告别几个月来并肩作战，即将去北京发展的Manager&nbsp;zhu。准备把做过的3GP/FLV/AVI格式整理一遍，&nbsp;算是对几个月辛苦成果的总结，&nbsp;也为后来者提供一些参考。</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-weight: bold; font-size: 12.0000pt; font-family: '宋体';">1.&nbsp;概述</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">流行的文件格式背后都有大公司的支持。FLV得益于ADOBE公司推动的网络视频分享风潮，而AVI则是MICROSOFT首创的RIFF即视频和音频交织在一起同步播放。&nbsp;3GP/MP4是APPLE提出并得到ISO标准支持作为NOKIA等手机的默认视频格式。3GP是MP4格式在手机上的简化版。MP4的codec组合一般是mpeg4&nbsp;+&nbsp;AAC,&nbsp;3GP则按版本演进分为3gpp&nbsp;r5(h.263/mpeg4&nbsp;+&nbsp;AMR-NB/AMR&nbsp;WB),&nbsp;3gpp&nbsp;r6(增加h.264视频和aacPlus音频支持)。</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">有人会把MP4和MPEG4搞混，&nbsp;前者是文件容器(container)，后者是视频编码格式，&nbsp;容器的作用是把压缩编码后的视频和音频数据尽可能紧凑的排布，就好像阿甘的巧克力盒子，你并不知道盒子里有什么，&nbsp;但你可以按照既定的线索解开文件，取出你需要的数据。</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">文件格式一般包括以下三要素：</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">header:&nbsp;标记文件类型，音视频码流的基本属性信息</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><br /></span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">index:&nbsp;索引表，每个frame有对应的offset,size,timestamp.</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><br /></span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">stream:&nbsp;真正的音视频流数据。</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><br /></span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">任何文件格式都应该有以上3要素。&nbsp;当然AVI视频没有索引也能播放，但不能拖放seek，需要自己重建索引。解析器(demuxer)根据frame_id找到其在文件中的offset和size,然后读取出来解码并播放。</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-weight: bold; font-size: 12.0000pt; font-family: '宋体';">2.&nbsp;文件格式分析</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">下面来分析一下3GP/MP4文件格式。APPLE的格式有2个特点，1.&nbsp;排布紧凑几乎没有冗余数据(AVI则有很多junk数据)，2.音视频码流数据可随意存放而不需按时间顺序排布。</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">3gp文件由一系列的box(atom)组成。每个box的结构都是4字节的size,4字节的type,&nbsp;还有一些data数据。用mp4info查看3gp文件的数据排布如下图：</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p><img src="http://pic002.cnblogs.com/images/2011/324517/2011100310542534.jpg" alt="" /></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">如上图,&nbsp;ftyp是表示文件的版本信息，&nbsp;mdat存放文字，音视频等数据。你可能要问，这些音视频数据怎么找到呢？&nbsp;是通过moov&nbsp;box里的子box&nbsp;trak，里面存放着音视频的属性描述以及每个sample的索引。</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-weight: bold; font-size: 12.0000pt; font-family: '宋体';">3.&nbsp;关于sample&nbsp;atoms</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">&nbsp;&nbsp;&nbsp;video和audio的码流属性(如视频width/height,codec&nbsp;id,&nbsp;音频采样率声道数等)存放在stsd&nbsp;box里；&nbsp;下面着重介绍MP4高效压缩的精华：stts,stss,stsc,stsz,stco五个box。对比AVI的索引表是每个sample都有对应的id,flag,offset,size，3GP的高效索引方式可以把AVI转码成同码率的MP4后，文件size减小成原来的20-30%!</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">1.&nbsp;stts&nbsp;atom(time&nbsp;to&nbsp;sample&nbsp;atoms，见quicktime&nbsp;format&nbsp;文档图2-28&nbsp;</span><span><a href="http://developer.apple.com/documentation/QuickTime/qtff/qtff.pdf"><span style="mso-spacerun: 'yes'; color: #0000ff; font-weight: bold; text-decoration: underline; font-size: 12.0000pt; font-family: '宋体';">标准文档点击下载</span></a></span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">):&nbsp;存储了sample的时间信息。stts能让很方便的根据timestamp找到对应的sample，或者获取某个sample对应的timestamp.&nbsp;sttstable记录着有相同duration的sample的数量count和时长dutation。</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">2.&nbsp;stss&nbsp;atom(sync&nbsp;sample&nbsp;atom，见文档图2-31):&nbsp;存储了每个关键帧的sample&nbsp;id。&nbsp;stss能让你很方便的找到当前帧最近的关键帧。</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">3.&nbsp;stsc&nbsp;atom(sample&nbsp;to&nbsp;chunk&nbsp;atom):&nbsp;sample存放在chunk里为了允许优化的数据读取。比如音频sample&nbsp;size都很小（amr-nb&nbsp;sample&nbsp;size为32字节），&nbsp;每次读取一个sample开销太大，&nbsp;可一次性读所在chunk里一堆sample。</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">4.&nbsp;stsz&nbsp;atom(sample&nbsp;size&nbsp;atom):&nbsp;stsz可以描述每个sample的size.</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">5.&nbsp;stco&nbsp;atom(chunk&nbsp;offset&nbsp;atoms):&nbsp;stco描述了每个chunk在文件中的绝对偏移位置。该offset可以是32位的</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">也可以是64位的，后者用来支持处理超大文件。</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-weight: bold; font-size: 12.0000pt; font-family: '宋体';">4&nbsp;.使用sample&nbsp;atoms来处理播放流程</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-left: 36.0000pt; text-indent: -18.0000pt; margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-weight: bold; font-size: 10.0000pt; font-family: 'Symbol';">&middot;&nbsp;</span><span style="mso-spacerun: 'yes'; font-weight: bold; font-size: 12.0000pt; font-family: '宋体';">查找sample</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">1．确定时间，相对于媒体时间坐标系统</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">2．检查time-to-sample&nbsp;atom来确定给定时间的sample序号。</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">3．检查sample-to-chunk&nbsp;atom来发现对应该sample的chunk。</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">4．从chunk&nbsp;offset&nbsp;atom中提取该trunk的偏移量。</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">5．利用sample&nbsp;size&nbsp;atom找到sample在trunk内的偏移量和sample的大小。</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">例如，如果要找第1秒的视频数据，过程如下：</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">1．&nbsp;第1秒的视频数据相对于此电影的时间为600</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">2．&nbsp;检查time-to-sample&nbsp;atom，得出每个sample的duration是40，从而得出需要寻找第600/40&nbsp;=&nbsp;15&nbsp;+&nbsp;1&nbsp;=&nbsp;16个sample</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">3．&nbsp;检查sample-to-chunk&nbsp;atom，得到该sample属于第5个chunk的第一个sample，该chunk共有4个sample</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">4．&nbsp;检查chunk&nbsp;offset&nbsp;atom找到第5个trunk的偏移量是20472</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">5．&nbsp;由于第16个sample是第5个trunk的第一个sample，所以不用检查sample&nbsp;size&nbsp;atom，trunk的偏移量即是该sample的偏移量20472。如果是这个trunk的第二个sample，则从sample&nbsp;size&nbsp;atom中找到该trunk的前一个sample的大小，然后加上偏移量即可得到实际位置。</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">6．&nbsp;得到位置后，即可取出相应数据进行解码，播放</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-left: 36.0000pt; text-indent: -18.0000pt; margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 10.0000pt; font-family: 'Symbol';">&middot;&nbsp;</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="mso-spacerun: 'yes'; font-weight: bold; font-size: 12.0000pt; font-family: '宋体';">查找关键帧</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">查找过程与查找sample的过程非常类似，只是需要利用sync&nbsp;sample&nbsp;atom来确定key&nbsp;frame的sample序号</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">确定给定时间的sample序号&nbsp;</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><br /></span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">检查sync&nbsp;sample&nbsp;atom来发现这个sample序号之后的key&nbsp;frame&nbsp;</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><br /></span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">检查sample-to-chunk&nbsp;atom来发现对应该sample的chunk&nbsp;</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><br /></span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">从chunk&nbsp;offset&nbsp;atom中提取该trunk的偏移量&nbsp;</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><br /></span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">利用sample&nbsp;size&nbsp;atom找到sample在trunk内的偏移量和sample的大小</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 5.0000pt; margin-top: 5.0000pt; text-align: left;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><br /></span><span style="mso-spacerun: 'yes'; font-weight: bold; font-size: 12.0000pt; font-family: '宋体';">5&nbsp;.3GP/MP4相关资源</span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><o:p></o:p></span></p>
<p class="p0" style="margin-bottom: 0pt; margin-top: 0pt;"><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;quicktime&nbsp;file&nbsp;format&nbsp;specification:&nbsp;最权威的格式文档&nbsp;</span><span><a href="http://developer.apple.com/documentation/QuickTime/qtff/qtff.pdf"><span style="mso-spacerun: 'yes'; color: #0000ff; text-decoration: underline; font-size: 12.0000pt; font-family: '宋体';">点击下载</span></a></span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';"><br /></span><span style="mso-spacerun: 'yes'; font-size: 12.0000pt; font-family: '宋体';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;开源的3GP/MP4解析器：&nbsp;ffmpeg,&nbsp;GPAC,&nbsp;helix,&nbsp;google&nbsp;opencore等&nbsp;</span></p><img src ="http://www.blogjava.net/mahang/aggbug/365027.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mahang/" target="_blank">马航</a> 2011-10-03 10:54 <a href="http://www.blogjava.net/mahang/archive/2011/10/03/365027.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>超经典的Android开源项目</title><link>http://www.blogjava.net/mahang/archive/2011/10/03/365028.html</link><dc:creator>马航</dc:creator><author>马航</author><pubDate>Mon, 03 Oct 2011 01:47:00 GMT</pubDate><guid>http://www.blogjava.net/mahang/archive/2011/10/03/365028.html</guid><wfw:comment>http://www.blogjava.net/mahang/comments/365028.html</wfw:comment><comments>http://www.blogjava.net/mahang/archive/2011/10/03/365028.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mahang/comments/commentRss/365028.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mahang/services/trackbacks/365028.html</trackback:ping><description><![CDATA[<table cellspacing="0" cellpadding="0" style="word-wrap: break-word; empty-cells: show; border-collapse: collapse; table-layout: fixed; width: 757px; padding: 0px; margin: 0px;">
<tbody style="word-wrap: break-word; padding: 0px; margin: 0px;">
<tr style="word-wrap: break-word; padding: 0px; margin: 0px;">
<td class="t_f" id="postmessage_30" style="word-wrap: break-word; font-size: 14px; padding: 0px; margin: 0px;">Android开发又将带来新一轮热潮，很多开发者都投入到这个浪潮中去了，创造了许许多多相当优秀的应用。其中也有许许多多的开发者提供了应用开 源项目，贡献出他们的智慧和创造力。学习开源代码是掌握技术的一个最佳方式。下面推荐几个应用开源项目，这些项目不仅提供了优秀的创意，也可以直接掌握 Android内核的接口使用：<br style="word-wrap: break-word; padding: 0px; margin: 0px;" /><br style="word-wrap: break-word; padding: 0px; margin: 0px;" />1、Android团队提供的示例项目<br style="word-wrap: break-word; padding: 0px; margin: 0px;" /><br style="word-wrap: break-word; padding: 0px; margin: 0px;" />如果不是从学习Android SDK中提供的那些样例代码开始，可能没有更好的方法来掌握在Android这个框架上开发。由Android的核心开发团队提供了15个优秀的示例项目，包含了游戏、图像处理、时间显示、开始菜单快捷方式等。<br style="word-wrap: break-word; padding: 0px; margin: 0px;" />地址：<a href="http://code.google.com/p/apps-for-android/" target="_blank" style="word-wrap: break-word; color: #336699; text-decoration: underline; padding: 0px; margin: 0px;">http://code.google.com/p/apps-for-android/</a><br style="word-wrap: break-word; padding: 0px; margin: 0px;" /><br style="word-wrap: break-word; padding: 0px; margin: 0px;" />2、 Remote Droid<br style="word-wrap: break-word; padding: 0px; margin: 0px;" /><br style="word-wrap: break-word; padding: 0px; margin: 0px;" />RemoteDroid是一个Android应用，能够让用户使用自己的无线网络使用无线键盘、触摸屏操作手机。这个项目为开发者提供了如网络连接、触摸屏手指运动等很好的样例。<br style="word-wrap: break-word; padding: 0px; margin: 0px;" />地址：<a href="http://code.google.com/p/remotedroid/" target="_blank" style="word-wrap: break-word; color: #336699; text-decoration: underline; padding: 0px; margin: 0px;">http://code.google.com/p/remotedroid/</a><br style="word-wrap: break-word; padding: 0px; margin: 0px;" /><br style="word-wrap: break-word; padding: 0px; margin: 0px;" />3、 TorProxy和Shadow<br style="word-wrap: break-word; padding: 0px; margin: 0px;" /><br style="word-wrap: break-word; padding: 0px; margin: 0px;" />TorProxy应用实现了Android手机无线电电传通讯(TOR)，和Shadow应用一起使用，可以使用手机匿名上网。从该项目源代码中，可以掌握socket连接、管理cookie等方法。<br style="word-wrap: break-word; padding: 0px; margin: 0px;" />地址：<a href="http://www.cl.cam.ac.uk/research/dtg/code/svn/android-tor/" target="_blank" style="word-wrap: break-word; color: #336699; text-decoration: underline; padding: 0px; margin: 0px;">http://www.cl.cam.ac.uk/research/dtg/code/svn/android-tor/</a><br style="word-wrap: break-word; padding: 0px; margin: 0px;" /><br style="word-wrap: break-word; padding: 0px; margin: 0px;" />4、 Android SMSPopup<br style="word-wrap: break-word; padding: 0px; margin: 0px;" /><br style="word-wrap: break-word; padding: 0px; margin: 0px;" />SMSPopup可以截获短信内容显示在一个泡泡形状的窗口中。从这个项目中可以掌握到如何使用内置的短信SMS接口。<br style="word-wrap: break-word; padding: 0px; margin: 0px;" />地址：<a href="http://code.google.com/p/android-smspopup/" target="_blank" style="word-wrap: break-word; color: #336699; text-decoration: underline; padding: 0px; margin: 0px;">http://code.google.com/p/android-smspopup/</a><br style="word-wrap: break-word; padding: 0px; margin: 0px;" /><br style="word-wrap: break-word; padding: 0px; margin: 0px;" />5、 Standup Timer<br style="word-wrap: break-word; padding: 0px; margin: 0px;" /><br style="word-wrap: break-word; padding: 0px; margin: 0px;" />Standup Timer应用用于控制站立会议时间，类似秒表倒计时，可以提醒每个人的讲话时间已到，从而保证每个与会者使用时间一样。从该项目的代码中，可以学会如何使用时间函数。另外，这个项目的代码是采用视图view、模型model严格分离的设计思路。<br style="word-wrap: break-word; padding: 0px; margin: 0px;" />地址：<a href="http://github.com/jwood/standup-timer" target="_blank" style="word-wrap: break-word; color: #336699; text-decoration: underline; padding: 0px; margin: 0px;">http://github.com/jwood/standup-timer</a><br style="word-wrap: break-word; padding: 0px; margin: 0px;" /><br style="word-wrap: break-word; padding: 0px; margin: 0px;" />6、 Foursquare<br style="word-wrap: break-word; padding: 0px; margin: 0px;" /><br style="word-wrap: break-word; padding: 0px; margin: 0px;" />是Foursquare.com的一个客户端应用，该应用主要分为两个模块：API(com.joelapenna.foursquare)和界面前端 (com.joelapenna.foursquared)两部分。从该项目代码中，可以学会如何同步、多线程、HTTP连接等技术。<br style="word-wrap: break-word; padding: 0px; margin: 0px;" />地址：<a href="http://code.google.com/p/foursquared/" target="_blank" style="word-wrap: break-word; color: #336699; text-decoration: underline; padding: 0px; margin: 0px;">http://code.google.com/p/foursquared/</a><br style="word-wrap: break-word; padding: 0px; margin: 0px;" /><br style="word-wrap: break-word; padding: 0px; margin: 0px;" />7、 Pedometer<br style="word-wrap: break-word; padding: 0px; margin: 0px;" /><br style="word-wrap: break-word; padding: 0px; margin: 0px;" />Pedometer应用用于记录你每天走路步数的。尽管记录不一定精准，但是从这个项目中，可以学习几个不同的技术：加速器交互、语音更新、后台运行服务等。<br style="word-wrap: break-word; padding: 0px; margin: 0px;" />地址：<a href="http://code.google.com/p/pedometer/" target="_blank" style="word-wrap: break-word; color: #336699; text-decoration: underline; padding: 0px; margin: 0px;">http://code.google.com/p/pedometer/</a><br style="word-wrap: break-word; padding: 0px; margin: 0px;" /><br style="word-wrap: break-word; padding: 0px; margin: 0px;" />8、 OpenSudoku-android<br style="word-wrap: break-word; padding: 0px; margin: 0px;" /><br style="word-wrap: break-word; padding: 0px; margin: 0px;" />OpenSudoku是一个简单的九宫格数独游戏。从代码中可以学习到如何在视图中显示表格数据，以及如何和一个网站交互等技术。<br style="word-wrap: break-word; padding: 0px; margin: 0px;" />地址：<a href="http://code.google.com/p/opensudoku-android/" target="_blank" style="word-wrap: break-word; color: #336699; text-decoration: underline; padding: 0px; margin: 0px;">http://code.google.com/p/opensudoku-android/</a><br style="word-wrap: break-word; padding: 0px; margin: 0px;" /><br style="word-wrap: break-word; padding: 0px; margin: 0px;" />9、 ConnectBot<br style="word-wrap: break-word; padding: 0px; margin: 0px;" /><br style="word-wrap: break-word; padding: 0px; margin: 0px;" />ConnectBot是Android平台的一个客户端安全壳应用。从该项目代码中，可以学习到很多Android安全方面的内容，这些是你在开发应用时经常需要考虑的安全问题。<br style="word-wrap: break-word; padding: 0px; margin: 0px;" />地址：<a href="http://code.google.com/p/connectbot/" target="_blank" style="word-wrap: break-word; color: #336699; text-decoration: underline; padding: 0px; margin: 0px;">http://code.google.com/p/connectbot/</a><br style="word-wrap: break-word; padding: 0px; margin: 0px;" /><br style="word-wrap: break-word; padding: 0px; margin: 0px;" />10、 WordPress的Android应用<br style="word-wrap: break-word; padding: 0px; margin: 0px;" /><br style="word-wrap: break-word; padding: 0px; margin: 0px;" />当然在最后不能不提WordPress的Android应用了，这是WordPress官方开发团队提供的一个项目。从代码中可以学习到XMLRPC调用（当然还有更多的优秀内容）。<br style="word-wrap: break-word; padding: 0px; margin: 0px;" />地址：<a href="http://android.svn.wordpress.org/trunk/" target="_blank" style="word-wrap: break-word; color: #336699; text-decoration: underline; padding: 0px; margin: 0px;">http://android.svn.wordpress.org/trunk/</a></td>
</tr>
</tbody>
</table><img src ="http://www.blogjava.net/mahang/aggbug/365028.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mahang/" target="_blank">马航</a> 2011-10-03 09:47 <a href="http://www.blogjava.net/mahang/archive/2011/10/03/365028.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>