MYSQL–事务处理

事务处理在各种管理系统中都有着广泛的应用,比如人员管理系统,很多同步数据库操作大都需要用到事务处理。比如说,在人员管理系统中,你删除一个人员,你即需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!
     删除的SQL语句
delete from userinfo where ~~~
delete from mail where ~~
delete from article where~~
~~
   如果没有事务处理,在你删除的过程中,假设出错了,只执行了第一句,那么其后果是难以想象的!
但用事务处理。如果删除出错,你只要rollback就可以取消删除操作(其实是只要你没有commit你就没有确实的执行该删除操作)

   一般来说,在商务级的应用中,都必须考虑事务处理的!

 

查看inodb信息
      shell> /usr/local/mysql -u root -p
      mysql> show variables like “have_%”
系统会提示:
+——————+——-+
| Variable_name     | Value |
+——————+——-+
| have_bdb          | YES    |
| have_crypt        | YES    |
| have_innodb       | YES    |
| have_isam         | YES    |
| have_raid         | YES    |
| have_symlink      | YES    |
| have_openssl      | NO     |
| have_query_cache | YES    |
+——————+——-+
8 rows in set (0.05 sec)
如果是这样的,那么我们就可以创建一张支持事务处理的表来试试了。

 

MYSQL的事务处理功能!

作者:Feifengxlq   Email:feifengxlq@sohu.com
一直以来我都以为MYSQL不支持事务处理,所以在处理多个数据表的数据时,一直都很麻烦(我是不得不将其写入文本文件,在系统重新加载得时候才写入数据库以防出错)~今天发现MYSQL数据库从4.1就开始支持事务功能,据说5.0将引入存储过程^_^
      先简单介绍一下事务吧!事务是DBMS得执行单位。它由有限得数据库操作序列组成得。但不是任意得数据库操作序列都能成为事务。一般来说,事务是必须满足4个条件(ACID)
      原子性(Autmic):事务在执行性,要做到“要么不做,要么全做!”,就是说不允许事务部分得执行。即使因为故障而使事务不能完成,在rollback时也要消除对数据库得影响!
     一致性(Consistency):事务得操作应该使使数据库从一个一致状态转变倒另一个一致得状态!就拿网上购物来说吧,你只有即让商品出库,又让商品进入顾客得购物篮才能构成事务!
     隔离性(Isolation):如果多个事务并发执行,应象各个事务独立执行一样!
     持久性(Durability):一个成功执行得事务对数据库得作用是持久得,即使数据库应故障出错,也应该能够恢复!
   
   MYSQL的事务处理主要有两种方法。
   1、用begin,rollback,commit来实现
        begin 开始一个事务
        rollback 事务回滚
        commit  事务确认
    2、直接用set来改变mysql的自动提交模式
       MYSQL默认是自动提交的,也就是你提交一个QUERY,它就直接执行!我们可以通过
      set autocommit=0   禁止自动提交
      set autocommit=1 开启自动提交
   来实现事务的处理。
但注意当你用 set autocommit=0 的时候,你以后所有的SQL都将做为事务处理,直到你用commit确认或rollback结束,注意当你结束这个事务的同时也开启了个新的事务!按第一种方法只将当前的作为一个事务!
个人推荐使用第一种方法!
   MYSQL中只有INNODB和BDB类型的数据表才能支持事务处理!其他的类型是不支持的!(切记!)

下次有空说下MYSQL的数据表的锁定和解锁!

       MYSQL5.0 WINXP下测试通过~   ^_^

mysql> use test;
Database changed
mysql> CREATE TABLE `dbtest`(
     -> id int(4)
     -> ) TYPE=INNODB;
Query OK, 0 rows affected, 1 warning (0.05 sec)

mysql> select * from dbtest
     -> ;
Empty set (0.01 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into dbtest value(5);
Query OK, 1 row affected (0.00 sec)

mysql> insert into dbtest value(6);
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from dbtest;
+——+
| id    |
+——+
|     5 |
|     6 |
+——+
2 rows in set (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into dbtest values(7);
Query OK, 1 row affected (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from dbtest;
+——+
| id    |
+——+
|     5 |
|     6 |
+——+
2 rows in set (0.00 sec)

mysql>

*******************************************************************************************************************

[PHP]
function Tran( $sql ) {
         $judge = 1;
         mysql_query(‘begin’);
         foreach ($sql as $v) {
                 if ( !mysql_query($v) ) {
                         $judge = 0;
                 }
         }
         if ($judge == 0) {
                 mysql_query(‘rollback’);
                 return false;
         }
         elseif ($judge == 1) {
                 mysql_query(‘commit’);
                 return true;
         }
}
[/PHP]

************************************************

<?php
$handler=mysql_connect(“localhost”,”root”,””);
mysql_select_db(“task”);
mysql_query(“SET AUTOCOMMIT=0”);//设置为不自动提交,因为MYSQL默认立即执行
mysql_query(“BEGIN”);//开始事务定义
if(!mysql_query(“insert into trans (id) values(‘2’)”))
{
mysql_query(“ROOLBACK”);//判断当执行失败时回滚
}
if(!mysql_query(“insert into trans (id) values(‘4’)”))
{
mysql_query(“ROOLBACK”);//判断执行失败回滚
}
mysql_query(“COMMIT”);//执行事务
mysql_close($handler);
?>

如何学习php框架

关于PHP框架的问题,是我们很多的一个方面。推荐一篇文章,详细介绍使用PHP框架的原因,供大家参考。

如今的PHP框架层出不穷,其中有些比其他的更加惹人耳目。我不是这方面的专家,甚至不能熟练地使用其中的一种,所以我不做推荐,也不想讨论哪些算是框架哪些不算框架(我本文的前提是所有自称为PHP框架的皆是框架)。这里我要讨论的是如何才能更快地开始使用某个新的框架。

首先你当然必须选择一个框架,比如ZF、Cake、Symfony、atk、Yii、CodeIgniter、Solar、PRADO等。选择哪个呢?有些框架提供了非常好“step-by-step”入门教程,另一些则比较难入门了。

我很喜欢这篇文章:《学习一种新的编程语言所需做的练习》,但我因为已经很熟悉PHP了,所以这个方法不能用在学习框架上。所以我想列举一些类似的练习用以学习PHP框架。

如果你还不知道怎么使用框架,何不按照本文的练习来学呢?

1、你好世界(hello world)

这里练习的必要性我就不多作说明了。在一个新的框架上构建一个应用,在页面中显示“‘hello world”。当然,做起来不会那么简单。

2、计算器(calculator)  

写一个简单的计算器程序,结合表单,对两个操作数进行加减乘除等运算,并把结果输出到页面上。你需要为每一种运算设置单独的动作,或者说方法(每个框架的叫法不一样),而且还要用到框架中的表单验证功能(如果框架提供了这一功能的话)。

3、留言板(guestbook)

让我们回到1998年——建立一个留言本程序,在页面上显示一个表单让用户填写,然后提交到这个应用程序里,继而存储到数据库或文本文件中(视你自己的情况而定),并把用户留言的内容显示到页面上。如果框架提供了创建HTML表单、对象模型或层等功能,就用上它们吧。

4、解析和分页(parse and paginate)  

选一个RSS源或其他XML源,解析其中的条目并显示出来。同时添加一个分页的功能,让用户可以五条五条地浏览,并在页面的顶部或底部添加页码。如果框架里提供了这样的功能,就使用它吧。

完成以上的练习后,你应该就可以清楚地知道如何使用这个框架了,并能用它完成更复杂的工作,或是继续探索这个框架的其他功能。如果你还是不会用,或者花了很多时间来完成以上练习,那么我觉得这个框架不适合你,还是找些其他的来用吧。

记住,如果在使用框架的过程中遇到困难,记得去该框架的社区里寻求帮助。一个有这强大社区支持的框架会为你未来的工作带来很大帮助,同时也表明这个框架是个不错的框架。没有人希望在使用某框架后的六个月,框架的开发者就宣布停止开发,这就太气人了。

希望通过本文的介绍,能给你带来帮助。

XMLRPC编码中文乱码问题解决办法

[原创]XMLRPC编码中文乱码问题解决办法

终于搞定了,整整一天,都在写XMLRPC的程序,之前测试,都直接随便打点英文

刚才试了用长的HTML代码做string提交,居然不成功

郁闷了半天,不管我怎么encode都不行,GBK,UTF-8,ASCII我都试了,还是不行.

资料也找不到,网上关于XMLRPC的资料实在太少了,WordPress官方更是少得可怜.

原来,xmlrpc.inc会自动转换编码,但提交后是乱码,是因为默认指定的是ISO-8859-1编码,我说怎么看着像MYSQL乱码,打开找编码的地方,发现有好多个编码的设置参数,试了半天才找到对的.就是 xmlrpc_internalencodeing

我的XMLRPC编码中文乱码解决办法:

贴图上瘾了,再来一张,不看图的直接看下面代码

[原创]XMLRPC编码中文乱码问题解决办法 image16

打开 xmlrpc.inc 第222行, 将

$GLOBALS[‘xmlrpc_internalencoding’]=’ISO-8859-1′;

改成

//$GLOBALS[‘xmlrpc_internalencoding’]=’ISO-8859-1′;
$GLOBALS[‘xmlrpc_internalencoding’]=’UTF-8′;

提交的数据用UTF-8,搞定
本文由21andy.com原创

Eclipse运行时提示failed to create the java virtual machine 如何解决

突然就遇到了这个问题,打开Eclipse就提示“failed to create the java virtual machine”,分析了一下,感觉应该是由于分配的内存过大引起的,果断更改,成功了!

更改方法:

找到Eclipse的安装目录,打开ZendStudio.ini文件

然后将-Xmx1024M这里面的1024改小点,我改为了512,不知道会不会出现其他的问题,但是打开就提示“failed to create the java virtual machine”的问题解决了。

OpenERP中销售订单的预收款及多次开票的处理

现实的销售、收款、发货的关系有些复杂。常见的关系有:1)收到全款后发货;2)预收部分款后发货;3)先发货再收款;4)分批收款,分批发货。每一笔收款都有对应的发票/收据,1)、3)两种情况,一张销售订单只要开一张票据(发票或收据,OpenERP中是Invoice),2)、4)两种情况,一张销售订单有多张票据。

1)收到全款后发货
这种情况比较简单,在OpenERP的Sales Order中,字段Shipping Policy 选择“ Payment Before Delivery”,表示先付款再发货。选择这个选项,销售订单确认时候,OpenERP会自动生成SO对应的Invoice,但不会自动生成SO对应的发货单(Picking List)。当财务人员确认Invoice,并确认收到该Invoice的款项时候,系统自动生成SO对应的发货单,允许发货。

2)预收部分款后发货
在Sales Order中,有个按钮“Advance Invoice”,表示预收款票据。点击它,选择预收款对应的产品项目,填入预收金额,系统会自动生成预收票据,并将该票据关联到SO上(在SO 的History属性页上显示出来)。“预收款对应的产品项目”是指,必须事先定义一个用于预收款的产品名称(诸如 销售预收款 之类的)。
控制预收款再发货,有两个办法,一个是,SO上的Shipping Policy 选择 “Shipping & Manual Invoice”,这表示,SO确认时候,系统不会自动生成对应的Invoice,而是要手动点击按钮“Create Final Invoice”生成发票。如果选择这种方式,预收款收到前,销售人员不要确认SO,这样,系统就不会自动生成发货单。
另一种办法是,Shipping Policy 选择“ Payment Before Delivery”,这样,如果确认SO时候,预收款发票尚未支付,则系统不会自动生成发货单,而是要待到确认收到款额时候系统才会自动生成发货单。

3) 多次开票的处理
SO上的Shipping Policy 选择 “Shipping & Manual Invoice”。如果点击SO上的按钮“Create Final Invoice”,系统会自动一次性生成SO的余额的发票,而不允许拆分金额多次开票。不过系统提供了“Lines to Invoice”的功能,该功能会列出所有已确认但未开票的SO明细行,允许对每一个明细行开票,并将明细行的发票自动关联到SO上。
如果一张发票对应多个SO,或者,对SO上的一个明细行开多张发票。那么,就必须在Account的Invoice界面上手工新建发票,且该发票不能与SO关联起来。建议严格基于SO开发票,革除根据收款额开销售发票的习惯。

4)收款和发票的关系
建议开票严格基于SO,但收款不必严格基于SO。即1)一个SO可以多次开票,但开票的最小单位是SO上的一个明细行;2)不允许一张发票包含多个SO的内容;3)一笔收款可以对应到多张发票(核销多张发票)。

OpenERP 7 默认值详解

1.激活开发者模式

在OpenERP 7目前的版本中,设置默认值必须进入开发者模式。

2.设置默认值

然后在你要配置默认值的表单里面,先填入对应的数据然后,在表单左上方的调试视图里面选择设置默认值。

OpenERP设置默认值步骤1

默认值的配置界面很直观。

OpenERP设置默认值步骤2

  • 默认:就是你要设置的默认值,下拉列表里面已经根据你当前表单显示出相应的字段和值,你只需要选取
  • 条件:   就是你的默认值生效的条件。例如下图意思就是,当产品类别是服务的,产品类型默认值为服务。(这里涉及到一个bug1112232不过在最新的版本里面已经修复好了)。

OpenERP设置默认值步骤3

怎么样的字段才能成为默认值的条件呢?字段定义里面的 change_default属性为True。

'categ_id': fields.many2one('product.category','Category',
required=True, change_default=True, domain="[('type','=','normal')]" ,
help="Select category for the current product"),
  • 仅用于你个人/所有用户:此默认值是只对当前用户生效还是对于所有用户生效。

 

3.删除默认值

到 设置->技术->动作->用户设定默认值 就能看到目前已经设定的默认值。

4.更多默认值

OpenERP的默认值还可以通过代码的方式来实现。例如下图就是产品模块的默认值

_defaults = {
 'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'product.template', context=c),
 'list_price': 1,
 'cost_method': 'standard',
 'standard_price': 0.0,
 'sale_ok': 1,
 'produce_delay': 1,
 'uom_id': _get_uom_id,
 'uom_po_id': _get_uom_id,
 'uos_coeff' : 1.0,
 'mes_type' : 'fixed',
 'categ_id' : _default_category,
 'type' : 'consu',
 }

问题:如果我既配置了_defaults 又在界面上配置了默认值那么怎么办?
答案:界面的优先级大于代码里面的。

问题:如果在界面上配置了多次默认值,那么会取哪个默认值呢?
答案:取最新的。

原文链接:http://cn.openerp.cn/openerp-7-set-dafault/

PHP开发:从程序化到面向对象编程

首先要明白此文较长,阅读时间基本在60分钟以上,请先做好准备,这是一篇不错的文章

这份教程的诞生源自一年多之前Robert C.Martin在演讲中带给我的启发。当时他的演讲主题在于讨论创造“终极编程语言”的可能性。在过程中,他提出了这样几个问题:为什么会存在“终极编程语言”?这样的语言应具备哪些特性?但随着他的讲解,我从中发现另一种有趣的思路:每种编程范式都在无形中给程序员带来诸多无法避免的局限性。为了正本溯源,我打算在正式进入PHP由程序化向面向对象转变这一话题之前,先与大家分享一些理论知识。

范式局限

每种编程范式都限制了我们将想象转化为现实的能力。这些范式去掉了一部分可行方案,却纳入另一些方案作为替代,但这一切都是为了实现同样的表示效果。模块化编程令程序规模受到制约,强迫程序员只能在对应模块范畴之内施展拳脚,且每个模块结尾都要以“go-to”来指向其它模块。这种设定直接影响了程序成品的规模。另外,结构化编程与程序化编程方式去掉了“go-to”声明,从而限制了程序员对序列、选择以及迭代语句的调整能力。序列属于变量赋值,选择属于if-else判断,而迭代则属于do-while循环。这些已经成为当下编程语言与范式的构建基石。

面向对象编程方式去掉了函数指针,同时引入多态特性。PHP使用指针的方式与C语言有所不同,但我们仍能从变量函数库中找到这些函数指针的变体形式。这使得程序员能够将某个变量的值当成函数名称,从而实现以下内容:


  1. 		function foo() {
  2.     echo “This is foo”;
  3. }
  4. function bar($param) {
  5.     echo “This is bar saying: $param”;
  6. }
  7. $function = ‘foo’;
  8. $function();        // Goes into foo()
  9. $function = ‘bar’;
  10. $function(‘test’);  // Goes into bar()

初看起来,这种特性似乎无关紧要。但仔细想想,大家一定会发现其中蕴含着极为强大的潜力。我们可以将一条变量作为参数发往某函数,然后让该函数根据参数数值调用其它函数。这绝对非同小可。它使我们能够在不了解函数功能的前提下对其进行调用,而且函数自身根本不会体现出任何差异。

这项技术也正是我们实现多态性调用的关键所在。

现在,我们姑且不谈函数指针的作用,先来看看其工作机制。函数指针中其实已经隐藏着“go-to”声明,或者至少以间接方式实现了与“go-to”相近的执行效果。这可不是什么好消息。事实上,PHP通过一种非常巧妙的方式在不直接使用的前提下实现“go-to”声明。如前例所示,我需要首先在PHP中做出声明。虽然这看起来不难理解,但在大型项目以及函数种类繁多且彼此关联的情况下,我们还是很难准确做出判断。而在C语言这边,这种关系就变得更加晦涩且极难理解。

然而仅仅消除函数指针还远远不够。面向对象的编程机制必然带来替代方案,事实也确实如此,它包含着多态特性与一套简单语法。重点来了,多态性正是面向对象编程的核心价值,即:控制流与源代码在依赖关系上正好相反。

\

在上面的图片中,我们描绘了一个简单的例子:多态性如何在两个不同范式之间发挥作用。在程序化或者结构化编程领域,控制流与源代码在依赖关系上非常相似——二者都指向更具体的输出行为。

而在面向对象编程方面,我们可以逆转源代码的依赖关系,使其指向抽象执行结果,并保持控制流仍旧指向具体执行结果。这一点至关重要,因为我们希望控制机制能尽可能触及具体层面与代码中的不稳定部分,这样我们才能真正让执行结果与预期相符。但在源代码这边,我们的要求却恰好相反。对于源代码,我们希望将具体结果与不稳定因素排除在外,从而简化修改流程、让改动尽量不影响其它代码。这样不稳定部分可以经常修正,但抽象部分则仍然有效。大家可以点击此处阅读由Robert C.Martin所撰写的依赖倒置原则研究论文。

试手任务

在本章中,我们将创建一款简单应用,旨在列出谷歌日程表及其事件提醒内容。首先,我们尝试利用程序化方式进行开发,只涉及简单功能、避免以任何形式使用类或对象。开发工作结束之后,我们更进一步、在不改动程序化代码的前提下通过行为进行代码整理。最后,尝试将其转化为面向对象版本。

谷歌PHP API客户端

谷歌专门针对PHP提供一套API客户端,我们将利用它与自己的谷歌账户进行对接,从而对日程表服务加以操作。要想让代码正确起效,大家需要通过设定让自己的谷歌账户接受来自日程表的查询。

虽然这是本篇指南文章的重要前提,但并不能算主要内容。为了避免在这方面浪费太多篇幅,请大家直接参考官方说明文档。各位不必担心,整个设置过程非常简单,而且只要五分钟左右即可搞定。

本教程附带的示例代码中包含谷歌PHP API客户端代码,建议大家就使用这一套以确保整个学习过程与文章说明保持一致。另外,如果大家想尝试自行安装,请点击此处查看官方说明文档。

接下来按照指示向apiAccess.php文件中填写信息。该文件在程序化与面向对象两套实例中都会用到,因此大家不必在新版本中重复填写。我在文件中留下了自己填写的内容,这样大家就能更轻松地找到对应位置并将其按自己的资料进行修改。

如果大家碰巧用的是NetBeans,我把各个项目文件保存在了包含有不同范例的文件夹当中。这样大家可以轻松打开该项目,并点选Run——>Run Project在本地PHP服务器(要求使用PHP 5.4)上直接加以运行。

与谷歌API对接的客户端库为面向对象型。为了示例的正常运行,我编写了一套小小的函数合集,其中囊括了本教程所需要的所有函数。通过这种方式,我们可以利用程序化层在面向对象客户端库之上进行软件编写,且代码不会涉及任何对象。

如果大家打算快速测试自己的代码与指向谷歌API的连接是否正常起效,则可以直接使用位于index.php文件中的代码。它会列出账户中所有日程表信息,且应该至少有一套具备summary字段的日程表中包含您的姓名。如果日程表中存在联系人生日信息,那么谷歌API将无法与之正常协作。不过大家不用惊慌,另选一套即可。


  1. 		require_once './google-api-php-client/src/Google_Client.php';
  2. require_once ‘./google-api-php-client/src/contrib/Google_CalendarService.php’;
  3. require_once __DIR__ . ‘/../apiAccess.php’;
  4. require_once ‘./functins_google_api.php’;
  5. require_once ‘./functions.php’;
  6. session_start();
  7. $client = createClient();
  8. if(!authenticate($client)) return;
  9. listAllCalendars($client);

这个index.php文件将成为我们应用程序的入口点。我们不会使用任何Web框架或者其它复杂的机制。我们要做的只是简单输出一些HTML代码而已。

程序化开发方案

现在我们已经了解了所需创建的目标以及所能使用的资源,接下来就是下载附件中的源代码。我会提供代码中的有用片段,但为了进一步了解全局情况,大家可能希望访问其初始来源。

在这套方案中,我们只求成果能按预期生效。我们的代码可能会显得有些粗糙,而且其中只涉及以下几个文件:

• index.php – 这是惟一一个我们需要通过浏览器直接访问并转向其GET参数的文件。

• functions_google_api.php – 囊括所有前面提到的谷歌API。

• functions.php – 一切奇迹在此发生。

functions.php将容纳应用程序的所有执行过程。包括路由逻辑、表现以及一切值与行为全部发生于此。这款应用非常简单,其主逻辑如下图所示:

\

这里有一项名为doUserAction()的函数,它的生效与否取决于一条很长的if-else声明;其它方法则根据GET变量中的参数决定调用情况。这些方法随后利用API与谷歌日程表对接,并在屏幕上显示出我们需要的任何结果。


  1. 		function printCalendarContents($client) {
  2.    putTitle(‘These are you events for ‘ . getCalendar($client, $_GET[‘showThisCalendar’])[‘summary’] . ‘ calendar:’);
  3.    foreach (retrieveEvents($client, $_GET[‘showThisCalendar’]) as $event) {
  4.       print(‘<div style=”font-size:10px;color:grey;”>’ . date(‘Y-m-d H:m’, strtotime($event[‘created’])));
  5.       putLink(‘?showThisEvent=’ . htmlentities($event[‘id’]) .
  6.             ‘&calendarId=’ . htmlentities($_GET[‘showThisCalendar’]), $event[‘summary’]);
  7.       print(‘</div>’);
  8.       print(‘<br>’);
  9.    }
  10. }

这个例子恐怕要算我们此次编写的代码中最为复杂的函数。它所调用的是名为putTitle()的辅助函数,其作用是将某些经过格式调整的HTML输出以充当标题。标题中将包含我们日程表的实际名称,这是通过调用来自functions_google_api.php文件中的getCalendar()函数来实现的。返回的日历信息是一个数组,其中包含一个summary字段,而这正是我们要找的内容。

$client变量被传递到我们的所有函数当中。它需要与谷歌API相连,不过这方面内容我们稍后再谈。

接下来,我们整理一下日程表中的全部现有事件。这份数组列表由封装在retrieveEvents()函数中的API请求运行得来。对于每个事件,我们都会显示出其创建日期及标题。

\

其余部分代码与我们之前讨论过的内容相近,甚至更容易理解。大家可以抱着轻松的心情随便看看,然后抖擞精神进军下一章。

组织程序化代码

我们当前的代码完全没问题,但我想我们可以通过调整使其以更合适的方式组织起来。大家可能已经从附带的源代码中发现,该项目所有已经组织完成的代码都被命名为“GoogleCalProceduralOrganized”。

使用全局客户端变量

在代码组织工作中,第一件让人心烦的事在于,我们把$client变量作为参数推广到全局以及嵌套函数的深层当中。程序化编程方案对这类情况提供了一种巧妙的解决办法,即全局变量。由于$client是由index.php所定义,而从全局观点来看,我们需要改变的只是函数对该变量的具体使用方式。因此我们不必改变$client参数,而只需进行如下处理:


  1. 		function printCalendars() {
  2.    global $client;
  3.    putTitle(‘These are your calendars:’);
  4.    foreach (getCalendarList($client)[‘items’] as $calendar) {
  5.       putLink(‘?showThisCalendar=’ . htmlentities($calendar[‘id’]), $calendar[‘summary’]);
  6.       print(‘<br>’);
  7.    }
  8. }

大家不妨将现有代码与附件中的代码成品进行比较,看看二者有何不同之处。没错,我们并没有将$client作为参数传递,而是在所有函数中使用global $client并将其作为只传递向谷歌API函数的参数。从技术角度看,即使是谷歌API函数也能够使用来自全局的$client变量,但我认为最好还是尽量保持API的独立性。

从逻辑中分离表示

某些函数的作用非常明确——只用于在屏幕上输出信息,但有些函数则用于判断触发条件,更有些函数身兼两种作用。面对这种情况,我们往往最好把这些存在特殊用途的函数放在属于自己的文件当中。我们首先整理只用于屏幕信息输出的函数,并将其转移到functions_display.php文件当中。具体做法如下所示:


  1. 		function printHome() {
  2.    print(‘Welcome to Google Calendar over NetTuts Example’);
  3. }
  4. function printMenu() {
  5.    putLink(‘?home’, ‘Home’);
  6.    putLink(‘?showCalendars’, ‘Show Calendars’);
  7.    putLink(‘?logout’, ‘Log Out’);
  8.    print(‘<br><br>’);
  9. }
  10. function putLink($href, $text) {
  11.    print(sprintf(‘<a href=”%s” style=”font-size:12px;margin-left:10px;”>%s</a> | ‘, $href, $text));
  12. }
  13. function putTitle($text) {
  14.    print(sprintf(‘<h3 style=”font-size:16px;color:green;”>%s</h3>’, $text));
  15. }
  16. function putBlock($text) {
  17.    print(‘<div display=”block”>’.$text.'</div>’);
  18. }

要完成剩余的表示分离工作,我们需要从方法中提取出表示部分。下面我们就以单一方法为例演示这一过程:


  1. 		function printEventDetails() {
  2.    global $client;
  3.    foreach (retrieveEvents($_GET[‘calendarId’]) as $event)
  4.       if ($event[‘id’] == $_GET[‘showThisEvent’]) {
  5.          putTitle(‘Details for event: ‘. $event[‘summary’]);
  6.          putBlock(‘This event has status ‘ . $event[‘status’]);
  7.          putBlock(‘It was created at ‘ .
  8.                date(‘Y-m-d H:m’, strtotime($event[‘created’])) .
  9.                ‘ and last updated at ‘ .
  10.                date(‘Y-m-d H:m’, strtotime($event[‘updated’])) . ‘.’);
  11.          putBlock(‘For this event you have to <strong>’ . $event[‘summary’] . ‘</strong>.’);
  12.       }
  13. }

我们可以明显看到,无论if声明中的内容如何、其代码都属于表示代码,而余下的部分则属于业务逻辑。与其利用一个庞大的函数处理所有事务,我们更倾向于将其拆分为多个不同函数:


  1. 		function printEventDetails() {
  2.    global $client;
  3.    foreach (retrieveEvents($_GET[‘calendarId’]) as $event)
  4.       if (isCurrentEvent($event))
  5.          putEvent($event);
  6. }
  7. function isCurrentEvent($event) {
  8.    return $event[‘id’] == $_GET[‘showThisEvent’];
  9. }

分离工作完成后,业务逻辑就变得简单易懂了。我们甚至提取了一个小型方法来检测该事件是否就是当前事件。所有表示代码现在都由名为putEvent($event)函数负责,且被保存在functions_display.php文件当中:


  1. 		function putEvent($event) {
  2.    putTitle(‘Details for event: ‘ . $event[‘summary’]);
  3.    putBlock(‘This event has status ‘ . $event[‘status’]);
  4.    putBlock(‘It was created at ‘ .
  5.          date(‘Y-m-d H:m’, strtotime($event[‘created’])) .
  6.          ‘ and last updated at ‘ .
  7.          date(‘Y-m-d H:m’, strtotime($event[‘updated’])) . ‘.’);
  8.    putBlock(‘For this event you have to <strong>’ . $event[‘summary’] . ‘</strong>.’);
  9. }

尽管该方法只负责显示信息,但其功能仍需在对$event结构非常了解的前提下方能实现。不过对于我们的简单实例来说,这已经足够了。对于其余方法,大家可以通过类似的方式进行分离。

清除过长的if-else声明

目前代码整理工作还剩下最后一步,也就是存在于doUserAction()函数中的过长if-else声明,其作用是决定每项行为的实际处理方式。在元编程方面(通过引用来调用函数),PHP具备相当出色的灵活性。这种特性使我们能够将$_GET变量的值与函数名称关联起来。如此一来,我们可以在$_GET变量中引入单独的action参数,并将该值作为函数名称。


  1. 		function doUserAction() {
  2.    putMenu();
  3.    if (!isset($_GET[‘action’])) return;
  4.       $_GET[‘action’]();
  5. }

基于这种方式,我们生成的菜单将如下所示:


  1. 		function putMenu() {
  2.    putLink(‘?action=putHome’, ‘Home’);
  3.    putLink(‘?action=printCalendars’, ‘Show Calendars’);
  4.    putLink(‘?logout’, ‘Log Out’);
  5.    print(‘<br><br>’);
  6. }

如大家所见,经过重新整理之后,代码已经呈现出面向对象式设计的特性。虽然目前我们还不清楚其面向的是何种对象、会执行哪些确切行为,但其特征已经初露端倪。

我们已经让来自业务逻辑的数据类型成为表示的决定性因素,其效果与我们在文首介绍环节中谈到的依赖倒置机制比较类似。控制流的方向仍然是从业务逻辑指向表示,但源代码依赖性则与之相反。从这一点上看,我认为整套机制更像是一种双向依赖体系。

设计倾向上的面向对象化还体现在另一个方面,即我们几乎没有涉及到元编程。我们可以调用一个方法,但却对其一无所知。该方法可以拥有任何内容,且过程与处理低级多态性非常相近。

依赖性分析

对于当前代码我们可以绘制出一份关系图,内容如下所示。通过这幅关系图,我们可以看到应用程序运行流程的前几个步骤。当然,把整套流程都画下来就太过复杂了。

\

蓝色线条代表程序调用。如大家所见,这些线条与始终指向同一个方向。图中的绿色线条则表示间接调用,可以看到所有间接调用都要经过doUserAction()函数。这两种线条代表控制流,显然控制流的走向基本不变。

红色线条则引入了完全不同的概念,它们代表着最初的源代码依赖关系。之所以说“最初”,是因为随着应用的运行其指向将变得愈发复杂、难以把握。putMenu()方法中包含着被特定关系所调用的函数的名称。这是一种依赖关系,同时也是适用于所有其它关系创建方法的基本规则。它们的具体关系取决于其它函数的行为。

上图中我们还能看到另一种依赖关系,即对数据的依赖。我前面曾经提到过$calendar与$event,输出函数需要清楚了解这些数组的内部结构才能实现既定功能。

完成了以上内容之后,我们已经做好充分准备、可以迎来本篇教程中的最后一项挑战。

面向对象解决方案

无论采用哪种范式,我们都不可能为问题找到完美的解决方案。因此以下代码组织方式仅仅属于我的个人建议。

从直觉出发

我们已经完成了业务逻辑与表现的分离工作,甚至将doUserAction()方法作为一个独立单元。那么我的直觉是先创建三个类,Presenter、Logic与Router。三者以后可能都需要进行调整,但我们不妨先从这里着手,对吧?

Router中将只包含一个方法,且实现方式与之前提到的方法非常相似。


  1. 		class Router {
  2.    function doUserAction() {
  3.       (new Presenter())->putMenu();
  4.       if (!isset($_GET[‘action’]))
  5.          return;
  6.       (new Logic())->$_GET[‘action’]();
  7.    }
  8. }

现在我们要做的是利用刚刚创建的Presenter对象调用putMenu()方法,其它行为则利用Logic对象加以调用。不过这样会马上产生问题——我们的一项行为并不包含在Logic类当中。putHome()存在于Presenter类中,我们需要在Logic中引入一项行为,借以在Presenter中作为putHome()方法的委托。请记住,目前我们要做的只是将现有代码整理到三个类当中,并将三者作为面向对象设计的备选对象。现在所做的一切只是为了让设计方案能够正常运作,待代码编写完成后、我们将进一步加以调试。

在将putHome()方法引入Logic类后,我们又遇上新的难题。怎样才能从Presenter中调用方法?我们可以创建一个Presenter对象,并将其传递至Logic当中。下面我们从Router类入手。


  1. 		class Router {
  2.    function doUserAction() {
  3.       (new Presenter())->putMenu();
  4.       if (!isset($_GET[‘action’]))
  5.          return;
  6.       (new Logic(new Presenter))->$_GET[‘action’]();
  7.    }
  8. }

现在我们可以向Logic添加一个构造函数,并将其添加到Presenter内指向putHome()的委托当中。


  1. 		class Logic {
  2.    private $presenter;
  3.    function __construct(Presenter $presenter) {
  4.       $this->presenter = $presenter;
  5.    }
  6.    function putHome() {
  7.       $this->presenter->putHome();
  8.    }
  9. […]
  10. }

通过对index.php的一些小小调整、让Presenter包含原有display方法、Logic包含原有业务逻辑函数、Router包含原有行为选择符,我们已经可以让自己的代码正常运行并具备“Home”菜单元素。


  1. 		require_once './google-api-php-client/src/Google_Client.php';
  2. require_once ‘./google-api-php-client/src/contrib/Google_CalendarService.php’;
  3. require_once __DIR__ . ‘/../apiAccess.php’;
  4. require_once ‘./functins_google_api.php’;
  5. require_once ‘./Presenter.php’;
  6. require_once ‘./Logic.php’;
  7. require_once ‘./Router.php’;
  8. session_start();
  9. $client = createClient();
  10. if(!authenticate($client)) return;
  11. (new Router())->doUserAction();

下面就是其执行效果。

\

接下来,我们需要在Logic类中适当变更指向display逻辑的调用指令,从而与$this->presenter相符。现在我们有两个方法——isCurrentEvent()与retrieveEvents()——二者只被用于Logic类内部。我们将其作为专用方法,并据此变更调用关系。

下面我们对Presenter类进行同样处理,并将所有指向方法的调用都变更为指向$this->something。由于putTitle()、putLink()与putBlock()都只由Presenter使用,因此需要将其变为专用。如果感到上述变更过程难于理解及操作,请大家查看附件源代码内GoogleCalObjectOrientedInitial文件夹中的已完成代码。

现在我们的应用程序已经能够正常运行,这些按面向对象语法整理过的程序化代码仍然使用$client全局变量,且拥有大量其它非面向对象式特性——但仍然能够正常运行。

如果要为目前的代码绘制依赖关系类图,则应如下所示:

\

控制流与源代码的依赖关系都通过Router、然后是Logic、最后通过表示层。最后一步变更削弱了我们在之前步骤中所观察到的依赖倒置特性,但大家千万不要因此受到迷惑——原理依然如故,我们要做的是使其更加清晰。

恢复源代码依赖关系

很难界定基础性原则之间哪一条更重要,但我认为依赖倒置原则对我们的应用设计影响最大也最直接。该原则规定:

A:高层模块不应依赖于低级模块,二者都应依赖于抽象。

B:抽象不应依赖于细节,细节应依赖于抽象。

简单来说,这意味着具体实施应依赖于抽象类。类越趋近抽象,它们就越不容易发生改变。因此我们可以这样理解:变更频繁的类应依赖于其它更为稳定的类。所以任何应用中最不稳定的部分很可能是用户界面,这在我们的应用示例中通过Presenter类来实现。让我们再来明确一下依赖倒置流程。

首先,我们让Router仅使用Presenter,并打破其对Logic的依赖关系。


  1. 		class Router {
  2.    function doUserAction() {
  3.       (new Presenter())->putMenu();
  4.       if (!isset($_GET[‘action’]))
  5.          return;
  6.       (new Presenter())->$_GET[‘action’]();
  7.    }
  8. }

然后我们变更Presenter,使其使用Logic实例并由此获取需要的信息。在我们的例子中,我认为由Presenter来建立该Logic实例也可以接受,但在生产系统当中、大家可能通常会利用Factories来创建与对象相关的业务逻辑,并将其注入表示层当中。

现在,原本同时存在于Logic与Presenter两个类中的putHome()函数将从Logic中消失。这一现象说明我们已经开始进行重复数据清除工作。指向Presenter的构造函数与引用也从Logic中消失了。另一方面,由构造函数所创建的Logic对象则必须被写入Presenter。


  1. 		class Presenter {
  2.    private $businessLogic;
  3.    function __construct() {
  4.       $this->businessLogic = new Logic();
  5.    }
  6.    function putHome() {
  7.       print(‘Welcome to Google Calendar over NetTuts Example’);
  8.    }
  9. […]
  10. }

以上变更完成之后,点击Show Calendars,屏幕上会出现错误提示。由于我们链接内部的所有行为都指向Logic类中的函数名称,因此必须通过更多一致性调整来恢复二者之间的依赖关系。下面我们对方法进行一一修改,先来看第一条错误信息:


  1. 		Fatal error: Call to undefined method Presenter::printCalendars()
  2. in /[…]/GoogleCalObjectOrientedFinal/Router.php on line 9

我们的Router希望调用Presenter中某个并不存在的方法,也就是printCalendars()。我们在Presenter中创建这样一个方法,并检查它会对Logic造成哪些影响。在结果中大家可以看到,它输出了一条标题,并在重复循环之后再次调用putCalendars()。在Presenter类中,printCalendars()方法如下所示:


  1. 		function printCalendars() {
  2.    $this->putCalendarListTitle();
  3.    foreach ($this->businessLogic->getCalendars() as $calendar) {
  4.       $this->putCalendarListElement($calendar);
  5.    }
  6. }

在Logic方面,该方法则非常单纯——直接调用谷歌API库。


  1. 		function getCalendars() {
  2.    global $client;
  3.    return getCalendarList($client)[‘items’];
  4. }

这可能让大家心中出现两个问题,“我们真的需要Logic类吗?”以及“我们的应用程序是否存在任何逻辑?”好吧,目前我们还不知道答案,现在能做的只是继续上述过程,直到所有代码都能正常工作且Logic不再依赖于Presenter。

接下来,我们将使用Presenter中的printCalendarContents()方法,如下所示:


  1. 		function printCalendarContents() {
  2.    $this->putCalendarTitle();
  3.    foreach ($this->businessLogic->getEventsForCalendar() as $event) {
  4.       $this->putEventListElement($event);
  5.    }
  6. }

这将反过来允许我们简化Logic中的getEventsForCalendar(),并将其转化为如下形式:


  1. 		function getEventsForCalendar() {
  2.    global $client;
  3.    return getEventList($client, htmlspecialchars($_GET[‘showThisCalendar’]))[‘items’];
  4. }

现在应用已经不再报错,但我却又发现了新的问题。$_GET变量同时被Logic与Presenter类所使用——$_GET应该只被Presenter类使用才对。我的意思是,由于需要创建用于填充$_GET变量的链接,Presenter是肯定需要感知$_GET的。这就意味着$_GET与HTTP密切相关。现在,我们希望自己的代码能与命令行或者桌面图形用户界面协同运作。

因此我们需要保证只有Presenter感知到这一情况,即将以上两个方法变换为下列内容:


  1. 		function getEventsForCalendar($calendarId) {
  2.    global $client;
  3.    return getEventList($client, $calendarId)[‘items’];
  4. }

  1. 		function printCalendarContents() {
  2.    $this->putCalendarTitle();
  3.    $eventsForCalendar = $this->businessLogic->getEventsForCalendar(htmlspecialchars($_GET[‘showThisCalendar’]));
  4.    foreach ($eventsForCalendar as $event) {
  5.       $this->putEventListElement($event);
  6.    }
  7. }

现在我们需要实现特定事件的输出功能。对于本文中的范例,我们假设自己无法直接检索任何事件,即必须亲自进行事件查找。Logic类这时候就要派上用场了,我们可以在其中操作事件列表并搜索特定ID:


  1. 		function getEventById($eventId, $calendarId) {
  2.    foreach ($this->getEventsForCalendar($calendarId) as $event)
  3.       if ($event[‘id’] == $eventId)
  4.          return $event;
  5. }

然后Presenter的对应调用会完成输出工作:


  1. 		function printEventDetails() {
  2.    $this->putEvent(
  3.       $this->businessLogic->getEventById(
  4.          $_GET[‘showThisEvent’],
  5.          $_GET[‘calendarId’]
  6.       )
  7.    );
  8. }

就是这样,我们已经成功完成了依赖倒置。

\

控制流仍然由Logic指向Presenter,所有输出内容也完全由Logic进行定义。这样如果我们打算接入其它日程表服务,则只需创建另一个Logic类并将其注入Presenter即可,Presenter本身不会感知到任何差异。再有,源代码依赖关系也被成功倒置。Presenter是惟一创建且直接依赖于Logic的类。这种依赖关系对于保证Presenter可随意变更数据显示方式而又不影响Logic内容而言至关重要。此外,这种依赖关系允许我们利用CLI Presenter或者其它任何向用户显示信息的方法来替代HTML Presenter。

摆脱全局变量

现在惟一漏网的潜在设计缺陷就只剩下$client全局变量了。应用程序中的所有代码都会对其进行访问,但与之形成鲜明对比的是,真正有必要访问$client的只有Logic类一个。最直观的解决办法肯定是使其变更为专用类变量,但这样一来我们就需要将$client经由Router传递至Presenter处,从而使presenter能够利用$client变更创建出Logic对象——这对于解决问题显然无甚作用。我们的设计初衷是在独立环境下建立类,并准确为其分配依赖关系。

对于任何大型类结构,我们都倾向于使用Factories;但在本文的小小范例中,index.php文件已经足以容纳逻辑创建了。作为应用程序的入口点,这个类似于高层体系结构中“main”的文件仍然处于业务逻辑的范畴之外。

因此我们将index.php中的代码变更为以下内容,同时保留所有内容以及session_start()指令:


  1. 		$client = createClient();
  2. if(!authenticate($client)) return;
  3. $logic = new Logic($client);
  4. $presenter = new Presenter($logic);
  5. (new Router($presenter))->doUserAction();

结语

现在工作彻底完成了。当然,我们的设计肯定还有很多改进的空间。我们可以为Logic类中的方法编写一些测试流程,也许Logic类本身也可以换个更有代表性的名称,例如GoogleCalendarGateway。我们还可以创建Event与Calendar类,从而更好地控制相关数据及行为,同时将Presenter的依赖关系根据数据类型拆分为数组。另一项改进与扩展方针则是创建多态性行为类,用于取代直接通过$_GET调用函数。总而言之,对于这一范例的改进可谓无穷无尽,有兴趣的朋友可以尝试将自己的想法转化为现实。我在附件的GoogleCalObjectOrientedFinal文件夹中保存有代码的最终版本,大家能够以此为起点进行探索。

如果大家的好奇心比较强,也可以试着将这款小应用与其它日程表服务对接,看看如何在不同平台上以不同方式实现信息输出。对于使用NetBeans的朋友,每个源代码文件夹中都包含有NetBeans项目,大家只要直接打开即可。在最终版本中,PHPUnit也已经准备就绪。不过我在其它项目中将其移除了——因为还没有经过测试。

感谢您的阅读。

附件下载地址:https://github.com/tutsplus/From-Procedural-to-Object-Oriented-PHP

原文链接:https://net.tutsplus.com/tutorials/php/from-procedural-to-object-oriented-php/

jQuery Wookmark-2 jQuery动态表格插件的效果展示

Wookmark是一个为了展示动态表格元素的一款非常实用的jQuery插件。

你可以到http://www.wookmark.com/jquery-plugin查看其示例。

\

 

配置

1.jQuery版本1.4.3或更高版本(最好不是2.0及以上版本)

2.将jquery.wookmark.js引入

用法

该插件可以被jQuery以不同的方式调用

可以用默认的方式调用,这也是官方推荐的方式:

$(‘.myElements’).wookmark();

其中myElements是你做的表格的,并且想让它成为wookmark这种动态表格元素展示的 class 样式

配置项

01. view plaincopy在CODE上查看代码片派生到我的代码片
02.
03.$('.myElements').wookmark({ 
04.align: 'center'
05.autoResize: false
06.comparator: null
07.container: $('body'), 
08.direction: undefined, 
09.ignoreInactiveItems: true
10.itemWidth: 0, 
11.fillEmptySpace: false
12.flexibleWidth: 0, 
13.offset: 2, 
14.onLayoutChanged: undefined, 
15.outerOffset: 0, 
16.resizeDelay: 50, 
17.possibleFilters: [] 
18.});

其中上边这些配置项中提及到的参数,在我们之前写的博客上也有所提及,大家可以在那边看:http://blog.csdn.net/sunyingyuan/article/details/17613627

 

itemWidth 和 flexibleWidth

这两个字段的值可以设置为数字类型(这时是被当做像素值来处理的),当然也可以设置成百分比,当 flexibleWidth 设置成 itemWidth != 0 是被用作列的最小宽度(这个地方我也没怎么看懂英文,等我好好实验下,然后再做修改)。

更新 trigger

元素被隐藏了是一直不可见的一直到它被设置为可视状态的时候,如果你在一个隐藏的选项卡上设置成wookmark属性,并不会立刻得到效果,当然你也可以手动触发触发器使得你的wookmark是可见的。

1. view plaincopy在CODE上查看代码片派生到我的代码片
2.
3.$('#myContent').trigger('refreshWookmark');

 

 

fillEmptySpace

 

有时候为了创建一个合适的布局,比如说在底部创建一个占位符。你可以在官方示例中的 example-placeholder 查看其具体使用方法,占位符需要使用到的class是 wookmark-placeholder ,当然你也可以覆盖class样式来满足你的个性化需求。

ignoreInactiveItems

 

 

当你设置 ignoreInactiveItems 为false的时候,不活动的项依然会展示。这个方法可以用来淡出过滤项目的方式。你可以查看这个示例。

comparator

你可以通过这个选项提供一个普通的比较函数作为一个排序的方式,你可以查看 example-sort or example-stamp 查看如何使用它。

原文地址: http://www.php100.com/html/program/jquery/2014/0328/6728.html

为您搜集20款开源搜索引擎系统

一些开源搜索引擎系统介绍,包含开源Web搜索引擎和开源桌面搜索引擎。
Sphider
Sphider是一个轻量级,采用PHP开发的web spider和搜索引擎,使用mysql来存储数据。可以利用它来为自己的网站添加搜索功能。Sphider非常小,易于安装和修改,已经有数千网站在使用它。
RiSearch PHP
RiSearch PHP是一个高效,功能强大的搜索引擎,特别适用于中小型网站。RiSearch PHP非常快,它能够在不到1秒钟内搜索5000-10000个页面。RiSearch是一个索引搜索引擎,这就意味着它先将你的网站做索引并建立一个数据库来存储你网站所有页面的关键词以便快速搜索。Risearch是全文搜索引擎脚本,它把所有的关键词都编成一个文档索引除了配置文件里面的定义排除的关键词。 RiSearch使用经典的反向索引算法(与大型的搜索引擎相同),这就是为什么它会比其它搜索引擎快的原因。
PhpDig
PhpDig是一个采用PHP开发的Web爬虫和搜索引擎。通过对动态和静态页面进行索引建立一个词汇表。当搜索查询时,它将按一定的排序规则显示包含关键字的搜索结果页面。PhpDig包含一个模板系统并能够索引PDF,Word,Excel,和PowerPoint文档。PHPdig适用于专业化更强、层次更深的个性化搜索引擎,利用它打造针对某一领域的垂直搜索引擎是最好的选择。
OpenWebSpider
OpenWebSpider是一个开源多线程Web Spider(robot:机器人,crawler:爬虫)和包含许多有趣功能的搜索引擎。
Egothor
Egothor是一个用Java编写的开源而高效的全文本搜索引擎。借助Java的跨平台特性,Egothor能应用于任何环境的应用,既可配置为单独的搜索引擎,又能用于你的应用作为全文检索之用。
Nutch
Nutch 是一个开源Java 实现的搜索引擎。它提供了我们运行自己的搜索引擎所需的全部工具。包括全文搜索和Web爬虫。
Lucene
Apache Lucene是一个基于Java全文搜索引擎,利用它可以轻易地为Java软件加入全文搜寻功能。Lucene的最主要工作是替文件的每一个字作索引,索引让搜寻的效率比传统的逐字比较大大提高,Lucen提供一组解读,过滤,分析文件,编排和使用索引的API,它的强大之处除了高效和简单外,是最重要的是使使用者可以随时应自已需要自订其功能。
Oxyus
是一个纯java写的web搜索引擎。
BDDBot
BDDBot是一个简单的易于理解和使用的搜索引擎。它目前在一个文本文件(urls.txt)列出的URL中爬行,将结果保存在一个数据库中。它也支持一个简单的Web服务器,这个服务器接受来自浏览器的查询并返回响应结果。它可以方便地集成到你的Web站点中。
Zilverline
Zilverline是一个搜索引擎,它通过web方式搜索本地硬盘或intranet上的内容。Zilverline可以从PDF, Word, Excel, Powerpoint, RTF, txt, java, CHM,zip, rar等文档中抓取它们的内容来建立摘要和索引。从本地硬盘或intranet中查找到的结果可重新再进行检索。Zilverline支持多种语言其中包括中文。
XQEngine
XQEngine用于XML文档的全文本搜索引擎。利用XQuery做为它的前端查询语言。它能够让你查询XML文档集合通过使用关键字的逻辑组合。有点类似于Google与其它搜索引擎搜索HTML文档一样。XQEngine只是一个用Java开发的很紧凑的可嵌入的组件。
MG4J
MG4J可以让你为大量的文档集合构建一个被压缩的全文本索引,通过使内插编码(interpolative coding)技术。
JXTA Search
JXTA Search是一个分布式的搜索系统。设计用在点对点的网络与网站上。
YaCy
YaCy基于p2p的分布式Web搜索引擎。同时也是一个Http缓存代理服务器。这个项目是构建基于p2p Web索引网络的一个新方法。它可以搜索你自己的或全局的索引,也可以Crawl自己的网页或启动分布式Crawling等。
Red-Piranha
Red-Piranha是一个开源搜索系统,它能够真正”学习”你所要查找的是什么。Red-Piranha可作为你桌面系统(Windows,Linux与Mac)的个人搜索引擎,或企业内部网搜索引擎,或为你的网站提供搜索功能,或作为一个P2P搜索引擎,或与wiki结合作为一个知识/文档管理解决方案,或搜索你要的RSS聚合信息,或搜索你公司的系统(包括SAP,Oracle或其它任何Database/Data source),或用于管理PDF,Word和其它文档,或作为一个提供搜索信息的WebService或为你的应用程序(Web,Swing,SWT,Flash,Mozilla-XUL,PHP, Perl或c#/.Net)提供搜索后台等等。
LIUS
LIUS是一个基于Jakarta Lucene项目的索引框架。LIUS为Lucene添加了对许多文件格式的进行索引功能如:Ms Word,Ms Excel,Ms PowerPoint,RTF,PDF,XML,HTML,TXT,Open Office序列和JavaBeans.针对JavaBeans的索引特别有用当我们要对数据库进行索引或刚好用户使用持久层ORM技术如:Hibernate,JDO,Torque,TopLink进行开发时。
Apache Solr
Solr是一个高性能,采用Java5开发,基于Lucene的全文搜索服务器。文档通过Http利用XML加到一个搜索集合中。查询该集合也是通过 http收到一个XML/JSON响应来实现。它的主要特性包括:高效、灵活的缓存功能,垂直搜索功能,高亮显示搜索结果,通过索引复制来提高可用性,提供一套强大Data Schema来定义字段,类型和设置文本分析,提供基于Web的管理界面等。
Paoding
Paoding中文分词是一个使用Java开发的,可结合到Lucene应用中的,为互联网、企业内部网使用的中文搜索引擎分词组件。 Paoding填补了国内中文分词方面开源组件的空白,致力于此并希翼成为互联网网站首选的中文分词开源组件。 Paoding中文分词追求分词的高效率和用户良好体验。
Carrot2
Carrot2是一个开源搜索结果分类引擎。它能够自动把搜索结果组织成一些专题分类。Carrot2提供的一个架构能够从各种搜索引擎(YahooAPI、GoogleAPI、MSN Search API、eTools Meta Search、Alexa Web Search、PubMed、OpenSearch、Lucene index、SOLR)获取搜索结果。
Regain
regain是一款与Web搜索引擎类似的桌面搜索引擎系统,其不同之处在于regain不是对Internet内容的搜索,而是针对自己的文档或文件的搜索,使用regain可以轻松地在几秒内完成大量数据(许多个G)的搜索。Regain采用了Lucene的搜索语法,因此支持多种查询方式,支持多索引的搜索及基于文件类型的高级搜索,并且能实现URL重写及文件到HTTP的桥接,并且对中文也提供了较好的支持。
Regain提供了两种版本:桌面搜索及服务器搜索。桌面搜索提供了对普通桌面计算机的文档与局域网环境下的网页的快速搜索。服务器版本主要安装在Web服务器上,为网站及局域网环境下的文件服务器进行搜索。

原文地址: http://www.php100.com/html/it/focus/2014/0404/6750.html