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

<channel>
	<title>追梦者，用汗水扬帆起航。</title>
	<atom:link href="http://www.14en.com/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://www.14en.com</link>
	<description>因为不聪明，所以要勤奋！</description>
	<lastBuildDate>Sat, 21 Dec 2019 10:20:31 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	
	<item>
		<title>如何给k8s服务做单元测试</title>
		<link>http://www.14en.com/?p=181</link>
		<comments>http://www.14en.com/?p=181#comments</comments>
		<pubDate>Sat, 21 Dec 2019 10:20:31 +0000</pubDate>
		<dc:creator><![CDATA[eekuang]]></dc:creator>
				<category><![CDATA[根目录]]></category>

		<guid isPermaLink="false">http://www.14en.com/?p=181</guid>
		<description><![CDATA[由于工作原因，最近半年在使用Go语言写一些k8s相关的服务，这些服务有的需要往k8s集群写入Pod资源，有的需 [&#8230;]]]></description>
				<content:encoded><![CDATA[<div>
<p>由于工作原因，最近半年在使用Go语言写一些k8s相关的服务，这些服务有的需要往k8s集群写入Pod资源，有的需要监听Node、Pod和其它资源的变更。在早期的时候，我是使用了官方提供的用于与k8s通信的SDK是client-go来做实际代码实现，但在单元测试上是自己实现了一个Mock对象，来做测试。最近仔细研究了client-go的源码后发现，其实client-go官方已经实现了相关的mock对象，在目录 <a href="http://k8s.io/client-go/kubernetes/fake" target="_blank">k8s.io/client-go/kubernetes/fake</a> 下。接下来，我们就以实际例子来看下具体怎么使用官方提供的fake包做相关的单元测试。</p>
</div>
<div>
<h4 id="1-添加k8s资源对象">1.添加k8s资源对象</h4>
</div>
<div>
<p>本文以测试添加一个pod作为例子，向集群中写入一个名为test-pod的pod。首先，给出指定pod名和namespace，往k8s集群写入一个pod资源的代码。特别说明，为了简洁方法的介绍，Pod信息做了精简，在实际情况中需要填入更多的pod参数才能写入到k8s集群。</p>
</div>
<div>
<pre><code>package k8s

import (

  v1 "k8s.io/api/core/v1"

  metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

  "k8s.io/client-go/kubernetes"

)

//API for operate k8s

type API struct {

  Client kubernetes.Interface

}

// NewPodWithNs creates a new pod with namespace
func (k API) NewPodWithNs(name, namespace string) error {

  p := &amp;v1.Pod{

​    ObjectMeta: metav1.ObjectMeta{

​      Name:      name,

​      Namespace: namespace,

​    },

  }

  _, err := k.Client.CoreV1().Pods(namespace).Create(p)
  if err != nil {

​    return err

  }
  return nil
}

</code></pre>
</div>
<div>
<p>在上述例子中，我们定义了一个名为API的对象，其有一个方法NewPodWithNs用于往k8s写入一个pod资源对象。我们就对这个方法进行单元测试。在对k8s应用进行单元测试时，我们一般可选择kubernetes.Interface或者kubernetes.Clientset来进行Mock测试。我选择的是kubernetes.Interface，这样的话就可以对整个k8s的API接口都mock掉，其fake包位置为<a href="http://k8s.io/client-go/kubernetes/fake" target="_blank">k8s.io/client-go/kubernetes/fake</a>。具体测试代码如下：</p>
</div>
<div>
<pre><code>package k8s

import (
	"testing"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	testclient "k8s.io/client-go/kubernetes/fake"
)

const (
	testPod       = "test-pod"
	testNamespace = "test-ns"
)

func TestNewPodWithNs(t *testing.T) {
	cases := []struct {
		name string
		ns   string
	}{
		{
			name: testPod,
			ns:   testNamespace,
		},
	}

	api := &amp;API{
		Client: testclient.NewSimpleClientset(),
	}

	for _, c := range cases {
		// create the postfixed namespace
		err := api.NewPodWithNs(c.name, c.ns)
		if err != nil {
			t.Fatal(err.Error())
		}

		if p, err := api.Client.CoreV1().Pods(c.ns).Get(c.name, metav1.GetOptions{}); nil != err {
			t.Errorf("get pod  err %v", err)
		} else if p.Name != c.name {
			t.Errorf("pod name err")
		}

	}
}
</code></pre>
</div>
<div>
<p>整个测试代码非常简单，使用官方的fake包生成一个client对象，然后往这个虚拟的k8s 集群的指定namespaces写入一个pod。通过Get接口进行获取，如果能获取到Pod则表示写入成功。通过短短几十行代码，就能验证我们内部的逻辑是否正常工作。如果你写入的Pod参数非常多的话，那测试用例也要更多才行。</p>
</div>
<div>
<p>这是一个简单的例子来验证写入Pod和查询Pod。删除和修改Pod及其它资源对象（namespace,node等）的增删改查也是类似的。如果你有相关的的需求，可以参照上述代码动手试试看。</p>
</div>
<div>
<h4 id="2-监听资源对象的变更">2.监听资源对象的变更</h4>
</div>
<div>
<p>我们以监听pod添加这一事件作为例子来示范如何做监听资源对象变更的单元测试。具体实现代码如下：</p>
</div>
<div>
<pre><code>package k8s

import (
	v1 "k8s.io/api/core/v1"
)

//Cache for operate k8s
type Cache struct {
	Pods map[string]*v1.Pod
}

// AddPod add a pod
func (c *Cache) AddPod(p *v1.Pod) error {
	c.Pods[p.Name] = p
	return nil
}
</code></pre>
</div>
<div>
<p>上述代码非常简单，就是本地做一份cache，然后保存Pod信息。测试代码则会复杂很多，具体的测试代码如下：</p>
</div>
<div>
<pre><code>package k8s

import (
	"context"
	"testing"
	"time"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes/fake"
	"k8s.io/client-go/tools/cache"
)

// TestAddPodEvent aim to test add pod event.
func TestAddPodEvent(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// Create the fake client.
	client := fake.NewSimpleClientset()

	c := Cache{Pods: make(map[string]*v1.Pod)}
	// We will create an informer that writes added pods to a channel.
	pods := make(chan *v1.Pod, 1)
	informers := informers.NewSharedInformerFactory(client, 0)
	podInformer := informers.Core().V1().Pods().Informer()
	podInformer.AddEventHandler(&amp;cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			pod := obj.(*v1.Pod)
			pods &lt;- pod
			t.Logf("pod added: %s/%s", pod.Namespace, pod.Name)
			if err := c.AddPod(pod); nil != err {
				t.Errorf("add pod err %v", err)
			}
		},
	})

	// Make sure informers are running.
	informers.Start(ctx.Done())

	// This is not required in tests, but it serves as a proof-of-concept by
	// ensuring that the informer goroutine have warmed up and called List before
	// we send any events to it.
	cache.WaitForCacheSync(ctx.Done(), podInformer.HasSynced)

	// Inject an event into the fake client.
	p := &amp;v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: TestPod}}
	_, err := client.CoreV1().Pods(TestNamespace).Create(p)
	if err != nil {
		t.Fatalf("error injecting pod add: %v", err)
	}

	select {
	case pod := &lt;-pods:
		if _, ok := c.Pods[pod.Name]; !ok {
			t.Errorf("no pod after add event")
		}
	case &lt;-time.After(wait.ForeverTestTimeout):
		t.Error("Informer did not get the added pod")
	}
}

</code></pre>
</div>
<div>
<p>上述例子仅对Pod的添加事件进行了监听，如果还需要监听更新和删除事件的话（一般的应用中都需要同时监听增删改事件），需要再注册两个方法到informer中，当然其实现也是类似的。同样，这种测试方式可以推广到Node,Namespace等其他方法。</p>
</div>
<div>
<h4 id="3-再说两句">3.再说两句</h4>
</div>
<div>
<p>上述两种测试的方法不仅仅适用于k8s自有的资源对象，同样也适用于CRD。有兴趣的同学可以研究下通过代码工具生成的CRD代码，其中也包含了fake的的代码实现。如有任何问题，欢迎交流~</p>
</div>
<p><span style="font-weight:bold;text-shadow:0 1px 0 #ddd;">声明:</span> 本文采用 <a rel="nofollow" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" title="署名-非商业性使用-相同方式共享">BY-NC-SA</a> 协议进行授权 | <a href="http://www.14en.com">追梦者，用汗水扬帆起航。</a><br />转载请注明转自《<a rel="bookmark" title="如何给k8s服务做单元测试" href="http://www.14en.com/?p=181">如何给k8s服务做单元测试</a>》</p>]]></content:encoded>
			<wfw:commentRss>http://www.14en.com/?feed=rss2&#038;p=181</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>如何成为一名合格的go开发者</title>
		<link>http://www.14en.com/?p=178</link>
		<comments>http://www.14en.com/?p=178#comments</comments>
		<pubDate>Sat, 21 Dec 2019 09:26:21 +0000</pubDate>
		<dc:creator><![CDATA[eekuang]]></dc:creator>
				<category><![CDATA[技术笔记]]></category>

		<guid isPermaLink="false">http://www.14en.com/?p=178</guid>
		<description><![CDATA[一、为什么要学go     作为一名后台开发工程师，学习golang的好处，可以列举出无数个。而我自己决定转投 [&#8230;]]]></description>
				<content:encoded><![CDATA[<div>
<h2 id="一-为什么要学go">一、为什么要学go</h2>
</div>
<div>
<p>    作为一名后台开发工程师，学习golang的好处，可以列举出无数个。而我自己决定转投go的怀抱，有四个点：1.工作需要，容器相关的重量级项目基本都由go编写；2.高性能；3.丰富的组件库；4.易于测试（作为一名C++开发者，每次想测试一个模块或者函数时，真是眼泪留下来）。</p>
</div>
<div>
<h2 id="二-怎么做">二、怎么做</h2>
</div>
<div>
<p>    依次做好如下几点，我觉得至少可以成为一个基本合格的go开发者。</p>
</div>
<div>
<h3 id="2-1 系统地学习基础知识">2.1 系统地学习基础知识</h3>
</div>
<div>
<p>    现在很多时候，我们都被要求快速迭代快速输出，不可能让你学习一个月之后，再开始写代码。尽管如此，我仍然认为必须通过至少一本书籍系统地学习go的基础知识。在此，我着重推荐开源书籍<a href="https://books.studygolang.com/gopl-zh/" target="_blank">《GO语言圣经》</a>,可以在电脑上看，也可以下载到kindle里碎片时间阅读。</p>
</div>
<div>
<h3 id="2-2 通过IDE写代码">2.2 通过IDE写代码</h3>
</div>
<div>
<p>    古语云：君子性非异也，善假于物也。IDE可以极大提升你写代码的效率，例如自动补全和自动生成单元测试用例。同时，现在IDE集成了各种检查工具，例如检查你的常量命名问题（很多人喜欢大写+下划线命名常量，go官方推荐驼峰命名法）。此外，IDE很多也集成了debug功能，也是排障的一大利器。推荐vs code和goland，我本人使用vs code。在使用IDE的时候，还需要花一定时间研究IDE的配置及各种快捷键，要释放出其最大的威力，提升你的编码效率。</p>
</div>
<div>
<p><img alt="" src="http://imgcache.oa.com/photos/54995/2078d57bcca97e2e136dd83bebe189a0.png" /></p>
</div>
<div>
<h3 id="2-3 写代码并持续重构">2.3 写代码并持续重构</h3>
</div>
<div>
<p>    要成为一名合格的开发者，一定的代码量是必不可少的。写完之后，可以隔一段时间来review自己的代码，如果发现写的太烂了，就把它重构掉。持续地写，持续地重构，逐步提升自己的代码味道。</p>
</div>
<div>
<h3 id="2-4 看优秀的代码并模仿">2.4 看优秀的代码并模仿</h3>
</div>
<div>
<p>    所谓既要埋头苦干，也要抬头看路。在2.3中，我建议写代码并持续重构，但如果只是一味地闭门造车，很可能写的一手垃圾代码自己还心满意足。那么，怎么样才能看清自己的代码水平呢？最好的办法就是看好代码是什么样子，然后和自己做对比。好的代码包括两部分：1.go官方库;2.优秀的go项目。比如，我之前看到context时，觉得很感兴趣，就把context源码撸了一遍。这块代码比较简单，也很适合新手看。其次，我因为工作原因，也撸了kubernetes的源码。看到一些有意思的实践方式的时候，可以将其应用到自己的一些代码中。</p>
</div>
<div>
<h3 id="2-5 测试">2.5 测试</h3>
</div>
<div>
<p>    永远不要相信自己的代码没有bug。而如果你坚定了这一点，就应该尽量地补全测试用例，尽量覆盖所有可测试的代码。单元测试是必不可少的，功能测试在很多情况下也是需要的。而且，每当你发现一处bug时，就应该尽量给它增加一个测试用例。而且，我建议在写代码之前，就先想好测试用例（即TDD）。</p>
</div>
<div>
<h3 id="2-6 注释和测试文档">2.6 注释和测试文档</h3>
</div>
<div>
<p>    好的代码，应该有代码即说明文档的既视感。但必要的说明文档仍然必不可少，介绍这个项目是什么，怎么用等。</p>
</div>
<div>
<h3 id="2-7 不给自己留借口">2.7 不给自己留借口</h3>
</div>
<div>
<p>    很多人说：听过很多道理，却依然写不好代码。我认为，这其中最大的问题就在于给自己找借口。因为时间太紧，所以来不及写测试用例，以后有时间再写，然后就再也没时间了。因为工作太忙，所以就不看书了，看完hello world就直接撸大型项目，然后代码就惨不忍睹了，最后可能都维护不下去。不给自己找借口，按最高的标准要求自己。</p>
</div>
<div>
<h2 id="三-后记">三、后记</h2>
</div>
<div>
<p>    写这篇文章时，我其实是有点忐忑的。忐忑在于，我没有太大底气认为自己已经是一个合格的开发者。而写这篇文章的初衷，是希望能将自己这近一年的学习历程分享出来，能够与其它同学有一些碰撞，希望大家不吝指教。希望，大家未来都能成为一名合格的go开发者。Let’s Go!</p>
</div>
<p><span style="font-weight:bold;text-shadow:0 1px 0 #ddd;">声明:</span> 本文采用 <a rel="nofollow" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" title="署名-非商业性使用-相同方式共享">BY-NC-SA</a> 协议进行授权 | <a href="http://www.14en.com">追梦者，用汗水扬帆起航。</a><br />转载请注明转自《<a rel="bookmark" title="如何成为一名合格的go开发者" href="http://www.14en.com/?p=178">如何成为一名合格的go开发者</a>》</p>]]></content:encoded>
			<wfw:commentRss>http://www.14en.com/?feed=rss2&#038;p=178</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>知道这20个正则表达式，能让你少写1,000行代码</title>
		<link>http://www.14en.com/?p=172</link>
		<comments>http://www.14en.com/?p=172#comments</comments>
		<pubDate>Tue, 26 Apr 2016 03:20:15 +0000</pubDate>
		<dc:creator><![CDATA[eekuang]]></dc:creator>
				<category><![CDATA[技术笔记]]></category>

		<guid isPermaLink="false">http://www.14en.com/?p=172</guid>
		<description><![CDATA[正则表达式，一个十分古老而又强大的文本处理工具，仅仅用一段非常简短的表达式语句，便能够快速实现一个非常复杂的业 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>正则表达式，一个十分古老而又强大的文本处理工具，仅仅用一段非常简短的表达式语句，便能够快速实现一个非常复杂的业务逻辑。熟练地掌握正则表达式的话，能够使你的开发效率得到极大的提升。</p>
<p>正则表达式经常被用于字段或任意字符串的校验，如下面这段校验基本日期格式的JavaScript代码：</p>
<pre><code>
var reg = /^(\\d{1,4})(-|\\/)(\\d{1,2})\\2(\\d{1,2})$/; 
var r = fieldValue.match(reg);             
if(r==null)alert('Date format error!');
</code></pre>
<p>&nbsp;</p>
<p>下面是技匠整理的，在前端开发中经常使用到的20个正则表达式。</p>
<p><strong>1 . 校验密码强度</strong><br />
密码的强度必须是包含大小写字母和数字的组合，不能使用特殊字符，长度在8-10之间。</p>
<pre><code>^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
</code></pre>
<p><strong> </strong></p>
<p><strong>2. 校验中文</strong><br />
字符串仅能是中文。</p>
<pre><code>^[\\u4e00-\\u9fa5]{0,}$
</code></pre>
<p><strong> </strong></p>
<p><strong>3. 由数字、26个英文字母或下划线组成的字符串</strong></p>
<pre><code>^\\w+$
</code></pre>
<p><strong> </strong></p>
<p><strong>4. 校验E-Mail 地址</strong><br />
同密码一样，下面是E-mail地址合规性的正则检查语句。</p>
<pre><code>[\\w!#$%&amp;'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&amp;'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[\\w](?:[\\w-]*[\\w])?
</code></pre>
<p>&nbsp;</p>
<p><strong>5. 校验身份证号码</strong></p>
<p>下面是身份证号码的正则校验。15 或 18位。</p>
<p><strong>15位：</strong></p>
<pre><code>^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}$
</code></pre>
<p><strong>18位：</strong></p>
<pre><code>^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9]|X)$
</code></pre>
<p><strong> </strong></p>
<p><strong>6. 校验日期</strong><br />
“yyyy-mm-dd“ 格式的日期校验，已考虑平闰年。</p>
<pre><code>^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$
</code></pre>
<p><strong> </strong></p>
<p><strong>7. 校验金额</strong><br />
金额校验，精确到2位小数。</p>
<pre><code>^[0-9]+(.[0-9]{2})?$
</code></pre>
<p><strong> </strong></p>
<p><strong>8. 校验手机号</strong><br />
下面是国内 13、15、18开头的手机号正则表达式。</p>
<pre><code>^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\\d{8}$
</code></pre>
<p><strong> </strong></p>
<p><strong>9. 判断IE的版本</strong><br />
IE目前还没被完全取代，很多页面还是需要做版本兼容，下面是IE版本检查的表达式。</p>
<pre><code>^.*MSIE [5-8](?:\\.[0-9]+)?(?!.*Trident\\/[5-9]\\.0).*$
</code></pre>
<p><strong> </strong></p>
<p><strong>10. 校验IP-v4地址</strong><br />
IP4 正则语句。</p>
<pre><code>\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b
</code></pre>
<p><strong> </strong></p>
<p><strong>11. 校验IP-v6地址</strong><br />
IP6 正则语句。</p>
<pre><code>(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))
</code></pre>
<p><strong> </strong></p>
<p><strong>12. 检查URL的前缀</strong><br />
应用开发中很多时候需要区分请求是HTTPS还是HTTP，通过下面的表达式可以取出一个url的前缀然后再逻辑判断。</p>
<pre><code>if (!s.match(/^[a-zA-Z]+:\\/\\//))
{
    s = 'http://' + s;
}
</code></pre>
<p><strong> </strong></p>
<p><strong>13. 提取URL链接</strong><br />
下面的这个表达式可以筛选出一段文本中的URL。</p>
<pre><code>^(f|ht){1}(tp|tps):\\/\\/([\\w-]+\\.)+[\\w-]+(\\/[\\w- ./?%&amp;=]*)?
</code></pre>
<p><strong> </strong></p>
<p><strong>14. 文件路径及扩展名校验</strong><br />
验证文件路径和扩展名</p>
<pre><code>^([a-zA-Z]\\:|\\\\)\\\\([^\\\\]+\\\\)*[^\\/:*?"&lt;&gt;|]+\\.txt(l)?$
</code></pre>
<p><strong> </strong></p>
<p><strong>15. 提取Color Hex Codes</strong><br />
有时需要抽取网页中的颜色代码，可以使用下面的表达式。</p>
<pre><code>\\#([a-fA-F]|[0-9]){3,6}
</code></pre>
<p><strong> </strong></p>
<p><strong>16. 提取网页图片</strong><br />
假若你想提取网页中所有图片信息，可以利用下面的表达式。</p>
<pre><code>\\&lt; *[img][^\\&gt;]*[src] *= *[\\"\\']{0,1}([^\\"\\'\\ &gt;]*)
</code></pre>
<p><strong> </strong></p>
<p><strong>17. 提取页面超链接</strong><br />
提取html中的超链接。</p>
<pre><code>(&lt;a\\s*(?!.*\\brel=)[^&gt;]*)(href="https?://)((?!(?:(?:www\\.)?'.implode('|(?:www\\.)?', $follow_list).'))[^"]+)"((?!.*\\brel=)[^&gt;]*)(?:[^&gt;]*)&gt;
</code></pre>
<p><strong> </strong></p>
<p><strong>18. 精炼CSS</strong><br />
通过下面的表达式，可以搜索相同属性值的CSS，从而达到精炼代码的目的。</p>
<pre><code>^\\s*[a-zA-Z\\-]+\\s*[:]{1}\\s[a-zA-Z0-9\\s.#]+[;]{1}
</code></pre>
<p><strong> </strong></p>
<p><strong>19. 抽取注释</strong><br />
如果你需要移除HMTL中的注释，可以使用如下的表达式。</p>
<pre><code>&lt;!--(.*?)--&gt;
</code></pre>
<p><strong> </strong></p>
<p><strong>20. 匹配HTML标签</strong></p>
<p>通过下面的表达式可以匹配出HTML中的标签。</p>
<pre><code>&lt;/?\\w+((\\s+\\w+(\\s*=\\s*(?:".*?"|'.*?'|[\\^'"&gt;\\s]+))?)+\\s*|\\s*)/?&gt;</code>

转载自公众号：小象</pre>
<p><span style="font-weight:bold;text-shadow:0 1px 0 #ddd;">声明:</span> 本文采用 <a rel="nofollow" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" title="署名-非商业性使用-相同方式共享">BY-NC-SA</a> 协议进行授权 | <a href="http://www.14en.com">追梦者，用汗水扬帆起航。</a><br />转载请注明转自《<a rel="bookmark" title="知道这20个正则表达式，能让你少写1,000行代码" href="http://www.14en.com/?p=172">知道这20个正则表达式，能让你少写1,000行代码</a>》</p>]]></content:encoded>
			<wfw:commentRss>http://www.14en.com/?feed=rss2&#038;p=172</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C++使用make编译，文件更新注意问题</title>
		<link>http://www.14en.com/?p=168</link>
		<comments>http://www.14en.com/?p=168#comments</comments>
		<pubDate>Sat, 23 Apr 2016 05:31:52 +0000</pubDate>
		<dc:creator><![CDATA[eekuang]]></dc:creator>
				<category><![CDATA[根目录]]></category>

		<guid isPermaLink="false">http://www.14en.com/?p=168</guid>
		<description><![CDATA[当使用make对c++进行编译时，我们有时候会发现出现莫名其妙的错误，而找不到原因。也有可能编译通过了，但是运 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>当使用make对c++进行编译时，我们有时候会发现出现莫名其妙的错误，而找不到原因。也有可能编译通过了，但是运行出错。这里，主要说下c++在编译过程中文件是如何更新的。使用到的源码文件有三个：test.cpp,calc.cpp,calc.h。</p>
<p>当cpp文件中新增或者修改函数时，头文件中对应的函数名会重新检查，但是不会修改h文件中其它函数的定义。比如说，修改cpp文件中的add函数，则系统会检查h文件中add函数的配置。但是如果此时h文件中的camera函数也修改了，则实际运行时仍然为旧版的camera函数。当仅仅修改h文件，而cpp文件没有修改时，则无法重新make，因为检测到cpp文件无修改，不需要重新编译链接。</p>
<p>附：</p>
<p>test.cpp:</p>
<p>int main(int argc ,char* argv[])<br />
{</p>
<p>Camera *camera=new Camera();</p>
<p>cout&lt;&lt;camera-&gt;getFaceTime()&lt;&lt;endl;<br />
cout&lt;&lt;camera-&gt;add()&lt;&lt;endl;<br />
return 0;<br />
}</p>
<p>&nbsp;</p>
<p style="text-align: left;">calc.h:</p>
<p style="text-align: left;">class Camera<br />
{<br />
private:<br />
public:<br />
int _iFaceTime;<br />
int getFaceTime();<br />
Camera(){<br />
_iFaceTime=10;<br />
}<br />
int add();<br />
};</p>
<p>calc.cpp:</p>
<p>using namespace std;</p>
<p>int Camera::getFaceTime()<br />
{<br />
return ++this-&gt;_iFaceTime;<br />
}</p>
<p>int Camera::add()<br />
{<br />
return 0;<br />
}</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span style="font-weight:bold;text-shadow:0 1px 0 #ddd;">声明:</span> 本文采用 <a rel="nofollow" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" title="署名-非商业性使用-相同方式共享">BY-NC-SA</a> 协议进行授权 | <a href="http://www.14en.com">追梦者，用汗水扬帆起航。</a><br />转载请注明转自《<a rel="bookmark" title="C++使用make编译，文件更新注意问题" href="http://www.14en.com/?p=168">C++使用make编译，文件更新注意问题</a>》</p>]]></content:encoded>
			<wfw:commentRss>http://www.14en.com/?feed=rss2&#038;p=168</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>制作一个可以进行简单交互的微信公众号</title>
		<link>http://www.14en.com/?p=163</link>
		<comments>http://www.14en.com/?p=163#comments</comments>
		<pubDate>Thu, 18 Feb 2016 13:47:05 +0000</pubDate>
		<dc:creator><![CDATA[eekuang]]></dc:creator>
				<category><![CDATA[技术笔记]]></category>

		<guid isPermaLink="false">http://www.14en.com/?p=163</guid>
		<description><![CDATA[近来微信公众号比较火，故趁着过年的空档，花了点时间捣鼓了下自己的公众号：kuang_xc，对其进行了简单的开发 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>近来微信公众号比较火，故趁着过年的空档，花了点时间捣鼓了下自己的公众号：kuang_xc，对其进行了简单的开发。开发之后的功能主要有三个：</p>
<p>1.根据回复关键字，自动回复多图文消息；</p>
<p>2.根据回复关键字检索数据库，回复一个图文消息；</p>
<p>3.根据回复关键字检索数据库，回复一句话。</p>
<p><strong>一、技术平台与技术手段</strong></p>
<p>本微信应用搭在在SAE（由于我本人的博客也搭载在SAE，目前为止效果还行，故没有重新寻找其它服务器提供商），网页开发语言为PHP，数据库为共享型mysql。应用开发遵从MVC模型，开发难度较小，仅供入门者参考。</p>
<p><strong>二、数据库与数据表</strong></p>
<p>本应用包含一个数据库，两个数据表，分别是 <a id="app_kuangxcoa.tb_articleList" title="浏览:  (1)" href="http://pma.tools.sinacloud.com/sql.php?db=app_kuangxcoa&amp;token=00e306c632232df4ce4dfc2570e82532&amp;table=tb_articleList&amp;pos=0">tb_articleList</a>和 <a id="app_kuangxcoa.tb_peopleInfo" title="浏览:  (1)" href="http://pma.tools.sinacloud.com/sql.php?db=app_kuangxcoa&amp;token=00e306c632232df4ce4dfc2570e82532&amp;table=tb_peopleInfo&amp;pos=0">tb_peopleInfo</a>。tb_articleList数据库用于记录文章网页信息，用于生成图文消息，tb_peopleInfo用于记录个人信息（本来是准备用它来给所有认识的人，定制一条过年短信的。奈何，妹子说俺的idea太boring）。两个表的生成命令字为：</p>
<p>CREATE TABLE `tb_articleList` (<br />
`id` int(10) NOT NULL AUTO_INCREMENT,<br />
`keyWord` varchar(32) NOT NULL,<br />
`title` varchar(1024) DEFAULT NULL,<br />
`imgUrl` varchar(2048) DEFAULT NULL,<br />
`url` varchar(2048) DEFAULT NULL,<br />
PRIMARY KEY (`id`)<br />
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8</p>
<p>CREATE TABLE `tb_peopleInfo` (<br />
`id` int(10) NOT NULL AUTO_INCREMENT,<br />
`name` varchar(32) NOT NULL,<br />
`birth` int(6) DEFAULT NULL,<br />
`relation` varchar(32) DEFAULT NULL,<br />
`description` varchar(2048) DEFAULT NULL,<br />
`comment` varchar(1024) DEFAULT NULL,<br />
PRIMARY KEY (`id`)<br />
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8</p>
<p>&nbsp;</p>
<p>表效果：</p>
<p><img class="alignnone" alt="" src="http://i13.tietuku.com/a4067ecda4f19fd5.jpg" width="783" height="223" /></p>
<p><img class="alignnone" alt="" src="http://i13.tietuku.com/eab5decd98824b9e.jpg" width="517" height="222" /></p>
<p><strong>三、php代码</strong></p>
<p>php代码分为四个文件interface.php、WechatApi.class.php、QueryService.class.php和SqlHelper.class.php。interface.php直接接收来自微信服务器的访问请求，WechatApi.class.php用于处理文字、语音、图片等具体微信信息，QueryService.class.php是逻辑处理页面，用于分析指定关键字是否可以在数据库中查询到信息，SqlHelper.class.php是数据库通信器。具体代码文件将在文章末尾给出共享链接。</p>
<p>&nbsp;</p>
<p><strong>四、效果</strong></p>
<p>输入任意文字</p>
<p><img class="alignnone" alt="" src="http://i13.tietuku.com/2f232f357346328a.jpg" width="1128" height="130" /></p>
<p>输入多图文关键字（不涉及到数据库，自动回复）</p>
<p><img class="alignnone" alt="" src="http://i11.tietuku.com/dda635fb1dcd52d5.jpg" width="871" height="414" /></p>
<p>输入图文关键字</p>
<p><img class="alignnone" alt="" src="http://i13.tietuku.com/052cb6adfbe0e6f9.jpg" width="1052" height="449" /></p>
<p>输入个人信息（姓名+生日）</p>
<p><img class="alignnone" alt="" src="http://i13.tietuku.com/355698b464ecead6.jpg" width="1136" height="116" /></p>
<p>&nbsp;</p>
<p><strong>五、未完待续</strong></p>
<p>这算是一个小东西吧，没花太多时间，也没打算花太多时间。很简陋的一个东西，当然暂时也不会对它进行进阶开发。如果后续有什么创意玩意儿，需要用到公众号，可能会对它进行再次开发。本文的目的，是希望给一样在微信开发的路上的朋友，一个小小的例子，供参考吧。</p>
<p>附代码：</p>
<p>&nbsp;</p>
<p><span style="font-weight:bold;text-shadow:0 1px 0 #ddd;">声明:</span> 本文采用 <a rel="nofollow" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" title="署名-非商业性使用-相同方式共享">BY-NC-SA</a> 协议进行授权 | <a href="http://www.14en.com">追梦者，用汗水扬帆起航。</a><br />转载请注明转自《<a rel="bookmark" title="制作一个可以进行简单交互的微信公众号" href="http://www.14en.com/?p=163">制作一个可以进行简单交互的微信公众号</a>》</p>]]></content:encoded>
			<wfw:commentRss>http://www.14en.com/?feed=rss2&#038;p=163</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>微信开发必备emoji表情代码大全</title>
		<link>http://www.14en.com/?p=155</link>
		<comments>http://www.14en.com/?p=155#comments</comments>
		<pubDate>Tue, 16 Feb 2016 13:00:48 +0000</pubDate>
		<dc:creator><![CDATA[eekuang]]></dc:creator>
				<category><![CDATA[技术笔记]]></category>

		<guid isPermaLink="false">http://www.14en.com/?p=155</guid>
		<description><![CDATA[文件链接: http://pan.baidu.com/s/1kU2LkZt 密码: 63ha 声明: 本文采用 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><img class="alignnone" alt="" src="http://i12.tietuku.com/6614914a6aad230c.png" width="603" height="2366" /></p>
<p><img class="alignnone" alt="" src="http://ww2.sinaimg.cn/large/74311666jw1f11i0czda0j20o37xbnpf.jpg" width="867" height="10271" /></p>
<p><img class="alignnone" alt="" src="http://i11.tietuku.com/5df0a81e41673e8c.png" width="867" height="10271" /></p>
<div id="bodyContent">
<div id="box">
<div id="box_inner">
<div id="text">
<div id="pages">
<div id="page1">
<div id="articleHeader">
<div id="bodyContent">
<div id="box">
<div id="box_inner">
<div id="text">
<div id="pages">文件链接: http://pan.baidu.com/s/1kU2LkZt 密码: 63ha</div>
<div></div>
<div></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<p><span style="font-weight:bold;text-shadow:0 1px 0 #ddd;">声明:</span> 本文采用 <a rel="nofollow" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" title="署名-非商业性使用-相同方式共享">BY-NC-SA</a> 协议进行授权 | <a href="http://www.14en.com">追梦者，用汗水扬帆起航。</a><br />转载请注明转自《<a rel="bookmark" title="微信开发必备emoji表情代码大全" href="http://www.14en.com/?p=155">微信开发必备emoji表情代码大全</a>》</p>]]></content:encoded>
			<wfw:commentRss>http://www.14en.com/?feed=rss2&#038;p=155</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>微信公众平台开发入门教程</title>
		<link>http://www.14en.com/?p=153</link>
		<comments>http://www.14en.com/?p=153#comments</comments>
		<pubDate>Tue, 16 Feb 2016 12:58:58 +0000</pubDate>
		<dc:creator><![CDATA[eekuang]]></dc:creator>
				<category><![CDATA[技术笔记]]></category>

		<guid isPermaLink="false">http://www.14en.com/?p=153</guid>
		<description><![CDATA[在这篇微信公众平台开发教程中，我们假定你已经有了PHP语言程序、MySQL数据库、计算机网络通讯、及HTTP/ [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>在这篇微信公众平台开发教程中，我们假定你已经有了PHP语言程序、MySQL数据库、计算机网络通讯、及HTTP/XML/CSS/JS等基础。</p>
<p>我们将使用微信公众账号方倍工作室作为讲解的例子，二维码见底部。</p>
<p>本系列教程将引导你完成如下任务：</p>
<ol>
<li>创建新浪云计算平台应用</li>
<li>启用微信公众平台开发模式</li>
<li>了解数据收发原理及消息格式</li>
<li>开发实现微信天气预报功能</li>
</ol>
<p>&nbsp;</p>
<p><strong>第一章 申请服务器资源</strong></p>
<p><strong>创建新浪云计算应用</strong></p>
<p><strong>申请账号</strong></p>
<p>我们使用SAE新浪云计算平台作为服务器资源，并且申请PHP环境+MySQL数据库作为程序运行环境。<br />
申请地址为：</p>
<p><strong><a href="http://t.cn/RbEUcgy" target="_blank">http://www.sinacloud.com/</a></strong></p>
<p>直接<a href="http://t.cn/R4pEhd7" target="_blank">点击上述网址</a>，可以看到右上角微博登录的链接。</p>
<p><img alt="" src="http://images0.cnblogs.com/blog2015/340216/201508/101218075041928.jpg" /></p>
<p>点击进入之后，使用新浪微博账号登录</p>
<p><img alt="" src="http://images0.cnblogs.com/blog2015/340216/201508/101219438328300.jpg" /></p>
<p>登录之后，按照提示注册个人信息即可。</p>
<p>&nbsp;</p>
<p><strong>创建新应用 </strong>http://www.cnblogs.com/txw1958/p/wechat-tutorial.html<a id="Editor_Edit_hlEntryLink" title="view: 微信公众平台开发入门教程" href="http://www.cnblogs.com/txw1958/p/wechat-tutorial.html" target="_blank"></a></p>
<p align="left">回到首页，在菜单顶部选择 <strong>控制台 </strong>，再选择 <strong>云应用SAE </strong>。</p>
<p align="left"><img alt="" src="http://images0.cnblogs.com/blog2015/340216/201508/101224403487778.jpg" /></p>
<p align="left">进入SAE应用列表</p>
<p align="left"><img alt="" src="http://images0.cnblogs.com/blog2015/340216/201508/101228269575983.jpg" /></p>
<p>点击下侧的创建新应用，这时会弹出提示， 禁止放置违法违规内容，点击继续创建，弹出如下窗口。</p>
<p><img alt="" src="http://images.cnitblog.com/blog2015/340216/201503/271332301458530.jpg" /></p>
<p>选择一个未使用的appid，如果老是已经被使用不知道该什么好，就填写你的QQ号或者手机号吧。</p>
<p>填写二级域名AppID、应用名称、验证码，开发语言选择<strong>PHP5.3，</strong>全部应用和框架下面选择第一个【<strong>PHP 空应用</strong>】。然后点击左下方的创建应用</p>
<p><img alt="" src="http://images.cnitblog.com/blog/340216/201401/07160215-973eb4c63145469dac9a717d7ed49573.jpg" /></p>
<p>应用创建成功。并自动跳转到应用列表中，可以看到已经有刚才创建的1354386063这个应用。</p>
<p><img alt="" src="http://images.cnitblog.com/blog/340216/201410/161150180606319.jpg" /></p>
<p><strong>创建数据库 </strong></p>
<p>点击刚才创建的应用名称，进入应用主页。</p>
<p>在左侧的<strong>数据库服务</strong>中找到<strong>MySQL</strong></p>
<p><img alt="" src="http://images2015.cnblogs.com/blog/340216/201601/340216-20160113191815007-469922420.png" /></p>
<p>点击进入MySQL类型选择，这里选择独享型MySQL</p>
<p><img alt="" src="http://images2015.cnblogs.com/blog/340216/201601/340216-20160113191910678-1071426458.png" /></p>
<p>在创建独享型MySQL中，使用<strong>微型</strong>配置，然后点击“确认初始化”</p>
<p><img alt="" src="http://images2015.cnblogs.com/blog/340216/201601/340216-20160113192058257-651224434.png" /></p>
<p>底部将显示任务进度。</p>
<p><img alt="" src="http://images2015.cnblogs.com/blog/340216/201601/340216-20160113192047991-270477776.png" /></p>
<p>等任务完成之后，再点击销毁MySQL按钮，</p>
<p><img alt="" src="http://images2015.cnblogs.com/blog/340216/201601/340216-20160113192209038-615659192.png" /></p>
<p>这样创建并销毁一次，可以多获得200云豆。以后使用的时候，可以使用免费的共享型MySQL或者使用收费但更稳定强大的独享型MySQL。</p>
<p><strong>创建版本 </strong>http://www.cnblogs.com/txw1958/p/wechat-tutorial.html</p>
<p>点击刚才创建的应用名称，进入应用主页。</p>
<p>点击左侧的<strong>应用管理</strong>下面的<strong>代码管理</strong>，</p>
<p><img alt="" src="http://images2015.cnblogs.com/blog/340216/201510/340216-20151016102046210-1199715414.png" /></p>
<p>&nbsp;</p>
<p>在代码管理中，选择使用<strong>SVN</strong>托管的方式，不要使用git的方式。</p>
<p><img alt="" src="http://images2015.cnblogs.com/blog/340216/201510/340216-20151016102102819-921377460.png" /></p>
<p>跳转到代码管理</p>
<p><img alt="" src="http://images2015.cnblogs.com/blog/340216/201510/340216-20151016102124694-104153745.png" /></p>
<p>点击右侧的“创建版本”</p>
<p><img alt="" src="http://images.cnitblog.com/blog/340216/201401/07160825-d148a50efba34fe3a92aec1013d3125d.jpg" /></p>
<p>版本号默认为1，点击创建，有时会弹出安全登录，需要输入安全密码，如果不知道或者忘记了，就点里面的找回密码，重新设置一下。：</p>
<p><img alt="" src="http://images.cnitblog.com/blog/340216/201410/161154056239273.jpg" /></p>
<p>验证通过之后，如下所示</p>
<p><img alt="" src="http://images2015.cnblogs.com/blog/340216/201510/340216-20151016102155616-1051723621.png" /></p>
<p>到这里，就成功创建了一个域名URL为 http://1354386063.sinaapp.com/ 的应用了，记住你的这个URL，后面将会用到。</p>
<p>原文：http://www.cnblogs.com/txw1958/p/wechat-tutorial.html</p>
<p><strong>上传代码 </strong>http://www.cnblogs.com/txw1958/p/wechat-tutorial.html<a id="Editor_Edit_hlEntryLink" title="view: 微信公众平台开发入门教程" href="http://www.cnblogs.com/txw1958/p/wechat-tutorial.html" target="_blank"></a></p>
<p>下述代码是一个微信接口文件，看不懂没有关系，你可以暂时不用弄明白它的意思。</p>
<p>如果想弄明白，可以<a href="http://redirect.simba.taobao.com/rd?w=unionnojs&amp;f=http%3A%2F%2Fai.taobao.com%2Fauction%2Fedetail.htm%3Fe%3DiaEuHH1QB%252Bq6k0Or%252B%252BH4tNDGiUb0kud7TbuPAry6zvGLltG5xFicOdXrTUTgh9sMDPIwxrc30rjMMEkER9S2vpbVMrCM0u%252BAECoJT1o2C2StMycyQu8ffm3abJM7sDg2i%252B5rgKdaJEzC4lasV4OWOg%253D%253D%26ptype%3D100010%26from%3Dbasic&amp;k=5ccfdb950740ca16&amp;c=un&amp;b=alimm_0&amp;p=mm_29363734_8476722_28642494" target="_blank">购买《微信公众平台开发最佳实践》</a>，在该书中第25页~第27页有详细讲解。</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<pre>&lt;?php
/*
    方倍工作室 http://www.cnblogs.com/txw1958/
    CopyRight 2013 www.doucube.com  All Rights Reserved
*/

define("TOKEN", "weixin");
$wechatObj = new wechatCallbackapiTest();
if (isset($_GET['echostr'])) {
    $wechatObj-&gt;valid();
}else{
    $wechatObj-&gt;responseMsg();
}

class wechatCallbackapiTest
{
    public function valid()
    {
        $echoStr = $_GET["echostr"];
        if($this-&gt;checkSignature()){
            header('content-type:text');
            echo $echoStr;
            exit;
        }
    }

    private function checkSignature()
    {
        $signature = $_GET["signature"];
        $timestamp = $_GET["timestamp"];
        $nonce = $_GET["nonce"];

        $token = TOKEN;
        $tmpArr = array($token, $timestamp, $nonce);
        sort($tmpArr, SORT_STRING);
        $tmpStr = implode( $tmpArr );
        $tmpStr = sha1( $tmpStr );

        if( $tmpStr == $signature ){
            return true;
        }else{
            return false;
        }
    }

    public function responseMsg()
    {
        $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];

        if (!empty($postStr)){
            $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
            $fromUsername = $postObj-&gt;FromUserName;
            $toUsername = $postObj-&gt;ToUserName;
            $keyword = trim($postObj-&gt;Content);
            $time = time();
            $textTpl = "&lt;xml&gt;
                        &lt;ToUserName&gt;&lt;![CDATA[%s]]&gt;&lt;/ToUserName&gt;
                        &lt;FromUserName&gt;&lt;![CDATA[%s]]&gt;&lt;/FromUserName&gt;
                        &lt;CreateTime&gt;%s&lt;/CreateTime&gt;
                        &lt;MsgType&gt;&lt;![CDATA[%s]]&gt;&lt;/MsgType&gt;
                        &lt;Content&gt;&lt;![CDATA[%s]]&gt;&lt;/Content&gt;
                        &lt;FuncFlag&gt;0&lt;/FuncFlag&gt;
                        &lt;/xml&gt;";
            if($keyword == "?" || $keyword == "？")
            {
                $msgType = "text";
                $contentStr = date("Y-m-d H:i:s",time());
                $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
                echo $resultStr;
            }
        }else{
            echo "";
            exit;
        }
    }
}
?&gt;</pre>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>我们将使用上述代码与微信公众平台对接。</p>
<p>将上述代码用专业的软件存为utf-8格式的index.php文件后再使用WinRAR压缩为index.zip，</p>
<p>或者直接下载方倍工作室已经压缩好的index.zip文件。<a href="http://pan.baidu.com/s/1c09CNrM" target="_blank"><strong>点此进入下载</strong></a></p>
<p>回到SAE的代码管理界面中。</p>
<p><img alt="" src="http://images2015.cnblogs.com/blog/340216/201510/340216-20151016102421101-1861603222.png" /></p>
<p>再选择“上传代码包”，点击上传文件，选择刚才的index.zip文件，点击上传，上传成功后中间是一个绿色的横条，如下所示</p>
<p><img alt="" src="http://images.cnitblog.com/blog/340216/201401/07160951-d3c9bf1091ef4f1c85d11246814bd514.jpg" /></p>
<p>如果没有绿色的横条，表示上传失败，需要重试。<strong>可以考虑在Chrome浏览器下重试一下。</strong></p>
<p>点击编辑代码按钮，</p>
<p><img alt="" src="http://images2015.cnblogs.com/blog/340216/201510/340216-20151016102430147-1423131646.png" /></p>
<p>有时候需要输入自己的安全密码，如果不记得了就点击“找回密码”。</p>
<p><img alt="" src="http://images.cnitblog.com/i/340216/201406/131140465772894.png" /></p>
<p>安全验证成功后继续之前的操作。</p>
<p>我们可以看到index.php已经上传成功，双击可以查看编辑里面的代码</p>
<p><img alt="" src="http://images.cnitblog.com/blog/340216/201401/05112932-8e1afffc72e748f0b245ed6724049ad9.jpg" /></p>
<p>新浪云应用的创建就成功了。</p>
<p>&nbsp;</p>
<p><strong>实名认证</strong></p>
<p>新浪SAE要求用户上传身份证进行实名认证才可以正常使用，在左侧菜单列表中可以找到“实名认证”这一标签可进行实名认证操作。实名认证过程是免费的。认证以后每月免费有5G的流量。认证审核需要1~3个工作日。</p>
<p>来不及准备身份证照片的话可以先继续下面的内容，改天再来进行实名认证。但在使用过程中会受点影响。</p>
<p><img alt="" src="http://images0.cnblogs.com/blog2015/340216/201508/101220151604163.jpg" /></p>
<p><strong>如果不进行实名认证，SAE会在回复的内容中会带上干扰的html内容信息，从而导致Token验证失败或者该公众号暂时无法提供服务,请稍后再试。</strong></p>
<p>实名认证需要填的信息如下</p>
<p><img alt="" src="http://images0.cnblogs.com/blog2015/340216/201508/101224258174519.jpg" /><br />
实名认证成功后，将如下图所示。</p>
<p><img alt="" src="http://images0.cnblogs.com/blog2015/340216/201508/101221042077712.jpg" /></p>
<p><strong>充值（本步骤可选择性进行）</strong></p>
<p>新浪云SAE实行的是配额免费+超额付费的方式，相关标准请查看SAE价格体系介绍。初期对于大部分用户来说免费配额已够用，如果您将来使用量比较大建议预先至少充值100元获得10000云豆，以免超额后应用被禁用而影响业务。</p>
<p><strong>第二章 启用开发模式</strong></p>
<p><strong>微信公众平台开发模式</strong></p>
<p><strong>高级功能</strong></p>
<p>微信公众平台地址：<a href="https://mp.weixin.qq.com/">https://mp.weixin.qq.com</a></p>
<p>登录微信公众平台后台，在左侧列表中最下方，找到“ 基本配置 ”，点击进入</p>
<p><img alt="" src="http://images2015.cnblogs.com/blog/340216/201601/340216-20160105184918028-3553084.png" /></p>
<p>进入服务器配置填写框。</p>
<p><img alt="" src="http://images.cnitblog.com/blog/340216/201410/230851290434442.jpg" /></p>
<p>点击“修改配置”按钮</p>
<p><img alt="" src="http://images.cnitblog.com/blog/340216/201410/230852463249398.jpg" /></p>
<p>此处的URL为上篇中介绍的云应用的域名，而Token在index.php中定义为weixin。EncodingAESKey则不用填，点击“随机生成”让自动生成一个，消息加解密方式选择“明文模式”，然后点击“提交”按钮。</p>
<p><img alt="" src="http://images.cnitblog.com/blog/340216/201410/230854277309950.jpg" /></p>
<p>&nbsp;</p>
<p>在弹出的提示框中，点击“确定”</p>
<p><img alt="" src="http://images.cnitblog.com/blog/340216/201410/230855014962870.jpg" /></p>
<p>配置修改后如图所示，再点击“启用”按钮</p>
<p><img alt="" src="http://images.cnitblog.com/blog/340216/201410/230855416993454.jpg" /></p>
<p>询问“是否确定开启服务器配置”，点击“确定”</p>
<p>如果提示“<strong>token验证失败</strong>”，可以先重次几次，微信服务器有时候不稳定。并<strong>确保你的SAE已经上传身份证通过实名认证！</strong></p>
<p>如果还是失败，请先用<strong><a href="http://debug.fangbei.org/" target="_blank">微信调试器</a></strong>测试一下url和token是否正确，<a href="http://www.cnblogs.com/txw1958/p/weixin-debugger.html" target="_blank">点此查看详细测试方法</a>。</p>
<p><img alt="" src="http://images.cnitblog.com/blog/340216/201410/230856050908206.jpg" /></p>
<p>成功启用后如图。</p>
<p>恭喜，你成功启用开发模式。</p>
<p>&nbsp;</p>
<p><strong>自动回复</strong></p>
<p>在上面的例子中，实现了一个发送“?”就能回复当前时间的功能。<br />
效果如下：</p>
<p><img alt="" src="http://images.cnitblog.com/blog/340216/201401/05115052-ffad462aed1d4b63a85d47e745094081.png" /></p>
<p>至此，你的微信公众平台账号已经实现自动回复了。</p>
<pre></pre>
<p align="center"><strong>第三章 数据收发原理及消息数据格式</strong></p>
<p>&nbsp;</p>
<p>★ 本章是理论部分，初学者会比较难以理解，不用太过追究。</p>
<p><strong>开发模式成为开发者时的消息校验原理</strong></p>
<p>在开发者首次提交验证申请时，微信服务器将发送GET请求到填写的URL上，并且带上四个参数（signature、timestamp、nonce、echostr），开发者通过对签名（即signature）的效验，来判断此条消息的真实性。</p>
<p>此后，每次开发者接收用户消息的时候，微信也都会带上前面三个参数（signature、timestamp、nonce）访问开发者设置的URL，开发者依然通过对签名的效验判断此条消息的真实性。效验方式与首次提交验证申请一致。</p>
<table border="1" cellspacing="0" cellpadding="4" align="center">
<tbody>
<tr>
<th>参数</th>
<th>描述</th>
</tr>
<tr>
<td>signature</td>
<td>微信加密签名，signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。</td>
</tr>
<tr>
<td>timestamp</td>
<td>时间戳</td>
</tr>
<tr>
<td>nonce</td>
<td>随机数</td>
</tr>
<tr>
<td>echostr</td>
<td>随机字符串</td>
</tr>
</tbody>
</table>
<p>开发者通过检验signature对请求进行校验（下面有校验方式）。若确认此次GET请求来自微信服务器，请原样返回echostr参数内容，则接入生效，成为开发者成功，否则接入失败。</p>
<pre><strong>加密/校验流程如下：</strong>
1. 将token、timestamp、nonce三个参数进行字典序排序
2. 将三个参数字符串拼接成一个字符串进行sha1加密
3. 开发者获得加密后的字符串可与signature对比，标识该请求来源于微信</pre>
<p>启用接口是由代码中的checkSignature()函数来实现校验的。如果对这一原理难以理解，可以暂时不用深究，继续看下面。</p>
<p>&nbsp;</p>
<p><strong>成为开发者后消息收发时的原理</strong></p>
<p>上一章节中图，当用户发送一个“?”时，系统回复了一个时间</p>
<p>这一原理的消息流程图如下所示。</p>
<p><img alt="" src="http://images.cnitblog.com/i/340216/201404/290134020804581.jpg" width="924" height="367" /></p>
<p>从上图可以看出，用户在发送一个?后，微信服务器将组装一个消息发送给我们自己的服务器，自己的服务器然后回复一个时间，并且将该时间也按一定的规则组装，回复给公众账号，公众账号再回复给用户，在这个收发过程中，发送方和接收方进行了调换(ToUserName和FromUserName值互换)，收发都是以xml格式在后台进行传输的，</p>
<p>所以掌握各种消息类型的接收回复就是进行微信公众平台开发的基础！</p>
<p>下面对前面所述的各种消息类型讲解其XML数据包的格式。</p>
<p>&nbsp;</p>
<p><strong>各种收发消息的XML数据包分析</strong></p>
<p><strong>接收消息</strong></p>
<p><strong>1. 文本（包括表情）</strong><br />
接收文本及表情</p>
<p><img alt="" src="http://images.cnitblog.com/blog/340216/201312/24212713-99cd9616dec941c89f5a1dfce7fe34d9.jpg" /></p>
<p>文字后台格式:</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<pre>&lt;xml&gt;
 &lt;ToUserName&gt;&lt;![CDATA[gh_680bdefc8c5d]]&gt;&lt;/ToUserName&gt;
 &lt;FromUserName&gt;&lt;![CDATA[oIDrpjqASyTPnxRmpS9O_ruZGsfk]]&gt;&lt;/FromUserName&gt;
 &lt;CreateTime&gt;1359028446&lt;/CreateTime&gt;
 &lt;MsgType&gt;&lt;![CDATA[text]]&gt;&lt;/MsgType&gt;
 &lt;Content&gt;&lt;![CDATA[测试文字]]&gt;&lt;/Content&gt;
 &lt;MsgId&gt;5836982729904121631&lt;/MsgId&gt;
&lt;/xml&gt;</pre>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>表情后台格式</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<pre>&lt;xml&gt;&lt;ToUserName&gt;&lt;![CDATA[gh_680bdefc8c5d]]&gt;&lt;/ToUserName&gt;
&lt;FromUserName&gt;&lt;![CDATA[oIDrpjqASyTPnxRmpS9O_ruZGsfk]]&gt;&lt;/FromUserName&gt;
&lt;CreateTime&gt;1359044526&lt;/CreateTime&gt;
&lt;MsgType&gt;&lt;![CDATA[text]]&gt;&lt;/MsgType&gt;
&lt;Content&gt;&lt;![CDATA[/::)/::~/::B/::|/:8-)]]&gt;&lt;/Content&gt;
&lt;MsgId&gt;5837051792978241864&lt;/MsgId&gt;
&lt;/xml&gt;</pre>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>XML格式讲解</p>
<div>
<pre>ToUserName 消息接收方微信号，一般为公众平台账号微信号
FromUserName 消息发送方微信号
CreateTime 消息创建时间
MsgType 消息类型；文本消息为text
Content 消息内容
MsgId 消息ID号</pre>
</div>
<p>可以看出，文本和表情的消息类型均为文本</p>
<p><strong>2. 图片</strong><br />
接收图片</p>
<p><img alt="" src="http://images.cnitblog.com/blog/340216/201312/24212902-120227ed8c2f481ea40f74f387167ccd.jpg" /></p>
<p>后台格式：</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<pre>&lt;xml&gt;&lt;ToUserName&gt;&lt;![CDATA[gh_680bdefc8c5d]]&gt;&lt;/ToUserName&gt;
&lt;FromUserName&gt;&lt;![CDATA[oIDrpjqASyTPnxRmpS9O_ruZGsfk]]&gt;&lt;/FromUserName&gt;
&lt;CreateTime&gt;1359028479&lt;/CreateTime&gt;
&lt;MsgType&gt;&lt;![CDATA[image]]&gt;&lt;/MsgType&gt;
&lt;PicUrl&gt;&lt;![CDATA[http://mmbiz.qpic.cn/mmbiz/L4qjYtOibummHn90t1mnaibYiaR8ljyicF3MW7XX3BLp1qZgUb7CtZ0DxqYFI4uAQH1FWs3hUicpibjF0pOqLEQyDMlg/0]]&gt;&lt;/PicUrl&gt;
&lt;MsgId&gt;5836982871638042400&lt;/MsgId&gt;
&lt;MediaId&gt;&lt;![CDATA[PGKsO3LAgbVTsFYO7FGu51KUYa07D0C_Nozz2fn1z6VYtHOsF59PTFl0vagGxkVH]]&gt;&lt;/MediaId&gt;
&lt;/xml&gt;</pre>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>XML格式讲解</p>
<div>
<pre>ToUserName 消息接收方微信号，一般为公众平台账号微信号
FromUserName 消息发送方微信号
CreateTime 消息创建时间
MsgType 消息类型；图片消息为image
PicUrl 图片链接地址，可以用HTTP GET获取
MsgId 消息ID号</pre>
</div>
<p><strong>3. 语音</strong><br />
接收语音</p>
<p><img alt="" src="http://images.cnitblog.com/blog/340216/201312/24212942-170dd66e27834ff3ac3d525cbbb60e7c.jpg" /></p>
<p>后台格式：</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<pre>&lt;xml&gt;
    &lt;ToUserName&gt;&lt;![CDATA[gh_d035bb259cf5]]&gt;&lt;/ToUserName&gt;
    &lt;FromUserName&gt;&lt;![CDATA[owEUGj4BW8yeWRvyEERiVGKwAF1Q]]&gt;&lt;/FromUserName&gt;
    &lt;CreateTime&gt;1364883809&lt;/CreateTime&gt;
    &lt;MsgType&gt;&lt;![CDATA[voice]]&gt;&lt;/MsgType&gt;
    &lt;MediaId&gt;&lt;![CDATA[JfmCezZ3Cwp0FwUvMADwwhvp-XScuvpictubpw0c6ALyA8tj3HLU4PoXzMpIY72P]]&gt;&lt;/MediaId&gt;
    &lt;Format&gt;&lt;![CDATA[amr]]&gt;&lt;/Format&gt;
    &lt;MsgId&gt;5862131322594912688&lt;/MsgId&gt;
&lt;/xml&gt;</pre>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>XML格式讲解</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<pre>ToUserName 消息接收方微信号，一般为公众平台账号微信号
FromUserName 消息发送方微信号
CreateTime 消息创建时间
MsgType 消息类型；语音消息为voice
MediaId 媒体ID
Format 语音格式，这里为amr
MsgId 消息ID号</pre>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<div>
<pre>附：AMR接口简介
全称Adaptive Multi-Rate，主要用于移动设备的音频，压缩比比较大，但相对其他的压缩格式质量比较差，由于多用于人声，通话，效果还是很不错的。</pre>
</div>
<p><strong>4. 视频</strong></p>
<p>接收视频</p>
<p><img alt="" src="http://images.cnitblog.com/blog/340216/201312/24213106-09fa409d830b447681d148a65f350aa7.jpg" /></p>
<p>后台格式：</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<pre>xml&gt;&lt;ToUserName&gt;&lt;![CDATA[gh_680bdefc8c5d]]&gt;&lt;/ToUserName&gt;
&lt;FromUserName&gt;&lt;![CDATA[oIDrpjqASyTPnxRmpS9O_ruZGsfk]]&gt;&lt;/FromUserName&gt;
&lt;CreateTime&gt;1359028186&lt;/CreateTime&gt;
&lt;MsgType&gt;&lt;![CDATA]&gt;&lt;/MsgType&gt;
&lt;MediaId&gt;&lt;![CDATA[DBVFRIj29LB2hxuYpc0R6VLyxwgyCHZPbRj_IIs6YaGhutyXUKtFSDcSCPeoqUYr]]&gt;&lt;/MediaId&gt;
&lt;ThumbMediaId&gt;&lt;![CDATA[mxUJ5gcCeesJwx2T9qsk62YzIclCP_HnRdfTQcojlPeT2G9Q3d22UkSLyBFLZ01J]]&gt;&lt;/ThumbMediaId&gt;
&lt;MsgId&gt;5836981613212624665&lt;/MsgId&gt;
&lt;/xml&gt;</pre>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>XML格式讲解</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<pre>ToUserName 消息接收方微信号，一般为公众平台账号微信号
FromUserName 消息发送方微信号
CreateTime 消息创建时间
MsgType 消息类型；视频消息为video
MediaId 媒体ID
ThumbMediaId 媒体缩略ID？
MsgId 消息ID号</pre>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p><strong>5. 位置</strong></p>
<p>接收位置</p>
<p><img alt="" src="http://images.cnitblog.com/blog/340216/201312/24213159-d14477a57e0b4aee89adc84d9ed8a05f.jpg" /></p>
<p>后台格式：</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<pre>&lt;xml&gt;
&lt;ToUserName&gt;&lt;![CDATA[gh_680bdefc8c5d]]&gt;&lt;/ToUserName&gt;
&lt;FromUserName&gt;&lt;![CDATA[oIDrpjqASyTPnxRmpS9O_ruZGsfk]]&gt;&lt;/FromUserName&gt;
&lt;CreateTime&gt;1359036619&lt;/CreateTime&gt;
&lt;MsgType&gt;&lt;![CDATA[location]]&gt;&lt;/MsgType&gt;
&lt;Location_X&gt;22.539968&lt;/Location_X&gt;
&lt;Location_Y&gt;113.954980&lt;/Location_Y&gt;
&lt;Scale&gt;16&lt;/Scale&gt;
&lt;Label&gt;&lt;![CDATA[中国广东省深圳市南山区华侨城深南大道9789号 邮政编码: 518057]]&gt;&lt;/Label&gt;
&lt;MsgId&gt;5837017832671832047&lt;/MsgId&gt;
&lt;/xml&gt;</pre>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>XML格式讲解</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<pre> ToUserName 消息接收方微信号，一般为公众平台账号微信号
 FromUserName 消息发送方微信号
 CreateTime 消息创建时间
 MsgType 消息类型，地理位置为location
 Location_X 地理位置纬度
 Location_Y 地理位置经度
 Scale 地图缩放大小
 Label 地理位置信息
 MsgId 消息ID号</pre>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p><strong>6. 链接</strong></p>
<p>接收链接</p>
<p><img alt="" src="http://images.cnitblog.com/blog/340216/201312/24213322-a711ae1e94a2446ea61d981af9304991.jpg" /></p>
<p>后台格式：</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<pre>&lt;xml&gt;
&lt;ToUserName&gt;&lt;![CDATA[gh_680bdefc8c5d]]&gt;&lt;/ToUserName&gt; 
&lt;FromUserName&gt;&lt;![CDATA[oIDrpjl2LYdfTAM-oxDgB4XZcnc8]]&gt;&lt;/FromUserName&gt; 
&lt;CreateTime&gt;1359709372&lt;/CreateTime&gt; 
&lt;MsgType&gt;&lt;![CDATA[link]]&gt;&lt;/MsgType&gt; 
&lt;Title&gt;&lt;![CDATA[微信公众平台开发者的江湖]]&gt;&lt;/Title&gt; 
&lt;Description&gt;&lt;![CDATA[陈坤的微信公众号这段时间大火，大家..]]&gt;&lt;/Description&gt; 
&lt;Url&gt;&lt;![CDATA[http://israel.duapp.com/web/photo.php]]&gt;&lt;/Url&gt; 
&lt;MsgId&gt;5839907284805129867&lt;/MsgId&gt; 
&lt;/xml&gt;</pre>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>XML格式讲解</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<pre> ToUserName 消息接收方微信号，一般为公众平台账号微信号
 FromUserName 消息发送方微信号
 CreateTime 消息创建时间
 MsgType 消息类型，链接为link
 Title 图文消息标题
 Description 图文消息描述
 Url 点击图文消息跳转链接
 MsgId 消息ID号</pre>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>&nbsp;</p>
<p><strong>回复消息</strong></p>
<p>只介绍三种格式的消息：文本、图文、音乐。其中图文消息包括单条图文消息和多条图文消息，展示方式有一点点不同。</p>
<p><strong>1. 文本消息格式</strong><br />
回复文本</p>
<p><img alt="" src="http://images.cnitblog.com/blog/340216/201312/24213436-1243e86e19e4460d9702096a2b43e444.jpg" /></p>
<p>后台格式：</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<pre>&lt;xml&gt;
&lt;ToUserName&gt;&lt;![CDATA[oIDrpjqASyTPnxRmpS9O_ruZGsfk]]&gt;&lt;/ToUserName&gt;
&lt;FromUserName&gt;&lt;![CDATA[gh_680bdefc8c5d]]&gt;&lt;/FromUserName&gt;
&lt;CreateTime&gt;1359036631&lt;/CreateTime&gt;
&lt;MsgType&gt;&lt;![CDATA[text]]&gt;&lt;/MsgType&gt;
&lt;Content&gt;&lt;![CDATA[【深圳】天气实况 温度：27℃ 湿度：59% 风速：东北风3级
11月03日 周日 27℃~23℃ 小雨 东北风4-5级
11月04日 周一 26℃~21℃ 阵雨 微风
11月05日 周二 27℃~22℃ 阴 微风]]&gt;&lt;/Content&gt;
&lt;FuncFlag&gt;0&lt;/FuncFlag&gt;
&lt;/xml&gt;</pre>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>XML格式讲解</p>
<div>
<pre> FromUserName 消息发送方
 ToUserName 消息接收方
 CreateTime 消息创建时间
 MsgType 消息类型，文本消息必须填写text
 Content 消息内容，大小限制在2048字节，字段为空为不合法请求
 FuncFlag 星标字段</pre>
</div>
<p><strong>2. 图文消息格式</strong><br />
2.1 单条图文消息<br />
回复单条图文</p>
<p><img alt="" src="http://images.cnitblog.com/blog/340216/201312/24213526-b06250e1b4124e5db281e5d53223d899.jpg" /><img alt="" src="http://images.cnitblog.com/blog/340216/201312/24213538-a63349c3a9f647f5a9df47429710c4ce.jpg" /><br />
后台格式：</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<pre>&lt;xml&gt;
    &lt;ToUserName&gt;&lt;![CDATA[oIDrpjqASyTPnxRmpS9O_ruZGsfk]]&gt;&lt;/ToUserName&gt;
    &lt;FromUserName&gt;&lt;![CDATA[gh_680bdefc8c5d]]&gt;&lt;/FromUserName&gt;
    &lt;CreateTime&gt;1359011899&lt;/CreateTime&gt;
    &lt;MsgType&gt;&lt;![CDATA[news]]&gt;&lt;/MsgType&gt;
    &lt;Content&gt;&lt;![CDATA[]]&gt;&lt;/Content&gt;
    &lt;ArticleCount&gt;1&lt;/ArticleCount&gt;
    &lt;Articles&gt;
        &lt;item&gt;
            &lt;Title&gt;&lt;![CDATA[[苹果产品信息查询]]&gt;&lt;/Title&gt;
            &lt;Description&gt;&lt;![CDATA[序列号：USE IMEI NUMBER
IMEI号：358031058974471
设备名称：iPhone 5C
设备颜色：
设备容量：
激活状态：已激活
电话支持：未过期[2014-01-13]
硬件保修：未过期[2014-10-14]
生产工厂：中国]]&gt;
    &lt;/Description&gt;
            &lt;PicUrl&gt;&lt;![CDATA[http://www.doucube.com/weixin/weather/icon/banner.jpg]]&gt;&lt;/PicUrl&gt;
            &lt;Url&gt;&lt;![CDATA[]]&gt;&lt;/Url&gt;
        &lt;/item&gt;
    &lt;/Articles&gt;
    &lt;FuncFlag&gt;0&lt;/FuncFlag&gt;
&lt;/xml&gt;</pre>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>2.2 多图文消息</p>
<p>回复多图文</p>
<p><img alt="" src="http://images.cnitblog.com/blog/340216/201312/24213651-ebb31b7df0fe4d1aadb44c699ed5c421.jpg" /><img alt="" src="http://images.cnitblog.com/blog/340216/201312/24213704-27ef22f35cf64155b739902ccc08b4a0.jpg" /></p>
<p>后台数据格式</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<pre>&lt;xml&gt;
    &lt;ToUserName&gt;&lt;![CDATA[oIDrpjqASyTPnxRmpS9O_ruZGsfk]]&gt;&lt;/ToUserName&gt;
    &lt;FromUserName&gt;&lt;![CDATA[gh_680bdefc8c5d]]&gt;&lt;/FromUserName&gt;
    &lt;CreateTime&gt;1359011829&lt;/CreateTime&gt;
    &lt;MsgType&gt;&lt;![CDATA[news]]&gt;&lt;/MsgType&gt;
    &lt;Content&gt;&lt;![CDATA[]]&gt;&lt;/Content&gt;
    &lt;ArticleCount&gt;5&lt;/ArticleCount&gt;
    &lt;Articles&gt;
        &lt;item&gt;
            &lt;Title&gt;&lt;![CDATA[【深圳】天气实况 温度：3℃ 湿度：43﹪ 风速：西南风2级]]&gt;&lt;/Title&gt;
            &lt;Description&gt;&lt;![CDATA[]]&gt;&lt;/Description&gt;
&lt;PicUrl&gt;&lt;![CDATA[http://www.doucube.com/weixin/weather/icon/banner.jpg]]&gt;&lt;/PicUrl&gt;
            &lt;Url&gt;&lt;![CDATA[]]&gt;&lt;/Url&gt;
        &lt;/item&gt;
        &lt;item&gt;
            &lt;Title&gt;&lt;![CDATA[06月24日 周四 2℃~-7℃ 晴 北风3-4级转东南风小于3级]]&gt;&lt;/Title&gt;
            &lt;Description&gt;&lt;![CDATA[]]&gt;&lt;/Description&gt;
            &lt;PicUrl&gt;&lt;![CDATA[http://www.doucube.com/weixin/weather/icon/d00.gif]]&gt;&lt;/PicUrl&gt;
            &lt;Url&gt;&lt;![CDATA[]]&gt;&lt;/Url&gt;
        &lt;/item&gt;
        &lt;item&gt;
            &lt;Title&gt;&lt;![CDATA[06月25日 周五 -1℃~-8℃ 晴 东南风小于3级转东北风3-4级]]&gt;&lt;/Title&gt;
            &lt;Description&gt;&lt;![CDATA[]]&gt;&lt;/Description&gt;
    &lt;PicUrl&gt;&lt;![CDATA[http://www.doucube.com/weixin/weather/icon/d00.gif]]&gt;&lt;/PicUrl&gt;
            &lt;Url&gt;&lt;![CDATA[]]&gt;&lt;/Url&gt;
        &lt;/item&gt;
        &lt;item&gt;
            &lt;Title&gt;&lt;![CDATA[06月26日 周六 -1℃~-7℃ 多云 东北风3-4级转东南风小于3级]]&gt;&lt;/Title&gt;
            &lt;Description&gt;&lt;![CDATA[]]&gt;&lt;/Description&gt;
&lt;PicUrl&gt;&lt;![CDATA[http://www.doucube.com/weixin/weather/icon/d01.gif]]&gt;&lt;/PicUrl&gt;
            &lt;Url&gt;&lt;![CDATA[]]&gt;&lt;/Url&gt;
        &lt;/item&gt;
        &lt;item&gt;
            &lt;Title&gt;&lt;![CDATA[06月27日 周日 0℃~-6℃ 多云 东南风小于3级转东北风3-4级]]&gt;&lt;/Title&gt;
            &lt;Description&gt;&lt;![CDATA[]]&gt;&lt;/Description&gt;
&lt;PicUrl&gt;&lt;![CDATA[http://www.doucube.com/weixin/weather/icon/d01.gif]]&gt;&lt;/PicUrl&gt;
            &lt;Url&gt;&lt;![CDATA[]]&gt;&lt;/Url&gt;
        &lt;/item&gt;
    &lt;/Articles&gt;
    &lt;FuncFlag&gt;0&lt;/FuncFlag&gt;
&lt;/xml&gt;</pre>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>XML格式讲解</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<pre>FromUserName 消息发送方
 ToUserName 消息接收方
 CreateTime 消息创建时间
 MsgType 消息类型，图文消息必须填写news
 Content 消息内容，图文消息可填空
 ArticleCount 图文消息个数，限制为10条以内
 Articles 多条图文消息信息，默认第一个item为大图
  Title 图文消息标题
  Description 图文消息描述
  PicUrl 图片链接，支持JPG、PNG格式，较好的效果为大图640*320，小图80*80
  Url 点击图文消息跳转链接
FuncFlag 星标字段</pre>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p><strong>3. 音乐消息</strong></p>
<p align="left">回复音乐消息</p>
<p align="left"><img alt="" src="http://images.cnitblog.com/blog/340216/201312/24214131-80e7000fac2a4cb08bf89b3a5519cebc.jpg" /></p>
<p>后台格式：</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<pre>&lt;xml&gt;
    &lt;ToUserName&gt;&lt;![CDATA[ollB4jqgdO_cRnVXk_wRnSywgtQ8]]&gt;&lt;/ToUserName&gt;
    &lt;FromUserName&gt;&lt;![CDATA[gh_b629c48b653e]]&gt;&lt;/FromUserName&gt;
    &lt;CreateTime&gt;1372310544&lt;/CreateTime&gt;
    &lt;MsgType&gt;&lt;![CDATA<embed src="http://www.14en.com/wp-content/themes/wordpress160/shortcode/doubanplayer.swf?url=&amp;autoplay=0" type="application/x-shockwave-flash" wmode="transparent" allowscriptaccess="always" width="400" height="30">]&gt;&lt;/MsgType&gt;
    &lt;Music&gt;
        &lt;Title&gt;&lt;![CDATA[最炫民族风]]&gt;&lt;/Title&gt;
        &lt;Description&gt;&lt;![CDATA[凤凰传奇]]&gt;&lt;/Description&gt;
        &lt;MusicUrl&gt;&lt;![CDATA[http://zj189.cn/zj/download/music/zxmzf.mp3]]&gt;&lt;/MusicUrl&gt;
        &lt;HQMusicUrl&gt;&lt;![CDATA[http://zj189.cn/zj/download/music/zxmzf.mp3]]&gt;&lt;/HQMusicUrl&gt;
    &lt;/Music&gt;
    &lt;FuncFlag&gt;0&lt;/FuncFlag&gt;
&lt;/xml&gt;</pre>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>XML格式讲解</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<pre>ToUserName     接收方帐号（收到的OpenID）
FromUserName     开发者微信号
CreateTime     消息创建时间
MsgType          消息类型，此处为music
    Title       音乐标题
    Description 音乐描述
    MusicUrl     音乐链接
    HQMusicUrl     高质量音乐链接，WIFI环境优先使用该链接播放音乐
FuncFlag     位0x0001被标志时，星标刚收到的消息。</pre>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>&nbsp;</p>
<p><strong>事件消息类型</strong></p>
<p>目前用户在关注和取消关注，以及点击菜单的时候会自动向公众平台发送事件推送消息：</p>
<p>1. 关注事件</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<pre>&lt;xml&gt;
    &lt;ToUserName&gt;&lt;![CDATA[gh_b629c48b653e]]&gt;&lt;/ToUserName&gt;
    &lt;FromUserName&gt;&lt;![CDATA[ollB4jv7LA3tydjviJp5V9qTU_kA]]&gt;&lt;/FromUserName&gt;
    &lt;CreateTime&gt;1372307736&lt;/CreateTime&gt;
    &lt;MsgType&gt;&lt;![CDATA[event]]&gt;&lt;/MsgType&gt;
    &lt;Event&gt;&lt;![CDATA[subscribe]]&gt;&lt;/Event&gt;
    &lt;EventKey&gt;&lt;![CDATA[]]&gt;&lt;/EventKey&gt;
&lt;/xml&gt;</pre>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>2. 取消关注事件</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<pre>&lt;xml&gt;
    &lt;ToUserName&gt;&lt;![CDATA[gh_b629c48b653e]]&gt;&lt;/ToUserName&gt;
    &lt;FromUserName&gt;&lt;![CDATA[ollB4jqgdO_cRnVXk_wRnSywgtQ8]]&gt;&lt;/FromUserName&gt;
    &lt;CreateTime&gt;1372309890&lt;/CreateTime&gt;
    &lt;MsgType&gt;&lt;![CDATA[event]]&gt;&lt;/MsgType&gt;
    &lt;Event&gt;&lt;![CDATA[unsubscribe]]&gt;&lt;/Event&gt;
    &lt;EventKey&gt;&lt;![CDATA[]]&gt;&lt;/EventKey&gt;
&lt;/xml&gt;</pre>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>3. 菜单点击事件</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<pre>&lt;xml&gt;
    &lt;ToUserName&gt;&lt;![CDATA[gh_680bdefc8c5d]]&gt;&lt;/ToUserName&gt;
    &lt;FromUserName&gt;&lt;![CDATA[oIDrpjqASyTPnxRmpS9O_ruZGsfk]]&gt;&lt;/FromUserName&gt;
    &lt;CreateTime&gt;1377886191&lt;/CreateTime&gt;
    &lt;MsgType&gt;&lt;![CDATA[event]]&gt;&lt;/MsgType&gt;
    &lt;Event&gt;&lt;![CDATA[CLICK]]&gt;&lt;/Event&gt;
    &lt;EventKey&gt;&lt;![CDATA[天气深圳]]&gt;&lt;/EventKey&gt;
&lt;/xml&gt;</pre>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>XML格式讲解</p>
<div>
<pre>ToUserName     接收方微信号
FromUserName 发送方微信号，若为普通用户，则是一个OpenID
CreateTime     消息创建时间
MsgType     消息类型，event
Event     事件类型，subscribe(订阅)、unsubscribe(取消订阅)、CLICK(自定义菜单点击事件)
EventKey 事件KEY值，与自定义菜单接口中KEY值对应</pre>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h2> <strong>第四章 实现天气预报功能</strong></h2>
<p>&nbsp;</p>
<p>这一章里，我们来实现微信上的天气预报功能，我们使用方倍工作室的天气预报接口，其接口为</p>
<div>
<pre>http://apix.sinaapp.com/weather/</pre>
</div>
<p>这个接口的参数appkey为公众号原始id，参数city为城市名</p>
<p>例如，查询深圳的天气预报时，将city值做urlencode，最终访问的url为</p>
<div>
<pre>http://apix.sinaapp.com/weather/?appkey=trialuser&amp;city=%E6%B7%B1%E5%9C%B3</pre>
</div>
<p>返回的内容如下</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<pre>[
    {
        "Title": "深圳天气预报",
        "Description": "",
        "PicUrl": "",
        "Url": ""
    },
    {
        "Title": "【实况】温度18℃ 湿度59%% 东北风2级 发布时间：08:55",
        "Description": "",
        "PicUrl": "",
        "Url": ""
    },
    {
        "Title": "【舒适】建议着长袖T恤、衬衫加单裤等服装。年老体弱者宜着针织长袖衬衫、马甲和长裤。",
        "Description": "",
        "PicUrl": "",
        "Url": ""
    },
    {
        "Title": "11月19日 周三 晴 23℃~17℃ 无持续风向 微风 日出日落：06:38~17:39",
        "Description": "",
        "PicUrl": "http://discuz.comli.com/weixin/weather/icon/d00.jpg",
        "Url": ""
    },
    {
        "Title": "11月20日 周四 多云 25℃~17℃ 无持续风向 微风 日出日落：06:39~17:38",
        "Description": "",
        "PicUrl": "http://discuz.comli.com/weixin/weather/icon/d01.jpg",
        "Url": ""
    },
    {
        "Title": "11月21日 周五 多云 26℃~18℃ 无持续风向 微风 日出日落：06:40~17:38",
        "Description": "",
        "PicUrl": "http://discuz.comli.com/weixin/weather/icon/d01.jpg",
        "Url": ""
    }
]</pre>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>我们在微信中调用这一接口来获取天气预报信息，实现代码如下</p>
<div>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
<pre>&lt;?php
/*
    方倍工作室
    CopyRight 2014 All Rights Reserved
*/

define("TOKEN", "weixin");

$wechatObj = new wechatCallbackapiTest();
if (!isset($_GET['echostr'])) {
    $wechatObj-&gt;responseMsg();
}else{
    $wechatObj-&gt;valid();
}

class wechatCallbackapiTest
{
    //验证签名
    public function valid()
    {
        $echoStr = $_GET["echostr"];
        $signature = $_GET["signature"];
        $timestamp = $_GET["timestamp"];
        $nonce = $_GET["nonce"];
        $token = TOKEN;
        $tmpArr = array($token, $timestamp, $nonce);
        sort($tmpArr);
        $tmpStr = implode($tmpArr);
        $tmpStr = sha1($tmpStr);
        if($tmpStr == $signature){
            echo $echoStr;
            exit;
        }
    }

    public function responseMsg()
    {
        $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
        if (!empty($postStr)){
            $this-&gt;logger("R ".$postStr);
            $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
            $RX_TYPE = trim($postObj-&gt;MsgType);

            $result = "";
            switch ($RX_TYPE)
            {
                case "event":
                    $result = $this-&gt;receiveEvent($postObj);
                    break;
                case "text":
                    $result = $this-&gt;receiveText($postObj);
                    break;
            }
            $this-&gt;logger("T ".$result);
            echo $result;
        }else {
            echo "";
            exit;
        }
    }

    private function receiveEvent($object)
    {
        switch ($object-&gt;Event)
        {
            case "subscribe":
                $content = "欢迎关注方倍工作室 ";
                break;
        }
        $result = $this-&gt;transmitText($object, $content);
        return $result;
    }

    private function receiveText($object)
    {
        $keyword = trim($object-&gt;Content);
        $url = "http://apix.sinaapp.com/weather/?appkey=".$object-&gt;ToUserName."&amp;city=".urlencode($keyword); 
        $output = file_get_contents($url);
        $content = json_decode($output, true);

        $result = $this-&gt;transmitNews($object, $content);
        return $result;
    }

    private function transmitText($object, $content)
    {
        if (!isset($content) || empty($content)){
            return "";
        }
        $textTpl = "&lt;xml&gt;
&lt;ToUserName&gt;&lt;![CDATA[%s]]&gt;&lt;/ToUserName&gt;
&lt;FromUserName&gt;&lt;![CDATA[%s]]&gt;&lt;/FromUserName&gt;
&lt;CreateTime&gt;%s&lt;/CreateTime&gt;
&lt;MsgType&gt;&lt;![CDATA[text]]&gt;&lt;/MsgType&gt;
&lt;Content&gt;&lt;![CDATA[%s]]&gt;&lt;/Content&gt;
&lt;/xml&gt;";
        $result = sprintf($textTpl, $object-&gt;FromUserName, $object-&gt;ToUserName, time(), $content);
        return $result;
    }

    private function transmitNews($object, $newsArray)
    {
        if(!is_array($newsArray)){
            return "";
        }
        $itemTpl = "    &lt;item&gt;
        &lt;Title&gt;&lt;![CDATA[%s]]&gt;&lt;/Title&gt;
        &lt;Description&gt;&lt;![CDATA[%s]]&gt;&lt;/Description&gt;
        &lt;PicUrl&gt;&lt;![CDATA[%s]]&gt;&lt;/PicUrl&gt;
        &lt;Url&gt;&lt;![CDATA[%s]]&gt;&lt;/Url&gt;
    &lt;/item&gt;
";
        $item_str = "";
        foreach ($newsArray as $item){
            $item_str .= sprintf($itemTpl, $item['Title'], $item['Description'], $item['PicUrl'], $item['Url']);
        }
        $newsTpl = "&lt;xml&gt;
&lt;ToUserName&gt;&lt;![CDATA[%s]]&gt;&lt;/ToUserName&gt;
&lt;FromUserName&gt;&lt;![CDATA[%s]]&gt;&lt;/FromUserName&gt;
&lt;CreateTime&gt;%s&lt;/CreateTime&gt;
&lt;MsgType&gt;&lt;![CDATA[news]]&gt;&lt;/MsgType&gt;
&lt;Content&gt;&lt;![CDATA[]]&gt;&lt;/Content&gt;
&lt;ArticleCount&gt;%s&lt;/ArticleCount&gt;
&lt;Articles&gt;
$item_str&lt;/Articles&gt;
&lt;/xml&gt;";

        $result = sprintf($newsTpl, $object-&gt;FromUserName, $object-&gt;ToUserName, time(), count($newsArray));
        return $result;
    }

    private function logger($log_content)
    {

    }
}
?&gt;</pre>
<div><a title="复制代码"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></div>
</div>
<p>上述代码的下载地址为 <a href="http://pan.baidu.com/s/1gdsyHWJ" target="_blank">http://pan.baidu.com/s/1gdsyHWJ</a>，同样的方法，可将代码上传到SAE上。</p>
<p>在公众账号中使用的命令如下：</p>
<ol>
<li>发送城市名称，如“深圳”，可以查询该城市的天气</li>
</ol>
<p>在你的公众账号输入相应的命令，实现效果类似如下所示：</p>
<p><img alt="" src="http://images.cnitblog.com/blog/340216/201402/261418519677515.png" /></p>
<p>&nbsp;</p>
<p><strong>第五章 小结</strong></p>
<p>&nbsp;</p>
<p>总的来说，通过本教程，你得到了以下收获：</p>
<ul>
<li>1. 你通过本教程得到了一个免费的新浪云计算空间，云计算哦</li>
<li>2. 你成功启用了开发模式，并且实现了时间的自动回复</li>
<li>3. 你了解了微信公众平台开发的原理，并且熟悉了各种消息及发送是怎么一回事</li>
<li>4. 你使用方倍工作室的天气预报接口，实现了一个微信公众平台上的天气预报功能。</li>
</ul>
<p>&nbsp;</p>
<p>本文转载自：http://www.cnblogs.com/txw1958/p/wechat-tutorial.html</p>
<p><span style="font-weight:bold;text-shadow:0 1px 0 #ddd;">声明:</span> 本文采用 <a rel="nofollow" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" title="署名-非商业性使用-相同方式共享">BY-NC-SA</a> 协议进行授权 | <a href="http://www.14en.com">追梦者，用汗水扬帆起航。</a><br />转载请注明转自《<a rel="bookmark" title="微信公众平台开发入门教程" href="http://www.14en.com/?p=153">微信公众平台开发入门教程</a>》</p>]]></content:encoded>
			<wfw:commentRss>http://www.14en.com/?feed=rss2&#038;p=153</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="http://zj189.cn/zj/download/music/zxmzf.mp3" length="0" type="audio/mpeg" />
		</item>
		<item>
		<title>说说春节抢票那件事&#8211;如何随时随地抢票</title>
		<link>http://www.14en.com/?p=144</link>
		<comments>http://www.14en.com/?p=144#comments</comments>
		<pubDate>Sat, 30 Jan 2016 09:42:03 +0000</pubDate>
		<dc:creator><![CDATA[eekuang]]></dc:creator>
				<category><![CDATA[生活札记]]></category>

		<guid isPermaLink="false">http://www.14en.com/?p=144</guid>
		<description><![CDATA[春节马上就要来啦，然而还有很多在上班的孩子没办法回家，因为.......没买到票。 好了，言归正传，今天说说抢 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>春节马上就要来啦，然而还有很多在上班的孩子没办法回家，因为.......没买到票。</p>
<p>好了，言归正传，今天说说抢票那点事儿。我说的不一定专业，但至少从目前实践来说，我觉得还是很实用的。我今天要说的是，如何随时随地抢票，不管在公司，在厕所，在野外还是在天上。有人说，手机端也有抢票软件。但经过我本人测试，觉得不太好用，抢票效果不是很好。所以，今天我要讲的是，如何将手机和电脑都利用起来，进行抢票。</p>
<p><strong>首先</strong>，抢票需要准备两个软件。一个是抢票软件，我使用的是360浏览器。一个是远程登陆软件（包括电脑端和手机端），我使用的是TeamViewer。这两个软件，都是直接可以从官网下载，百度一下就能找到。</p>
<p><strong>接着</strong>，安装电脑端的两个软件，并打开。软件是长这样的。</p>
<p><img class="alignnone" alt="" src="http://i4.tietuku.com/89d2ea848781d15e.jpg" width="196" height="115" /></p>
<p><strong>然后</strong>，打开360浏览器，点击上方的360抢票王进行抢票。这个不用多介绍了吧。好了，360的使用就到此结束了。</p>
<p><strong>接下来</strong>，打开TeamViewer，点击软件右边的注册，进行用户注册。注册成个人用户就行了，可以满足日常使用。注册页面是长这样的。</p>
<p><img class="alignnone" alt="" src="http://i4.tietuku.com/3f922c1d1544475c.jpg" width="369" height="288" /></p>
<p>注册完之后，登陆TeamViewer，然后在左侧的加号处，点击添加本计算机，设置名称和密码。</p>
<p><img class="alignnone" alt="" src="http://i4.tietuku.com/8c0421ec8c50c70c.jpg" width="344" height="233" /></p>
<p>&nbsp;</p>
<p>好了，电脑端的工作就完成了。你只需要24小时开着机，就一直能帮你抢票了。</p>
<p><b>最后</b>，在手机应用市场里搜索“TeamViewer”，然后下载安装。安装完成之后，点击打开。进入软件界面，登陆用户。然后在我的计算机里发现有台电脑在线了，就是下面这个样子。点击右侧的蓝色连接按钮，就能登录进入你的电脑，神奇地在手机端用电脑进行抢票啦！</p>
<p><img class="alignnone" alt="" src="http://i13.tietuku.com/ca98e081fce1c724.jpg" width="194" height="346" /><img class="alignnone" alt="" src="http://i13.tietuku.com/7a2fa9b9352e8fac.jpg" width="194" height="346" /><img class="alignnone" alt="" src="http://i13.tietuku.com/362ab8c1748a7506.jpg" width="194" height="346" /></p>
<p>&nbsp;</p>
<p>再补充几点：</p>
<p>首先，我为什么要选360呢？主要是看中了他的自动抢票功能。对比来说，猎豹也可以抢票，但是需要手动点击图片提交订单。如果不常在电脑端的话，自动抢票就尤为重要了。由于本人对抢票也没有深入研究过，所以目前仅知道360的自动抢票比较好用。</p>
<p>还有就是，现在12306网站对用户端登陆似乎做了很多限制，所以导致经常需要重新登陆甚至有时候登陆不上去。所以，有时候抢票也挺烦的。</p>
<p>另外，我在网上也搜集到了一些其他的抢票软件，大家有兴趣可以试试。本人不保证效果。个人推荐直接用上述的360+TeamViewer组合就行了，瞎折腾也累。鄙人就是用上述软件，成功帮女神抢到硬座票一枚。</p>
<p>最后，祝大家都能顺利回家！</p>
<p>附：</p>
<p>12306Bypass 分流抢票<br />
<a href="http://www.viidii.info/?http://yunpan______cn/c3VfgWN3KbI24&amp;z" target="_blank">http://yunpan.cn/c3VfgWN3KbI24</a> （提取码：0c7a）<br />
12306v2.2官网手机版<br />
<a href="http://www.viidii.info/?http://yunpan______cn/c3VfKbRJEHu2y&amp;z" target="_blank">http://yunpan.cn/c3VfKbRJEHu2y</a> （提取码：f05a）<br />
12306订票助手.NET_9.1.2.1<br />
<a href="http://www.viidii.info/?http://yunpan______cn/c3VfVDxtbGqQ3&amp;z" target="_blank">http://yunpan.cn/c3VfVDxtbGqQ3</a> （提取码：db58）<br />
360抢票专版<br />
<a href="http://www.viidii.info/?http://yunpan______cn/c3Vfd5EbIF8nL&amp;z" target="_blank">http://yunpan.cn/c3Vfd5EbIF8nL</a> （提取码：20e8）<br />
5E打码版<br />
<a href="http://www.viidii.info/?http://yunpan______cn/c3VfHaEXWunw7&amp;z" target="_blank">http://yunpan.cn/c3VfHaEXWunw7</a> （提取码：49af）<br />
5E手动打码版<br />
<a href="http://www.viidii.info/?http://yunpan______cn/c3VfuTnsbdX5M&amp;z" target="_blank">http://yunpan.cn/c3VfuTnsbdX5M</a> （提取码：1dc2）<br />
猎豹抢票浏览器 2016春运版<br />
<a href="http://www.viidii.info/?http://yunpan______cn/c3VfYXmI6RFqh&amp;z" target="_blank">http://yunpan.cn/c3VfYXmI6RFqh</a> （提取码：6721）<br />
榴莲抢票王<br />
<a href="http://www.viidii.info/?http://yunpan______cn/c3VfSZxqfVBx2&amp;z" target="_blank">http://yunpan.cn/c3VfSZxqfVBx2</a> （提取码：62a9）<br />
木鱼抢票软件最新版<br />
<a href="http://www.viidii.info/?http://yunpan______cn/c3VfEvBzIMCiC&amp;z" target="_blank">http://yunpan.cn/c3VfEvBzIMCiC</a> （提取码：1027）<br />
人生日历抢票软件(2016抢票专版)<br />
<a href="http://www.viidii.info/?http://yunpan______cn/c3Vf5DxQpD2AP&amp;z" target="_blank">http://yunpan.cn/c3Vf5DxQpD2AP</a> （提取码：35bb）<br />
山鸟抢票<br />
<a href="http://www.viidii.info/?http://yunpan______cn/c3VfnZxj8Cf3a&amp;z" target="_blank">http://yunpan.cn/c3VfnZxj8Cf3a</a> （提取码：3d2e）<br />
搜狗抢票浏览器<br />
<a href="http://www.viidii.info/?http://yunpan______cn/c3Vf9PiUi7IS4&amp;z" target="_blank">http://yunpan.cn/c3Vf9PiUi7IS4</a> （提取码：90d3）<br />
铁客网络订票系统<br />
<a href="http://www.viidii.info/?http://yunpan______cn/c3VfD9ibtuj3J&amp;z" target="_blank">http://yunpan.cn/c3VfD9ibtuj3J</a> （提取码：9c51）<br />
铁路通533正式版<br />
<a href="http://www.viidii.info/?http://yunpan______cn/c3Vf4KiXPgetr&amp;z" target="_blank">http://yunpan.cn/c3Vf4KiXPgetr</a> （提取码：263c）<br />
吾易购票112802<br />
<a href="http://www.viidii.info/?http://yunpan______cn/c3VfNXmY28SYS&amp;z" target="_blank">http://yunpan.cn/c3VfNXmY28SYS</a> （提取码：5494）<br />
智行火车票<br />
<a href="http://www.viidii.info/?http://yunpan______cn/c3VfTIsQGhbXY&amp;z" target="_blank">http://yunpan.cn/c3VfTIsQGhbXY</a> （提取码：bed4）</p>
<p><span style="font-weight:bold;text-shadow:0 1px 0 #ddd;">声明:</span> 本文采用 <a rel="nofollow" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" title="署名-非商业性使用-相同方式共享">BY-NC-SA</a> 协议进行授权 | <a href="http://www.14en.com">追梦者，用汗水扬帆起航。</a><br />转载请注明转自《<a rel="bookmark" title="说说春节抢票那件事&#8211;如何随时随地抢票" href="http://www.14en.com/?p=144">说说春节抢票那件事&#8211;如何随时随地抢票</a>》</p>]]></content:encoded>
			<wfw:commentRss>http://www.14en.com/?feed=rss2&#038;p=144</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>互联网及相关公司的求职经历分享</title>
		<link>http://www.14en.com/?p=132</link>
		<comments>http://www.14en.com/?p=132#comments</comments>
		<pubDate>Mon, 07 Dec 2015 08:06:48 +0000</pubDate>
		<dc:creator><![CDATA[eekuang]]></dc:creator>
				<category><![CDATA[技术笔记]]></category>

		<guid isPermaLink="false">http://www.14en.com/?p=132</guid>
		<description><![CDATA[找工作算是告一段落了。从今年过年回来开始，到这个月，整整9个月的求职路。然而，如果真的算找工作所花的时间，又怎 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>找工作算是告一段落了。从今年过年回来开始，到这个月，整整9个月的求职路。然而，如果真的算找工作所花的时间，又怎么可能仅仅9个月就可以完成所有的工作。不过，这篇文章就不铺开太多了，仅讨论找实习找工作的一些经验体会吧。我找工作这段时间，除了中途投了一个唯品会的php工程师，其它应聘的岗位都是C++工程师相关的。所以，我下文所讲的内容，很大一部分都是针对C++软件开发工程师的。当然，我觉得软开工程师也可以从中得到部分借鉴。<br />
<strong>一、找实习</strong><br />
去年寒假时，就开始有同学陆续准备找实习了，甚至在研二的时候就有同学通过某些途径（自己网投or朋友推荐）进入公司实习。我所知道的，有个同学就是师兄带着进了4399实习了几个月。我算是准备的比较晚的了，我当时是带了两本书（大话数据结构和C++ primer）回家过寒假，不过基本没动。带书回家不看，似乎是所有同学的通病啊 Y(^_^)Y。正月回学校之后，突然感觉压力很大了。因为，身边的同学似乎都已经有一些准备了。有时候，大家讨论简单的C++语法或者数据结构的时候，都感觉自己跟不上节奏了。所以，回来之后我马上就开始做准备了。所谓的准备，就是看书手写代码，然后还在电脑上做了一些简单的编程题。看书的话，从最基础的开始，《大话数据结构》和《C++ primer》。<br />
然而，时间是相当不够的。转眼间，三月份就来了。第一个来公司招聘的是CVTE公司，来得最早，也各种宣传。当时，感觉自己完全不行的情况下，参加了C++开发工程师的笔试，结果很惨，笔试没过，挂了。这次考试对我的冲击很大。可以说是，从觉得自己很差到自己的确很差，而且差到笔试都过不了的一种体验。知耻而后勇，在接下来的一个多月，我变得更努力。除了这两本书之外，我还看了下《剑指offer》、《鸟哥的私房菜》、《深入理解计算机系统》和《TCP/IP协议详解》这几本书。主要精力放在大话、C++和剑指offer这三本书。鸟哥我之前看过，所以算是复习指令用的。深入理解和TCP/IP这两本书算是了解系统底层用的。<br />
接着，迎来了腾讯的笔试面试。这是我人生的一大转折。我顺利通过了腾讯的笔试和面试，据说笔试成绩还可以，也顺利拿到了offer。腾讯这个算是走得比较顺利，也部分因为公司考查基础知识比较多，没有问太深入的东西吧。笔试是中规中矩的题目，C++、数据结构和算法、操作系统、Linux基本指令等。有编程题，比较简单，具体题目情况可以自己百度找资料。然后，面试一面问了比较多的项目经验和C++数据结构之类的基础知识。二面问了一些Linux的东西，问了操作系统的东西，然后也聊了一些项目经验。三面HR，基本就没问题了，闲聊。我觉得自己比较顺利还有一个原因就是因为简历上项目经验比较多，然后也是软件这一块的，所以还能跟面试官扯得比较久。如果简历上没什么可看的项目经历的话，很有可能就会问基础技术知识，或者深挖技术底层，这就考验个人基础是否扎实了。去公司实习时，发现一面是leader，二面是隔壁组leader，然后三面是部门的秘书。感觉世界小，不过这也是后话了。腾讯给我的感觉就是愿意给年轻人机会，然后难度也没这么大。因为在深圳，是南方企业，所以在南方招的人很多，尤其是华工中大这两个学校。所以，大家的机会都很多。感觉，相比BA，也难度小一点，这仅仅是个人体会。当然，拿到这个offer并不代表我有多牛逼。之后，投了阿里，直接笔试就挂了，题目难度相当大，最后三个大题，两个编程题都没有做出来，只做了最后一个类似于开放新的题目，毫无疑问的挂了。不过，后来听同学说，有很多人霸面成功了。当时，由于已经是五月份了，已经签了腾讯，我基本也没太想了，所以我就没去霸面了。阿里的笔试直接又甩了我一脸，让我认清了自己的面目。即使是准备了一个多月，我仍然是个水货。路漫漫其修远兮，吾将继续努力！之后还有百度公司，比较坑，由于投简历比较早，后来不知道什么鬼，连笔试通知都没有到。在这里提醒大家一点，百度的实习信息貌似比较晚，大家一定不要太早投简历。我当时投的时候岗位很少。这种情况属于，实际上实习校招信息还没有放出来。投早了，岗位不符合拒了你，后面再投就没动静了。百度的实习网站是最坑的，好像没人管似的。<br />
除上述公司，我还找了其它类型的公司。华为，比较简单，先机试，三道编程题，我做出了两道，题目很简单，我有些同学拿了满分的。面试，问一些基础知识，不会问很深的题目，然后问问项目经历。一面问技术，二面有的也问点技术，有的就闲聊。华为对学校出身，对你的科研经历、学习成绩和项目经历很看重，反而在面试中对于个人能力的考察会少一些。如果学校比较差，简历比较简单，就差不多没太大希望了。投了网易游戏，C++游戏开发工程师，还是内推。不过，实习竞争太大，笔试机会都没有获得。据说，笔试是写小游戏，难度比较大。印象中只有两个同学拿到实习offer了。还有多益游戏，实习工资超高，10000！我这个情况比较奇葩，当时因为有事没去参加笔试，所以在面试当天做了笔试题然后直接参加了面试。笔试题也中规中矩，都是基础的算法题和C++，最后编程题没写完。编程题一直是我的弱项，算法能力太弱。之后，面试，也中规中矩，问了C++，数据库和SQL语句，问了操作系统的知识，问了点项目的事情。面试是三个面一个，两个问一个记录，感觉还ok，没有给压力。最后华为跟多益offer也都拿到了。<br />
<strong>二、实习</strong><br />
实习去了腾讯，由于老板不放人，七月初才过去。实习具体内容就不说了。腾讯内部很nice，公司文化也很棒，同事和上司都很友好和随和。感觉实习就是努力干活，去适应公司的工作节奏和工作内容吧。说实话，由于个人能力不足，还感觉蛮累的。有时候也感觉蛮有压力的，不过既然选择了软开的职业道路，就不可能悠闲的过日子。至于留用的问题，我感觉腾讯内部之间差异是很大的，有的部门实习基本都留下，有的部门它本来就是差额招的实习生，有很多人最后不得不淘汰。但是，不管有没有机会留下，都该好好努力。在一家中国数一数二的互联网企业实习，这是多么难得的一个学习机会啊！<br />
希望我的一些经历与体会，能给即将走上求职之路的你，一些启发或触动。<br />
<strong>三、校招</strong><br />
实习了两个月，我在九月中回学校了。回学校之前也顺利拿到了腾讯的留用offer。说实话，感觉自己能力还是不够，能留下来有一部分原因是因为部门有足够的hc吧。由于拿到了腾讯的offer，所以找工作的时候基本也没太大的动力了。校招的细节我就不说了，基本跟实习的时候一致。我主要说下几家公司的一个笔试面试情况吧。<br />
首先是百度。我投的岗位是基础平台开发，也就是类似于后台开发的一个类型的岗位。笔试是在线的，选择题+编程题，题目比较常规，难度不是很大。百度是一家非常注重技术的公司，我总共经历了三面，听说有的人经历了四面，全部都是技术面试。百度面试的特点是，只问你懂的，然后深挖。也就是说，千万别把了解说成了熟练掌握，不然他会深挖你这块的知识，直到你挂掉。三面类型都差不多，聊聊项目，然后问你懂什么，然后就在这方面深挖。问过一些算法题和实际应用的题。比如说，有个很大的文件，可能达到T级别，在两台机子同步的过程中出现了异常，导致有一台机子的文件没有得到更新。问，如何将没有得到更新的那台机子的文件进行更新，要求效率尽量的高。这个题当时答得不是很好，不过他说大家都答得不太好，哈哈。总的来说，感觉面试都还可以，顺利进行到了终面。但最后，没有结果，听说这样是被刷了。不知道是不是因为能力不行，还是因为今年百度招的人少。忘了说，我投的是深圳的岗位，招聘人数很少。然后是华为，投的IT软件开发岗位。由于实习拿到过offer，所以直接进行面试，跳过机试。面试第一面，很基础都是问了C++和数据结构的东西，而且很基础不会问很深的。其中有个问题就是问指针操作的问题，汗颜，没答出来。之前已经说了，华为其实对面试不是很看重，主要看你简历的情况。所以，也比较顺利的拿到了offer。第三个公司是yy语音，岗位是C++开发工程师。笔试题考得比较基础，不过面非常广，好几十个选择题，还有多选。大题里，有填空题，程序语句填空。有一个编程题，关于堆栈相关实现的，还有一个B+树的题目。面试经历了三面，两个技术加一个HR。面试也很常规，问C++和算法操作系统之类的，不会问很难的题目，也会问一些实际应用中遇到的问题。比如说，给亿级别的数字，求最大的500个数，或者对这些数字进行排序。yy的校招真够混乱的，经常面试等一个多小时，坑爹。然后薪资起点也比较低，开发9K。不过，听说给年轻人机会比较多，不知是真是假。最后说下网易游戏，简直是个bug，今年给的工资超高，然后也扩招了，很遗憾错过了。我投的是平台，不过听说招的人很少。哎，笔试就被刷了，基础不牢地动山摇啊。<br />
<strong>四、该有的准备</strong><br />
笔试面试经历写完了，说下个人关于找工作的一些准备吧。首先是简历。简历相当于你的名片，所以非常重要，应该花大力气去设计。不过设计好之后，基本就能用到校招结束，中间不需要大改，只需要增删内容即可。简历内容多就两页，内容少就一页搞定。作为程序员，不用把简历弄得太花哨，个人觉得简洁为主，然后非技术的内容尽量简洁阐述，技术相关内容选择性详细介绍。当然，如果有好的创意，设计一份让人眼前一亮的简历也是极好的。下图是我的个人简历，可以做个参考。关于笔试面试，建议多上网找找资料，看看别人怎么准备的。兼听则明偏信则暗，多看看别人的准备经历，和同学多交流，就能找到自己的准备方法策略。还有就是，要努力付出。no pain no gain.别人付出了，你不付出，那失败的基本就是你了。关于书籍，该买的书一定要买，别老想着节约钱，能借就绝不买。现在互联网还没进入寒冬，要找一份好的工作还是比较容易的。<br />
其他废话不多说了，有什么问题可以与我取得联系，大家相互学习。</p>
<p>&nbsp;</p>
<p>附：个人简历图<img style="line-height: 1.5em;" alt="这里写图片描述" src="http://i12.tietuku.com/28fdc9afa2f977a7.png" /></p>
<p><span style="font-weight:bold;text-shadow:0 1px 0 #ddd;">声明:</span> 本文采用 <a rel="nofollow" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" title="署名-非商业性使用-相同方式共享">BY-NC-SA</a> 协议进行授权 | <a href="http://www.14en.com">追梦者，用汗水扬帆起航。</a><br />转载请注明转自《<a rel="bookmark" title="互联网及相关公司的求职经历分享" href="http://www.14en.com/?p=132">互联网及相关公司的求职经历分享</a>》</p>]]></content:encoded>
			<wfw:commentRss>http://www.14en.com/?feed=rss2&#038;p=132</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>关于百度地图在web端二次开发经验分享</title>
		<link>http://www.14en.com/?p=122</link>
		<comments>http://www.14en.com/?p=122#comments</comments>
		<pubDate>Sun, 08 Feb 2015 05:27:27 +0000</pubDate>
		<dc:creator><![CDATA[eekuang]]></dc:creator>
				<category><![CDATA[技术笔记]]></category>
		<category><![CDATA[js]]></category>
		<category><![CDATA[物联网]]></category>
		<category><![CDATA[百度地图]]></category>

		<guid isPermaLink="false">http://eekuang.cn/?p=122</guid>
		<description><![CDATA[前言 研一跟着导师做了一个关于城市沙井盖监控的项目，其中的沙井盖管理中心（网站形式）就采用了百度地图的WEB接 [&#8230;]]]></description>
				<content:encoded><![CDATA[<h2>前言</h2>
<p>研一跟着导师做了一个关于城市沙井盖监控的项目，其中的沙井盖管理中心（网站形式）就采用了百度地图的WEB接口。其实项目早在14年9月份就已经结束了，奈何本人患有拖延症，一直没有静下心来写一写关于百度地图二次开发的经历。转眼间，研二上学期就结束了，还有十天，就是农历新年了。就现在吧，写写开发经验，技术大牛轻喷。</p>
<h2>项目需求</h2>
<p>我做的是一个物联网项目——城市沙井盖监控。我们通过百度地图，将沙井盖节点可视化显示在百度地图上，然后通过点击井盖节点进行管理（授权、去授权、告警响应、查询）。由于WEB不能一直保持在线，故我们在进行节点管理的时候，实际上是通过数据库来进行数据中转。硬件端直接与上位机数据交互，上位机和WEB端实时读取数据库的数据信息，实现与硬件端的数据交互。整个系统的架构如下图所示（CANET可近似认为是井盖物理节点）：</p>
<p>&nbsp;</p>
<p><img alt="" src="http://img.blog.csdn.net/20150207180019479" /></p>
<p>举个例子，现在某井盖节点被恶意打开，此时节点通过通信线路将数据发送到上位机软件，上位机软件接收到数据后立即将该节点的状态信息更新至MySQL数据库，WEB端通过实时读取数据库数据，更新地图上的显示。此时，数据库中该节点的状态数据更新为“非法打开”，地图上该节点的状态图标为对应的非法打开图样，如下图所示。</p>
<p><img alt="" src="http://img.blog.csdn.net/20150207180443103" /></p>
<p>&nbsp;</p>
<h2>百度API简介</h2>
<p>如今的主流的几种地图（谷歌地图、百度地图、高德地图等）都提供了API接口，考虑到谷歌这年对国内支持不太够，百度地图相对内容更为详尽，我选择了百度地图。百度地图为开发者提供了丰富的开发接口，为WEB端提供了JS API和Flash API(已停止更新)，我选择的是JS API。特别注意，API版本在v1.5以上的，就必须申请密钥(ak)才能调用接口。密钥申请较为简单，此处就不再赘言。</p>
<p>&nbsp;</p>
<h2>如何调用API</h2>
<div></div>
<p>作为一个技术小白，你的第一感觉应该是：这就是百度地图接口？那我怎么拿来用呢？</p>
<p>由于地图使用的是JS代码，故首先你得对javascript有大概认识（至少要能读懂）。新手建议先试试百度地图提供的地图生成器，通过手动生成一些地图代码，来了解地图的代码结构。生成器网址：http://api.map.baidu.com/lbsapi/createmap/index.html。看完示例代码，实际上可以看出来，百度地图是通过在网页上嵌入一个固定大小DIV容器，在容器内显示从百度地图官网中调用来的地图数据。</p>
<p>当然，仅仅看完示例代码，你也只能创建一个静态的地图，不能自定义地在地图上添加各种你想要的功能。下面我就说说我用到的功能的一些实现办法。当然，由于我也仅仅只是用到了百度地图的部分功能，所以本文章阐述的东西还是非常有限的。</p>
<p>&nbsp;</p>
<h2>实现需求</h2>
<div>在百度地图接口中，实际上，是将整个地图封装成一个类——map类，而地图的所有内容都封装成了类里的成员和函数。例如，用户自定义的覆盖物（marker），就是以数组的形式存在map类中，地图的缩放功能通过类中的enableDragging()和disableDragging()来启用和禁用。至于具体某个功能通过类里的什么成员、成员函数来实现，就需要在开发指南中通过查找相关信息了。这是JavaScript API大众版的地址:<a href="http://developer.baidu.com/map/index.php?title=jspopular" target="_blank">点击打开链接</a></div>
<div>在我的项目中，首先我需要从数据库加载预设的井盖节点数据，显示在地图上，接着定时查询更新的数据信息，更新地图上的节点显示。我使用了简单的AJAX代码实现了异步获取节点数据，然后显示在地图上。所谓异步就是，我先加载地图，然后异步获取数据库的节点信息，将节点的图层添加在地图上。注意，在js代码中，我们将井盖节点（网络编号、子网编号、经度、纬度、状态、描述信息）存入一个全局一维数组中，每个数组成员中包含该节点的所有信息。例如数组中某元素存储字符串为"218.192.171.79:5001|90|113.35255|23.159962|0|一教旁"，则表示该节点处于218.192.171.79：5001这个网络中，子网内的编号为90，经度113.35255，纬度23.159962，状态为0（正常），备注信息“一教旁”。贴出添加节点的javascript函数代码：</div>
<div></div>
<div></div>
<p>&nbsp;</p>
<pre>    function iniMarkers()
    {
    	var xmlhttp;
    	var user=document.getElementById("user").innerText; //获取当前登陆管理员id
	    if (window.XMLHttpRequest)
	  	  {// code for IE7+, Firefox, Chrome, Opera, Safari
	  	   xmlhttp=new XMLHttpRequest();
	  	  }
	  	else
	  	  {// code for IE6, IE5
	  	  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
	  	  }
	  	xmlhttp.onreadystatechange=function()
	  	  {
	  	  if (xmlhttp.readyState==4 &amp;&amp; xmlhttp.status==200)
	  	    {
	  		  if(xmlhttp.responseText!="")
	  		  {
	  			    wellArr=xmlhttp.responseText.split(";");//结点数据通过";"分割
	  			    addMarker();//将数据添加到地图图层
	  			    updateInfo();//定时刷新地图数据显示  
	  		  }
	  		  else
	  		  {
	  			  window.alert("该用户暂未安排节点监控管理。");
	  		  }
	  	    }
  	  }
  	xmlhttp.open("GET","mcmProcess.php?flag=fetchWelllist&amp;user="+user,true);//获取结点数据
  	xmlhttp.send();    	
    }</pre>
<pre>    function addMarker(){
    	point= new BMap.Point(wellArr[0].split("|")[2],wellArr[0].split("|")[3]);
        map.centerAndZoom(point,17);//设定地图的中心点和坐标并将地图显示在地图容器中
        for(var i=0;i&lt;window.wellArr.length-1;i++){
             canet[i] = window.wellArr[i].split("|")[0];
             canid[i] = window.wellArr[i].split("|")[1];
             lng[i] =  window.wellArr[i].split("|")[2];
             lat[i] =  window.wellArr[i].split("|")[3];
             state[i] = window.wellArr[i].split("|")[4];
             descr[i] = window.wellArr[i].split("|")[5];         
            var point = new BMap.Point(lng[i],lat[i]);
            var sateImg;
            switch(state[i])
            {
            case '1':
            	stateImg="img/authored.png";
            	break;
            case '2':	
            	stateImg="img/authoropened.png";
            	break;
            case '3':
            	stateImg="img/warn.png";
            	break;
            case '19':
            	stateImg="img/warnacked.png";
            	break;
            case '255':
            	stateImg="img/lost.png";
            	break;
            default:
            	stateImg="img/normal.png";
        	break;
            }
			var iconImg = new BMap.Icon(stateImg,new BMap.Size(20,20));
            var marker = new BMap.Marker(point,{icon:iconImg});
			var iw = createInfoWindow(i);
			var label = new BMap.Label(canid[i],{"offset":new BMap.Size(17,0)});//右，下，
			marker.setLabel(label);
            map.addOverlay(marker);
            markers[i]=marker;
            label.setStyle({
                        borderColor:"#808080",
                        color:"#333",
                        cursor:"pointer"
            });

			(function(){
				var index = i;
				var _iw = createInfoWindow(i);
				var _marker = marker;
				_marker.addEventListener("click",function(){
				    this.openInfoWindow(_iw);
				    document.getElementById("canet").value=canet[index];
				   document.getElementById("canid").value=canid[index];

			    });
			    _iw.addEventListener("open",function(){
				    _marker.getLabel().hide();
			    })
			    _iw.addEventListener("close",function(){
				    _marker.getLabel().show();
			    })
				label.addEventListener("click",function(){
			    })
					label.show();
			})()
        }
    }</pre>
<pre></pre>
<p>当然，显示出来还是第一步，之后还要定时获取数据库更新的数据，更新地图显示。我将更新这一过程封装在updateinfo()函数中，具体实现代码如下：</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<pre>    function updateInfo()
    {
    	if(timeCount!=0)
    	{
    		if(timeCount==5)
    		{
    			document.getElementById("report").value=
    				document.getElementById("report").value+"\n无法与数据库取得连接，通信异常！";
    			return;
    		}
    		++timeCount;
    		setTimeout("updateInfo()",2000);
    		return;
    	}
    	if (window.XMLHttpRequest)
    	  {// code for IE7+, Firefox, Chrome, Opera, Safari
    	  xmlhttp=new XMLHttpRequest();
    	  }
    	else
    	  {// code for IE6, IE5
    	  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
    	  }
    	xmlhttp.onreadystatechange=function()
    	  {
    	  if (xmlhttp.readyState==4 &amp;&amp; xmlhttp.status==200)
    	    {
    		  if(xmlhttp.responseText!="")
    		  {
    	    	    reportProcess(xmlhttp.responseText);    			  
    		  }
            setTimeout("updateInfo()",2000);
    	    timeCount=0;
    	    }
    	  }
    	user=document.getElementById('user').innerText;
    	xmlhttp.open("GET","mcmProcess.php?flag=fetchReport&amp;user="+user,true);
    	xmlhttp.send();
    	++timeCount;
    }</pre>
<p><span style="font-size: medium;"> 在updateinfo()函数中，我使用了Window的一个method，setTimeout()。该函数可以定时执行某一函数，我们用它定时执行updateinfo()函数。updateinfo函数通过AJAX技术，定时查询更新的数据，然后将更新数据显示出来。上述函数中嵌套了reportProcess子函数，就是用于更新显示。具体实现代码如下：</span></p>
<p>&nbsp;</p>
<pre><span style="font-size: medium;">    function reportProcess(responseStr)
     {
    	var reportStr=document.getElementById("report").value;
    	reportArr=responseStr.split(";");
    	var iconImg;  
		var stateStr;
    	for(var i=0;i!=reportArr.length;++i)
    	{
    		switch(reportArr[i].split("|")[3])
    		{
    		case "255":
				iconImg=new BMap.Icon("img/lost.png",new BMap.Size(20,20));    			
    			if(reportArr[i].split("|")[2]=="0")
    			{//canet失联了
    				reportStr=reportStr+reportArr[i].split("|")[0]+" CANET:"+
    				reportArr[i].split("|")[1]+"失联！\n";
    				for(var j=0;j!=window.canet.length;++j)
    				{
    					if(window.canet[j]==reportArr[i].split("|")[1])
    					{
    						markers[j].setIcon(iconImg);

    					}	
    				}
    			}
    			else
    			{//节点失联了
    				for(var j=0;j!=window.canet.length;++j)
    				{
    					if(window.canet[j]==reportArr[i].split("|")[1]&amp;&amp;
    							window.canid[j]==reportArr[i].split("|")[2])
    					{
    						markers[j].setIcon(iconImg);
    	    				reportStr=reportStr+reportArr[i].split("|")[0]+" CANET:"
    	    				+reportArr[i].split("|")[1]+"节点:"+reportArr[i].split("|")[2]+"失联！\n";
    					}	
    				}
    			}
    			break;
    		case "0"://正常关闭
				var iconImg=new BMap.Icon("img/normal.png",new BMap.Size(20,20));    			
    			if(reportArr[i].split("|")[2]=="0")
    			{//canet建立连接了
    				reportStr=reportStr+reportArr[i].split("|")[0]+" CANET:"
    				          +reportArr[i].split("|")[1]+"状态正常！\n";
    				for(var j=0;j!=window.canet.length;++j)
    				{
    					if(window.canet[j]==reportArr[i].split("|")[1])
    					{
    						markers[j].setIcon(iconImg);	
    					}	
    				}
    			}
    			else
    			{//节点查询到了
    				for(var j=0;j!=window.canet.length;++j)
    				{
    					if(window.canet[j]==reportArr[i].split("|")[1]&amp;&amp;
    							window.canid[j]==reportArr[i].split("|")[2])
    					{
    						markers[j].setIcon(iconImg);
    	    				reportStr=reportStr+reportArr[i].split("|")[0]+" CANET:"
    	    				+reportArr[i].split("|")[1]+"节点:"+reportArr[i].split("|")[2]+"正常！\n";
    					}	
    				}
    			}    			
    			break;
    		case "1"://授权关闭
    		case "2"://授权打开
    		case "3"://非法打开
    		case "9"://确认完成授权 
    		case "11"://取消授权成功
    			if(reportArr[i].split("|")[3]=="1")
    			{
        			iconImg=new BMap.Icon("img/authored.png",new BMap.Size(20,20));  
        			stateStr="处于授权关闭！\n";
    			}else if(reportArr[i].split("|")[3]=="2")
    			{
        			iconImg=new BMap.Icon("img/authoropened.png",new BMap.Size(20,20));  
        			stateStr="处于授权打开！\n";    				
    			}else if(reportArr[i].split("|")[3]=="3")
    			{
        			iconImg=new BMap.Icon("img/warn.png",new BMap.Size(20,20));  
        			stateStr="处于非法打开！\n";   	
    			}else if(reportArr[i].split("|")[3]=="9")
    			{
        			iconImg=new BMap.Icon("img/authored.png",new BMap.Size(20,20));  
        			stateStr="授权成功！\n";   	
    			}else if(reportArr[i].split("|")[3]=="11")
    			{
        			iconImg=new BMap.Icon("img/normal.png",new BMap.Size(20,20));  
        			stateStr="取消授权成功！\n";   	
    			}
				for(var j=0;j!=window.canet.length;++j)
				{
					if(window.canet[j]==reportArr[i].split("|")[1]&amp;&amp;
							window.canid[j]==reportArr[i].split("|")[2])
					{
						markers[j].setIcon(iconImg);
	    				reportStr=reportStr+reportArr[i].split("|")[0]+" CANET:"
	    				+reportArr[i].split("|")[1]+"节点:"+reportArr[i].split("|")[2]+stateStr;						
					}	
				}    			   			
    			break; 
    		case "10"://授权失败
    		case "12"://取消授权失败    	
    		case "13"://已处于授权状态
    		case "14"://已处于非授权状态
    		case "19"://非法打开，已响应
    			if(reportArr[i].split("|")[3]=="10")
    			{
    				stateStr="授权失败！\n";
    			}else if(reportArr[i].split("|")[3]=="12")
    			{
    				stateStr="取消授权失败！\n";
    			}else if(reportArr[i].split("|")[3]=="13")
    			{
    				stateStr="已处于授权状态！\n";
    			}else if(reportArr[i].split("|")[3]=="14")
    			{
    				stateStr="已处于非授权状!\n";
    			}else if(reportArr[i].split("|")[3]=="19")
    			{
    				iconImg=new BMap.Icon("img/warnacked.png",new BMap.Size(20,20));  
    				stateStr="非法打开，已响应报警！\n";
    			}
				for(var j=0;j!=window.canet.length;++j)
				{
					if(window.canet[j]==reportArr[i].split("|")[1]&amp;&amp;
							window.canid[j]==reportArr[i].split("|")[2])
					{
						markers[j].setIcon(iconImg);
	    				reportStr=reportStr+reportArr[i].split("|")[0]+" CANET:"
	    				+reportArr[i].split("|")[1]+"节点:"+reportArr[i].split("|")[2]+stateStr;						
					}	
				}    			
    			break;
    		}
    	}
    	document.getElementById("report" ).value=reportStr;
    }</span></pre>
<p><span style="font-size: medium;"> 我这里使用的代码方法比较笨，就是用遍历的办法逐个更新节点。但其实，对于本项目性能上是能够满足的。为什么这么说呢？首先，在本项目中，虽然监控的总的井盖节点数据众多，但实际上每个区域的井盖节点是不多的。在实际情况中，各个系统用户应该只是管理他所在辖区内的井盖节点，这些节点是有限数目的。因而，这样的代码从性能上是能够保证顺畅运行的。但，这并不代表这些代码是高效率的。算是本人的惰性吧，在完成功能实现后，没有花太多心思用在提高代码执行效率上，没有重构代码。所以，本文仅希望能给初学者稍稍启发，读者就别吐槽俺的糟糕代码了。<img alt="害羞" src="http://static.blog.csdn.net/xheditor/xheditor_emot/default/shy.gif" /><img alt="害羞" src="http://static.blog.csdn.net/xheditor/xheditor_emot/default/shy.gif" /><img alt="害羞" src="http://static.blog.csdn.net/xheditor/xheditor_emot/default/shy.gif" /></span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h2>结束语</h2>
<p><span style="font-size: medium;"> 从开发难度上来说，百度地图的二次开发难度还是不大的。个人认为，在官网上已经提供了足够详细的开发文档，所以开发人员只要熟读开发指南，就足以能够进行快速的二次开发。地图的开放接口为广大商家大大节约了自己制作和维护地图的成本，给各大地图提供商点个赞！</span></p>
<p><span style="font-size: medium;"> </span></p>
<p><span style="font-weight:bold;text-shadow:0 1px 0 #ddd;">声明:</span> 本文采用 <a rel="nofollow" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" title="署名-非商业性使用-相同方式共享">BY-NC-SA</a> 协议进行授权 | <a href="http://www.14en.com">追梦者，用汗水扬帆起航。</a><br />转载请注明转自《<a rel="bookmark" title="关于百度地图在web端二次开发经验分享" href="http://www.14en.com/?p=122">关于百度地图在web端二次开发经验分享</a>》</p>]]></content:encoded>
			<wfw:commentRss>http://www.14en.com/?feed=rss2&#038;p=122</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
