八宝书库 > 文学其他电子书 > Java编程思想第4版[中文版](PDF格式) >

第146部分

Java编程思想第4版[中文版](PDF格式)-第146部分

小说: Java编程思想第4版[中文版](PDF格式) 字数: 每页4000字

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




自CGI 程序传回的任何东西,只需从 URL 对象里取得一个 InputStream (输入数据流)即可。这是用URL 对 

象的openStream()方法实现,它要封装到一个DataInputStream 里。随后就可以读取数据行,若readLine() 

返回一个null (空值),就表明CGI 程序已结束了它的输出。  

我们即将看到的CGI 程序返回的仅仅是一行,它是用于标志成功与否(以及失败的具体原因)的一个字串。 

这一行会被捕获并置放第二个 Label 字段里,使用户看到具体发生了什么事情。  

  

1。 从程序片里显示一个Web 页  

程序亦可将 CGI 程序的结果作为一个Web 页显示出来,就象它们在普通 HTML 模式中运行那样。可用下述代码 

做到这一点:  

getAppletContext()。showDocument(u);  

其中,u 代表URL 对象。这是将我们重新定向于另一个Web 页的一个简单例子。那个页凑巧是一个CGI 程序 

的输出,但可以非常方便地进入一个原始的HTML 页,所以可以构建这个程序片,令其产生一个由密码保护的 

网关,通过它进入自己Web 站点的特殊部分:  

  

//: ShowHTML。java  

import java。awt。*;  

import java。applet。*;  

import java。*;  

import java。io。*;  

  

public class ShowHTML extends Applet {  

  static final String CGIProgram = 〃MyCGIProgram〃;  

  Button send = new Button(〃Go〃);  

  Label l = new Label();  

  public void init() {  

    add(send);  

    add(l);  

  }  

  public boolean action (Event evt; Object arg) {  

    if(evt。target。equals(send)) {  

      try {  

        // This could be an HTML page instead of  

        // a CGI program。 Notice that this CGI   

        // program doesn't use arguments; but   

        // you can add them in the usual way。  

        URL u = new URL(  



                                                                                        565 


…………………………………………………………Page 567……………………………………………………………

          getDocumentBase();   

          〃cgi…bin/〃 + CGIProgram);  

        // Display the output of the URL using  

        // the Web browser; as an ordinary page:  

        getAppletContext()。showDocument(u);  

      } catch(Exception e) {  

        l。setText(e。toString());  

      }   

    }  

    else return super。action(evt; arg);  

    return true;  

  }  

} ///:~  

  

URL 类的最大的特点就是有效地保护了我们的安全。可以同一个Web 服务器建立连接,毋需知道幕后的任何 

东西。  



15。6。3 用 C++ 写的 CGI 程序  



经过前面的学习,大家应该能够根据例子用ANSI C 为自己的服务器写出CGI 程序。之所以选用 ANSI C,是 

因为它几乎随处可见,是最流行的 C 语言标准。当然,现在的 C++也非常流行了,特别是采用GNU C++编译器 

 (g++)形式的那一些(注释④)。可从网上许多地方免费下载g++,而且可选用几乎所有平台的版本(通常 

与Linux 那样的操作系统配套提供,且已预先安装好)。正如大家即将看到的那样,从 CGI 程序可获得面向 

对象程序设计的许多好处。  

  

④:GNU 的全称是“Gnu's Not Unix”。这最早是由“自由软件基金会”(FSF)负责开发的一个项目,致力 

于用一个免费的版本取代原有的Unix 操作系统。现在的 Linux 似乎正在做前人没有做到的事情。但 GNU 工具 

在Linux 的开发中扮演了至关重要的角色。事实上,Linux 的整套软件包附带了数量非常多的 GNU 组件。  

  

为避免第一次就提出过多的新概念,这个程序并未打算成为一个“纯”C++程序;有些代码是用普通C 写成 

的——尽管还可选用C++的一些替用形式。但这并不是个突出的问题,因为该程序用C++制作最大的好处就是 

能够创建类。在解析CGI 信息的时候,由于我们最关心的是字段的“名称/值”对,所以要用一个类 

 (Pair )来代表单个名称/值对;另一个类(CGI_vector)则将CGI 字串自动解析到它会容纳的Pair 对象里 

 (作为一个vector),这样即可在有空的时候把每个Pair (对)都取出来。  

这个程序同时也非常有趣,因为它演示了 C++与Java 相比的许多优缺点。大家会看到一些相似的东西;比如 

class 关键字。访问控制使用的是完全相同的关键字public 和private,但用法却有所不同。它们控制的是 

一个块,而非单个方法或字段(也就是说,如果指定private: ,后续的每个定义都具有private 属性,直到 

我们再指定 public:为止)。另外在创建一个类的时候,所有定义都自动默认为private。  

在这儿使用 C++的一个原因是要利用C++ “标准模板库”(STL)提供的便利。至少,STL 包含了一个 vector 

类。这是一个C++模板,可在编译期间进行配置,令其只容纳一种特定类型的对象(这里是 Pair 对象)。和 

Java 的Vector 不同,如果我们试图将除Pair 对象之外的任何东西置入 vector,C++的vector 模板都会造成 

一个编译期错误;而Java 的Vector 能够照单全收。而且从 vector 里取出什么东西的时候,它会自动成为一 

个Pair 对象,毋需进行造型处理。所以检查在编译期进行,这使程序显得更为“健壮”。此外,程序的运行 

速度也可以加快,因为没有必要进行运行期间的造型。vector 也会过载operator'',所以可以利用非常方便 

的语法来提取Pair 对象。vector 模板将在CGI_vector 创建时使用;在那时,大家就可以体会到如此简短的 

一个定义居然蕴藏有那么巨大的能量。  

若提到缺点,就一定不要忘记 Pair 在下列代码中定义时的复杂程度。与我们在 Java 代码中看到的相比, 

Pair 的方法定义要多得多。这是由于C++的程序员必须提前知道如何用副本构建器控制复制过程,而且要用 

过载的 operator=完成赋值。正如第 12 章解释的那样,我们有时也要在Java 中考虑同样的事情。但在C++ 

中,几乎一刻都不能放松对这些问题的关注。  

这个项目首先创建一个可以重复使用的部分,由C++头文件中的 Pair 和 CGI_vector 构成。从技术角度看, 

确实不应把这些东西都塞到一个头文件里。但就目前的例子来说,这样做不会造成任何方面的损害,而且更 

具有Java 风格,所以大家阅读理解代码时要显得轻松一些:  



                                                                             566 


…………………………………………………………Page 568……………………………………………………………

  

//: CGITools。h  

// Automatically extracts and decodes data  

// from CGI GETs and POSTs。 Tested with GNU C++   

// (available for most server machines)。  

#include   

#include  // STL vector  

using namespace std;  

  

// A class to hold a single name…value pair from  

// a CGI query。 CGI_vector holds Pair objects and  

// returns them from its operator''。  

class Pair {  

  char* nm;  

  char* val;  

public:  

  Pair() { nm = val = 0; }  

  Pair(char* name; char* value) {  

    // Creates new memory:  

    nm = decodeURLString(name);  

    val = decodeURLString(value);  

  }  

  const char* name() const { return nm; }  

  const char* value() const { return val; }  

  // Test for 〃emptiness〃  

  bool empty() const {  

    return (nm == 0) || (val == 0);  

  }  

  // Automatic type conversion for boolean test:  

  operator bool() const {  

    return (nm != 0) && (val != 0);  

  }  

  // The following constructors & destructor are  

  // necessary for bookkeeping in C++。  

  // Copy…constructor:  

  Pair(const Pair& p) {  

    if(p。nm == 0 || p。val == 0) {  

      nm = val = 0;  

    } else {  

      // Create storage & copy rhs values:  

      nm = new char'strlen(p。nm) + 1';  

      strcpy(nm; p。nm);  

      val = new char'strlen(p。val) + 1';  

      strcpy(val; p。val);  

    }  

  }  

  // Assignment operator:  

  Pair& operator=(const Pair& p) {  

    // Clean up old lvalues:  

    delete nm;  

    delete val;  

    if(p。nm == 0 || p。val == 0) {  



                                                                                          567 


…………………………………………………………Page 569……………………………………………………………

      nm = val = 0;  

    } else {  

      // Create storage & copy rhs values:  

      nm = new char'strlen(p。nm) + 1';  

      strcpy(nm; p。nm);  

      val = new char'strlen(p。val) + 1';  

      strcpy(val; p。val);  

    }  

    return *this;  

  }   

  ~Pair() { // Destructor  

    delete nm; // 0 value OK  

    delete val;  

  }  

  // If you use this method outide this class;   

  // you're responsible for calling 'delete' on  

  // the pointer that's returned:  

  static char*   

  decodeURLString(const char* URLstr) {  

    int len = strlen(URLstr);  

    char* result = new char'len + 1';  

    memset(result; len + 1; 0);  

    for(int i = 0; j = 0; i = 'A')  

      return (hex & 0xdf) 'A' + 10;  

    else  

      return hex '0';  

  }  

};  

  

// Parses any CGI query and turns it  

// into an STL vector of Pair objects:  

class CGI_vector : public vector {  

  char* qry;  

  const char* start; // Save starting position  

  // Prevent assignment and copy…construction:  

  void operator=(CGI_vector&);  



                                                                                               568 


…………………………………………………………Page 570……………………………………………………………

  CGI_vector(CGI_vector&);  

public:  

  // const fields must be initialized in the C++  

  // 〃Constructor initializer list〃:  

  CGI_vector(char* query) :  

      start(new char'strlen(query) + 1') {  

    qry = (char*)start; // Cast to non…const  

    strcpy(qry; query);  

    Pair p;  

    while((p = nextPair()) != 0)  

      push_back(p);  

  }  

  // Destructor:  

  ~CGI_vector() { delete start; }  

private:  

  // Produces name…value pairs from the query   

  // string。 Returns an empty Pair when there's   

  // no more query string left:  

  Pair nextPair() {  

    char* name = qry;  

    if(name == 0 || *name == '0')  

      return Pair(); // End; return null Pair  

    char* value = strchr(name; '=');  

    if(value == 0)  

      return Pair(); // Error; return null Pair  

    // Null…terminate name; move value to start  

    // of its set of characters:  

    *value = '0';  

    value++;  

    // Look for end of value; marked by '&':  

    qry = strchr(value; '&');  

    if(qry == 0) qry = 〃〃; // Last pair found  

    else {  

      *qry = '0'; // Terminate value string  

      qry++; // Move to next pair  

 

返回目录 上一页 下一页 回到顶部 0 1

你可能喜欢的