Posts Tagged ‘语言’

WEB页面多语言支持解决方案

星期二, 06月 3rd, 2008

首先建立语言档,在项目中加入.resx文件
例如:
message.zh-cn.resx ‘简体中文
message.zh-tw.resx ‘繁体中文
message.en ‘英文
…………..
=========================================
然后利用Name –Value 键值对 填入您要在页面上显示de语言
如:
name value
message.zh-cn.resx中:
res_loginbname 登陆名 :
message.zh-tw.resx中:
res_loginbname 登陸名 :
message.zh-cn.resx中:
res_loginbname Login Name :

=========================================
然后在Golbal.asax中加入多语言设定支持相关代码(浏览器需要支持Cookie)

‘=========================================
‘ Application_BeginRequest Event

‘ The Application_BeginRequest method is an ASP.NET event that executes
‘ on each web request into the portal application.

‘ The thread culture is set for each request using the language
‘ settings

‘=========================================
Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
Try
If Not Request.Cookies(”resource”) Is Nothing Or Request.Cookies(”resource”).Value = “” Then
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(Request.Cookies(”resource”).Value)
Else
Thread.CurrentThread.CurrentCulture = New CultureInfo(ConfigurationSettings.AppSettings(”DefaultCulture”))
End If
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture
Catch ex As Exception
Thread.CurrentThread.CurrentCulture = New CultureInfo(ConfigurationSettings.AppSettings(”DefaultCulture”))
End Try
End Sub ‘Application_BeginRequest

在Web.Config中加入如下相关代码,用于设定编码和默认语种,在Global.asax中有调用:

=========================================
<globalization requestEncoding=”utf-8″ responseEncoding=”utf-8″ />
<appSettings>
<add key=”DefaultCulture” value=”zh-cn” />
<!– zh-cn:簡體中文 zh-tw:繁體中文 en:英文 –>
</appSettings>

=========================================
页面相关代码中使用多语言支持:

Imports System.Resources

Public Class 类名
Inherits System.Web.UI.Page
Protected LocRM As ResourceManager = New ResourceManager(”项目文件名.message”, GetType(类名).Assembly)

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
lblLogin.Text = LocRM.GetString(”res_login”)
End Sub
End Class


=========================================

到这里多语言支持de工作就作完了,接下来自己去慢慢Key
message.zh-cn.resx ‘简体中文
message.zh-tw.resx ‘繁体中文
message.en ‘英文

这几个语言档吧

为自己的ASP网站系统构建一套标记语言

星期二, 06月 3rd, 2008

  作为动态网站在建设过程中难免遇到在线编辑文章de问题.HTML提供了一个textarea标记,但是实际上没有解决这个问题,因为从textareade是纯文本.除非在输入de时候使用了HTML标记,否则在输出de时候将获得从头到尾毫无结构de一盘文字.WEB设计中通过DHTML构建一类所见即所得de在线编辑器对这个问题有了很好de解决.
  但是所见即所得并不是唯一de解决办法.笔者在上网过程中发现一些门户网站de在线编辑器非常有特色.它并不是所见即所得(但是提供了一个预览功能),而是一个textareade文本域,但是又不支持HTML标记语言.而是有它自己de一套标记语言.

按此在新窗口浏览图片

图1

按此在新窗口浏览图片

图2
  笔者使用觉得非常流畅,总结其优点如下:
  第一, 它de标记不多,相对于HTML而言非常简单,而且通过回车可以自动生成段落,容易被一般用户所接受.笔者认为如果使用中文标记,可以被更多国内用户接受.
  第二, 相对所见即所得de编辑器而言用户更能掌握自己de文章结构,生成乱码少.
  第三, 可见性相对于HTML而言要好得多,加上预览功能后更佳.
  第四, 由于自己de标记语言不支持脚本,因而是更安全de.
  经过笔者一番思考和实践,现把构建这种属于自己de标记语言de方法公示:
  首先,我为自己de网站确定一套简单而必要de标记语言.确定时把一些不必要de省略.拿我而言,我为自己de网站确定de标记语言如下:
  [图片]图片de网址[/图片]
  [大标题]文字内容[/大标题]
  [小标题]文字内容[/小标题] (考虑到用户可能会细分所以加上)
  [粗体]文字内容[/粗体]
  [斜体]文字内容[/斜体]
  [链接]网址[/链接]
  然后,提供一定de机制,让浏览器读懂我de标记.那么,怎么让浏览器读懂我自己确定de标记呢? 在内容显示de页面,我需要写一个程序将我de所有标记翻译成为标准deHTML标记,但是此前必须过滤掉用户输进来deHTML相关代码.
  第一步:过滤HTML相关代码.
  这个其实很简单,只要将所有de “<” 标签替换为 “<” ,另外把所有 “>” 替换为 “>” 就可以了.在ASP中通过如下语句实现:
Content=replace(content,”<”,”<”)
Content=replace(content,”>”,”>”)
  (以上相关代码中,content是储存了我要显示de内容de变量,下文中若出现也表示一样de意思.)
  第二步:将我de标记翻译为HTML
  这个相对复杂一些,因为并不是简单de将所有[标签替换为<和]替换为>然后将里面de中文(比如图片)翻译为英文(比如IMG)就可以de.原因有两个:
  1 是我de标记里面de内容,根据不同de分类需要做不同de处理:
  第一类,直接显示给用户de,比如:
[大标题]文字[/大标题]
  此时确实是只要将标签翻译成相应de英文,比如上面de标记翻译为<h1>文字</h1>就可以了.
  第二类,不直接呈现给用户de,比如:
[图片]图片网址[/图片]
  此时,标签中间de内容”图片网址”只是我要显示de网址,在HTML中是作为<IMG>标签deSRC属性,而且这个标签在HTML中是不要结尾标签de.所以直接翻译de结果是肯定错误de.
  第三类,直接呈现同时又作为属性,比如:
  [链接]网址[/链接]
  2 是并非所有出项标记de地方都是要翻译de,比如,有时候用户需要用符号”[“和符号”]”来表现他们de内容,而这时候如果将这样de标记翻译为”<”和”>”肯定不是符合用户de心意de.
  分析了出现de问题,笔者将在下面给出编写程序de思路参考和一个参考de程序.
  由于不同de标签需要de翻译方式不一样,所以必须针对不同de标签,一个个de翻译.
  对于任何单个de标记,一篇文章内可能出现多此,也可能一次也不出现,程序应当从头到尾首先检查某一标记de开始标记(比如对”图片]图片地址[/图片]”是”[图片]”)出现de位置,一旦检查到了,然后从那个位置开始检查结束标记,如果也检查到了,则说明这是我要de标记;如果结束标记没有检查到,那么说明那不是我要de标记,而只是用户自己展示de内容.检查到之后,将标记翻译为HTML标记,并根据不同类型对标记中de内容作不同de处理.坐完以后从结束标记de位置又继续检查,直到文章结束.
  实际编写中,需要用到递归de思想.下面给出翻译[图片]图片地址[/图片]这个标记de例子程序.

Function TranslateImg(Str)
 Start=instr(str,”[图片]”) ‘检查标记de开始位置
 If start=0 then exit function ‘开始位置为0,表示没有这个标记,那么程序结束
 End=instr(start,str,”[/图片]” ‘检查继该开始位置之后所出现de结束标记位置
 If end=0 then exit function ‘结束标记出现位置为0,表示没有结束标记,程序结束
 MidStr=mid(str,start 4,end-start-4) ‘标记中间de内容
 ReplaceStr=mid(str,start,end-start 5) ‘标记中间de内容加上标记,作为将要替换de内容
 Str=replace(instr,ReplaceStr,”<img src=”&MidStr&”>”) ‘将标记翻译为HTML
 TranslateImg Str ‘递归执行该函数
End Function

  通过以上分析,相信读者能够通过自己de分析为自己de网站构建一套”MyHTML”标记语言了.
  在实际de开发中还会有一些课题需要攻破,比如:标记嵌套de处理;是在将用户提交到数据库之前就翻译还是待用户浏览文章从数据库中调出来时才翻译;为用户提供一些自动插入标记de按钮方便用户de操作体验登.本文仅作抛砖引玉之用希望引得读者一点欣赏.

Java语言的接口与类型安全

星期一, 06月 2nd, 2008

接口是实现构件可插入性de关键,可插入构件de关键在于存在一个公用de接口,以及每个构件实现了这个接口.
  什么是接口?
  Java中de接口是一系列方法de声明,是一些方法特征de集合,一个接口只有方法de特征没有方法de实现,因此这些方法可以在不同de地方被不同de类实现,而这些实现可以具有不同de行为(功能).
  接口de两种含义:一,Java接口,Java语言中存在de结构,有特定de语法和结构;二,一个类所具有de方法de特征集合,是一种逻辑上de抽象.前者叫做“Java接口”,后者叫做“接口”.
  在Java语言规范中,一个方法de特征仅包括方法de名字,参数de数目和种类,而不包括方法de返回类型,参数de名字以及所抛出来de异常.在Java编译器检查方法de重载时,会根据这些条件判断两个方法是否是重载方法.但在Java编译器检查方法de置换时,则会进一步检查两个方法(分处超类型和子类型)de返还类型和抛出de异常是否相同.
  接口继承和实现继承de规则不同,一个类只有一个直接父类,但可以实现多个接口.
  Java接口本身没有任何实现,因为Java接口不涉及表象,而只描述public行为,所以Java接口比Java抽象类更抽象化.
  Java接口de方法只能是抽象de和公开de,Java接口不能有构造器,Java接口可以有public,静态de和final属性.
  接口把方法de特征和方法de实现分割开来.这种分割体现在接口常常代表一个角色,它包装与该角色相关de操作和属性,而实现这个接口de类便是扮演这个角色de演员.一个角色由不同de演员来演,而不同de演员之间除了扮演一个共同de角色之外,并不要求其它de共同之处.
  为什么使用接口?
  两个类中de两个类似de功能,调用他们de类动态de决定一种实现,那他们提供一个抽象父类,子类分别实现父类所定义de方法.
  问题de出现:Java是一种单继承de语言,一般情况下,哪个具体类可能已经有了一个超类,解决是给它de父类加父类,或者给它父类de父类加父类,只到移动到类等级结构de最顶端.这样一来,对一个具体类de可插入性de设计,就变成了对整个等级结构中所有类de修改.
  接口是可插入性de保证.
  在一个等级结构中de任何一个类都可以实现一个接口,这个接口会影响到此类de所有子类,但不会影响到此类de任何超类.此类将不得不实现这个接口所规定de方法,而其子类可以从此类自动继承这些方法,当然也可以选择置换掉所有de这些方法,或者其中de某一些方法,这时候,这些子类具有了可插入性(并且可以用这个接口类型装载,传递实现了他de所有子类).
  我关心de不是那一个具体de类,而是这个类是否实现了我需要de接口.
  接口提供了关联以及方法调用上de可插入性,软件系统de规模越大,生命周期越长,接口使得软件系统de灵活性和可扩展性,可插入性方面得到保证.
  类型
  使用Java接口将软件单位与内部和外部耦合起来.使用Java接口不是具体de类进行变量de类型声明,方法de返还类型声明,参量de类型声明,以及数据类型de转换.
  在理想de情况下,一个具体deJava类应当只实现Java接口和抽象Java类中声明de方法,而不应当给多余方法.
  类型等级结构
  Java接口(以及抽象类)一般用来作为一个类型de等级结构de起点.
  如果一个类已经有了一个主要de超类型,那么通过实现一个接口,这个类可以拥有另一个次要de超类型,这种次要de超类型叫做混合类型.
  Java接口常用方法

  单方法接口
  public interface Actionlistener(){
  public abstract void actionPerformed(ActionEvent event);
  }
  仅且只有一个方法,只有实现了这个接口(重写这个接口中de唯一一个方法),您才有资格去事件监听器列表里注册(参数为Actionlistener类型),当事件源变动时,自动调用这个唯一deactionPerformed方法.
  标识接口
  是没有任何方法和属性de接口.标识接口不对实现它de类有任何语意上de要求,它仅仅表明了实现它de类属于一个特定de类型(传递).
  不推荐过多de使用标识接口.
  常量接口
  用Java接口来声明一些常量,然后由实现这个接口de类使用这些常量(以前在做画板de时候这么干过).建议不要模仿这种常量接口de做法.
  Java语言类型安全问题
  Java是强类型de语言.这意味着Java编译器会对相关代码进行检查,以确定没一次赋值,每一次方法de调用是符合类型de.如果有任何不相符合de情况,Java编译器就会给出错误.
  类型检查是基于这样一个简单de事实:每一变量de声明都给这个变量一个类型;每一个方法包括构造器de声明都给这个方法de特征.这样一来,Java编译器可以对任何de表达式推断出一个明显类型,Java编译器可以基于明显类型对类型进行检查.
  Java语言是类型安全de.这就是说,任何被Java编译器接受de合法deJava类保证是类型安全de.换言之,在程序运行期间,不会有任何类型de错误.一个Java程序根本不可能将一个本来属于一个类型de变量当作另一个类型处理,因此也就不会产生由此而引起de错误.
  简单de说,Java语言依靠三种机制做到了类型安全:编译期间de类型检查,自动de存储管理,数组de边界检查.
  注:本篇大部分内容出之阎宏老师de《Java与模式》.

Java语言中链表和双向链表

星期一, 06月 2nd, 2008

  链表是一种重要de数据结构,在程序设计中占有很重要de地位.C语言和C++语言中是用指针来实现链表结构de,由于Java语言不提供指针,所以有人认为在Java语言中不能实现链表,其实不然,Java语言比C和C++更容易实现链表结构.Java语言中de对象引用实际上是一个指针(本文中de指针均为概念上de意义,而非语言提供de数据类型),所以我可以编写这样de类来实现链表中de结点.
  class Node
  {
  Object data;
  Node next;//指向下一个结点
  }
  将数据域定义成Object类是因为Object类是广义超类,任何类对象都可以给其赋值,增加了相关代码de通用性.为了使链表可以被访问还需要定义一个表头,表头必须包含指向第一个结点de指针和指向当前结点de指针.为了便于在链表尾部增加结点,还可以增加一指向链表尾部de指针,另外还可以用一个域来表示链表de大小,当调用者想得到链表de大小时,不必遍历整个链表.下图是这种链表de示意图:

  链表de数据结构
  我可以用类List来实现链表结构,用变量Head、Tail、Length、Pointer来实现表头.存储当前结点de指针时有一定de技巧,Pointer并非存储指向当前结点de指针,而是存储指向它de前趋结点de指针,当其值为null时表示当前结点是第一个结点.那么为什么要这样做呢?这是因为当删除当前结点后仍需保证剩下de结点构成链表,如果Pointer指向当前结点,则会给操作带来很大困难.那么如何得到当前结点呢,我定义了一个方法cursor(),返回值是指向当前结点de指针.类List还定义了一些方法来实现对链表de基本操作,通过运用这些基本操作我可以对链表进行各种操作.例如reset()方法使第一个结点成为当前结点.insert(Object d)方法在当前结点前插入一个结点,并使其成为当前结点.remove()方法删除当前结点同时返回其内容,并使其后继结点成为当前结点,如果删除de是最后一个结点,则第一个结点变为当前结点.
  链表类Listde源相关代码如下:
  import java.io.*;
  public class List
  {
  /*用变量来实现表头*/
  private Node Head=null;
  private Node Tail=null;
  private Node Pointer=null;
  private int Length=0;
  public void deleteAll()
  /*清空整个链表*/
  {
  Head=null;
  Tail=null;
  Pointer=null;
  Length=0;
  }
  public void reset()
  /*链表复位,使第一个结点成为当前结点*/
  {
  Pointer=null;
  }
  public boolean isEmpty()
  /*判断链表是否为空*/
  {
  return(Length==0);
  }
  public boolean isEnd()
  /*判断当前结点是否为最后一个结点*/
  {
  if(Length==0)
   throw new java.lang.NullPointerException();
  else if(Length==1)
   return true;
  else
   return(cursor()==Tail);
  }
  public Object nextNode()
  /*返回当前结点de下一个结点de值,并使其成为当前结点*/
  {
  if(Length==1)
   throw new java.util.NoSuchElementException();
  else if(Length==0)
   throw new java.lang.NullPointerException();
  else
  {
   Node temp=cursor();
   Pointer=temp;
   if(temp!=Tail)
    return(temp.next.data);
   else
    throw new java.util.NoSuchElementException();
  }
  }
  public Object currentNode()
  /*返回当前结点de值*/
  {
  Node temp=cursor();
  return temp.data;
  }
  
  public void insert(Object d)
  /*在当前结点前插入一个结点,并使其成为当前结点*/
  {
  Node e=new Node(d);
  if(Length==0)
  {
   Tail=e;
   Head=e;
  }
  else
  {
   Node temp=cursor();
   e.next=temp;
   if(Pointer==null)
    Head=e;
   else
    Pointer.next=e;
  }
  Length++;
  }
  public int size()
  /*返回链表de大小*/
  {
  return (Length);
  }
  public Object remove()
  /*将当前结点移出链表,下一个结点成为当前结点,如果移出de结点是最后一个结点,则第一个结点成为当前结点*/
  {
  Object temp;
  if(Length==0)
   throw new java.util.NoSuchElementException();
  else if(Length==1)
  {
   temp=Head.data;
   deleteAll();
  }
  else
  {
   Node cur=cursor();
   temp=cur.data;
   if(cur==Head)
    Head=cur.next;
   else if(cur==Tail)
   {
    Pointer.next=null;
    Tail=Pointer;
    reset();
   }
   else
    Pointer.next=cur.next;
    Length--;
  }
  return temp;
  }
  private Node cursor()
  /*返回当前结点de指针*/
  {
  if(Head==null)
   throw new java.lang.NullPointerException();
  else if(Pointer==null)
   return Head;
  else
   return Pointer.next;
  }
  public static void main(String[] args)
  /*链表de简单应用举例*/
  {
  List a=new List ();
  for(int i=1;i<=10;i++)
   a.insert(new Integer(i));
   System.out.println(a.currentNode());
   while(!a.isEnd())
    System.out.println(a.nextNode());
    a.reset();
    while(!a.isEnd())
    {
     a.remove();
    }
    a.remove();
    a.reset();
    if(a.isEmpty())
     System.out.println(”There is no Node in List \n”);
     System.in.println(”You can press return to quit\n”);
    try
    {
     System.in.read();
     //确保用户看清程序运行结果
    }
    catch(IOException e)
    {}
   }
  }
  class Node
  /*构成链表de结点定义*/
  {
   Object data;
   Node next;
   Node(Object d)
   {
    data=d;
    next=null;
   }
  }
  读者还可以根据实际需要定义新de方法来对链表进行操作.双向链表可以用类似de方法实现只是结点de类增加了一个指向前趋结点de指针.
  可以用这样de相关代码来实现:
  class Node
  {
  Object data;
  Node next;
  Node previous;
  Node(Object d)
  {
  data=d;
  next=null;
  previous=null;
  }
  }
  当然,双向链表基本操作de实现略有不同.链表和双向链表de实现方法,也可以用在堆栈和队列de实现中,这里就不再多写了,有兴趣de读者可以将List类de相关代码稍加改动即可.

JDO 2.0查询语言的特点

星期一, 06月 2nd, 2008

  查询语言de改进是JDO2.0规范中de重要环节,本文从较高de层面阐述JDO2.0所提供de一些新功能.由于JDO2.0规范还未进入公开草案状态,目前还没有任何内容敲定下来,一切都还可能面临变化.不过,JDO2.0将会很快进入最后阶段,而这里提到de查询特性是JDO2.0专家组(译者注:David Jordan就是专家组重要成员)花费时间最多,并且相对来说最为稳定.因此,我有足够理由相信,最终规范与这里de描述将会基本一致.
  如果各位读者觉得本文遗漏了某些重要de特性,建议立即到JDO论坛(http://www.jdocentral.com/forums/index.php?showforum=10)去提出并讨论.这里我需要感谢JDO2.0规范领导人Craig Russell授权给我公开这些JDO2.0查询语言de新特性.
  查询结果
  您可以创建一个对A类de查询,通过contains()引用到B类,再通过又一层contains()引用到C类,最后再使用一个“.”操作符引用到D类.但最终返回de集合中只会包含A类de对象实例,如果要从结果中获得其它类,就必须通过A类de引用来逐个获取相关de其它类对象.如果您de查询条件里面包含了B、C或D类de约束,那么在结果集中通过A类对象引用其它类对象时,必须重新将这些约束在Java相关代码中重复一遍,也就是说,您不得不在Java和JDOQL中重复声明限制条件.再者,您可能只关心满足查询条件deD类对象,而不希望中间deB、C类对象被JDO底层创建从而节省内存或相关资源.
  在JDO2.0中,您再也不受缚于这些限制了.您可以返回:
  数据类(PersistentCapable)de一个或多个字段
  候选类以外de其它类对象

  统计数据
  这意味着您可以返回A、B、C、D类对象,或者它们de某些字段,或者二者de混和结果.您还可以计算类似min或max之类de统计结果.基本上,您想返回什么结果都可以.
  当您创建一个查询时,您可以指定一个“结果定义(Result Specification)”来指定返回什么样de内容.它是一个包含一个或多个以逗号分隔de“结果表达式(Result Expression)”.结果表达式可以是:
  this关键字,表示返回候选类de对象实例.这与JDO1.0是一样de字段,标明候选类或引用类de某个字段de值,如 address.street.name 字段表达式,代表对多个字段进行JDO预定义de几种算术运算而获得de结果变量,代表查询条件中出现de某个中间变量引用表达式,也就是JDO1.0中de通过“.”操作符进行de对象之间de引用 统计表达式通过对以上这几种结果表达式de组合运用,您可以获得任何您想要de结果.
  JDO2.0支持下面de统计函数:
  count(表达式),表达式可以是this
  sum(数字型字段表达式),“数字型字段表达式”可以是通过字段或字段de运算得到de数字型de结果
  min(数字型字段表达式)
  max(数字型字段表达式)
  avg(数字型字段表达式)
  对查询结果de指定是通过下面deAPI:
  void javax.jdo.Query.setResult(String result)
  如果您不调用这个方法,或者参数是null,则返回候选类de对象实例(相当于设置为“this”),即JDO1.0de返回结果.如果您只指定了唯一结果表达式,则返回集合de元素类型与该结果de类型一致.另外,在默认方式下,如果指定了多个结果表达式,则返回de集合元素类型将是 Object[].
  您可以在结果定义字符串de开头标上distinct来保证结果不会重复.而如果结果定义串中包含好几个表达式,那么distinct可以保证结果集中不会有重复de数据组.
  每个结果表达式可以指定一个名称,对于简单de字段,系统会默认以该字段de名称作为结果中该项de名称.对复杂de表达式,您可以使用下面de语法指定名称:
  result_expression as name
  
  名称de使用可以让结果中de该项作为结果类中de一个属性来进行设置和使用.您可以指定一个结果类(result class),用来返回查询结果.如果查询结果是一个单值,结果类可以是任何JDO支持de类(Integer, Double, String, BigInteger, BigDecimal, java.util.Date, java.sql.Date, java.sql.Time, java.sql.Timestamp).Query中设置结果类de方法是:
  void setResultClass(Class resultClass)

  如果查询结果包含多个结果表达式,您可以定义一个结果类来保留结果中de各项数据,这个类必须有一个无参数de构造器.此外,每个结果表达式必须对应此类中de一个属性,不论是一个publicde字段,还是一个publicdesetXxx()方法,并且这种直接de或bean风格de属性名称与查询结果中各项结果表达式de名称保持一致.

    组操作(Grouping)
  统计功能可用于一个分组操作中.JDO2.0提供类似SQL中deGROUP BY和HAVING子句.Query方法:

  void setGrouping(String groupSpec)

  用于指定分组de原则.groupSpec参数包含一个或多个以逗号分隔de分组表达式,还可以跟上一个以“having ”开头de过滤条件.调用此方法后,setResult()参数de每个结果表达式项必须是groupSpec中de一项,或者是groupSpec中de一项或多项de运算结果.所有groupSpec项de值均相同de结果被归在同一组中(同一条结果记录).having子句de过滤条件可以包含boolean结果de判断语句或者是对分组表达式de统计运算.与SQL一样,having子句用于对分组后de结果集进行条件过滤.
  唯一性(Uniqueness)
  很多人一直奇怪为什么Queryde执行(execute)结果是一个Object类型de对象,因为这样给开发人员造成必须手工强制将结果转换成Collectionde不便.JDO1.0中查询结果一般有多个元素,但JDO专家组计划在JDO2.0中加入对返回单值结果de查询de支持,于是将Queryde执行结果定义为Object类型.
  您有时会执行一个您确定结果只会有一条de查询(比如统计总数或者按具有唯一索引de会员帐号查找对象等等),在JDO2.0中,您可以调用Query方法来声明:

  void setUnique(boolean unique)

  当您传入“true”后,Query执行de结果将是一个单独de值对象,如果无任何结果返回,则结果是null.如果JDO发现查询结果返回了多条记录,则会扔出一个异常.
  限制返回结果de大小
  设计用户界面de时候,我常常会显示结果集de某一部分子集(比如分页显示或只显示前十条之类).为了性能和效率,您多半会需要限制返回结果de范围.Queryde方法可以完成这一点:

  void setRange(int fromInclusive, int toExclusive)

  该方法返回de结果集只包含原结果集de第fromInclusive条到第toExclusive-1条.
  新de过滤条件操作符
  一些新de操作符被加到JDOQL中,以便执行针对引用、Map、字符串和数字de操作.instanceof操作符返回一个boolean值,可以让您过滤某个指定类de对象;同样返回boolean值decontainsKey(Object)函数和containsValue(Object)用于访问Map元素.
  字符串处理方面加入了很多函数,toLowerCase()和toUpperCase()分别完成大小写转换,另外还有下列函数用于查找子串位置和获得子串:

  int indexOf(String)
  int indexOf(String, int) String substring(int) String substring(int,int)

  另外,Stringde方法:

  boolean matches(String pattern)

  用于执行正则式匹配.目前只能提供有限de匹配功能.“.”和“.*”可表示通配符,而“(?i)”表示匹配不区分大小写.
  对数字型de字段,JDO2.0增加了两个函数:

  Math.abs(numeric) Math.sqrt(numeric)

  预定义查询(Named Queries)
  您可以在JDO描述符(metadata)中声明常用deJDOQL查询语句,这样就不用将查询嵌入到Java源相关代码中.这样可以提供一些灵活性,比如将查询语句写到一个配置好de文本文件中,而需要修改时可以直接改该文件,而不用更改Java源码.描述符中de每个查询都有一个名字,而要执行某个查询时,可以使用下面de方法来创建查询:
  Query newNamedQuery(Class cls, String queryName)
  JDO将会搜索描述符来找到对应de预定义查询语句并生成相应deQuery对象.
  访问静态字段(static fields)
  您将可以在JDOQL中访问数据类中以public static final方式声明de常量.比如
  public static final int FEMALE = 0;
  public static final int MALE = 1;
  public static final int UNKNOWN = 2;

  而在查询中使用类似“salary > 5000.0 && gender == MALE”de过滤条件.
  批量删除(Deletion by Query)
  在JDO1.0中,要删除一个对象,必须先将其载入内存,再删除,然而很多情况下,您在删除之前并不需要访问该对象,这样de做法比较低效.在JDO2.0中,提供了Queryde几个方法来删除符合查询条件de一组对象:
  Object deletePersistentAll(Object[] parameters) Object deletePersistentAll(Map parameters) Object deletePersistentAll()
  此查询结果de对象会被全部从数据库删除.这些方法返回被删除对象de集合.您de程序可以决定是否需要对被删除de对象逐个访问.如果您不访问这些对象,Query执行de性能将不会受到任何影响,换句话说,这些对象将不会在内存中生成.
  
  厂商扩展de查询特性
  JDO厂商可以给JDOQL提供各种各样de特殊查询功能.每个厂商可以定义一组属于该厂商自己de扩展功能.如果您需要使用其中de功能,您需要将该厂商de扩展加到程序运行环境中.每个扩展有一个名字和一个可选de值.您可以单独设置每个扩展,或者一次性设置多个扩展.Queryde下列方法用于设置厂商扩展特性:
  void setExtensions(Map extensions) void addExtension(String key, Object value)
  SQL直接访问
  如果JDO2.0de查询功能不能满足需要,并且以下条件都满足:
  您de应用运行在关系数据库上
  
  您需要de查询有SQL语句可以实现
  您知道从您de类模型到数据库de映射细节
  您就可以创建一个SQL查询,方法是调用PersistentMangerde方法:
  Query newQuery(String language, Object query)
  
  每一个参数需要设置为“javax.jdo.query.SQL”,而query是一个具体deSQL语句.如果您de查询需要返回类de实例,则这个SQL语句必须返回该类de相应主键字段.使用直接deSQL时,JDOQL提供de函数将不能被使用,否则将会扔出异常JDOUserException,比如,您不能对该Query设置过滤条件字符串、排序声明或变量声明.使用SQL查询时,参数都是未指定类型de,在SQL语句中以“?”表示,并且按出现de顺序被绑定.
  结束语
  各位读者已经看到,JDO2.0对查询语句增加了很多新de功能和特性,我认为其中de查询结果定义是最大de改进.正如我在文章开头说de,这一部分变化目前来说是JDO2.0中最稳定de部分,不会有大de变化.厂商可以开始提供很多这样de功能,不用考虑专家组还在讨论deJDO2.0其余部分将如何变化.
  在JDO2.0提供标准de对象/关系映射de前提下,这里描述de查询功能和一个用于多层结构deJDO应用de脱钩/挂钩(detach/attach)机制,将使JDO占领更多de市场.对这一点有深切体会de厂商将不遗余力地争取率先推出稳定、完整、高效deJDO2.0产品.JDO将是基于数据库存储和管理de应用开发de首先API,开发人员们将享受面向对象de模型设计和高效de数据存储管理系统.

Java数据对象JDO 2.0查询语言的特点

星期一, 06月 2nd, 2008

查询语言de改进是JDO2.0规范中de重要环节,本文从较高de层面阐述JDO2.0所提供de一些新功能.由于JDO2.0规范还未进入公开草案状态,目前还没有任何内容敲定下来,一切都还可能面临变化.不过,JDO2.0将会很快进入最后阶段,而这里提到de查询特性是JDO2.0专家组(译者注:David Jordan就是专家组重要成员)花费时间最多,并且相对来说最为稳定.因此,我有足够理由相信,最终规范与这里de描述将会基本一致.
  如果各位读者觉得本文遗漏了某些重要de特性,建议立即到JDO论坛(http://www.jdocentral.com/forums/index.php?showforum=10 )去提出并讨论.这里我需要感谢JDO2.0规范领导人Craig Russell授权给我公开这些JDO2.0查询语言de新特性.
  查询结果
  我首先从最深入de改进开始介绍.在JDO1.0中,查询结果总是您所指定de类de实例集合.考虑下面deUML类图,它表达了A、B、C、D四个类及之间de关系:

  您可以创建一个对A类de查询,通过contains()引用到B类,再通过又一层contains()引用到C类,最后再使用一个“.”操作符引用到D类.但最终返回de集合中只会包含A类de对象实例,如果要从结果中获得其它类,就必须通过A类de引用来逐个获取相关de其它类对象.如果您de查询条件里面包含了B、C或D类de约束,那么在结果集中通过A类对象引用其它类对象时,必须重新将这些约束在Java相关代码中重复一遍,也就是说,您不得不在Java和JDOQL中重复声明限制条件.再者,您可能只关心满足查询条件deD类对象,而不希望中间deB、C类对象被JDO底层创建从而节省内存或相关资源.
  在JDO2.0中,您再也不受缚于这些限制了.您可以返回:
  数据类(PersistentCapable)de一个或多个字段
  候选类以外de其它类对象
  统计数据
  这意味着您可以返回A、B、C、D类对象,或者它们de某些字段,或者二者de混和结果.您还可以计算类似min或max之类de统计结果.基本上,您想返回什么结果都可以.
  当您创建一个查询时,您可以指定一个“结果定义(Result Specification)”来指定返回什么样de内容.它是一个包含一个或多个以逗号分隔de“结果表达式(Result Expression)”.结果表达式可以是:
  this关键字,表示返回候选类de对象实例.这与JDO1.0是一样de字段,标明候选类或引用类de某个字段de值,如 address.street.name 字段表达式,代表对多个字段进行JDO预定义de几种算术运算而获得de结果变量,代表查询条件中出现de某个中间变量引用表达式,也就是JDO1.0中de通过“.”操作符进行de对象之间de引用 统计表达式通过对以上这几种结果表达式de组合运用,您可以获得任何您想要de结果.
  JDO2.0支持下面de统计函数:
  count(表达式),表达式可以是this
  sum(数字型字段表达式),“数字型字段表达式”可以是通过字段或字段de运算得到de数字型de结果
  min(数字型字段表达式)
  max(数字型字段表达式)
  avg(数字型字段表达式)
  对查询结果de指定是通过下面deAPI:

void javax.jdo.Query.setResult(String result)


  如果您不调用这个方法,或者参数是null,则返回候选类de对象实例(相当于设置为“this”),即JDO1.0de返回结果.如果您只指定了唯一结果表达式,则返回集合de元素类型与该结果de类型一致.另外,在默认方式下,如果指定了多个结果表达式,则返回de集合元素类型将是 Object[].
  您可以在结果定义字符串de开头标上distinct来保证结果不会重复.而如果结果定义串中包含好几个表达式,那么distinct可以保证结果集中不会有重复de数据组.
  每个结果表达式可以指定一个名称,对于简单de字段,系统会默认以该字段de名称作为结果中该项de名称.对复杂de表达式,您可以使用下面de语法指定名称:

result_expression as name

  
  名称de使用可以让结果中de该项作为结果类中de一个属性来进行设置和使用.您可以指定一个结果类(result class),用来返回查询结果.如果查询结果是一个单值,结果类可以是任何JDO支持de类(Integer, Double, String, BigInteger, BigDecimal, java.util.Date, java.sql.Date, java.sql.Time, java.sql.Timestamp).Query中设置结果类de方法是:

void setResultClass(Class resultClass)


  如果查询结果包含多个结果表达式,您可以定义一个结果类来保留结果中de各项数据,这个类必须有一个无参数de构造器.此外,每个结果表达式必须对应此类中de一个属性,不论是一个publicde字段,还是一个publicdesetXxx()方法,并且这种直接de或bean风格de属性名称与查询结果中各项结果表达式de名称保持一致.

组操作(Grouping)
  统计功能可用于一个分组操作中.JDO2.0提供类似SQL中deGROUP BY和HAVING子句.Query方法:

void setGrouping(String groupSpec)

  用于指定分组de原则.groupSpec参数包含一个或多个以逗号分隔de分组表达式,还可以跟上一个以“having ”开头de过滤条件.调用此方法后,setResult()参数de每个结果表达式项必须是groupSpec中de一项,或者是groupSpec中de一项或多项de运算结果.所有groupSpec项de值均相同de结果被归在同一组中(同一条结果记录).having子句de过滤条件可以包含boolean结果de判断语句或者是对分组表达式de统计运算.与SQL一样,having子句用于对分组后de结果集进行条件过滤.
  唯一性(Uniqueness)
  很多人一直奇怪为什么Queryde执行(execute)结果是一个Object类型de对象,因为这样给开发人员造成必须手工强制将结果转换成Collectionde不便.JDO1.0中查询结果一般有多个元素,但JDO专家组计划在JDO2.0中加入对返回单值结果de查询de支持,于是将Queryde执行结果定义为Object类型.
  您有时会执行一个您确定结果只会有一条de查询(比如统计总数或者按具有唯一索引de会员帐号查找对象等等),在JDO2.0中,您可以调用Query方法来声明:
void setUnique(boolean unique)

  当您传入“true”后,Query执行de结果将是一个单独de值对象,如果无任何结果返回,则结果是null.如果JDO发现查询结果返回了多条记录,则会扔出一个异常.
  限制返回结果de大小
  设计用户界面de时候,我常常会显示结果集de某一部分子集(比如分页显示或只显示前十条之类).为了性能和效率,您多半会需要限制返回结果de范围.Queryde方法可以完成这一点:
void setRange(int fromInclusive, int toExclusive)

  该方法返回de结果集只包含原结果集de第fromInclusive条到第toExclusive-1条.
  新de过滤条件操作符
  一些新de操作符被加到JDOQL中,以便执行针对引用、Map、字符串和数字de操作.instanceof操作符返回一个boolean值,可以让您过滤某个指定类de对象;同样返回boolean值decontainsKey(Object)函数和containsValue(Object)用于访问Map元素.
  字符串处理方面加入了很多函数,toLowerCase()和toUpperCase()分别完成大小写转换,另外还有下列函数用于查找子串位置和获得子串:
int indexOf(String)
int indexOf(String, int) String substring(int) String substring(int,int)

  另外,Stringde方法:
boolean matches(String pattern)

  用于执行正则式匹配.目前只能提供有限de匹配功能.“.”和“.*”可表示通配符,而“(?i)”表示匹配不区分大小写.
  对数字型de字段,JDO2.0增加了两个函数:
Math.abs(numeric) Math.sqrt(numeric)

  预定义查询(Named Queries)
  您可以在JDO描述符(metadata)中声明常用deJDOQL查询语句,这样就不用将查询嵌入到Java源相关代码中.这样可以提供一些灵活性,比如将查询语句写到一个配置好de文本文件中,而需要修改时可以直接改该文件,而不用更改Java源码.描述符中de每个查询都有一个名字,而要执行某个查询时,可以使用下面de方法来创建查询:
Query newNamedQuery(Class cls, String queryName)

  JDO将会搜索描述符来找到对应de预定义查询语句并生成相应deQuery对象.
  访问静态字段(static fields)
  您将可以在JDOQL中访问数据类中以public static final方式声明de常量.比如
public static final int FEMALE = 0;
public static final int MALE = 1;
public static final int UNKNOWN = 2;

  而在查询中使用类似“salary > 5000.0 && gender == MALE”de过滤条件.
  批量删除(Deletion by Query)
  在JDO1.0中,要删除一个对象,必须先将其载入内存,再删除,然而很多情况下,您在删除之前并不需要访问该对象,这样de做法比较低效.在JDO2.0中,提供了Queryde几个方法来删除符合查询条件de一组对象:
Object deletePersistentAll(Object[] parameters) Object deletePersistentAll(Map parameters) Object deletePersistentAll()

  此查询结果de对象会被全部从数据库删除.这些方法返回被删除对象de集合.您de程序可以决定是否需要对被删除de对象逐个访问.如果您不访问这些对象,Query执行de性能将不会受到任何影响,换句话说,这些对象将不会在内存中生成.

厂商扩展de查询特性
  JDO厂商可以给JDOQL提供各种各样de特殊查询功能.每个厂商可以定义一组属于该厂商自己de扩展功能.如果您需要使用其中de功能,您需要将该厂商de扩展加到程序运行环境中.每个扩展有一个名字和一个可选de值.您可以单独设置每个扩展,或者一次性设置多个扩展.Queryde下列方法用于设置厂商扩展特性:

void setExtensions(Map extensions) void addExtension(String key, Object value)

  SQL直接访问
  如果JDO2.0de查询功能不能满足需要,并且以下条件都满足:
  您de应用运行在关系数据库上
  
  您需要de查询有SQL语句可以实现
  您知道从您de类模型到数据库de映射细节
  您就可以创建一个SQL查询,方法是调用PersistentMangerde方法:
Query newQuery(String language, Object query)
  
  每一个参数需要设置为“javax.jdo.query.SQL”,而query是一个具体deSQL语句.如果您de查询需要返回类de实例,则这个SQL语句必须返回该类de相应主键字段.使用直接deSQL时,JDOQL提供de函数将不能被使用,否则将会扔出异常JDOUserException,比如,您不能对该Query设置过滤条件字符串、排序声明或变量声明.使用SQL查询时,参数都是未指定类型de,在SQL语句中以“?”表示,并且按出现de顺序被绑定.
  结束语
  各位读者已经看到,JDO2.0对查询语句增加了很多新de功能和特性,我认为其中de查询结果定义是最大de改进.正如我在文章开头说de,这一部分变化目前来说是JDO2.0中最稳定de部分,不会有大de变化.厂商可以开始提供很多这样de功能,不用考虑专家组还在讨论deJDO2.0其余部分将如何变化.
  在JDO2.0提供标准de对象/关系映射de前提下,这里描述de查询功能和一个用于多层结构deJDO应用de脱钩/挂钩(detach/attach)机制,将使JDO占领更多de市场.对这一点有深切体会de厂商将不遗余力地争取率先推出稳定、完整、高效deJDO2.0产品.JDO将是基于数据库存储和管理de应用开发de首先API,开发人员们将享受面向对象de模型设计和高效de数据存储管理系统.

发挥语言的威力–融合PHP与ASP

星期一, 06月 2nd, 2008

本人在项目开发中,开始一直用php,在享受着phpde灵活de功能时,同时也遇到了一些问题,如phpdeODBC接口连接"远程oracle"问题,就是报告您无m骺幏ń馕鯰NS服务名,经过一番捉摸,现在还是没有找到问题de答案,燃眉之急!
情急之中,想出一妙计,众君请看:
我用ASP连接远程数据库,当然一切OK,联想我以前利用浮动桢de心得,何不把访问远程Oraclede相关代码用ASP浮动桢实现,方法如下:
(1).在PHP页内建立一
<DIV id="iframeASPDiv" style="hidden">
<iframe id="iframeASP" src="./inc/XXX.asp"></iframe>
</DIV>
(2)把访问远程Oraclede相关代码放入./inc/XXX.ASP页
如set conn=Server.CreatObject("ADODB.Connection")…

(3)在../inc/XXX.ASP脚本位置放置如下相关代码:
<script language="JavaScript">
parent.XXXID.value="<%=YYY%>";//==访问父窗口元素
parent.XXXXID.innerHTML="<%=ZZZ%>";
</script>
以上方法是本人de心得,只是起到抛砖引玉de作用,类似de,我可以使用
PERL,ASP ,CGI,JSP,PHPde大融合,一是可以发挥各自语言优点,弥补不足.二是为网页模块化提供一点思路,特别开发大型项目时可以众人合作.关于脚本混合编程de问题,我会继续把我de新de奉献给大家!

将PHP作为Shell脚本语言使用

星期一, 06月 2nd, 2008

--英文原著:Darrell Brogdon,发表于 http://www.phpbuilder.com/columns/darrell20000319.php3)
可能很多人都想过使用PHP编写一些定时发信之类de程序,但是却没有办法定时执行PHP;一次去PHPBuilderde时候,发现了这一篇文章,于是想给大家翻译一下(同时做了一些修改),希望对大家有用.第一次翻译文章,不好请多多见谅.

我都知道,PHP是一种非常好de动态网页开发语言(速度飞快,开发周期短……).但是只有很少数de人意识到PHP也可以很好de作为编写Shell脚本de语言,当PHP作为编写Shell脚本de语言时,他并没有Perl或者Bash那么强大,但是他却有着很好de优势,特别是对于我这种熟悉PHP但是不怎么熟悉Perlde人.
要使用PHP作为Shell脚本语言,您必须将PHP作为二进制deCGI编译,而不是Apache模式;编译成为二进制CGI模式运行dePHP有一些安全性de问题,关于解决de方法可以参见PHP手册(http://www.php.net).
一开始您可能会对于编写Shell脚本感到不适应,但是会慢慢好起来de:将PHP作为一般de动态网页编写语言和作为Shell脚本语言de唯一不同就在于一个Shell脚本需要在第一行生命解释本脚本de程序路径:
#!/usr/local/bin/php -q
我在PHP执行文件后面加入了参数“-1”,这样子PHP就不会输出HTTPHeader(如果仍需要作为Webde动态网页,那么您需要自己使用header函数输出HTTPHeader).当然,在Shell脚本de里面您还是需要使用PHPde开始和结束标记:
<?php 相关代码 ?>
现在让我看一个例子,以便于更好de了解用PHP作为Shell脚本语言de使用:
#!/usr/local/bin/php -q
<?php
print(”Hello, world!\n”);
?>
上面这个程序会简单de输出“Hello, world!”到显示器上.

一、传递Shell脚本运行参数给PHP:
作为一个Shell脚本,经常会在运行程序时候加入一些参数,PHP作为Shell脚本时有一个内嵌de数组“$argv”,使用“$argv”数组可以很方便de读取Shell脚本运行时候de参数(“$argv[1]”对应de是第一个参数,“$argv[2]”对应de是第二个参数,依此类推).比如下面这个程序:
#!/usr/local/bin/php -q
<?php
$first_name = $argv[1];
$last_name = $argv[2];
printf(”Hello, %s %s! How are you today?\n”, $first_name, $last_name);
?>
上面de相关代码在运行de时候需要两个参数,分别是姓和名,比如这样子运行:
[dbrogdon@artemis dbrogdon]$ scriptname.ph Darrell Brogdon
Shell脚本在显示器上面会输出:
Hello, Darrell Brogdon! How are you today?
[dbrogdon@artemis dbrogdon]$
在PHP作为动态网页编写语言de时候也含有“$argv”这个数组,不过和这里有一些不同:当PHP作为Shell脚本语言de时候“$argv[0]”对应de是脚本de文件名,而当用于动态网页编写de时候,“$argv[1]”对应de是QueryStringde第一个参数.

二、编写一个具有交互式deShell脚本:
如果一个Shell脚本仅仅是自己运行,失去了交互性,那么也没有什么意思了.当PHP用于Shell脚本de编写de时候,怎么读取用户输入de信息呢?很不幸de是PHP自身没有读取用户输入信息de函数或者方法,但是我可以效仿其他语言编写一个读取用户输入信息de函数“read”:
<?php
function read() {
$fp = fopen(’/dev/stdin’, ‘r’);
$input = fgets($fp, 255);
fclose($fp);
return $input;
}
?>
需要注意de是上面这个函数只能用于Unix系统(其他系统需要作相应de改变).上面de函数会打开一个文件指针,然后读取一个不超过255字节de行(就是fgetsde作用),然后会关闭文件指针,返回读取de信息.
现在我可以使用函数“read”将我前面编写de程序1修改一下,使他更加具有“交互性”了:
#!/usr/local/bin/php -q
<?php
function read() {
$fp = fopen(’/dev/stdin’, ‘r’);
$input = fgets($fp, 255);
fclose($fp);
return $input;
}
print(”What is your first name? “);
$first_name = read();
print(”What is your last name? “);
$last_name = read();
print(”\nHello, $first_name $last_name! Nice to meet you!\n”);
?>
将上面de程序保存下来,运行一下,您可能会看到一件预料之外de事情:最后一行de输入变成了三行!这是因为“read”函数返回de信息还包括了用户每一行de结尾换行符“\n”,保留到了姓和名中,要去掉结尾de换行符,需要把“read”函数修改一下:
<?php
function read() {
$fp = fopen(’/dev/stdin’, ‘r’);
$input = fgets($fp, 255);
fclose($fp);
$input = chop($input); // 去除尾部空白
return $input;
}
?>

三、在其他语言编写deShell脚本中包含PHP编写deShell脚本:
有时候我可能需要在其他语言编写deShell脚本中包含PHP编写deShell脚本.其实非常简单,下面是一个简单de例子:
#!/bin/bash
echo This is the Bash section of the code.

/usr/local/bin/php -q << EOF
<?php
print(”This is the PHP section of the code\n”);
?>
EOF
其实就是调用PHP来解析下面de相关代码,然后输出;那么,再试试下面de相关代码:
#!/bin/bash
echo This is the Bash section of the code.

/usr/local/bin/php -q << EOF
<?php
$myVar = ‘PHP’;
print(”This is the $myVar section of the code\n”);
?>
EOF
可以看出两次de相关代码唯一de不同就是第二次使用了一个变量“$myVar”,试试运行,PHP竟然给出出错de信息:“Parse error: parse error in - on line 2”!这是因为Bash中de变量也是“$myVar”,而Bash解析器先将变量给替换掉了,要想解决这个问题,您需要在每个PHPde变量前面加上“\”转义符,那么刚才de相关代码修改如下:
#!/bin/bash
echo This is the Bash section of the code.

/usr/local/bin/php -q << EOF
<?php
\$myVar = ‘PHP’;
print(”This is the \$myVar section of the code\n”);
?>
EOF

好了,现在您可以用PHP编写您自己deShell脚本了,希望您一切顺利.如果有什么问题,可以去http://www.PHPBuilder.com或者http://www.zPHP.com上面讨论.

在Zeus Web Server中安装PHP语言支持

星期一, 06月 2nd, 2008

前言
Zeus是一个运行于Unix下de非常优秀deWeb Server,而PHP则是Unix下一个非常优秀de后台脚本语言. 这两个产品都是为非常喜欢de产品.为什么要写这样de一个Howto呢?是因为有大量de网站脚本是使用PHP开发de, 而这些程序运行在Zeus下也是一个非常好de选择.写这份文档de目de在于能让大家dePHP系统良好de运行于Zeus服务器上.
很早de时候我写过一份整合Zeus和PHPde文章,它主要是讲如何将PHP以FastCGIde本地调用方式来运行于Zeus中de, 本份Howto主要是来讲如何让PHP运行于Remote Responders方式下.因为这样会比以local方式有更高de可扩展性和运行效率.

准备工作
首先您应该Zeus安装完成,也不会过多de讲如何安装和配置Zeus服务器本身,因为它de安装和配置实在是太简单了.
如果有可能,最好将ports使用cvsup来升级一下.
对于PHP依赖de相关软件如果能提前装,则从ports中安装好.如MySQL、GD等. 安装fastcgi
注意,如果您安装dePHPde版本会低于4.3.0哪么您才需要这步.新dePHP版本已经内置了fastcgide库.安装fastcgide方法非常de简单:

root@~$cd /usr/ports/www/fcgi/
root@/usr/ports/www/fcgi$make;make install;make clean
编译完成后我可以在/usr/local/lib目录中看到有libfcgi.a文件,同时在/usr/local/include目录中会有fastcgide所有头文件.

编译PHP
编译PHP可以使用通常dePHP编译选项,下面是我使用de一个配置:

./configure –prefix=/usr/local/php –enable-fastcgi –with-mysql=/usr/local
需要注意de是在PHP 4.3.0以上版本是使用de –enable-fastcgi 选项,而PHP 4.3.0以前de版本应使用–with-fastcgi参数.
接着就是安装PHP到系统中:
make
make install
编译完成后,我来测试一下安装dephp是能正确运行:

root@~$cd /usr/local/php/bin/
root@/usr/local/php/bin$./php
这时将进入php相关代码输入状态,输入

<? phpinfo(); ?>
按ctrl-d运行后会见到php返回de信息则为正确.

配置FastCGI/PHP
配置FastCGI
进入Zeus管理控制台,打开需要配置deVHost配置.进入 API Support 中de FastCGI 设置.在其中设置:
Enabling Support for FastCGI Programs : Enable
在Configuring FastCGI Remote Responders中设置:
Directory name : /usr/local/php/bin/php
Location: Machine name: localhost
Additional methods supported?:None
如果您dePHP应用不在本机,即使PHP没有安装在本机上,哪么也要设置 Docroot path 参数,它可以不存在于相应de目录下.
都设置完成后,点击 Apply 按钮. 配置PHP解析指向
进入 URL Handling 中de Handlers 设置.在 Adding a Handler 中设置以下参数:

File Extension : php
Specify the path and filename of the handler, relative to the document root : /usr/local/php/bin/php
HTTP 404 errors are handled by : The handler
注意,这里de Specify the path and filename of the handler, relative to the document root 应和您上一步设置de Directory name 值相同.
都设置完成后,点击 Apply 按钮.
所有de设置完成后使用vhostdecommit功能将更 改提交并应用.这样Zeus就设置好了Fastcgi和PHPde相关参数.

配置FastCGI/PHP启动
在Zeusderc.d目录中新建一个S05phpde文件,内容为:

#!/bin/sh

# Script to start and stop the persistent PHP runner for FastCGI.
# Please check paths before use.

# FastCGI PHP binary
FPHPBIN=/usr/local/php/bin/php

# Location to place semaphore
SEMFILE=/tmp/php.pid
PHP_FCGI_CHILDREN=100
PHP_FCGI_MAX_REQUESTS=1000
export PHP_FCGI_CHILDREN
export PHP_FCGI_MAX_REQUESTS

# This is Linux - use /proc to increase the local (ephemeral) port range
#echo 1024 65000 > /proc/sys/net/ipv4/ip_local_port_range

if [ -z "$ZEUSHOME" ]
then
cd `dirname $0`/..
ZEUSHOME=`pwd`
export ZEUSHOME
fi

case “$1″ in
’start’)

if [ -e $SEMFILE ]
then
echo FastCGI PHP error: already running.Restart FastCGI PHP now
kill `cat $SEMFILE`
sleep 5
fi

if [ ! -x $FPHPBIN ]
then
echo FastCGI PHP error: please check that $FPHPBIN is executable and exists.
exit 1
fi

echo Starting FastCGI PHP.
$ZEUSHOME/web/bin/fcgirunner –user=65534 –group=65534 –pidfile=$SEMFILE 8002 $FPHPBIN
;;

’stop’)
if [ -e $SEMFILE ]
then
echo Stopping FastCGI PHP.
kill `cat $SEMFILE`
rm $SEMFILE
exit 0
fi
‘restart’)
if [ -e $SEMFILE ]
then
echo Stopping FastCGI PHP.
kill `cat $SEMFILE`
sleep 5
fi
echo Starting FastCGI PHP.
$ZEUSHOME/web/bin/fcgirunner –user=65534 –group=65534 –pidfile=$SEMFILE 8002 $FPHPBIN
*)
echo “usage: $0 {start|stop|restart}”
;;

esac
exit 1

在这个脚本中有以下内容需要视系统情况而 修改:

FPHPBIN=/usr/local/php/bin/php 应设置为phpde路径
SEMFILE=/tmp/php.pid 生成php.pidde路径,该目录必须可写
PHP_FCGI_CHILDREN=100 php进程数目
PHP_FCGI_MAX_REQUESTS=1000 每个phpde进程在退出前能够响应de请求数,用于释放资源 上面两个根据硬件配置和网站访问量设置,默认值是8,500. 一般来说 PHP_FCGI_CHILDREN > 访问并发最大值 10
PHP_FCGI_MAX_REQUESTS 如果设置过小,访问量大de网站会因为php进程重起频繁增加负荷.
#echo 1024 65000 > /proc/sys/net/ipv4/ip_local_port_range 只用于linux
–user=65534 –group=65534 为php进程运行de用户和组,一般设置为nobody用户和组FreeBSD是65534/65534,Linux是99/99
最后,将S05php文件设置为可执行文件,并将FastCGI/PHP运行起来:

chmod 755 S05php
./S05php start
一但启动后就会在ps -ax列表中显示出PHP_FCGI_CHILDREN 1个php进程.
到您devhost对应deDocroot目录中建一个info.php文件,内容为:
<?
phpinfo();
?>
使用浏览器访问vhost中deinfo.php文件,应该就可以看到PHPdeinfo页面了.

附注
感谢CCFde坛主hunreal写出deS05php脚本,它真de非常好用!
如果还有什么想了解de可以到 Zeus PHP支持 页得到更多de信息.

注:任何转载或摘抄请注明文章出处(中文FreeBSD用户组 http://www.cnfug.org)

用PHP编程语言开发动态WAP页面

星期一, 06月 2nd, 2008

  文/成都 yell


  WAP(无线通讯协议)是在数字移动电话、个人手持设备(PDA等)及计算机之间进行通讯de开放性全球标准协议.随着无线通讯de不断发展,静态deWAP页面在很多方面已经不能满足用户个性化de要求,因此开发者可以在WAP服务器端使用诸如PHP等语言产生动态deWML页面,来满足用户de需要.


   WAPde应用结构非常类似于Internet,一个典型deWAP应用请求步骤描述如下:

   1. 具有WAP用户代理功能de移动终端(如WAP手机),通过内部运行de微浏览器向某一网站发送WAP服务请求.该请求先由WAP网关截获,对信息内容进行编码压缩,以减少网络数据流量,同时根据需要将WAP协议转换成HTTP协议.

   2. 协议将处理后de请求转送到相应WAP服务器.在WAP服务器端,根据页面扩展名等属性,被请求de页面直接或由服务器端脚本解释后输出,再经过网关传回给用户.

  从上述deWAP应用流程可以发现,生成动态WAP页面与动态产生Web网页de过程非常相似.但是由于WAP应用使用deWML语言来源于语法严格deXML,因此要求输出de格式必须按WAP网页de规范输出.同时,由于WAP协议de应用范围及移动客户端de软、硬件配置等局限性,对每次输出de页面de大小、图像de格式及容量都有一定限制.本文笔者将以PHP语言为例,和广大网络程序开发爱好者共同探讨动态输出WAP页面de方法和应用.

  输出简单de动态WAP页面

  由于生成WAP页面de过程和生成一般deWeb页面非常类似,笔者通过一个最简单deWAP页面de例子来介绍.不过提醒一句:由于需要PHP解释器来解释该程序并输出WAP页面,因此所有类似de程序应以“php”为扩展名哦.

  < ?php

  header(”Content-type: text/vnd.wap.wml”); //定义输出文档为WML类型

  echo (” “);

  echo ( “Hello WAP” );

  echo (”");

  ?>

  该实例可以在WAP手机模拟器中浏览,输出一句经典de“Hello WAP”语句,但是在普通de网络浏览器中是无法识别de,原因很简单,在程序开头声明了该输出文档为WML类型,只有WAP设备能够识别并解释.不过又要提醒一句:常见deHTML语言对规范性要求不严,大多数浏览器能“宽容”地接受其中de编写错误,但是WMLde规范相当严格,任何de错误都可能导致无法输出所需de页面.

   实例1 动态生成图像

  WAP使用de图像是一种特殊de黑白图像格式:WBMP.开发者可以使用一些现有de工具将一般图像转换成WBMP格式,然后在WML文档中使用.但是如果在WAP程序中能动态地生成所需图像(如股市deK线图),将会使程序有极其广阔de应用前景.PHP提供了强大de图形绘制功能,下面de实例将将在WAP模拟器中显示一个黑色de矩形框.

   (注意:要使用GDde图像函数库,必须在PHP配置中加载“PHP_GD.DLL”库文件.)

  < ?PHP

  Header(”Content-type: image/vnd.wap.wbmp”); //定义输出de图像格式为WBMP

  Sim = ImageCreate(50, 50);

  Swhite = ImageColorAllocate(Sim,255,255,255);

  Sblack = ImageColorAllocate(Sim,0,0,0);

  ImageRectangle(Sim, 5, 5, 20, 20, Sblack);

  ImageWBMP(Sim);

  ImageDestroy(Sim);

  ?>

  实例2 处理汉字

  作为一种全球应用de协议,WAP选择了UNICODE 2.0作为其标准字符集编码,能够同时处理英、中、日、法等多种文字.但是开发者日常处理de汉字是GB2312编码,不同de内码标准必定不能通用,因此,如果不在两种编码之间通过码制de转换,就会出现汉字乱码de现象.目前de大多数WAP手机(Nokia7110、爱立信R320S等等)都使用UTF-8(即UNICODE)来编码de.如果直接在WML使用中文字符(GB2312编码),将会产生乱码,导致手机用户无法识别,因此在输出中文之前,必须使用程序或函数(关于此类dePHP函数库,网络上已有非常多技术上成熟de产品可以下载)对中文进行UNICODEde编码.而在少数支持GB2312编码de手机或WAP终端设备中,开发者只需在程序中定义文档de内码类型后,即可直接正确显示汉字,看一个实例:

  < ?php

  header(”Content-type: text/vnd.wap.wml; charset=gb2312″); //定义字符de编码为GB2312

  echo (”");

  echo (”您好”);

  echo (”");

  ?>

   在程序de“header”语句中,定义了文字de编码为GB2312,如果用户de手机支持GB2312编码,将会显示“您好”de字样.

  作为未来网络通讯de主导,WAP程序de开发已日趋热门.相信通过本文de阅读,能使开发者对使用PHP进行WAP开发有一个初步de印象,希望广大读者能在本文de基础上,参考WML语言,开发出更加强大deWAP应用程序.


大众网络报