基于Flask的微博系统开发

起因

个人认为学习一门技术最好是能够做一些项目,『这儿』是一个基于Flask搭建的轻博客,用户可以发帖关注等基本功能。从开发到基本上能用花了大概三个星期时间,我学习这个是跟随这《Flask Web开发》这本书开始做起来的。全书共205页,薄薄的一本,这本书是去年和公司同事凑单买下来的。一只放在书桌上没看,十一月份正好没有什么其他事情,就像做这个项目练练手。
网址:
http://zheer.me
github:
https://github.com/hsiunien/Phantom
主机:阿里云

Continue reading “基于Flask的微博系统开发”

利用nginx转发实现本地调试微信公众号后台

一直想注册一个服务号未遂,于是只能注册为坑爹的个人账号,才发现各种限制,既不能认证(高级接口需要认证后才能用),开发者认证还得交钱,哎,说好的再小的个体也有自己的品牌呢???
最近遇到最大的问题就是没法本地调试,你得看着接口文档把代码写好,部署到后台去,才能进行测试。
其实我机是可以通过外网访问的。

怎么实现通过外网访问我的电脑的呢?

Continue reading “利用nginx转发实现本地调试微信公众号后台”

Spring MVC 中post json数据返回415错误的一种解决办法

我是通过angular js 发送post 请求给服务器,返回415(不支持的媒体类型),这个问题一度导致我的小项目没有进一步开展,本来我可以换一种方式的,但是不知道哪根筋出问题,非得要post 一段json数据给后台解析。国内外网站找了N种办法均没有解.

Continue reading “Spring MVC 中post json数据返回415错误的一种解决办法”

C# 多线程编程 ThreadStart ParameterizedThreadStart

在实例化Thread的实例,需要提供一个委托,在实例化这个委托时所用到的参数是线程将来启动时要运行的方法。在.net中提供了两种启动线程的方式,一种是不带参数的启动方式,另一种是带参数的启动的方式。
不带参数的启动方式
如果启动参数时无需其它额外的信息,可以使用ThreadStart来实例化Thread,如下面的代码:


1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Threading;
5
6 namespace StartThread
7 {
8 class Program
9 {
10 int interval = 200;
11 static void Main(string[] args)
12 {
13 Program p = new Program();
14 Thread nonParameterThread = new Thread(new ThreadStart(p.NonParameterRun));
15 nonParameterThread.Start();
16 }
17 ///

18 /// 不带参数的启动方法
19 ///

20 public void NonParameterRun()
21 {
22 for (int i = 0; i < 10; i++) 23 { 24 Console.WriteLine("系统当前时间毫秒值:"+DateTime.Now.Millisecond.ToString()); 25 Thread.Sleep(interval);//让线程暂停 26 } 27 } 28 }

程序的运行效果我们不用运行也会知道,那就是在循环中将系统当前时间的毫秒部分输出出来,在每次输出之后会将当前线程暂停一下,直到10次之后运行完毕,终止线程的执行。
在上面的代码中我们是通过定义全局变量的方法来指定线程暂停间隔,按照这种方法,假如要运行10个线程,每个线程的暂停间隔不一样的话,就需要定义10个全局变量,虽然最终不影响系统的运行效果,但是总觉得不是太爽。
有没有比较简单一点的办法呢?有!那就是使用带参数的启动方法。
带参数的启动方法
如果要在实例化线程时要带一些参数,就不能用ThreadStart委托作为构造函数的参数来实例化Thread了,而要 ParameterizedThreadStart委托,和ThreadStart一样的是它也是线程启动时要执行的方法,和ThreadStart不同的是,它在实例化时可以用一个带有一个Object参数的方法作为构造函数的参数,而实例化ThreadStart时所用到的方法是没有参数的。
为什么是Object这样的参数呢?很简单,因为在.net中Object是所有类型的基类,用它可以表示Array(数组)、Interface(接口)、ValueType(值类型,如bool,byte,char,short,int,float,long,double等)、class(类)等.net中的类型。当然,这也意味着如果你要启动一个线程,给它传递一个int类型参数时,必须在 启动方法中进行相应的类型转换。
下面就是一个例子,在启动线程时指定了线程的暂停间隔,代码如下:

1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Threading;
5
6 namespace StartThread
7 {
8 class Program
9 {
10 int interval = 200;
11 static void Main(string[] args)
12 {
13 Program p = new Program();
14
15 Thread parameterThread = new Thread(new ParameterizedThreadStart(p.ParameterRun));
16 parameterThread.Name = "Thread A:";
17 parameterThread.Start(30);
18 }
19
20 ///

21 /// 带参数的启动方法
22 ///

23 ///让线程在运行过程中的休眠间隔 24 public void ParameterRun(object ms)
25 {
26 int j = 10;
27 int.TryParse(ms.ToString(), out j);//这里采用了TryParse方法,避免不能转换时出现异常
28 for (int i = 0; i < 10; i++) 29 { 30 Console.WriteLine(Thread.CurrentThread.Name+"系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString()); 31 Thread.Sleep(j);//让线程暂停 32 } 33 } 34 } 35 }

在这个方法里,我们在启动线程时顺便指定了线程的暂停间隔,也就是这句:
parameterThread.Start(30);
线程启动时运行的方法是public void ParameterRun(object ms),这个值为30的int类型变量被装箱成object,所以在方法中还需要将它转换成int类型,这个可以通过拆箱或者其它办法解决。
假如我们要启动两个线程,每个线程的暂停间隔不一样,启动代码如下:

  


1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Threading;
5
6 namespace StartThread
7 {
8 class Program
9 {
10 int interval = 200;
11 static void Main(string[] args)
12 {
13 Program p = new Program();
14
15 Thread parameterThread = new Thread(new ParameterizedThreadStart(p.ParameterRun));
16 parameterThread.Name = "Thread A:";
17 parameterThread.Start(30);
18 //启动第二个线程
19 parameterThread = new Thread(new ParameterizedThreadStart(p.ParameterRun));
20 parameterThread.Name = "Thread B:";
21 parameterThread.Start(60);
22 }
23
24 ///

25 /// 带参数的启动方法
26 ///

27 ///让线程在运行过程中的休眠间隔 28 public void ParameterRun(object ms)
29 {
30 int j = 10;
31 int.TryParse(ms.ToString(), out j);//这里采用了TryParse方法,避免不能转换时出现异常
32 for (int i = 0; i < 10; i++) 33 { 34 Console.WriteLine(Thread.CurrentThread.Name+"系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString()); 35 Thread.Sleep(j);//让线程暂停 36 } 37 } 38 } 39 }

对上面的代码做一点说明,就是线程启动之后,线程的实例不必再存在,例如在上面的代码中我用的是同一个实例实例化了两个线程,并且这两个线程运行很正常。
继续探索
上面解决了一个问题,如果在启动线程时需要参数如何解决,如果针对上面的问题继续发掘,比如:在启动线程时不但要指定线程的暂停间隔,还需要指定循环次数(在上面的所有例子中都是执行10次的),这个问题该如何解决呢?
有两种办法可以解决:
首先可以继续在ParameterizedThreadStart这里做文章,因为这里可以使用一个Object类型的参数,那么可以通过数组或者一个类来解决(因为它们都是Object的子类)。我在做某个系统时确实采用数组处理过这种情况,这样就要求在线程启动方法中必须清楚知道数组中每个参数的用途,不是太方便。
这里说说重新定义一个实体类来解决的方法,代码如下。

1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Threading;
5
6 namespace StartThread
7 {
8 class MyThreadParameter
9 {
10 private int interval;
11 private int loopCount;
12 ///

13 /// 循环次数
14 ///

15 public int LoopCount
16 {
17 get { return loopCount; }
18 }
19
20 ///

21 /// 线程的暂停间隔
22 ///

23 public int Interval
24 {
25 get { return interval; }
26 }
27 ///

28 /// 构造函数
29 ///

30 ///线程的暂停间隔 31 ///循环次数 32 public MyThreadParameter(int interval,int loopCount)
33 {
34 this.interval = interval;
35 this.loopCount = loopCount;
36 }
37 }
38 class Program
39 {
40 int interval = 200;
41 static void Main(string[] args)
42 {
43 Program p = new Program();
44
45 Thread parameterThread = new Thread(new ParameterizedThreadStart(p.MyParameterRun));
46 parameterThread.Name = "Thread A:";
47 MyThreadParameter paramter = new MyThreadParameter(50, 20);
48 parameterThread.Start(paramter);
49 }
50
51
52 ///

53 /// 带多个参数的启动方法
54 ///

55 ///方法参数 56 public void MyParameterRun(object ms)
57 {
58 MyThreadParameter parameter = ms as MyThreadParameter;//类型转换
59 if (parameter != null)
60 {
61 for (int i = 0; i < parameter.LoopCount; i++) 62 { 63 Console.WriteLine(Thread.CurrentThread.Name + "系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString()); 64 Thread.Sleep(parameter.Interval);//让线程暂停 65 } 66 } 67 } 68 } 69 }

第二种方法和上面方法有些相似,也是需要引入外部类,并且将Thread实例放在引入的类中,这种情况适合于在线程中处理的业务逻辑比较复杂的情况。在前不久处理的一个项目中我用过这种情况,它是用来实现双向数据传输的。
如果实现上面的效果,代码如下:

  

1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Threading;
5
6 namespace StartThread
7 {
8 class MyThreadParameter
9 {
10 private int interval;
11 private int loopCount;
12 private Thread thread;
13
14 ///

15 /// 构造函数
16 ///

17 ///线程的暂停间隔 18 ///循环次数 19 public MyThreadParameter(int interval,int loopCount)
20 {
21 this.interval = interval;
22 this.loopCount = loopCount;
23 thread = new Thread(new ThreadStart(Run));
24 }
25
26 public void Start()
27 {
28 if (thread != null)
29 {
30 thread.Start();
31 }
32 }
33
34 private void Run()
35 {
36 for (int i = 0; i < loopCount; i++) 37 { 38 Console.WriteLine("系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString()); 39 Thread.Sleep(interval);//让线程暂停 40 } 41 } 42 } 43 class Program 44 { 45 static void Main(string[] args) 46 { 47 MyThreadParameter parameterThread = new MyThreadParameter(30, 50); 48 parameterThread.Start(); 49 } 50 51 } 52 }

上面的代码的运行效果和前面的代码运行效果类似,只不过是将业务处理代码放在一个单独的类MyThreadParameter中,使得MyThreadParameter看起来也像一个Thread,实际上维护的还是其内部的Thread,在一些大型系统中这样做的好处是便于维护。
总结:在本篇主要讲述如何启动线程的问题,在启动时可能会遇到无需参数、需要多个参数的情况,在这里讲述了如何解决这些问题的思路。在.net类库中虽然存在着庞大的类库,但是并不是总会有合适的类来解决我们所遇到的问题,但是只要肯动脑筋总会想到合适的办法。

wordpress搬迁到新浪sae

今天花了几个小时终于搞定了,把网站从主机屋搬迁到了新浪sae。写这些东西确实有点小菜,老鸟莫笑。首先分析一下难点在哪里。主机屋是普通的虚拟主机,搭建的时候只要把数据库导入数据库,然后把网站上传到服务器上就可以了。但是sae的架构不一样,但是理解起来也简单。sae采用的是分布式的架构,你的资源和你的数据库是保存在别的服务器上的,比如其附件是单独存在saestorage中,不能存放在代码目录中的,这些问题我想还好理解。同时也理解了大型应用是如何处理这些压力的。

废话少说,首先通过ftp把主机屋上的网站下载到本地。数据库通过主机屋提供的 PHPMyAdmin进行全部备份到本地。如果不确定有没有没问题的话可以先在本地搭建环境跑一边。

然后创建一个php应用 具体教程在这里

http://sae.sina.com.cn/?m=devcenter&catId=20

但是。。。。。 sae如果直接装我们自己搭建的wordpress会有很多问题的,因为它是分布式的架构,一种简便的方法是我们之间创建一个WordPress for SAE 地址在:http://sae.sina.com.cn/?m=apps&a=detail&aid=1

安装完成后我们找到创建的应用〉服务管理〉管理Mysql 进入phpMyAdmin管理界面 里面的表全删掉,然后导入我们 之前从主机屋上备份的sql文件。

然后在本地创建一个空文件夹,用TortoiseSVN迁出版本库中的文件到空白文件夹中。svn具体教程在

http://sae.sina.com.cn/?m=devcenter&a=index&catId=212

下一步我把我们之前本地的网站中的 wp-contentuploads文件夹单独剪切出来,其它文件拷贝到版本库中,(就是你迁出的那个默认目录是 1) 注意同名不要覆盖掉版本库中的文件,然后commit 到服务器上。

然后利用另外一个工具cyberduck 把文件提交到saeStorage中,

也可以在

下载地址:

http://src.sae.sinacdn.com/clients/Cyberduck-Installer-4.2.1.exe

使用方法

http://sae.sina.com.cn/?m=devcenter&catId=204&content_id=375

同时可以在服务管理〉storage中查看更多内容。。

 

最后 如果少的话慢慢修改你文章中 相册中的附件地址吧(要改成storage中的地址,比如

http://应用名-wordpress.stor.sinaapp.com/uploads/xxx.jpg)。如果多的用sql要快很多(这个你就自己去写吧).