[转载]“Heartbleed”漏洞恐令数十万服务器泄密 | 36氪

mikel阅读(878)

[转载]“Heartbleed”漏洞恐令数十万服务器泄密 | 36氪.

“Heartbleed”漏洞恐令数十万服务器泄密

据专家透露,运行特定版本 OpenSSL 的 web 服务器均存在一个名为“Heartbleed”的漏洞,黑客利用此漏洞可盗走网站用于加密在线交易和 web 连接的密钥,并导致用户在进行搜索或邮箱登录时个人信息被泄露。

SSL(安全套接层)协议是使用最为普遍网站加密技术,而 OpenSSL 则是开源的 SSL 套件,为全球成千上万的 web 服务器所使用。Web 服务器正是通过它来将密钥发送给访客然后在双方的连接之间对信息进行加密。URL 中使用 https 打头的连接都采用了 SSL 加密技术。在线购物、网银等活动均采用 SSL 技术来防止窃密及避免中间人攻击

Heartbleed 漏洞之所以得名,是因为用于安全传输层协议(TLS)及数据包传输层安全协议(DTLS)的 Heartbeat 扩展存在漏洞。Heartbeat 扩展为 TLS/DTLS 提供了一种新的简便的连接保持方式,但由于 OpenSSL 1.0.2-beta 与 OpenSSL 1.0.1 在处理 TLS heartbeat 扩展时的边界错误,攻击者可以利用漏洞披露连接的客户端或服务器的存储器内容,导致攻击者不仅可以读取其中机密的加密数据,还能盗走用于加密的密钥。

据估计受影响的服务器数量可能多达几十万。其中已被确认受影响的网站包括 Imgur、OKCupid、Eventbrite 以及 FBI 网站等,不过 Google 未受影响。

此外,漏洞还可能导致用户信息的泄露。比方说黑客已经可以利用此漏洞通过查看最近访问受影响服务器的用户的 cookie 来获取其个人信息。已有开发者报告说发现可利用此漏洞查看到以保护用户隐私出名的搜素引擎 DuckDuckGo 上的用户搜索记录,Yahoo 也被发现存在此漏洞导致用户凭证的泄露

该漏洞 2011 年就已经被引入,但直到最近才被人发现。受影响服务器必须给自己的 OpenSSL 打上补丁,同时还需要更改密钥才能避免进一步受到影响。专家建议,为了免受此漏洞影响,用户最安全的应对措施是最近几天都不要参与敏感的网上活动,如购物、使用网银等。

漏洞的介绍视频:

[消息来源:theguardian.com]

[转载]浅谈抓取网页数据(奉上Demo) - fzl - 博客园

mikel阅读(860)

[转载]浅谈抓取网页数据(奉上Demo) – fzl – 博客园.

Demo源码

背景

曾经在公司做过一个比价系统,就是抓取其它网站上商品的价格并和自己公司的商品进行对应,然后展示出来,给pm提供一个定价的参考。后来,有同 事的朋友在找工作的时候,猎头让其做一个抓取去哪网最低价机票的程序,然后,我就帮忙整了一下。本文的目的在于提供这个程序的源码,然后和大家探讨一下网 页信息抓取的相关点。Demo使用C#并在vs2012环境下运行。

项目结构一览

下面是Demo的项目结构图:

运行结果

下面是Demo的运行结果图:

思路&问题分析

  • 个人以为,网页信息的获取分为两个阶段:1 知道目标网页和相关参数,并获取网页的源码 2 将获取到的源码抽取出我们需要的信息,并转换成C#对象
  • 在Demo中的HttpHelper.cs文件下的类的职责就是设定目标网页地址和相关参数,该类是在网上找到的,据说可以无视cookie、证书等验证,很牛,推荐小伙伴们使用,所以,第一个目标是比较容易能够完成的
  • 难点在于第二个目标,我们如何抓取html源码(json数据)中的有效信息并转换成我们需要的c#对象呢?Demo中获取的是json数据,然 后用正则抓出了其中的一部分,再转换成一个实体类的列表。Demo中的AsyncRegexHelper是异步的正则匹配帮助类,在使用正则匹配的过程 中,经常遇到无限回溯的问题,使用这个帮助类可以异步地执行匹配并且有一个超时时间。现在碰到的问题是正则匹配比较不靠谱,难度较大且不易扩展,目前打算 想用Html Agility Pack来进行数据的匹配,希望伙伴们能指点下,谢谢大家。

总结

本人文笔拙劣,感谢大家的支持。提供源码,大家分享一下,希望能做一个通用点的系统,只需要输入网址和一些简单的规则,就能够获取我们所需要的信息。

Demo源码

[转载]ASP.NET MVC下的四种验证编程方式 - Artech - 博客园

mikel阅读(1023)

[转载]ASP.NET MVC下的四种验证编程方式 – Artech – 博客园.

ASP.NET MVC采用Model绑定为目标Action生成了相应的参数列表,但是在真正执行目标Action方法之前,还需要对绑定的参数实施验证以确保其有效 性,我们将针对参数的验证成为Model绑定。总地来说,我们可以采用4种不同的编程模式来进行针对绑定参数的验证。

一、手工验证绑定的参数

在 定义具体Action方法的时候,对已经成功绑定的参数实施手工验证无疑是一种最为直接的编程方式,接下来我们通过一个简单的实例来演示如何将参数验证逻 辑实现在对应的Action方法中,并在没有通过验证的情况下将错误信息响应给客户端。我们在一个ASP.NET MVC应用中定义了如下一个Person类作为被验证的数据类型,它的Name、Gender和Age三个属性分别表示一个人的姓名、性别和年龄。

public class Person
{
    [DisplayName("姓名")]
    public string Name { get; set; }

    [DisplayName("性别")]
    public string Gender { get; set; }

    [DisplayName("年龄")]
    public int? Age { get; set; }
}

接下来我们定义了如下一个HomeController。在针对GET请求的Action方法Index中,我们创建了一个Person对象并将其 作为Model呈现在对应的View中。另一个支持POST请求的Index方法具有一个Person类型的参数,我们在该Action方法中先调用 Validate方法对这个输入参数实施验证。如果验证成功(ModeState.IsValid属性返回True),我们返回一个内容为“输入数据通过 验证”的ContentResult,否则将此参数作为Model呈现在对应的View中。

public class HomeController : Controller
{
    [HttpGet]
    public ActionResult Index()
    {
        return View(new Person());
    }

    [HttpPost]
    public ActionResult Index(Person person)
    {
        Validate(person);

        if (!ModelState.IsValid)
        {
            return View(person);
        }
        else
        {
            return Content("输入数据通过验证");
        }
    }

    private void Validate(Person person)
    {
        if (string.IsNullOrEmpty(person.Name))
        {
            ModelState.AddModelError("Name", "'Name'是必需字段");
        }

        if (string.IsNullOrEmpty(person.Gender))
        {
            ModelState.AddModelError("Gender", "'Gender'是必需字段");
        }
        else if (!new string[] { "M", "F" }.Any(
            g => string.Compare(person.Gender, g, true) == 0))
        {
            ModelState.AddModelError("Gender", 
            "有效'Gender'必须是'M','F'之一");
        }

        if (null == person.Age)
        {
            ModelState.AddModelError("Age", "'Age'是必需字段");
        }
        else if (person.Age > 25 || person.Age < 18)
        {
            ModelState.AddModelError("Age", "有效'Age'必须在18到25周岁之间");
        }
    }
}

如上面的代码片断所示,我们在Validate该方法中我们对作为参数的Person对象的3个属性进行逐条验证,如果提供的数据没有通过验证,我 们会调用当前ModelState的AddModelError方法将指定的验证错误消息转换为ModelError保存起来。我们采用的具体的验证规则 如下。

  • Person对象的Name、Gender和Age属性均为必需字段,不能为Null(或者空字符串)。
  • 表示性别的Gender属性的值必需是“M”(Male)或者“F”(Female),其余的均为无效值。
  • Age属性表示的年龄必须在18到25周岁之间。

如下所示的是Action方法Index对应View的定义,这是一个Model类型为Person的强类型View,它包含一个用于编辑人员信息 的表单。我们直接调用HtmlHelper<TModel> 的扩展方法EditorForModel将作为Model的Person对象以编辑模式呈现在表单之中。

@model Person
<html>
<head>
    <title>编辑人员信息</title>
</head>
<body>
    @using (Html.BeginForm())
    { 
        @Html.EditorForModel()
        <input type="submit" value="保存"/>
    }
</body>
</html>
直接运行该程序后,一个用于编辑人员基本信息的页面会被呈现出来,如果我们在输入不合法的数据并提交后,相应的验证信息会以图1所示的形式呈现出来。

二、使用ValidationAttribute特性

将针对输入参数的验证逻辑和业务逻辑定义在Action方法中并不是一种值得推荐的编程方式。在大部分情况下,同一个数据类型在不同的应用场景中具 有相同的验证规则,如果我们能将验证规则与数据类型关联在一起,让框架本身来实施数据验证,那么最终的开发者就可以将关注点更多地放在业务逻辑的实现上 面。实际上这也是ASP.NET MVC的Model验证系统默认支持的编程方式。当我们在定义数据类型的时候,可以在类型及其数据成员上面应用相应的 ValidationAttribute特性来定义默认采用的验证规则。

“System.ComponentModel.DataAnnotations”命名空间定义了一系列具体的 ValidationAttribute特性类型,它们大都可以直接应用在自定义数据类型的某个属性上对目标数据成员实施验证。这些预定义验证特性不是本 章论述的重点,我们会在“下篇”中对它们作一个概括性的介绍。

常规验证可以通过上面列出的这些预定义ValidationAttribute特性来完成,但是在很多情况下我们需要通过创建自定义的 ValidationAttribute特性来解决一些特殊的验证。比如上面演示实例中针对Person对象的验证中,我们要求Gender属性指定的表 示性别的值必须是“M/m”和“F/f”两者之一,这样的验证就不得不通过自定义的ValidationAttribute特性来实现。

针对 “某个值必须在指定的范围内”这样的验证规则,我们定义一个DomainAttribute特性。如下面的代码片断所示,DomainAttribute 具有一个IEnumerable<string>类型的只读属性Values提供了一个有效值列表,该列表在构造函数中被初始化。具体的验证 实现在重写的IsValid方法中,如果被验证的值在这个列表中,则视为验证成功并返回True。为了提供一个友好的错误消息,我们重写了方法 FormatErrorMessage。

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field,   AllowMultiple = false)]
public class DomainAttribute : ValidationAttribute
{
    public IEnumerable<string> Values { get; private set; }

    public DomainAttribute(string value)
    {
        this.Values = new string[] { value };
    }

    public DomainAttribute(params string[] values)
    {
        this.Values = values;
    }

    public override bool IsValid(object value)
    {
        if (null == value)
        {
            return true;
        }
        return this.Values.Any(item => value.ToString() == item);
    }

    public override string FormatErrorMessage(string name)
    {
        string[] values = this.Values.Select(value => string.Format("'{0}'",  value)).ToArray();
        return string.Format(base.ErrorMessageString, name,string.Join(",",   values));
    }
}

由于ASP.NET MVC在进行参数绑定的时候会自动提取应用在目标参数类型或者数据成员上的ValidationAttribute特性,并利用它们对提供的数据实施验 证,所以我们不再需要像上面演示的实例一样自行在Action方法中实施验证,而只需要在定义参数类型Person的时候应用相应的 ValidationAttribute特性将采用的验证规则与对应的数据成员相关联。

如下所示的是属性成员上应用了相关ValidationAttribute特性的Person类型的定义。我们在三个属性上均应用了 RequiredAttribute特性将它们定义成必需的数据成员,Gender和Age属性上则分别应用了DomainAttribute和 RangeAttribute特性对有效属性值的范围作了相应限制。

public class Person
{
    [DisplayName("姓名")]
    [Required(ErrorMessageResourceName = "Required",    ErrorMessageResourceType = typeof(Resources))]
    public string Name { get; set; }

    [DisplayName("性别")]
    [Required(ErrorMessageResourceName = "Required",   ErrorMessageResourceType = typeof(Resources))]
    [Domain("M", "F", "m", "f", ErrorMessageResourceName = "Domain",  ErrorMessageResourceType = typeof(Resources))]
    public string Gender { get; set; }

    [DisplayName("年龄")]
    [Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(Resources))]
    [Range(18, 25, ErrorMessageResourceName = "Range",  ErrorMessageResourceType = typeof(Resources))]
    public int? Age { get; set; }
}

三个ValidationAttribute特性采用的错误消息均定义在项目默认的资源文件中(我们可以采用这样的步骤创建这个资源文件:右键选择 Solution Exploror中的项目,并在上下文菜单中选择“属性”选项打开“项目属性”对象框。最后在对话框中选择“资源”Tab页面,通过点击页面中的链接创建 一个资源文件),具体定义如图2所示。

由于ASP.NET MVC会自动提取应用在绑定参数类型上的ValidationAttribute特性对绑定的参数实施自动化验证,所以我们根本不需要在具体的 Action方法中来对参数作手工验证。如下面的代码片断所示,我们在Action方法Index中不再显式调用Validate方法,但是运行该程序并 在输入不合法数据的情况下提交表单后依然会得到如图1所示的输出结果。

public class HomeController : Controller
{
    //其他成员
    [HttpPost]
    public ActionResult Index(Person person)
    {
        if (!ModelState.IsValid)
        {
            return View(person);
        }
        else
        {
            return Content("输入数据通过验证");
        }
    }
}

三、让数据类型实现IValidatableObject接口

除了将验证规则通过ValidationAttribute特性直接定义在数据类型上并让ASP.NET MVC在进行参数绑定过程中据此来验证参数之外,我们还可以将验证操作直接定义在数据类型中。既然我们将验证操作直接实现在了数据类型上,意味着对应的数 据对象具有“自我验证”的能力,我们姑且将这些数据类型称为“自我验证类型”。这些自我验证类型是实现了具有如下定义的接口 IValidatableObject,该接口定义在“System.ComponentModel.DataAnnotations”命名空间下。

public interface IValidatableObject
{
    IEnumerable<ValidationResult> Validate(  ValidationContext validationContext);
}

如上面的代码片断所示,IValidatableObject接口具有唯一的方法Validate,针对自身的验证就实现在该方法中。对于上面演示实例中定义的数据类型Person,我们可以按照如下的形式将它定义成自我验证类型。

public class Person: IValidatableObject
{
    [DisplayName("姓名")]
    public string Name { get; set; }

    [DisplayName("性别")]
    public string Gender { get; set; }

    [DisplayName("年龄")]
    public int? Age { get; set; }

    public IEnumerable<ValidationResult> Validate( ValidationContext validationContext)
    {
        Person person = validationContext.ObjectInstance as Person;
        if (null == person)
        {
            yield break;
        }
        if(string.IsNullOrEmpty(person.Name))
        {
            yield return new ValidationResult("'Name'是必需字段", new string[]{"Name"});
        }

        if (string.IsNullOrEmpty(person.Gender))
        {
            yield return new ValidationResult("'Gender'是必需字段", new string[] { "Gender" });
        }
        else if (!new string[]{"M","F"}.Any( g=>string.Compare(person.Gender,g, true) == 0))
        {
            yield return new ValidationResult("有效'Gender'必须是'M','F'之一",   new string[] { "Gender" });
        }

        if (null == person.Age)
        {
            yield return new ValidationResult("'Age'是必需字段",    new string[] { "Age" });
        }
        else if (person.Age > 25 || person.Age < 18)
        {
            yield return new ValidationResult("'Age'必须在18到25周岁之间",    new string[] { "Age" });
        }            
    }
}

如上面的代码片断所示,我们让Person类型实现了IValidatableObject接口。在实现的Validate方法中,我们从验证上下 文中获取被验证的Person对象,并对其属性成员进行逐个验证。如果数据成员没有通过验证,我们通过一个ValidationResult对象封装错误 消息和数据成员名称(属性名),该方法最终返回的是一个元素类型为ValidationResult的集合。在不对其他代码作任何改动的情况下,我们直接 运行该程序并在输入不合法数据的情况下提交表单后依然会得到如图1所示的输出结果。

四、让数据类型实现IDataErrorInfo接口

上面我们让数据类型实现IValidatableObject接口并将具体的验证逻辑定义在实现的Validate方法中,这样的类型能够被 ASP.NET MVC所识别,后者会自动调用该方法对绑定的数据对象实施验证。如果我们让数据类型实现IDataErrorInfo接口也能实现类似的自动化验证效果。

IDataErrorInfo接口定义在“System.ComponentModel”命名空间下,它提供了一种标准的错误信息定制方式。如下面 的代码片段所示,IDataErrorInfo具有两个成员,只读属性Error用于获取基于自身的错误消息,而只读索引用于返回指定数据成员的错误消 息。

public interface IDataErrorInfo
{
    string Error { get; }
    string this[string columnName] { get; }
}

同样是针对上面演示的实例,现在我们对需要被验证的数据类型Person进行了重新定义。如下面的代码片断所示,我们让Person实现了 IDataErrorInfo接口。在实现的索引中,我们将索引参数columnName视为属性名称,根据它按照上面的规则对相应的属性成员实施验证, 并在验证失败的情况下返回相应的错误消息。在不对其他代码作任何改动的情况下,我们直接运行该程序并在输入不合法数据的情况下提交表单后依然会得到如图1 所示的输出结果。

public class Person : IDataErrorInfo
{
    [DisplayName("姓名")]
    public string Name { get; set; }

    [DisplayName("性别")]
    public string Gender { get; set; }

    [DisplayName("年龄")]
    public int? Age { get; set; }

    [ScaffoldColumn(false)]
    public string Error { get; private set; }

    public string this[string columnName]
    {
        get 
        {
            switch (columnName)
            {
                case "Name":
                    { 
                        if(string.IsNullOrEmpty(this.Name))
                        {
                            return "'姓名'是必需字段";
                        }
                        return null;
                    }
                case "Gender":
                    {
                        if (string.IsNullOrEmpty(this.Gender))
                        {
                            return "'性别'是必需字段";
                        }
                        else if (!new string[] { "M", "F" }.Any(
                            g => string.Compare(this.Gender, g, true) == 0))
                        {
                            return "'性别'必须是'M','F'之一";
                        }
                        return null;
                    }
                case "Age":
                    {
                        if (null == this.Age)
                        {
                            return "'年龄'是必需字段";
                        }
                        else if (this.Age > 25 || this.Age < 18)
                        {
                            return "'年龄'必须在18到25周岁之间";
                        }
                        return null;
                    }
                default: return null;

            }
        }
    }
}

[转载]聊一聊,程序员的恶性循环!-移动开发者社区_Android开发

mikel阅读(818)

[转载]聊一聊,程序员的恶性循环!-移动开发者社区_Android开发.

穷人的恶性循环:

  穷 -> 需要努力工作 -> 没有时间去交际 -> 人脉越来越狭窄 -> 工作越来越难做 -> 越需要努力去工作 -> 越没有时间去发展人脉 -> 越穷

富人的良性循环:
  有钱 -> 工作很轻松 -> 很多时间都在交际上 -> 人脉越来越广 -> 工作越来越不用努力 -> 越有更多的时间精力去发展人脉 -> 越富有 

程序员的恶性循环:
  加班 -> 没空学习 -> 老是写同等水平代码 -> 无法提升代码质量 -> 老是出BUG -> 老是需要修改 -> 加班 -> ….
1.想到个事情,IP5都出来的时候,我还是在用那种只能打电话接电话的直板手机,每次公司聚会的时候,老总给每个人发邮件,大家都拿出触屏的来收邮件,唯独自己一个人还是那种最老的手机 —— 三星E110C,当时自己真恨不得找个地洞钻下去,完全来错了地方一样。上司都说你每个月工资也五六K了,怎么不换个好一点的手机?穷惯了,舍不得,所受的教育一定要节俭,思想斗争,还是坚持节俭。舍不得花三四K买个好的手机。。。从小穷惯了节俭惯了,思想迂腐,只知道省钱不知道投资。

2.还 想到一个事情,我在广州天河太古汇那上班,中午吃饭,每次都不敢进那种装修好一点的餐馆吃饭。总觉得那种地方贵吧,具体有多贵自己也说不出来也不知道,反 正就是一想到就觉得贵,舍不得心疼钱。然后我每次中午要跑很远去离工作地点很远的石牌城中村吃午餐,十多二十几块钱的一份盒饭,又不卫生人有超级多,但是 自己一直忍着,没办法没钱,穷命穷受罪。有一次忙一个东西实在是太远,一狠心就在上班的楼下那些餐馆吃饭吧,结果一看菜单,才发现哇靠原来这么便宜,10元一份的比比皆是,而且还有座位,环境比起城中村的那些没座位还脏兮兮的好不知道多少倍。突然之间我似乎明白出一些道理。


3.第三件事,我以前总是没有鞋子穿,不信可以看我以前在论坛水区发的贴,提问什么鞋子耐穿。那时候我每次都是找那种15 25元一双的亏本甩卖的鞋店去买鞋,里面都是15 25一双,但是我总会挑选5099一双的,为的是希望可以穿得久一点,不过很遗憾,每次都是最多2个月就破了报废了。然后每天都是没鞋子穿,每天都是穿着破鞋去上班,而屋里总是一大堆鞋子,但是都破了,每隔一两个月就要去这样的店铺买鞋子。后来偶然一次我算了一下,每月几乎要买一双鞋子,花费50993个月就是150,还不如买一双好一点的名牌鞋子试试。但由于一直穿的鞋子不管是25 还是 50 还是99都是不到2个月就坏了,所以更是不敢去买几百一双的鞋子。恶性循环!最后一次铤而走险,花了几百块去专卖店买了一双某牌子的鞋子(这里还是隐藏牌号,免得广告)。发现居然穿了3个月都没坏掉现在还一直穿着很好。从此之后我再也不进那种25元一双的鞋店买鞋子

4.第四件事,我用的第一部智能手机是HTC,G13。当时在车上、外面看到每个人用的都是HTC,认为HTC应该是非常不错的吧,ZOL手机上都拍第二了,很牛逼吧!于是花了将近2000块在国美买了一国行HTC。不过用了几个月就越来越卡,越来越慢,512M内存。一年保修期之后 刷机了,删除自带的软件了还是就只能打电话接电话了,根本算不上智能机了。之后对只能手机产生了严重的怀疑,科技这么发达,怎么一个排名第二的智能手机这么差,不说运行游戏就连QQ都运行不了了!最后想过换三星的手机,因为都是安卓的,担心又会像HTC这样,完全就只能打电话发短信。咬牙买苹果。其实我很高心自己当时能做这样的决定,用了才发现对比之下HTC根本就不能算智能手机!苹果512M内存都可以安装无数个软件应用,而 HTC G13安装了QQ QQ空间 QQ同步助手 UC浏览器 搜狗输入法就什么都装不了,且一运行就黑屏


第五件事,我在广州一家网络公司做网站程序员,月薪4K5,是我在武汉2K工资的2倍还多,心里非常哈皮,所以工作非常努力卖命。公司就我一个PHP程序员,一开始不怎么加班,但到最后我却弄得每天都加班,,,,撑了2年我最后还是累的主动辞职了,,,出来之后才发现这公司给的工资比行情低至少2K,,,,但我2年间根本从没去打探过行情,也没时间精力去打探,,,

[转载]【Java心得总结三】Java泛型上——初识泛型 - DreamTea - 博客园

mikel阅读(998)

[转载]【Java心得总结三】Java泛型上——初识泛型 – DreamTea – 博客园.

一、函数参数与泛型比较

泛型(generics),从字面的意思理解就是泛化的类型,即参数化类型。泛型的作用是什么,这里与函数参数做一个比较:

无参数的函数:

    public int[] newIntArray(){
        return new int[6];
    }

函数功能即返回一个大小为6的数组,但是这个函数只能返回固定大小为6的数组,如果想返回不同size的数组则还要重新编写函数。解决方法就是使用函数参数,传入一个代表数组大小的size。

有参数的函数:我们在写一个函数时,往往需要向函数传入一些参数,使得函数具有一定的通用性,完成某些特定的功能,如:

    public int[] newIntArray(int size){
        return new int[size];
    }

这是一个简单的函数,传入参数size,函数会生成相应大小的整型数组返回给我们。但是这里有一个限制,我们只能得到整型的数组,这就大大限制了这个函数的功能和可重用性,那么当我们想要得到一个浮点型数组时又要编写一个非常类似的函数。这里的解决办法就是使用泛型:

有参数且使用泛型的函数

    @SuppressWarnings("unchecked")
    public static <T> T[] newArray(int size) {
        Object array = new Object[size];
        return (T[])array;
    }

在函数内部我们使用了Object来新建数组,而不是直接用类型参数T直接声明(由于Java泛型的擦除所致,见【Java心得总结四】Java泛型中——万恶的擦除)。通过这个函数,我们就能够得到“任意大小任意类型”的数组。

总结:比较上面三个示例,我们就能理解为什么要有泛型这个概念了。在上面的示例中,每一级的例子都比前一级的例 子功能上更加扩展,可重用性更加的高。第一个示例我们只能得到固定大小的数组;为了更加泛化,我们使用参数传入size来得到不同大小的数组;同样为了得 到不同类型的数组,我们甚至将类型也作为参数传递入函数,从而得到任意大小任意类型的数组。

综上,我们利用泛型来解耦类或方法与所使用的类型之间的约束,将类型也作为一种参数传入,使得类或方法的可重用性大大提高。

二、泛型类

声明格式:

复制代码
public class Generics<K, V> {
    K k;
    V v;

    public Generics(K k, V v) {
        this.k = k;
        this.v = v;
    }
}
复制代码

泛型类的声明一般放在类名之后,可以有多个泛型参数,用尖括号括起来形成类型参数列表。

应用:

泛型类应用最广泛的就是我们在平时Java编程中最最常用到的容器类(博文后续),举一个容器的简单例子:

复制代码
import java.util.ArrayList;
import java.util.Date;
import java.util.Random;

public class RandomList<T> {
    private ArrayList<T> storage = new ArrayList<T>();
    private Random rand = new Random(new Date().getTime());

    public void add(T item) {
        storage.add(item);
    }

    public T select() {
        return storage.get(rand.nextInt(storage.size()));
    }
}
复制代码

这段代码将原有的ArrayList容器进行了封装,调用select函数会随机的返回一个列表中的元素。

三、泛型接口

声明格式:

public interface Generator<T> {
    public T next();
}

同泛型类的声明类似,在接口名之后,用尖括号将所有类型参数括起来。注:这里声明的是一个工厂设计模式常用的生成器接口。

应用:

我们平时编程最常见的泛型接口就是Iterable接口,即迭代器接口(博文后续),举一个简单的例子:

复制代码
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.Random;

public class RandomList<T> implements Iterable<T> {
    private ArrayList<T> storage = new ArrayList<T>();
    private Random rand = new Random(new Date().getTime());

    public void add(T item) {
        storage.add(item);
    }

    public T select() {
        return storage.get(rand.nextInt(storage.size()));
    }

    /* 实现Iterable接口 */
    public Iterator<T> iterator() {
        return storage.iterator();
    }
}
复制代码

还是上面泛型类举得容器例子,这次我们给RandomList类部署了Iterable接口,这样我们就可以利用foreach语句对RandomList中的元素进行遍历。

四、泛型方法

声明格式:

    public <T> T genericMethod(T t){
        return t;
    }

泛型方法的声明和泛型类的声明略有不同,它是在返回类型之前用尖括号列出类型参数列表,而函数传入的形参类型可以利用泛型来表示。

应用:

见文章开头的例子。

五、Java泛型的局限性

1.基本类型【Java心得总结一】Java基本类型和包装类型解析无法作为类型参数即ArrayList<int>这样的代码是不允许的,如果为我们想要使用必须使用基本类型对应的包装器类型ArrayList<Integer>

2.在泛型代码内部,无法获得任何有关泛型参数类型的信息(见【Java心得总结四】Java泛型中——万恶的擦除)。换句话说,如果传入的类型参数为T,即你在泛型代码内部你不知道T有什么方法,属性,关于T的一切信息都丢失了(类型信息,博文后续)。

3.注,在能够使用泛型方法的时候,尽量避免使整个类泛化。

 

[转载]微信公众平台开发基础概念 - Luminji - 博客园

mikel阅读(962)

[转载]微信公众平台开发基础概念 – Luminji – 博客园.

一:如何开始

1:如果没有公众帐号,可以先申请一个测试帐号:http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login

2:登录之后界面是这样滴:

image

3:接下来,我需要准备自己的网站,然后发布自己的 URL。于是,我用 ASP.NET 写了一个 WeixinTest.ashx,其代码如下:

public void ProcessRequest(HttpContext context)
{
string echoStr = HttpContext.Current.Request.QueryString[“echoStr”];
string signature = HttpContext.Current.Request.QueryString[“signature”];
string timestamp = HttpContext.Current.Request.QueryString[“timestamp”];
string nonce = HttpContext.Current.Request.QueryString[“nonce”];

if (!string.IsNullOrEmpty(echoStr))
{
HttpContext.Current.Response.Write(echoStr);
HttpContext.Current.Response.End();
}
}

在自己的服务器上发布了这个网站后,我们填写地址和 TOKEN(注意,我的测试代码中并没有验证这个 TOKEN)。然后在上文图中点击 提交 后,得到了这个界面:

image

以上界面的出现即意味这提交成功。

4:用手机上微信扫一扫刚才的二维码后发生了什么?

上面说到了这个测试的公众号在管理端的表现,那么如果关注了它,你自己的微信发生了什么变化。是的,它出现在了你的订阅号中。话说,一开始我以为这 个测试号不是服务号呢就不能享受一些高级功能。不过,不会的,既然是测试号,就应该让我测的快乐高兴,于是,我们来看看如何生成菜单。不过,先稍后,我们 首先来理清下思路,看看微信公众号的数据流转到底是个怎么回事。如果没有理清这点,你就会跟我一样,一天内都摸不清头脑。

二:关于数据流转

1:注册测试帐号

注册测试帐号,是在微信的网站上完成的,输入 url 和 token,则表明我们已经创建了这个公众号。

2:关注了你的公众号的他人如何与你互动

当有人关注了这个公众号,他首先访问的就是这个我们在创建时刻使用的 url,没错,该 url 很重要。注册的时候,微信的网站会访问它,看它合法否。注册成功后,该 url 就成为他人在手机上使用微信来跟你互动的唯一地址。

3:你如何推送内容给他人

这就分为两个部分了,

第一个情形:通过在微信网站上配置信息或者调用微信接口,我们就让我们的公众号绑定了一些信息:如自定义菜单。这样,当他人关注公众号的时候,就能看到自定义菜单等信息;

第二个情形:第一种情形我们理解为配置阶段,那么第二种情形就是真正的开发阶段了,在这个阶段,我们接收用户的消息 (text,click,view 等),然后用户的消息,推送给用户 text,image,网站页面(可以跟你的 url 是一个网站,也可以是第三方网站)。

你可以推送这些信息给他人:自定义菜单

 

三:实例-如何生成自定义菜单

这就是上文中所说到的第一种情形。既然,它实际上跟真正的微信开发没有多大关系,或者说你可以独立写段代码来完成调用接口从而配置信息,那么好吧,我就用微信自己提供的程序吧:

image

记住,输入的必须是 JSON 格式的内容,要满足其格式要求,可以参考微信的开发者档案。

然后我们取消之前的关注,从新再关注公众号,就能看到这个新创建的菜单了(注意,有延迟,若不愿意等,则可以换个其它的微信号关注下,就出来了)。由于我手机不能拍摄自己,这里就不出效果图了。

3.1 关于 access_token

注意,在这里,我们还需要输入一个 access_token,这个值我们同样也可以使用这个接口调试工具获得:

image

需要值得注意的是,该值是有失效期。

 

四:实例-一个真正的 url 处理程序

public void ProcessRequest(HttpContext param_context)
{
if (HttpContext.Current.Request.HttpMethod.ToUpper() == “POST”)
{
using (Stream stream = HttpContext.Current.Request.InputStream)
{
Byte[] postBytes = new Byte[stream.Length];
stream.Read(postBytes, 0, (Int32)stream.Length);
Handle(Encoding.UTF8.GetString(postBytes));
}
}
else
{
Auth();
}
}

为什么要做个判断是 POST 呢?因为申请公众号的时候的,微信网站对这个 url 的验证是使用 GET 进行了,那样,我们就可以用 Auth 这个方法了,而交互,则是用 POST 进行的。接下来,我们可以开始做真正意义上的微信开发了:)~~

 

参考:

1:开发者档案,http://mp.weixin.qq.com/wiki/index.php?title=%E5%BC%80%E5%8F%91%E8%80%85%E8%A7%84%E8%8C%83

[转载]【高德地图API】如何用云图记录生活(旅游app,美食记录,免费停车,通讯录都适用) - 酸奶小妹 - 博客园

mikel阅读(1059)

[转载]【高德地图API】如何用云图记录生活(旅游app,美食记录,免费停车,通讯录都适用) – 酸奶小妹 – 博客园.

摘要:记录每天的生活轨迹,分享美食心得,哪里有免费停车,制作班级通讯录等等,都可以用到云图。无论你是开发者,还是app用户,都可以用云图制作一张属于你的专属地图。

———————————————————————————————————

一、通过坐标拾取工具得到经纬度:

http://zhaoziang.com/amap/picpoint.html

(当然,如果你是开发者,你可以使用定位SDK,获取自己的经纬度,详见:http://api.amap.com/location/index )

 

二、建立自己的数据表

( 数据保存为CSV格式哟)

tag,name,lng,lat,tel,content
免费停车场,免费停车场001,116.430359,39.958175,010-52294832,停过5次没贴条
免费停车场,免费停车场002,116.279297,40.00132,010-52294832,停过1次没贴条
免费停车场,免费停车场003,116.202393,39.825413,010-52294832,停过2次没贴条
免费停车场,免费停车场004,116.564941,39.835959,010-52294832,停过7次没贴条
免费停车场,免费停车场005,116.437225,39.806426,010-52294832,停过20次没贴条
通讯录,酸奶小妹,116.441345,39.961333,18393727348,喝酸奶补钙
通讯录,吴蔚,116.374054,39.957122,15000038375,蹦跶的幽默感
通讯录,王倩,116.233978,39.943436,1348377294,房姐白富美
通讯录,张小颖,116.353455,39.929748,1869393933,精明俏主妇
美食记录,望京总店马兰拉面,116.183167,40.022356,010-39382872,嘴巴起泡都要吃!西安辣椒爽到翻!
美食记录,绿茶,116.411133,39.992904,010-39382872,就是便宜啊,麻婆豆腐才8元。港丽你敢这么卖麽?
美食记录,西贝莜面村,116.507263,39.855992,010-39382872,猜拳赢了115元!老板叫了11个黄馍馍,11个莜面!
美食记录,酷圣石,116.133728,39.880235,010-39382872,K总最爱的酷石头,全北京最好吃冰淇淋。其实量太大,吃不完就化掉了。
美食记录,吉野家,116.336975,39.886558,010-39382872,有学生卡啊,就去买啊。
美食记录,鹿港小镇,116.383667,39.916056,010-39382872,海南鸡饭比三亚的还好吃!爱,赞!
美食记录,星巴克,116.523743,40.008683,010-39382872,如果不是傻2的买了2张98的会员卡,你以为我会去消费麽!
旅行记录,天安门,116.483917,39.91395,010-283764648,我爱北京天安门
旅行记录,红螺寺,116.419373,39.941331,010-283764648,爬山,没看到寺庙
旅行记录,大觉寺,116.411133,39.889719,010-283764648,玉兰花美,银杏树大
旅行记录,鸟巢,116.27655,39.838068,010-283764648,住的地方,空气好点
旅行记录,大兴西瓜村,116.433105,39.785323,010-283764648,西瓜贵死人

 

将数据导入云图:

http://yuntu.amap.com/datamanager/index.html

 

当然,如果你没那么多记录,一次不能导入那么多数据的话。你可以每天记录一点点哟!

点击右上角的按钮,可以手工输入一个点哦!

 

三、建立索引(这步灰常重要!很多开发者因为没建立索引,而导致无法检索到自己数据哦)

 

文本索引

 

塞选排序索引

 

 

四、好啦,要开始写代码啦。

不用担心,我都写好在这里了,你直接copy去用吧。

当然更多复杂功能,你可以看看官网的开发指南啊,类参考啊,示例啊。http://api.amap.com/yuntu/guide

(如果你是移动端的开发者,可以使用REST API,就是webservice服务,来获取json数据,并展示在自己的应用上。)

var mapObj;
//初始化地图对象,加载地图
function mapInit(){
mapObj = new AMap.Map("iMap",{center:new AMap.LngLat(116.39946,39.907629),level:10});
addCloudLayer(); //用于展示麻点图
}
//叠加云数据图层
function addCloudLayer() {
//清除地图上数据
mapObj.clearMap();
//加载云图层插件
mapObj.plugin('AMap.CloudDataLayer', function () {
var layerOptions = {
query:{keywords: ''},
clickable:true
};
cloudDataLayer = new AMap.CloudDataLayer('533ccc56e4b08ebff7d539eb', layerOptions); //实例化云图层类
cloudDataLayer.setMap(mapObj); //叠加云图层到地图

AMap.event.addListener(cloudDataLayer, 'click', function (result) {
var clouddata = result.data;
var infoWindow = new AMap.InfoWindow({
content:"
<h3>"+ clouddata._name + "</h3>
" + "

分类:" + clouddata.tag + "

一句话:"+ clouddata.content +"

",
size:new AMap.Size(300, 0),
autoMove:true,
offset:new AMap.Pixel(0,-5)
});
infoWindow.open(mapObj, clouddata._location);
});
AMap.event.addListener(mapObj,"click",function(){
mapObj.clearInfoWindow();
});
});
}

清除图层


//清除图层
function clearMap(){
cloudDataLayer.setMap(null);
}

这次清除图层之后,要再次显示图层,需要重新建立地图对应关系。

cloudDataLayer.setMap(mapObj);

通过索引渲染图层,实时渲染的哦

//索引检索
function getType(tag){
cloudDataLayer.setMap(mapObj);
var op={
query:{keywords:tag}
}
cloudDataLayer.setOptions(op);
}

效果展示图:

 

demo地址:http://zhaoziang.com/amap/mydata.html

 

注册你自己的key,填在源代码里哦:http://api.amap.com/key/index

全部源代码:

<!DOCTYPE HTML>  
<html>  
<head>  
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">  
<title>酸奶小妹-毕设-自有数据</title>  
<style type="text/css">
div,h2{border:none;padding:0;margin:0;line-height:1em;}
#iMap{height:500px;width:600px;float:left;}
.info{width:300px;float:left;margin:0 0 0 10px;height:500px;}
label{width:80px;float:left;}
.menu a{text-decoration:none;}
.detail{border:1px solid #33ffef;padding:10px 0;display:none;}
</style>
<script language="javascript" src="http://webapi.amap.com/maps?v=1.2&key=填写你的key"></script>  
</head>  
<body onLoad="mapInit()">  
    <div id="iMap"></div>
    <div class="info" id="info">
        <h1>查询自己的数据</h1>
        <div class="menu">
            <p><a href="javascript:void(0);" onclick="getType('免费停车场|通讯录|美食记录|旅行记录');"> 全部自有数据</a></p>
            <p><a href="javascript:void(0);" onclick="clearMap();"> 清除图层</a></p>
            <p>
                <a href="javascript:void(0);" onclick="getType('免费停车场')"> 免费停车场</a>
                <a href="javascript:void(0);" onclick="getType('通讯录')"> 通讯录</a>
                <a href="javascript:void(0);" onclick="getType('美食记录')"> 美食记录</a>
                <a href="javascript:void(0);" onclick="getType('旅行记录')"> 旅行记录</a>
            <p>
        </div>
        <div class="detail" id="detail"></div>
    </div>
<!-- tongji begin-->
<script type="text/javascript">
var _bdhmProtocol = (("https:" == document.location.protocol) ? " https://" : " http://");
document.write(unescape("%3Cscript src='" + _bdhmProtocol + "hm.baidu.com/h.js%3Faeff88f19045b513af7681b011cea3bd' type='text/javascript'%3E%3C/script%3E"));
</script>
<!-- tongji end -->
</body>  
<script language="javascript">  
var mapObj;  
var keywords;
var cloudDataLayer;
var marker = new Array();  
var windowsArr = new Array();  
//初始化地图对象,加载地图  
function mapInit(){  
    mapObj = new AMap.Map("iMap",{center:new AMap.LngLat(116.39946,39.907629),level:10});      
    addCloudLayer();  //用于展示麻点图
    cloudSearch();  //查询出来的数据,用于展示在右侧详细数据
}  
function cloudSearch(){
    mapObj.clearMap();  
    var arr = new Array();  
    //绘制多边形     
    arr.push(new AMap.LngLat(116.074677,40.121141));   
    arr.push(new AMap.LngLat(116.065063,39.702961));   
    arr.push(new AMap.LngLat(116.754456,39.718807));   
    arr.push(new AMap.LngLat(116.721497,40.135841));  
    var polygon = new AMap.Polygon({  
        map:mapObj,   
        path:arr,   
        strokeColor:"#3366FF",   
        strokeOpacity:0.2,   
        strokeWeight:2,   
        fillColor: "#3366FF",   
        fillOpacity: 0.2   
    });    
    var search;  
    var searchOptions = {  
        keywords:'免费停车场',  
        //orderBy:'_id:ASC'  
    };  
    //加载CloudDataSearch服务插件  
    mapObj.plugin(["AMap.CloudDataSearch"], function() {         
        search = new AMap.CloudDataSearch('533ccc56e4b08ebff7d539eb', searchOptions); //构造云数据检索类  
        AMap.event.addListener(search, "complete", cloudSearch_CallBack); //查询成功时的回调函数  
        AMap.event.addListener(search, "error", errorInfo); //查询失败时的回调函数  
        search.searchInPolygon(arr); //多边形检索  
    });  
}
//检索成功回调函数   
function cloudSearch_CallBack(data) {   
    var resultStr="";  
    var resultArr = data.datas;  
    var resultNum = resultArr.length;    
    for (var i = 0; i < resultNum; i++) {    
        resultStr += "分类:" + resultArr[i].tag;  
        addmarker(i, resultArr[i]);  
    }  
    mapObj.setFitView();  
    document.getElementById("detail").innerHTML = resultStr;  
}   
//检索错误回调函数  
function errorInfo(data) {  
    resultStr = data.info;  
    document.getElementById("detail").innerHTML = resultStr;  
} 
//叠加云数据图层  
function addCloudLayer() {  
    //清除地图上数据
    mapObj.clearMap();
    //加载云图层插件  
    mapObj.plugin('AMap.CloudDataLayer', function () {  
        var layerOptions = {   
            query:{keywords: ''},   
            clickable:true  
        };  
        cloudDataLayer = new AMap.CloudDataLayer('533ccc56e4b08ebff7d539eb', layerOptions); //实例化云图层类  
        cloudDataLayer.setMap(mapObj); //叠加云图层到地图 
        
        AMap.event.addListener(cloudDataLayer, 'click', function (result) {  
            var clouddata = result.data;  
            var infoWindow = new AMap.InfoWindow({  
                content:"<h3>"+ clouddata._name + "</h3>" + "<p>分类:" + clouddata.tag + "</p><p>一句话:"+ clouddata.content +"</p>",  
                size:new AMap.Size(300, 0),  
                autoMove:true,  
                offset:new AMap.Pixel(0,-5)  
            });                
            infoWindow.open(mapObj, clouddata._location);              
            document.getElementById("detail").innerHTML = "<h3>" + clouddata._id + "." + clouddata._name + "</h3><p>分类:" + clouddata.tag + "</p><p>一句话:" + clouddata.content + "</p>";
        });  
        AMap.event.addListener(mapObj,"click",function(){
            mapObj.clearInfoWindow();
        });        
    });  
}  
//索引检索
function getType(tag){
cloudDataLayer.setMap(mapObj);
    var op={
        query:{keywords:tag}
    }
    cloudDataLayer.setOptions(op);    
}
//清除图层
function clearMap(){
cloudDataLayer.setMap(null);
}
//点击空白处关闭信息窗口
document.getElementById("info").onclick = function(){
    mapObj.clearInfoWindow();
}
</script>  
</html>

[转载]cocos2d-x平台搭建菜鸟学习日志(二) Windows7+Eclipse+cocos2d-x平台搭建(无需Cygwin和VC) - 宇坤 - 博客园

mikel阅读(903)

[转载]【cocos2d-x】【平台搭建】菜鸟学习日志(二) Windows7+Eclipse+cocos2d-x平台搭建(无需Cygwin和VC) – 宇坤 – 博客园.

——一篇详尽的、条理的、面向纯菜鸟的 cocos2d-x 开发平台搭建攻略

0.写在前面

  经测试,本方法在 Windows XP 下同样适用。

  这是一篇充满怨念的攻略,中间穿插着作者怨念的吐槽。不过没关系,我已经把重点的部分加红了,不想看吐槽的同学直接照着红字和图片做就好了!

  那么接下来就正式开始吧!

  先看看这次平台搭建我们所用到的一些工具的下载包:

 

  3个官方zip包,名字中包含了它们的版本信息。如果它们的版本对你来说已经很旧了,那么这篇教程可能并不适合你。不过我相信它能给你带来一些重要的参考。

  先说说写这篇教程的初衷。

  首先我本身也是一个菜鸟。这几天和舍友想进行一些基于cocos2d-x的移动游戏开发方面的尝试。做开发自然避不开开发环境的搭建。

  平台的搭建是由我进行的。在互联网上查阅相关资料和参考实践的过程中,我发现虽然网上有大量的教程,但是其中大部分是过时的、繁琐的、不通用的、不清楚的。有些教程是对其他教程的直接引述。照着好多篇教程弄下来都没能成功。

  这是一个痛苦的过程。有时候信息太多了反而和没有信息是一样的。想做一件事却连第一步也迈不出去。

  于是我觉定在最终把平台搭建成功之后写一篇详细的最新的原创攻略供像我一样的菜鸟们参考。当然,终于有一天这篇攻略也会变得过时。不过还是很高兴地告诉正在阅读你的:这篇攻略最终问世了!

  然后说一说这篇教程的特点:

  首先,教程中提供的是一个简单的平台,你并不需要下载很多东西。并且通过简单的配置就可以运行了。

  得益于最新开发工具的支持,我们不必要配置麻烦的Cygwin了。

  其次,这个开发平台所需要的所有工具都是开源的/免费的。你可以通过官网来下载得到一切需要的工具,使用这个平台的同时你也是在为反盗版做贡献。

  顺便一说,不使用VC/VS并不是因为它不好,恰恰相反,VC对C++有更好的支持。但是网上下载到的VC通常都是破解 版。虽然VS的官网为我们的提供3个月的免费试用。想用VC的朋友可以去找找相关教程,使用也很简单。不想用VC的就跟着我做吧,反正咱们菜鸟这也够用 了!

  最后,本文凝练了众多的教程,去掉了它们过时的、无用的部分,尽量采用了可视化的、通用的操作方式。说实话,经过提炼,我发现现在各个工具的版本其实对编程人员已经十分友好了,整个过程十分简单,以至于我开始怀疑写这篇教程的必要性了。

  这篇教程的篇幅大,主要是因为我配了大量的图片,不是因为有大量的吐槽,真的不是因为有大量的吐槽!

1.安装Java

  做过安卓应用开发的同学应该知道安卓系统的最上层是用Java编制的一套API,所以一般的安卓应用开发是在Java环境下的。而Java作为一种优秀的跨平台高级语言,它的一大特色就是需要Java虚拟机的支持。

  所以我们的第一步就从能让Java跑起来的JAR开始说起。

  网上有很多教程叫我们安装JDK(Java Development Kit),即Java开发包,其中包含一些函数库 和编译程序等。其实不用这样,最新的Eclipse中已经集成了JDK,所以我们只需要安装一个 JRE(Java Runtime Environment),即Java运行环境,就可以了!至于Eclipse,不要急,稍后你就会看到了。

    安装JRE非常简单,进入官网:

    www.java.com/zh_CN/ (你也可以百度“JAVA”,第一个的官网就是了)

    你就能很显眼地看到“免费JAVA下载”的按钮了,点击,然后系统会自动给你找到适合你的JAVA,下载就可以了。如图:

 

    下载之后的安装和你平时安装软件是一样样的。

  等Java安装完之后,我们第一步工作也就做好啦!

2.获得Android SDK(Software Development Kit)

  Android SDK是官网提供给我们的安卓专用开发者工具包,里面包含了安卓定制的Eclipse、 ADT(Android Developer Tools)集、Android SDK工具、Android 平台通用工具以及最新的安卓平台版本(我这 里目前的版本是4.4.2,你也可以通过里面的SDK Manager下载其他版本的安卓来使用)。

  注意这里面包含了安卓定制的Eclipse!

  Eclipse是一个开源的、可扩展的基于Java的集成开发平台。以前做过Java开发的同学可能用过这个东西。网上有些教程就是基于原版的Eclipse,然后一步步添加诸如ADT的安卓开发插件,最终搭建起这个开发平台的。

  现在我告诉你:不用这样!安卓官网SDK里面自带定制好的Eclipse,你只要下载SDK,解压,拿里面的Eclipse出来就可以直接开发通常的安卓应用了!

    具体的下载地址是:

    http://developer.android.com/sdk/index.html

    进去之后就可以看到“Download the SDK”的按钮了。点击,阅读(你确定?)并同意相关条款,然后选择适合你机型的版本(我的是Windows7 32位系统,所以选择 32bit),下载就可以了。

    我直接下载到了D盘根目录下,你可以下载到任何你喜欢的位置。下载之后直接解压就可以了。如图:

 

 

3.下载cocos2d-x

  既然是基于cocos2d-x的安卓游戏开发,下载一个cocos2d-x当然也是必须的啦!Cocos2d-x是什么我就不多说了,问度娘去吧!我也是第一次接触,说不清这是什么。

    Cocos2d-x的下载当然也要去官网啦!

    http://cocos2d.cocoachina.com/download

  上面的地址是中国官网的下载页面。作为一个跨平台的游戏引擎,这里提供了适用于各个版本的cocos2d-x供我们下载。

    瞧好了,我们要下载的是稳定版!如图:

 

  你可能发现这里还提供不稳定版的v3.*。是的,v3版引入了很多不错的新特性。不过作为第一次接触这款引擎的菜鸟,还是用稳定的v2版本吧,网上的教程也多一些……

    下载包也是一个zip压缩包,解压到任意你喜欢的位置就行了。

 

4.为Eclipse添加CDT(C/C++ Development Tooling)插件

  再前面一些我们说到把SDK解压。解压后的文件夹里面就有一个 eclipse 包,里面的Eclipse就可以直接用 来编写通常的安卓应用了。然而,我们做的是基于cocos2d-x这个游戏引擎的安卓应用,这个游戏引擎的核心是C++的,然后通过交叉编译来生成各个平 台的安装包(可以说用这个引擎写游戏基本和JAVA语言没啥关系了,之前不知道的同学好好补补C吧……)。而我们的Eclipse本身是基于Java的。 怎么办呢?好在Eclipse是一个可扩展的开发平台,我们可以通过添加CDT插件来使我们的Eclipse可以编辑和调试C!

  获取CDT有两种途径,一种是离线添加,这种方法是直接下载CDT包,然后把它手动添加到Eclipse的相关目录下。这种方式下载速度可能比较快,但是下载之后的配置比较麻烦。还有一种方法是用Eclipse进行在线安装,这种方式下载慢一点,但是比较无脑、通用。

  作为一遍面向纯菜鸟的攻略,我在这里只介绍后一种方法。

    在此之前,先把你刚刚解压到的Eclipse打开吧!

    首先去到

    www.eclipse.org/cdt

    这个地方,Download的按钮很明显:

 

    点进去之后我们可以获得这个网址:

    http://download.eclipse.org/tools/cdt/releases/kepler

    这个地址复制到剪切板吧,一会用得到(你当然也可以直接从这个攻略上拷贝)。

 

    然后回到Eclipse,点击Help => Install New Software

    点击Add,在弹出的对话框中:

    Name填入 :CDT   

    Location填入:之前复制好的网址

    点击OK

 

    过一会它会帮你搜索到两个待选项,选择 :CDT Main Features

    然后next,之后该同意的同意,该继续的继续。

 

  整个过程会持续一会,然后它会要你重启Eclipse。

  重启之后这一步就也完工了!

5.获取Android NDK

  前面的CDT是为了让Eclipse支持C的,但是CDT只是给了我们诸如项目管理、语法着色以及集成调试等写代码的功能,真正要把写好的C代码编译、链接并打包,单靠它还是不够的。这是我们需要NDK来帮助我们完成这些内容。

  网上很多的教程中提到了 Cygwin ,这是一个在windows平台上运行的类UNIX模拟环境。用这个的原因好像是我们写好的C++代码在编译时用到了UNIX的bash工具等。不过Cygwin的安装和相关配置极其繁琐,非我等菜鸟所能驾驭。

  好消息是,最新版的NDK里面已经集成了bash相关的功能,也就是说即使不用Cygwin,我们也可以编译我们的C++代码了!所以,让Cygwin这种过时的东西见鬼去吧!

    下载NDK的地址是:

    http://developer.android.com/tools/sdk/ndk/index.html

    和SDK一样,这也是官网提供给我们的工具。在这里选择适合你机型的版本,下载并解压就可以了!如图:

6.运行示例应用HelloCpp

  到目前为止,我们的下载和安装工作就基本结束了。我在做到这一步的时候也松了一口气,可是万万没想到这才是恶梦的开始呀!不过你们大可放心啦,我已经摸索到了最简单的方法,看下去吧!

  Cocos2d-x解压后的文件夹里提供了一些示例应用。用接下来的篇幅,我带大家一步一步地把HelloCpp这个应用程序折腾成.apk让它能在你的手机或虚拟机上跑起来!

    首先,打开Eclipse。

    据说按照官网推荐的方法,在导入 HelloCpp 之前,我们先来导入下面的一个工程,其目的是把类库加到我们的工作平台。

  这里我忍不住要吐槽一番:网上有很多教程是这样引入类库的:它教大家去某个路径之下把 lib 文件夹拷贝到 HelloCpp 的相应路径下,然后刷新工程,以此来达到引入 lib 的目的。

  这样做有很多缺点。首先切出 Eclipse 去拷贝和复制文件本来就是一种我很反感的、没有通用性的方法。而且经过我 的测试,这样做的结果往往不好。以我的理解,用我接下来介绍的方法来做,系统会智能地将你需要的库函数引入,这样的好处就最终生产的apk会比直接拷贝库 更小。通过两种方法打包,直接拷贝的apk大小是4M左右,而用下面方法得到的apk只有1M左右!更重要的是,这是一种通用的方法!

    在 Eclipse 中:

    File => New => Other…

 

    在弹出的 New 对话框中,选择:

    Android => Android Project from Existing Code

    Next >

 

    在弹出的对话框的 Root Directory 项中,参考我的路径填入你的路径。可以通过Browse… 键来选取这个路径:

    F:\cocos2d-x-2.2.3\cocos2dx\platform\android\java

    系统会自动帮你检测到工程,并帮你勾选。点击 Finish 就好了

 

    用同样的方法,我们导入 HelloCpp 工程:

    File => New => Other…

    Android => Android Project from Existing Code

    Next >

    这次我们的路径如下:

    F:\cocos2d-x-2.2.3\samples\Cpp\HelloCpp\proj.android

    你会发现 HelloCpp 目录下除了proj.android 之外还有 proj.各种。这些包是为其他的平台准备的。这也是 cocos2d-x 跨平台的体现。

    Finish

 

   做到这一步,你会发现导入的 HelloCpp 有红叉。没关系,跟着我慢慢做吧!

    首先,HelloCpp 这个示例程序需要用到一些额外的图片资源,你可以在如下路径中找到:

    F:\cocos2d-x-2.2.3\samples\Cpp\HelloCpp\Resources\iphone

  真是偏心啊,只提供 iPhone 的图片资源!不过话说安卓的机型那么多,确实是配不过来呢!

    把找到的3个图片资源一起复制一下,然后在Eclipse中直接粘贴到目录下就行了!

 

    在 Eclipse 中:

    Window => Preferences

 

    在弹出的Preferences 对话框中,点击 Android 项

    在 SDK Location 项中填入我们之前下好的SDK的路径如下(可能已经填好了)。你也可以Browse 进这个路径。

    D:\adt-bundle-windows-x86-20140321\sdk

 

    然后再到 Android 的子项目 NDk中

    在NDK Location 中填入之前下好的NDK的路径如下:

    D:\android-ndk-r9d

    点击OK

 

  接下来是为我们的项目配置 bulid 的过程。经过我的测试和优化,接下来的步骤也很容易。

    选中 HelloCpp 项目右键单击 => properties(这一项在最底下)

    会弹出一个 Properties for HelloCpp 对话框

  耐心的读者,请容许我在这里再吐槽一番吧!

  网上很多教程这时会叫我们去 Build 中做这样一个工作:把原有的 CDT Builder 反勾选掉,然后新建一 个自己的 Builder,然后是在 Environment 中添加一些环境变量。之后就是很大篇幅的关于如何配置这个 Builder 和环境变量的 繁琐过程。我想问一句,你们这样做真的成功了吗?反正我是一直遇到一个 Program “bash” not found in PATH 的错误!

  我在这个地方挣扎了很久,终于发现这一步根本是多余的!

  唉,说多了都是泪……

    下面我们选中对话框左边的 C/C++ Build 这一项继续我们的配置吧。

    首先在 Build command 项中填入我们 ndk-build.com 的路径:

    D:\android-ndk-r9d\ndk-build.cmd 

 

    OK完成这部分的配置。

    到我们的 HelloCpp 工程中打开 jni 中的 Application.mk,在最后加入下面的语句。

    NDK_MODULE_PATH:= F:/cocos2d-x-2.2.3;F:/cocos2d-x-2.2.3/cocos2dx/platform/third_party/android/prebuilt

    注意:这个路径是我的路径,你要认真比较改写成你的相应路径!注意这里的斜杠的方向!还有就是这是由两个路径组合成的,中间用分号隔开!

  这一步好像也是关于环境变量方面的。作为一个菜鸟,我还不太了解环境变量的用处,不能给大家说更多细节。不过这一步是必不可少的。

 

    输入完之后保存一下。

 

    在 Eclipse 中

    Project => Clean

 

    在弹出的 Clean 对话框中,选取 Clean all projects (已经选好了),

    OK

 

    待一切结束之后,右键点击工程 HelloCpp 

    Run as => Android Application

    这就是整个过程的最后一步了!

 

    观察,一下Console窗口,你会发现它已经开始紧锣密鼓地开始工作了!

 

    第一次因为要编译库,所以这个工作会持续较长的一段时间。别着急,我们马上就要成功了!

 

    最后Eclipse会弹出一个对话框,跟你说找不到安卓虚拟机,问你是不是要开启一个。不用管它,关掉叫行了!说实话,用电脑运行ADT里的安卓虚拟机真是慢得不能再慢了,光是启动就要很久!还是用我们的手机测试吧!

    如果一切顺利的话,在 HelloCpp 工程的这个目录下你应该就能找到打包好的HelloCpp.apk了:

    HelloCpp => bin => res

    把这个拷贝到你的手机里安装吧!恭喜你成功跨出了cocos2d-x 跨平台游戏开发的第一步!

7.用Python创建自己的工程

  哈哈,这个算是结尾的小彩蛋吧!你以为教你运行一个实例程序就没有了吗?那你也低估这篇文章的诚意了!接下来我还会教你怎么用 Python 来创建属于你自己的工程!

  Python 也是一种很有意思的语言,它的特性让它经常被用来生成各种其他语言的程序原型!

    当然了,在这里你完全不用了解这个语言,只要去官网下载它就好了!

    官网的地址是:

    www.python.org/

    然后在 Downloads 下找到 Python 2.7.6 下载

    注意:这里一定不要贪新去下 Python 3.*!截止目前为止,cocos2d-x 的工程创建还不支持 Python 3.* 。我亲自测试,它会提示你语法错误,虽然根本没有错。

 

 

    下好之后安装就行了。安装过程很无脑,一直next最好finish就行了。

    系统会默认把 Python 安装在这个路径下:

    C:\Python27\

 

    之后需要为 Python 配置一下环境变量

    在Windows7下直接搜索环境变量,在搜索结果中点击 编辑系统的环境变量

 

 

    在弹出的对话框中点击 环境变量

 

    在弹出的环境变量对话框中,找到 系统变量

    在path中添加 Python 的安装路径

    ;C:\Python27\

    在PATHEXT中添加 Python 支持的两个文件格式

    ;.PY;.PYM

    不要把原来的删除,添加到后面就可以了。注意用英文分号“;”把它们隔开!

    确定

 

    用同样的方法在Windows7下搜索并打开 cmd 

 

  可以看到默认路径是在你的用户目录下,而我们现在要去的目录是:

  F:\cocos2d-x-2.2.3\tools\project-creator

  因为这个目录下有我们要用来创建工程原型的 create_project.py

    在控制台下输入

    F:

    敲击回车

    这是我们就到了F:根目录下。

    然后通过 cd 命令来转入上面的路径:

    在控制台下输入

    cd F:\cocos2d-x-2.2.3\tools\project-creator

    回车

    输入下面的命令:

    Create_project.py -project MyCpp -pacakge com.TestCpp.MyCpp -language cpp

    回车

    注意:有的教程上说 -package 的参数必须是3级目录。我没有测试过,大家就照着做吧!

    如果你的控制台显示的东西和我下面的图一样的话,就说明你成功了!否则很有可能是你输错了,好好检查一番!

 

    这样,我们的工程就在如下路径中创建好了:

    F:\cocos2d-x-2.2.3\projects

    去这个路径把刚刚创建好的 MyCpp 点开看看,你会发现这和 HelloCpp 里的布局差不多。是的,这就是所谓的原型喽。是不是很简单?

    到此为止,我们就算真正可以开始编写游戏啦!现在想想是不是还有点小激动呢?不过接下来还有大量的 cocos2d-x 学习内容需要进行。同为菜鸟的我只能帮你到这啦!

    另外如果本教程中有什么不足之处,恳请各位真正的大神们指出!

[转载]移动应用图标颜色选择的诀窍 - 产品运营 - 创业邦

mikel阅读(1107)

[转载]移动应用图标颜色选择的诀窍 – 产品运营 – 创业邦.

蓝色是受到最普遍喜爱的颜色。这就是为什么许多公司用蓝色作为商标颜色或者移动应用程序的图标颜色。但是,这并不意味着大多数公司都应该选择蓝色,因为这样难以在竞争对手中脱颖而出。

对于移动应用的图标来说,颜色的选择尤其重要,因为它们会同时出现在用户的手机或者其他设备屏幕上。商标图像本身是重要的,但颜色的选择也是一个需要深思熟虑的重大决策。

产品的目标用户是什么,产品的个性是什么,图标将会出现在用户设备上的什么地方,等等,这些都是在选择图标颜色时需要考虑的问题。

正 如一家公司的个性可以通过其品牌颜色而定,许多老牌公司已经影响了公众对各种颜色的看法。当你看到全食公司(Whole Foods),英国石油公司( British Petroleum),和美国女童子军(Girl Scouts),你就会想到绿色,健康,自然,新鲜等。

相反,红色使人想到兴奋,青春,强烈——想想美国有线电视新闻网(CNN),维珍( Virgin),可口可乐,和红牛。在确定哪种颜色作为商标颜色时,考虑采用了该颜色的其他品牌的个性也是重要的。

那么,一个新的移动产品采用哪种颜色的图标最好?没有标准答案。但是,像Facebook 、苹果和雅虎等成功企业的商标,以及下面这些新兴企业的产品图标可以帮助我们指导决策。

红色

TapStory是iPad上的一个应用程序,它可以通过开放式的参与游戏,培养儿童的创新思维。TapStory的开发团队选择了红色作为主要颜色,因为红色代表激情、能量和年轻,它们是与其产品个性相关联的三个核心要素。

其他许多公司也选择红色作为其应用程序的图标颜色,包括耐克、ESPN和Yelp。红色是一种浓烈的颜色,它是App Store上最流行的图标颜色之一,和蓝色不相上下。

橙色

橙色是一种友好、欢快的颜色。越来越多的公司在选择图标颜色时开始避开常见的红色和蓝色,所以橙色逐渐成为一种流行的图标颜色。

Playground是一款为大学生提供活动发现和管理的应用,它选择了橙色作为其图标颜色。这是因为橙色的快乐和活力可以很好地表现激情和参与的理念,这是该公司创始人希望传达给用户的。

黄色

和橙色一样,黄色正在慢慢成为产品图标颜色的首选。虽然各种黄色色调并不十分有魅力,但其明亮和愉快的特质能向潜在用户传递一些温暖而乐观。

DHL和Sprint公司已经大胆地采用了黄色作为图标颜色。像Velloe这样的小型初创公司也采用了黄色。黄色的快乐特质可以给潜在用户一种安慰,而其鲜亮的色调也使它在蓝色和红色图标的大海中显得突出。

绿色

大多数个人理财应用是绿色的,因为大家都知道,绿色是最经常与金钱相关联的颜色。但是公司选择绿色还有其他的理由,包括绿色的和平和健康特质。与红色相比,绿色与财务的关联更恰当。

Long Weekend公司选择了绿色图标来代表其移动应用。该公司旨在帮助个人财富“像自然、有机的东西一样增长”。

蓝色

我已经提到蓝色是世界上最受欢迎的颜色,这也是为什么有这么多公司用蓝色作为公司商标颜色和移动应用图标颜色的原因之一。

Coinbolt是一个比特币钱包应用,所以蓝色对于它来说是一个明智的选择。Chase, American Express和IBM公司选择蓝色,因为它代表信任,实力和可靠性,这些正是用户对银行,或者对比特币钱包的期待。

紫色

紫色是最不常见的图标颜色之一,这或许是它由于它偏于女性化。

Jolimi是一款时尚应用,目标用户是17至25的城市女性,它选用紫色是最明智的选择,因为它需要一种代表有趣、创新、幽默的颜色和图标。紫色不但能很好地传达其实质,而且使它在其他颜色中脱颖而出。

雅虎已经选择紫色代表其身份,其他像HotelTonight和Luna这样的公司也恰到好处的运用了紫色。

想想你需要传递的信息

选择应用图标的颜色是一个新兴公司最重要的品牌决策之一,公司可以开发和推出新产品的时候做一个。每一件产品都不同,图标需要沟通的个性,使其不会丢失的手机屏幕上。

选择应用程序的图标颜色是一个公司在推出新产品时的重要品牌决策之一。每一种产品都不一样,图标需要个性化,颜色也一样,这样才不会让它在用户的移动屏幕上被别的图标淹没。

[转载]对付“熊孩子”利器,“工程师爸爸儿童桌面”让你一键打开手机儿童模式,放心交给孩子玩耍 | 36氪

mikel阅读(906)

[转载]对付“熊孩子”利器,“工程师爸爸儿童桌面”让你一键打开手机儿童模式,放心交给孩子玩耍 | 36氪.

对付“熊孩子”利器,“工程师爸爸儿童桌面”让你一键打开手机儿童模式,放心交给孩子玩耍

当爹当妈的想必一定有过这样的顾虑:孩子想玩手机上的“鳄鱼小顽皮爱洗澡”,但直接把手机给他总是不放心,毕竟小孩子好奇心强,万一打开了其他不适 宜的应用怎么办?万一点到了应用内的支付怎么办?而且现在很多孩子已经拥有了自己的智能手机,他们使用了哪些应用,每天有没有玩太长时间的游戏,家长都不 能很好的控制。更何况,千万不要忘记了你七大姑八大姨家的熊孩子!抢到你的手机你就完蛋了!而现在,这些问题看起来有了一套完整的解决方案,这就是“工程 师爸爸儿童桌面”。

工程师爸爸儿童桌面”事实上是由“工程师爸爸”团队开发的一个安卓 launcher 应用,可以让家长一键创建一个全新的桌面环境,方便地替换掉原来的桌面内容,取而代之的是一些适合孩子使用的游戏、有声读物应用。

同时工程师爸爸桌面还能够防沉迷。家长能为孩子设定可供使用的应用个数、每天能够使用的次数、使用时长以及使用间隔,避免孩子长时间使用手机。

工程师爸爸还拥有“儿童锁”功能,在将儿童桌面设为默认启动器之后,儿童锁可以防止孩子返回了手机原来的桌面。而在孩子尝试自行安装推荐外的应用,或是违反防沉迷规则使用手机时,这些行为会被儿童锁拒绝,需要家长解锁后才能继续使用。

“前不久,三星不是发布了 Galaxy S5 嘛,他手机里有个‘儿童模式’,我们于是意识到,针对儿童的这个领域会迅速地被国外类似 Apple,国内类似小米、魅族等等跟进,于是我们就推出了工程师爸爸儿童桌面。”创始人李文华这么告诉我。

但其实,工程师爸爸儿童桌面想做的可不仅仅是个桌面 launcher,它想要、并且也有实力成为国内专业的儿童内容平台。

工程师爸爸儿童桌面上目前有两大块的内容,其中之一是各种儿童游戏,另一块儿则是正版的有声读物内容。

李文华告诉我说:“从 2012 年起,工程师爸爸就开始作为一个儿童教育应用分享博客存在了,当时主要是大家在一起分享一些好的儿童应用。”这些经验被延续下来,工程师爸爸会给每款应用标记适合的年龄,教育点,和使用方法,方便家长选择安装。

“也是在博客中与大家地不断交流中,我们意识到,儿童有声读物,比如儿歌啊,唐诗啊之类的内容非常受到欢迎,此类的应用,常常会排在 APP store 儿童类应用前几位,我们意识到这是个非常好的机会。”

其结果就是,2012 年,工程师爸爸推出了 APP“故事口袋”, 并且经过多次的迭代之后,故事口袋现在已经是横跨 Android、iOS 双平台,下载量超过 800 万的成功产品。在这个过程中,工程师爸爸团队掌握了儿童读物从内容原创、配音制作到后期的营销分发、付费运营等等一系列的运作经验,这些经验则会直接丰富 其平台上的正版有声读物内容。

谈到盈利模式时,李文华告诉我,工程师爸爸儿童桌面上的付费儿童有声读物应用已经收获了超过两万名付费用户,并且,新的包月付费服务模式也在紧锣密 鼓的筹备中。而类似于平台上的儿童应用,儿童桌面本身也可以充当儿童应用的分发渠道来获得营收。并且,工程师爸爸团队还利用儿童桌面收集了大量儿童的年 龄、性别、地理位置等数据,利用这些数据,与早教机构关联的 O2O 商业模式也在进行相应的探索。

目前,工程师爸爸团队在 20 人左右,大部分都是技术向。创始人李文华曾经供职于盛大文学,负责云中书城平台的技术。并且在儿童相关的领域,工程师爸爸算是他的第三次创业了,对整个儿童相关的行业他有着自己的看法:“和儿童相关的产品,不论外界的环境如何变化,这一块的需求是始终存在的,基本属于刚需。现在很大的问题在于,用户有付费的意愿,却没有优秀的产品提供给他们。因此,这也是为什么,工程师爸爸希望成为国内一流的儿童内容平台。”

特别值得一提的是,事实上,三星此前在发布儿童模式之前已经与工程师爸爸团队有过接触,希望工程师爸爸可以为其儿童模式贡献内容,但被拒绝了。“我们当然要拒绝,他希望我们成为纯粹的内容供应商,放弃‘工程师爸爸’,这我们自然是不愿意的。”

回到工程师爸爸儿童桌面这款产品。现在,很多国内的安卓应用分发平台都设有专门的儿童应用板块,比如“91儿童应用中心”、“360 应用中心儿童频道”等等,windows phone 8也设置了儿童模式,36Kr 曾经还报道过一个叫做“小牧童” 的儿童 ROM(目前其网站已经打不开)。专门针对儿童设计产品是个不错的方向,但工程师爸爸儿童桌面现在还存在一些问题,launcher 应用带来的最显著的问题就是用户的学习成本过高。用户在反复的切换桌面过程中会感到郁闷,并且肯定有相当比例的用户完全搞不懂 launcher 是怎么一回事,这需要长期培养用户习惯来解决。除此之外,我在使用过程中发现,儿童桌面中的应用中,有的依旧有内付费项目,这也需要工程师爸爸团队持续地 进行改进。

[36氪原创文章,作者: cookirss]