转载: 做人、做事,做架构师——架构师能力模型解析

要想从一名普通程序员发展成为优秀的架构师,“个人特性”与“技术技能”缺一不可;而“技术专业能力”、“人际关系能力”和“业务能力”更是优秀架构师重要的三种能力。

文 / 周爱民(《程序员》2008年4月刊)

引子

究竟是什么让你在同一个位置上——例如程序员或技术负责人——工作了三年、五年或者更久,而仍然得不到任何的发展空间?你觉得自己已成为技术圈中的大牛,并信心满满地去拿明天就要颁发的某某大奖,然而却仍然停留在同样的技术职位上,去年到今年涨的薪水甚至填不平物价升幅?于是,你开始对老板不满,对员工不满,对昨天升职的那个同事不满……你开始计划明天就要跑单,或者准备考虑提出加薪却又心怀忐忑。

如果技术人员有发展的轨迹,那么他要么“ 看透工具的本质,把关注点转移到‘团队’的圈子里去”,要么“顺着代码铺就的道路,亦步亦趋地成为良匠大师”。仅以技术方向而言,你大概可以做到架构师、总架构师甚至首席架构师;但问题是:你现在还只是一个程序员。那要如何才能踏上通往架构师之路呢?本文为你解析一个架构师的能力模型。

你能不能做一个好的架构师?

架构师不是界定一个技术高下的职位名称,而是一个职务。所谓职务,包括职——职位,务——工作。前者决定了你具备哪些资源,可以影响到怎样的范围,以及面向的机构,后者则简单地是你需要完成的工作列表。

所以我说“架构师”不是指“一个能做架构的人”。前者是把架构师当职能,后者是当工人。能做一份工作列表中的事,并不等于就成为相应职位上的人。在管理体系里面,你的个人特性决定了你在哪个位置,而技术技能只是做事实施的必需。架构师这个职务,同时要求较高的个人素质和技术能力,因此它的进取之路总结起来就是:做人、做事,做架构师。

因此“模型”由“个人特性”和“技术技能”两个方面构成,在第一张图中,我特别说明“个人特性”既包括人际关系的能力,也包括(具体)业务能力;“技术技能”也是如此。所以个人特性主要与“做人”有关,部分地也包含“做事”的要素。

                                            图1 架构师能力模型

“ 有效沟通”以及“学会谈判”与做具体的事无关,是个人能力特性的公共方面。前者是过程,后者是知道如何定目标与求结果。而“风险与防备”是做事过程控制的关键,与前面两项正好构成了一个做事基本能力的完整体系。基本上,这三项个人特性都是一个“普通程序员”所不具备的,甚至在大多数情况下,普通程序员并不愿意去具备这样的个人特性,因为在许多陷于技术泥淖的开发人员看来:沟通总是会使事情变得更加麻烦,谈判则徒耗时间而无济于事。然而事实上,在整个的架构决策过程中,架构师需要不停地沟通与谈判。将“架构”变成“决策”的过程,其实就是对各个技术角色(及其思想)兼容并包的过程,你需要不断地协调需求、实现之间的各种问题,也需要面对各种投资者(时间、资金、人才等方面的决策者)进行谈判,以确定项目的规模——没有规模也就没有范围,没有范围如何展开设计呢?

一部分开发人员会认为上述过程是“项目经理”的事情,但真的如此吗?当你作为一个更高级别的架构师,以至于要影响到多个项目的决策时,你就全然不会有这种感受了。因为这种情况下,你的决策将先于项目的启动,或者说你已经不单单是一个技术角色了。

设计是架构能力的一部分,但架构师不是设计师——看清楚二者之间的不同,你才真正迈出了架构师职业生涯的第一步。

抽象是思维能力、模型化是表达能力

个人特性中另一个非常重要的方面是“抽象思维”,而这是与架构师角色直接相关的一种能力。这种能力既有职业技能特征,又是普遍性的能力。

所谓普遍性的能力,是指“抽象”在我们——作为人这种个体的——生活中无处不在。例如我们说花、草,说桌、椅……我们用语言去指称任何一个既已存在的(可以脱离我们的语言而自然存在的)事物时,就用到了抽象。说“桌子”的时候,既没有描述桌子的具体形式,也没有说明它的规格,但我们用这个名词时,所有人都知道“桌子是什么”。所以,名词概念是整个抽象逻辑系统中的主体。如果失去了这些名词定义,我们基本上不能说话,也不能描述任何东西——那便到了“只可意会不可言传”的境地。

用现有的成熟语汇去描述你的系统时,大多数人会理解你所表达的含义,例如我们说“这个系统设计为一个三层结构”。然而架构师面临的系统在许多细节上并不见得能够用成熟的语汇去描述,因此必须自已构建一个抽象系统,这就需要概念抽象能力、概念表达能力和基于概念的逻辑表达能力。

概念抽象能力是一种思维能力。简单地说,就是“把目标分解或概括清楚”:你要么概而言之“它是什么”,要么详细地说明“它包括什么 ”。必须使用大量的语汇来陈述这个“什么”,这不单单是表达为文字,也表达为你在思想过程中的一个完整系统。通常用的方法是“映射系统”。例如你可以用数学中的“数轴”来映射“实数域”。将目标系统形式化为一个概念化的、可讨论的结构系统后,你的抽象过程就基本结束了。

                                            图2 能力模型中的个人特性

然而这个“抽象系统”可能只构建在你的思维意识里,还必须把它描绘出来。因为不能只是你自己思考清楚,系统就能设计完成。这个“描绘”就依赖于后面两种表达能力,一种是描绘概念实体,一种是描绘实体上的逻辑——有趣的是,这似乎又回到了“程序=结构+算法”。

现在大家回过头来看看UML,或者更多种类的ML(建模语言),他们就用于表达这两个方面的东西:要么是概念实体(例如用一个框表明系统边界),要么是实体上的逻辑(例如用箭头表明逻辑时序)。

所以大家应该清楚,我们再如何称赞UML,它也只是一种对模型化系统的“表达能力”,你只能把它当一种辅助表达的工具去使用,它本身既不能帮助思考,也不见得能作为抽象过程中的或抽象思维环境中的参考。

任何一个优秀的架构师都有自己独特的思考方式,这决定了他如何抽象系统,以及如何“创造性地”设计与构画这个系统。这种“独特的思考方式”贯彻他从孩童开始的整个成长过程,直至他形成独立的社会观、人生观与世界观。他认识世界的方式和接受世界的能力决定于他如何思考,也反映了他这种思考方式的“独特性”。但这并不表明他有特立独行的行为特性(我们这里只说他的思考方式),我们不应介意他是否用某种语言(例如UML或者形式化编程语言)来表达他的思考结果。

推动:设计做大,实施做小

架构师首先是把问题的真正目标确定下来,然后变成系统设计、平台设计或架构设计。而在此之后设计输出将会有两个方向的发展,一是被忠实地贯彻下来,二是被变形地发展下去。两个方向都存在致命的危险:架构最终能否被完整实现。对前者来说,可能是架构设计过度,或设计本身出现了错误;后者则是对架构直接的伤害。

所以架构师必须参与实施的全程——尤其是在架构被映射为目标系统的前期。在这个阶段中,架构师的任务就是推动架构实施,以保证在项目全程的设计/架构/体系的一致性。除了直接跟设计师或设计团队沟通,以保证他们的设计在你可以控制的范围之内以外,架构师还必须有阶段化设计的能力。这种能力用于将一个原本规模宏大的架构设计,变成较小的、易于实施的、对开发团队来说可控的关键点。例如在体系层次的规划上,设计可能是独立、异质的、可迁移的存储框架来实现数据层,但在(前期的)实施上,这里可能被表达为本地数据库,并要求前端开发人员必须通过一个清晰的数据交互层来访问——例如一组数据存取接口,或一个独立数据服务组件。开发人员可能在这里遇到障碍:因为要通过这些中间层来访问本地数据库,纯粹是多余的。然而,正是这“多余的工作”提供了系统弹性,为并行团队开发公共存储服务争取了周期,也为将来的灵活部署与数据迁移提供了可能。

这里的关键就在于,无论原始系统设定有多大,实施时总是在“做小 ”。每一个局部的实施块都是可控的,并为它在整个体系空间中留下了位置和接口,这样才可能由“小的部分”做大。一个大系统的架构师可能同时在考虑许多个项目中的、不同位置的架构,并且清楚这些项目最终的总体规模。而这,就是平台架构师和体系架构师所涉的领域。

                                            图3 架构师模型图中的“实现能力”

架构真的是“好不好”的问题吗?如同我对工程的理解一样,架构问题的根本,也并不在于它是否完美或漂亮,而是在于是否合用。因此架构师必须对实施架构的团队以及实施过程有充分了解,知道他们的能力缺陷,知道实现过程要消耗的资源,清楚每个环节可能的故障以及先兆。只有这样,架构师才能设计一个让这个团队能实现,而且在实现过程中能受控的架构。

要知道,你作为架构师被请来,不是画几张图纸交给项目经理,说:你们去做吧,做不出来是你们不会做。即使你可以身体力行,在这个团队中教大家、培养大家,那么公司的开销呢?风险呢?这些东西难道就不考虑了?项目的周期因为实现的复杂程度而无法控制时,项目就死掉了。那么,追根究底来说,是不是架构师的问题?是啊,你为什么会做了一份“不合用”的架构呢?——你都不知道项目如何开发、由谁实施、如何管理等等,又如何能面对这些实际环境去设计架构呢?

所以这一部分能力,是要在你的开发经验、团队经验以及用人识人的经验中去找的。参考模型图的“实现能力”下的“设计能力→了解你的主要沟通对象”和“架构推行”等分支,对你或有一些可用的提示。

局部与全局

架构是一个从全局到局部的过程,而实施正好反过来,是从局部到全局。这也正是“设计做大,实施做小”的另一个层面的含义。设计大才可以见到全局,才知道此全局对彼全局的影响;实施小才可能关注细节,才谈得上品质与控制。

事实上,大多数情况下架构是在为“当前项目之外”去考虑,这可以看成全局关注的一个组成部分。因此我们需要界定所谓“全局”的范围:超出公司或整个产品系列、产品线或规划的范围才是多余的。

所以当架构决策谈及“全局”时,其目标并不见得是“保障当前项目”,而又必须由当前项目去完成。

一个经常被用到的例子是:如果仅为当前项目考虑,那么只需要做成DLL模块;如果为产品线考虑,可能会是“管道+插件”的结构形式。而“管道+插件”的形式显然比做成DLL模块更费时,这个时间成本(以及其它成本)就变成了当前项目的无谓开销。

这种全局策略对局部计划的影响是大多数公司不能忍受的,也被很多团队所垢病。然而这却是架构师角色对体系的“近乎必然”的影响——如果你试图在体系中引用架构师这个角色的话。一些情况下,体系能够容纳这种影响,例如“技术架构师”试图推动某种插件框架,而正好开发人员对这项技术感兴趣,那就顺其自然地花点工夫去实现了。但如果不是这样,实施者或实施团队看不到“多余的部分”对他们的价值时,来自局部的抵触就产生了。

这种情况下,平衡这些抵触就成了架构推行的实务之一。在我看来,“平衡”是全局的艺术和局部的技术。也就是说,一方面架构师要学会游说,另一方面也要寻求更为简洁的、成本更小的实现技术。只有当整个体系都意识到(你所推行的)架构的重要性,而且实施成本在他们可以接受的范围之内时,他们才会积极行动起来。

所以所谓平衡,其实也是折衷的过程。构架师只有眼中见大,才知道哪些折衷可以做,而哪些不能。所谓设计评估(模型图中的实现能力->设计能力->设计评估分支)并不是去分析一个设计结果好或不好,而是从中看到原始的需求,看到体系全局的意图,然后知道在将设计变得更为“适当”时可以做哪些折衷。同样的原因,架构师也必须知道自己的决策会产生的影响,才能控制它们,以防它们变成团队的灾难。有些时候,架构师甚至需要抛弃一些特性,以使得项目能够持续下去。因为产品的阶段性产出只是整个战略中的一个环节,而不是全部。

其它

“怎么做一个架构师”这个问题得分成两个部分来看,一个是“做到”,一个是“做好”。由于架构师本身不过是一个技术职位,所以时机成熟了自然会做得到。但问题是,真有一天你被放在这个位置上了,你能做得好吗?

我浏览过几套所谓培训机构的有关架构师的教程,也翻阅过一些讲架构的书。我发现他们普遍地是将架构作为一种“职业技术”来讲,就像培养程序员或者缝纫工一样来教育。但就我的经验来说,架构并不是一件纯粹表现技术能力的工作,所以并不是翻几本书学几种方法就可以投入“实战”的。更深层的问题是,架构师其实不是 “战”出来的。昨天跟同事讨论这个话题,他把我们这几年来的一些思考用了三句话来概括,非常精彩:从无到有的,是架构;从表到里的,是抽象;从粗到细的,是设计。

那么到底什么是架构呢?从上面的概括中你是看不到答案的。到底如何做架构呢?从本文中你也是看不到答案的。然而我说,“你看不到答案”的根源其实是在于你的眼光与心性——后面这个词换成现代白话,就是“思想”。真正阻碍了你成为优秀架构师的,也许正是你既有的知识与思想方法,扔掉它们,接受一些全然有别的信息,也许正是良好的开端。

或许你现在正愤愤然:这篇文章怎么空洞无物?——我甚至能想象到一些读者的表情。然而请在问题面前停下来,不要急于给出答案。正如你将“?”稍微变下形,它就成为了“!”一样,问题的本身,就是答案。

作者简介

周爱民(aimingoo),具有十余年的软件开发、项目管理和团队建设的经验,现担任盛大网络的平台架构师,著有《大道至简》、《Delphi源代码分析》等。

spring事务错误:no matching editors or conversion strategy

错误日志:no matching editors or conversion strategy spring事务中会出现。

spring bean proxy默认代理的是接口,如果用来代理类,要在事务配置中添加以下代码声明:

<property name="proxyTargetClass" >
   <value>true</value>
</property>, 否则就会出现上面的错误。

spring 声明式事务,Propagation属性列表

这些属性在TransactionDefinition接口中定义,共有7种选项可用:

PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务(还不是太明白),如果当前没有事务,就新建一个事务。

TransactionDefinition中定义的隔离(isolation)级别,有5种:

1 ISOLATION_DEFAULT 默认的隔离级别
下面几个都是 JDBC isolation levels 一一对应:
2 ISOLATION_READ_UNCOMMITTED Connection.TRANSACTION_READ_UNCOMMITTED
指示防止发生脏读的常量;不可重复读和虚读有可能发生。
3 ISOLATION_READ_COMMITTED Connection.TRANSACTION_READ_COMMITTED
指示可以发生脏读 (dirty read)、不可重复读和虚读 (phantom read) 的常量。
4 ISOLATION_REPEATABLE_READ Connection.TRANSACTION_REPEATABLE_READ
指示防止发生脏读和不可重复读的常量;虚读有可能发生。
5 ISOLATION_SERIALIZABLE Connection.TRANSACTION_SERIALIZABLE
指示防止发生脏读、不可重复读和虚读的常量。

注:
脏读 dirty reads:当事务读取还未被提交的数据时,就会发生这种事件。举例来说:Transaction 1 修改了一行数据,然后 Transaction 2 在 Transaction 1 还未提交修改操作之前读取了被修改的行。如果 Transaction 1 回滚了修改操作,那么 Transaction 2 读取的数据就可以看作是从未存在过的。
不可重复的读 non-repeatable reads:当事务两次读取同一行数据,但每次得到的数据都不一样时,就会发生这种事件。举例来说:Transaction 1 读取一行数据,然后 Transaction 2 修改或删除该行并提交修改操作。当 Transaction 1 试图重新读取该行时,它就会得到不同的数据值(如果该行被更新)或发现该行不再存在(如果该行被删除)。
虚读 phantom read:如果符合搜索条件的一行数据在后面的读取操作中出现,但该行数据却不属于最初的数据,就会发生这种事件。举例来说:Transaction 1 读取满足某种搜索条件的一些行,然后 Transaction 2 插入了符合 Transaction 1 的搜索条件的一个新行。如果 Transaction 1 重新执行产生原来那些行的查询,就会得到不同的行。

struts2 错误解决

错误日志:

[com.opensymphony.xwork2.interceptor.ParametersInterceptor]-[ERROR] ParametersInterceptor - [setParameters]: Unexpected Exception catched: Error setting expression ’start’ with value ‘[Ljava.lang.String;@2a590d’

解决方法:

在action 添加相应的属性(start). 或是删除页面表单和url中的多余的参数。

这个问题并不影响运行,干嘛要报个error呢,提示个警告不就OK,不明白 。

 

eclipse设置

1.  myeclipse默认编码设置

     项目默认编码设置:Window–>Preferences–>General–>WorkSpace

     文件系统默认编码设置:Window–>Preferences–>General–>Content Types

 

2.  Eclipse 中Alt+/快捷键失效的解决办法

       Eclipse下进入Windows ->Preperences ->General ->keys(快捷键按住ctrl+shif同时双击L )

      把word completion的快捷键设置alt+/删掉或改成其他的!

      把Content Assist的快捷键由ctrl+space改成alt+/

关于Hibernate源码 org.hibernate.hql.antlr包为空的问题

Hibernate3的源码中org.hibernate.hql.antlr包是空的,代码是由Antlr产生的。

1, 配置ANtlr, 将antlr.jar设置到CLASSPATH环境变量或拷贝到jdk的lib下边。懒得写配置环境,直接拷贝到JDK的lib下方便。

2, 开始生成java 文件 到源码的grammar下看到有3个.g文件,

       首先运行>java antlr.Tool hql.g

       接着运行>java antlr.Tool hql-sql.g

       最后运行>java antlr.Tool sql-gen.g OK,

关于HSQL的源码生成完毕,拷贝到org.hibernate.hql.antlr包下即可。

struts2.0标签应用(2)–for循环的实现

 

Java代码
  1. <s:bean name="org.apache.struts2.util.Counter" id="counter">    
  2.   <s:param name="first" value="1" />    
  3.   <s:param name="last" value="10" />    
  4.   <s:iterator>    
  5.     counter:<s:property value="current-1"/>    
  6.   </s:iterator>    
  7. </s:bean>    

其中first属性指定循环起始值,last指定循环终止值,其它相关属性可以查看org.apache.struts2.util.Counter类源码。在下面迭代器中输入循环的当前值,即:current-1

Counter类源码
  1. /* 
  2.  * $Id: Counter.java 471756 2006-11-06 15:01:43Z husted $ 
  3.  * 
  4.  * Licensed to the Apache Software Foundation (ASF) under one 
  5.  * or more contributor license agreements.  See the NOTICE file 
  6.  * distributed with this work for additional information 
  7.  * regarding copyright ownership.  The ASF licenses this file 
  8.  * to you under the Apache License, Version 2.0 (the 
  9.  * "License"); you may not use this file except in compliance 
  10.  * with the License.  You may obtain a copy of the License at 
  11.  * 
  12.  *  http://www.apache.org/licenses/LICENSE-2.0 
  13.  * 
  14.  * Unless required by applicable law or agreed to in writing, 
  15.  * software distributed under the License is distributed on an 
  16.  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
  17.  * KIND, either express or implied.  See the License for the 
  18.  * specific language governing permissions and limitations 
  19.  * under the License. 
  20.  */  
  21. package org.apache.struts2.util;  
  22.   
  23. import java.io.Serializable;  
  24.   
  25.   
  26. /** 
  27.  * A bean that can be used to keep track of a counter. 
  28.  * <p/> 
  29.  * Since it is an Iterator it can be used by the iterator tag 
  30.  * 
  31.  */  
  32. public class Counter implements java.util.Iterator, Serializable {  
  33.   
  34.     private static final long serialVersionUID = 2796965884308060179L;  
  35.   
  36.     boolean wrap = false;  
  37.   
  38.     // Attributes —————————————————-  
  39.     long first = 1;  
  40.     long current = first;  
  41.     long interval = 1;  
  42.     long last = -1;  
  43.   
  44.   
  45.     public void setAdd(long addition) {  
  46.         current += addition;  
  47.     }  
  48.   
  49.     public void setCurrent(long current) {  
  50.         this.current = current;  
  51.     }  
  52.   
  53.     public long getCurrent() {  
  54.         return current;  
  55.     }  
  56.   
  57.     public void setFirst(long first) {  
  58.         this.first = first;  
  59.         current = first;  
  60.     }  
  61.   
  62.     public long getFirst() {  
  63.         return first;  
  64.     }  
  65.   
  66.     public void setInterval(long interval) {  
  67.         this.interval = interval;  
  68.     }  
  69.   
  70.     public long getInterval() {  
  71.         return interval;  
  72.     }  
  73.   
  74.     public void setLast(long last) {  
  75.         this.last = last;  
  76.     }  
  77.   
  78.     public long getLast() {  
  79.         return last;  
  80.     }  
  81.   
  82.     // Public ——————————————————–  
  83.     public long getNext() {  
  84.         long next = current;  
  85.         current += interval;  
  86.   
  87.         if (wrap && (current > last)) {  
  88.             current -= ((1 + last) - first);  
  89.         }  
  90.   
  91.         return next;  
  92.     }  
  93.   
  94.     public long getPrevious() {  
  95.         current -= interval;  
  96.   
  97.         if (wrap && (current < first)) {  
  98.             current += (last - first + 1);  
  99.         }  
  100.   
  101.         return current;  
  102.     }  
  103.   
  104.     public void setWrap(boolean wrap) {  
  105.         this.wrap = wrap;  
  106.     }  
  107.   
  108.     public boolean isWrap() {  
  109.         return wrap;  
  110.     }  
  111.   
  112.     public boolean hasNext() {  
  113.         return ((last == -1) || wrap) ? true : (current <= last);  
  114.     }  
  115.   
  116.     public Object next() {  
  117.         return new Long(getNext());  
  118.     }  
  119.   
  120.     public void remove() {  
  121.         // Do nothing  
  122.     }  
  123. }  

 

 

struts2.0标签应用(1)

%{}用于计算表达式
如%{10+20}结果将输出30
如%{"a"+"b"}结果将输出"ab"
#通常强调从上下文取
如#parameters.name[0]等价于request.getParameter("name")
如#session.name等价于session.getAttribute("name")
如#request.name等价于request.getAttribute("name")
%{#}仍然用于计算表达式,只不过操作元可以是变量
如先定义一个变量
<s:set name="age" value="%{25}"/>
则%{#age}将输出25,也可以省略"#",写为%{age}
若将age加10,可这么写:
%{#age+10},将输出30.不能省略"#"。也就说变量用于计算时不能省略"#"

关于搜索提示功能的实现(一)

/**
   *
   *作者:野四abin
   * 时间:2009-3-27
   */

  搜索引擎现在越来越流行了,好多网站都有了自己的搜索引擎,但是对于类型GOOGLE的提示并不多,在我的印象中并没有太多(google,baidu.todou,youku…),而大多数都是一些比较大型的网站在使用这个功能.由于公司的搜索引擎的需求要求实现关于类型google提示功能!

如下图

   通过浏览别人做的搜索引擎提示总结出来我所面临的问题如下:

1、提示中的那些关键字是如何获得的

2、提示中的关于那些关键字的搜索数据条数如何获得的

3、关于得到这些数据的访问速度

通过上述问题我总结出来了关于这些问题的实现方案

对于第1个问题,我认为应当是用户通过搜索引擎搜索使用关键字的记录的。我是如果得到这些记录和如何存储这些记录的呢!

首先我新建一个表(关键字搜索记录表)主要是存储使用关键字搜索记录,它包括以下几个字段(ID,关键字,使用次数) 其中关键字是唯一的!我是怎样存储这些数据的呢!首先我创建一个searchkeys.txt文本文件,每个搜索使用的关键字写入文本中,每个关键字点一行,我是通过定时器来把这个数据存储到数据库当中的,通过分析这些数据如果有N个相同的关键字使用次数就为N个,我是每天0点的时候把这些数据存储在数据库中,为什么要选择0点,因为0点的时候访问量并不会太多,加入数据库中也不会影响网站的速度。同时能过分析数据中的记录生成一个名叫searchkeys.js的文件,它的格式如下:

JavaScript代码
  1. var keyArr1=new Array();  
  2. keyArr1[0]=["1","办公摆挂件","1000"]  
  3. keyArr1[1]=["2","办公剪刀","1000"]  
  4. keyArr1[2]=["3","办公沙发","1000"]  
  5. keyArr1[3]=["4","办公饰品","1000"]  
  6.   
  7. function getArr1(skey){  
  8. function funsort(x,y){//通过使用次数来排序  
  9. return y[1] - x[1];  
  10. }  
  11. var j=0;  
  12. var testArray = new Array();  
  13. var keyArray = new Array();  
  14. for (var i = 0; i < keyArr1.length; i++) {  
  15. if (keyArr1[i][1].indexOf(skey)==0) {//根据字来查找  
  16. testArray[j]= new Array(keyArr1[i][1],keyArr1[i][2]);  
  17. j++;  
  18. }  
  19. }  
  20. testArray.sort(funsort);  
  21. for (var sk = 0; sk < testArray.length; sk++) {  
  22. if(sk<10){//只取前10条结果  
  23.     keyArray[sk]= new Array(testArray[sk][0],testArray[sk][1]);  
  24. }else{  
  25. break;  
  26. }  
  27. }  
  28. return keyArray;  
  29. }  

为什么要使用这个JS呢?减少与数据库连接,

那关键字后面的结果条数怎么得来的呢,我认为是通过对关键字的的分词,再去通过分词后的字,去索引中查找关于这些关键字的HITS的记录,这里我只得到这些个数,并通过使用memcached来存储这个使用关键字与得到的结果个数!

测试结果:

输入关键字和出现提示的时间差<0.001s

Formatter格式化输出—— java古怪代码(4)

Java代码
  1. import java.util.Formatter;  
  2.   
  3. public class FormatterTester {  
  4.   
  5.     public static void main(String[] args) {  
  6.           
  7.         StringBuilder sb = new StringBuilder();  
  8.         float balance = 223.33522f;  
  9.         String str = "String values";  
  10.           
  11.         Formatter formatter = new Formatter(sb);  
  12.           
  13.         formatter.format("格式化输出balance的值(float):$%.2f "  
  14.                 +"字符串值:%s",balance,str);  
  15.         System.out.println(sb.toString());  
  16.           
  17.         System.out.printf("格式化输出balance的值(float):$%.2f "  
  18.                 +"字符串值:%s",balance,str);  
  19.     }  
  20.       
  21. }  

 

运行结果
  1. 格式化输出balance的值(float):$223.34 字符串值:String values  
  2. 格式化输出balance的值(float):$223.34 字符串值:String values

语法类似C语言中的printf,习惯用C语法的可以试试这个。