频 道 直 达 - 新闻 - 培训 - 软件 - 教程 - 前沿 - 组网 - 系统应用 - 安全 - 编程 - 存储 - 操作系统 - 数据库 - 服务器 - 专题 - 产品 - 案例库 - 读书 - 博客 - BBS
51CTO.COM_中国最大的网络技术网站
找资料:

3.3 实现:组合电子阅读器

作者: Michael Morrison著/李松风译 出处:机械工业出版社  2008-04-21 12:48    砖    好    评论   进入论坛
阅读提示:《Ajax构建工具箱指南》第3章为您介绍的是动态加载Web数据:XML电子书阅读器,本节主要讲了实现:组合电子阅读器。

3.3   实现:组合电子阅读器

要构建这个令人兴奋的Booker应用程序,最好的方式就是先将其化整为零。下面就是需要加入到这个应用程序中的三个主要部件:

XML文件(book_alicewonderland.xml、book_frankenstein.xml等)
HTML网页(booker.html)
PHP服务器端脚本(booker.php)

下面几节将对Booker应用程序的这几个部分进行详细讨论,同时揭示各个部分的相关代码。

注意

又要学习另一种新技术PHP了。尽管最好是懂PHP,但绝对不是只有PHP程序员才能理解和自定义这个或者本书中其他的应用程序。为此,我有意将本书所有示例应用程序中的PHP代码都保持在极其简单而且代码量也最少的程度。你所碰到的许多PHP代码都是“样板文件”,也就是说根本不需要动它们就能够自定义应用。假如真有机会需要你微调PHP代码,我也会明确指出应该修改哪里和为什么需要那么改。

XML电子书

在原先的Booker示例中,电子书是以纯文本文件保存的,它们都带有我们熟悉的.txt扩展名。而应用程序则将每本电子书的全部数据,作为一个巨大的文本块打开来显示。本章的新Booker应用程序则需要电子书保存为XML数据格式,通过该格式可以清晰地表示章和其他信息(比如图书名称、图书作者、章名称等)。与文本文件类似,XML文件也可以通过任何文本编辑器软件打开和编辑。实际上,你可以将XML文件想像为一个HTML网页文件,只不过它使用的是定制的词汇表(标签集),而不是<html>、<p>、<div>等这些HTML中的标签。XML文件的扩展名都是.xml。

注意

在讨论XML时,你经常会看到文件和文档这两个术语。一般而言,它们的含义是相同。而当一段XML代码并不与硬盘中的某个文件相关时,这两个术语的差别就会体现出来。例如,XML代码完全可以(有时候也是必须的)由程序动态生成,对动态生成的代码就无所谓文件的概念了。此时,使用更抽象的术语—文档会更贴切。在本书中,我将使用同样的术语。

那么你打算使用哪种XML词汇表来表现一本电子书呢?虽然当前有一些标准的电子书词汇表,但这些词汇表对本章的示例来说明显过于复杂,所以我们还是自己创建为好。与其逐个地介绍每个标签的含义,不如直接看一看实际的XML电子书的部分代码:

<?xml version="1.0" encoding="utf-8"?>
<ebook>
<title>ALICE'S ADVENTURES IN WONDERLAND</title>
<author>Lewis Carroll</author>
<chapters>
<chapter num="Chapter I" title="Down the Rabbit-Hole">
Alice was beginning to get very tired of sitting by her
sister on the bank, and of having nothing to do...
</chapter>
<chapter num="Chapter II" title="The Pool of Tears">
&#39;Curiouser and curiouser!&#39; cried Alice (she was so
much surprised, that for the moment she quite forgot how to
speak...
</chapter>
...
</chapters>
</ebook>

第一行可能略显神秘一些,实际上,其中的代码表示的是该XML文件遵守XML 1.0标准,而且使用的是标准字符编码方案(UTF-8)。这行代码几乎是在所有XML文档中都会出现的标准代码。除此这外,其他代码都与具体的电子书相关,其中的标签和属性名非常容易理解。

具体来说,每本电子书的代码都以分层方式包含在一对ebook元素中,ebook元素由下面这样的开标签和闭标签组成:

 <ebook>
...
</ebook>
在ebook元素中,我们放了另一个容器元素(chapters),表示章的集合。下面就是添加了chapters元素后的电子书代码:
<ebook>
<chapters>
...
</chapters>
</ebook>

一本电子书中的每一章都以一对<chapter>标签表示,chapter元素还有两个保存章编号和章名称的属性:num和title。除了这两个属性之外,<chapter>标签本身还作为保存章文本的容器。因此,单独一章的代码如下所示:

 <chapter num="Chapter II" title="The Pool of Tears">
&#39;Curiouser and curiouser!&#39; cried Alice (she was so much
surprised, that for the moment she quite forgot how to speak...
</chapter>

章文本中古怪的“&#39;”表示一个撇号('),使用这种特殊的编码是为了避免XML文档解析程序将撇号与其他代码混淆。对这个元素(在XML中也称实体)还可以使用标准的撇号实体来表示,即“&apos;”。在电子书中还需要进行类似编码的是引号字符,在XML文件中引号要使用“&#34;”,而不是实际的引号(")。

在理解了一本电子书的XML文档结构,并且也知道了如何将电子书中每一章的内容编码为XML文档的基础上,理解整本书的XML代码就比较容易了。以下就是H. G. Wells所著The War of the Worlds中的部分XML代码:

 <?xml version="1.0" encoding="utf-8"?>
<ebook>
<title>The War of the Worlds</title>
<author>H. G. Wells</author>
<chapters>
<chapter num="" title="INTRO">
But who shall dwell in these worlds if they be
inhabited? .  .  .  Are we or they Lords of the
World? .  .  .  And how are all things made for man?
- KEPLER (quoted in The Anatomy of Melancholy)
</chapter>
<chapter num="BOOK ONE, CHAPTER ONE"
title="THE EVE OF THE WAR">
THE COMING OF THE MARTIANS
  No one would have believed in the last years of the
nineteenth century that this world was being watched keenly
and closely by intelligences greater than man&#39;s and yet
as mortal as his own...
</chapter>
<chapter num="BOOK ONE, CHAPTER TWO"
title="THE FALLING STAR">
Then came the night of the first falling star. It was seen
early in the morning, rushing over Winchester eastward, a
line of flame high in the atmosphere. Hundreds must have
seen it, and taken it for an ordinary falling star...
</chapter>
...
</chapters>
</ebook>

但愿你能看懂这些XML代码,毕竟我们已经见过使用相同格式的两本书的代码了。对于The War of the Worlds被分成两“册”的特殊情况也很容易处理。不用为了适应标识章的不同方式而修改全部数据格式,在这里我们把书的编号整合到了章编号中。与其他电子书不同,这本书同时还利用了章编号以及章名称,这也证明了chapter元素的这两个属性是必要的。

虽然这并不是什么有趣的事,但我还是通过手工把上一章中的那五个示例电子书,转换成了刚刚看到的XML格式。转换开始时并不费劲,直至遇到非人性的(简直就是!)Moby Dick—这本书居然分了102章!这让我连对War and Peace发脾气的机会都没有了。War and Peace是一本规模宏大的小说,它为Booker应用程序提供了极好的压力测试。在根据自己的需要定制Booker应用程序的过程中,你最终会发现把电子书编码为XML格式是其中最耗时的一个部分。

在本章前面我们曾提到过,尽管XML文件实际上就是文本文件,也必须使用.xml扩展名。下面就是要在更新后的Booker应用程序中使用的示例电子书,以及它们各自的文件名:

 Alice誷 Adventures in Wonderland—book_alicewonderland.xml
Frankenstein—book_frankenstein.xml
Moby Dick—book_mobydick.xml
War and Peace—book_warandpeace.xml
The War of the Worlds—book_warofworlds.xml
这些电子书仍然使用了同以前一样的简略名称进行命名—唯一的差别就是它们的扩展名是.xml而不是.txt。这表明我们可以通过下面的表达式以程序化的方式构建一个XML电子书的文件名:
  "book_" + AbbrevTitle + ".xml"


下一节内容揭示了使用这个文件名连同章索引一起生成对服务器的Ajax请求的Booker应用程序的代码。
Booker的网页部分

尽管Booker应用程序中有服务器端组件,但大多数工作量都发生在客户端,这就是应用程序的HTML网页部分—booker.html。图3-4中显示了新Booker应用程序在Web浏览器中运行的界面,在经过更新的用户界面中提供了用于导航章的按钮。

注意

如果你奇怪在这个Booker应用程序中的Ajax诊断栏到哪里去了,答案是我把它隐藏起来了,以免它分散你的注意力。事实上,诊断栏在本书其余的应用程序中都不会再出现。不过,可以在这个网页的HTML代码中删除Ajax状态div(ID值为ajaxState)的样式值dispaly:none,或者把该样式值改为display:block来启用它。如果你想留着这个样式,那么在后面可以再禁用它。

 

这幅插图展示了应用程序中一些新的界面元素。首先,章名称正好显示在电子书选择列表的下方。这个区域实际上可以同时显示章编号和章名称,但在显示War of the Worlds中前言的情况下,则只显示章编号(INTRO)。

在章标题(编号+名称)下方,是两个导航按钮,分别用于导航到第1章和前一章。不过这两个按钮现在在插图中是被禁用的,这是一种细微但却有用的用户界面提示,表明读者当前正在阅读电子书的第1章。再往下是章文本,章文本的后面又是两个按钮,用于导航到下一章和最后一章。

为了测试方便,我最初把所有这些导航按钮都集中放在了章文本的上方。但后来我想到当读者看到一章的结尾时,必须要把页面滚动回顶部才能导航到下一章,这样导航的作用就被削弱了。所以,最终我把Next和End(>>)按钮放在了章文本的下方。

界面外观介绍的差不多了,下面我们继续看一下页面主体中的代码,这些代码定义了用户界面并连接起了脚本化的事件:

<body style="background:#EEEEEE"
onload="document.getElementById('book').selectedIndex = 0;
loadChapter(document.getElementById('book').options[
document.getElementById('book').selectedIndex].value, 0)">
<div id="ajaxState" style="display:none"></div>
<br />
<div style="margin-left:10%">Select book:
<select id="book"
onchange="loadChapter(this.options[
this.selectedIndex].value, 0)">
<option value="alicewonderland">Alice's Adventure's in
Wonderland by Lewis Carroll</option>
<option value="frankenstein">Frankenstein by Mary
Shelley</option>
<option value="mobydick">Moby Dick by Herman
Melville</option>
<option value="warandpeace">War and Peace by Leo
Tolstoy</option>
<option value="warofworlds">The War of the Worlds by
H.G. Wells</option>
</select>
</div>
<br />
<div id="chapinfo" style="margin-left:10%; font-size:large">
</div>
<br />
<div style="margin-left:10%">
<input id="homeButton" type="button" value="<<"
style="width:60px"
onclick="curchapIndex = 1; prevChapter()" />
<input id="prevButton" type="button"
value="< Previous" style="width:120px"
onclick="prevChapter()" />
</div>
<br />
<div id="chaptext"
style="margin-left:10%; margin-right:10%; padding:2%;
background:#FFFFFF; border:thin solid #333333"></div>
<br />
<div style="margin-left:10%">
<input id="nextButton" type="button" value="Next >"
style="width:120px" onclick="nextChapter()"   />
<input id="endButton" type="button" value=">>"
style="width:60px"
onclick="curchapIndex = (totalChapters - 2);
nextChapter()" />
</div>
</body>

同时,我知道对于一本不需要你懂JavaScript的书来说,这些代码中的JavaScript有点过份。不过,请记住本书的宗旨是为了让你在自己的应用中重用这些代码。而重用这些代码完全可以在你不理解每一行代码含义的情况下做到。虽然如此,还是有必要从大体上讲解一下,以便你进行修改时有的放矢。而且,不要忘了所有这些代码(以及本节中其余的代码)都能在本书附带的Live Linux CD中booker.html文件中找到。

首先,用户界面被组织到一些div元素中,这些div元素为清晰地组织章信息和导航按钮提供了良好的手段。与前一版的应用程序相似,包含电子书的选择列表使用HTML中的<select>标签定义。这一版中更有趣的是导航按钮,它们是使用<input>标签定义的。

Previous和Next导航按钮的功能是通过调用prevChapter()和nextChapter()这两个JavaScript函数实现的,稍后我们会讲到这两个函数。Home(<<)和End(>>)按钮也使用了相同的函数,但同时配合使用了跟踪当前章索引的变量curChapIndex。在后面我们讲解与应用相关的JavaScript代码时,会讨论这个变量的工作原理。
Booker网页主体中另一个非常重要的代码块,是基于选择列表中选项的变化加载电子书的代码:

loadChapter(this.options[this.selectedIndex].value, 0)

这行代码与前一版应用程序中的选择变化代码是相同的,只不过这行代码除了传递当前选择的电子书(this.options[this.selectedIndex].value)之外,还传递了章索引(0)。而且,函数的名称也从loadBook()修改为loadChapter(),用以表明只会加载一章的内容。在<body>标签的onload事件处理程序中同样也调用了loadChapter()函数,这里的调用目的是当第一次打开页面时,加载列表中第一本电子书的第一章内容。

下面就是loadChapter()函数的代码,该函数通过Ajax请求给定的简略电子书名称和章索引,加载单独一章的内容:

  function loadChapter(title, chapIndex) {
// 应该是打开了一本新书,因而需要初始化导航按钮
if (chapIndex == 0) {
document.getElementById("homeButton").disabled = true;
document.getElementById("prevButton").disabled = true;
document.getElementById("nextButton").disabled = false;
document.getElementById("endButton").disabled = false;
}
  // 设置当前的章索引
curchapIndex = chapIndex;
  // 清除上一次加载的章文本
replaceText(document.getElementById("chaptext"),
"Loading...");
  // 发送Ajax请求加载新一章的内容
var bookURL = "booker.php?title=" +
encodeURIComponent(title) +
"&chapIndex=" + encodeURIComponent(chapIndex);
ajaxSendRequest("GET", bookURL, handleRequest);
}

这个函数的前几行代码对导航按钮进行了初始化,以便适应第一本书的第1章来启用和禁用相应按钮。要保存当前的章索引是因为需要根据它来成功地从一章导航到另一章 。章文本区域具有双重用途,当章的内容被加载期间,该区域会提示正在加载中,其内容被设置为“Loading...”。而当加载完成后,其内容又被替换成实际的章文本。最后,通过将简略名称和章索引绑定到URL中,并通过GET请求方法来发送实际的Ajax请求。注意,我们熟悉的handleRequest()函数仍然被指定为请求处理程序,也就是说当请求完成时会调用这个函数。

在这个Booker应用程序中,handleRequest()函数承担了最大的工作量,在这里它要负责取得XML图书数据、解析出重要的信息并更新页面中相应的元素。在讨论这个函数的代码之前,我们再简单地看一下在Ajax响应中由服务器发送回来的XML数据的格式:

 <bookData>
<chapNum />
<chapTitle>INTRO</chapTitle>
<chapText>
But who shall dwell in these worlds if they be
inhabited? .  .  .  Are we or they Lords of the
World? .  .  .  And how are all things made for man?
- KEPLER (quoted in The Anatomy of Melancholy)
</chapText>
<totalChapters>28</totalChapters>
</bookData>
这就是将由handleRequest()函数进行处理的XML数据格式的示例,该函数的代码如下:
function handleRequest() {
if (request.readyState == 4 && request.status == 200) {
// 存储XML响应数据
var xmlData = request.responseXML.getElementsByTagName(
"bookData")[0];

// 存储总章数
totalChapters =
getText(xmlData.getElementsByTagName("totalChapters")[0]);

// 显示章信息
var chapNum = getText(xmlData.getElementsByTagName(
"chapNum")[0]);
var chapTitle =
getText(xmlData.getElementsByTagName("chapTitle")[0]);
var chapInfo;
if (chapNum.length > 0 && chapTitle.length > 0)
chapInfo = chapNum + " : " + chapTitle;
else
chapInfo = chapNum + chapTitle;
replaceText(document.getElementById("chapinfo"), chapInfo);

// 显示章文本
replaceText(document.getElementById("chaptext"),
getText(xmlData.getElementsByTagName("chapText")[0]));
}
ajaxUpdateState();
}

以上代码首先检查并确保Ajax请求成功完成,然后将XML数据削减为第一个bookData元素的内容,此时仅有一个bookData元素。自此之后,开始使用JavaScript的DOM函数从XML数据中仔细地提取每一段数据。例如,通过下面这行代码取得总章数并存储在totalChapters变量中:
totalChapters =
getText(xmlData.getElementsByTagName("totalChapters")[0]);
如果总章数在XML中使用了不同的标签名(比如<NumberOfChapters>),那么前面这行代码应该改成下面这样:
 totalChapters =
getText(xmlData.getElementsByTagName("NumberOfChapters")[0]);

这就是一个示范在不必深究DOM函数具体细节的条件下,如何修改本应用程序中的XML处理代码的例子。

注意

在这个Booker应用程序中使用的getText()和replaceText()函数不是标准的JavaScript DOM函数,而是包含在本书domkit.js文件中的辅助函数。前一章解释了这两个函数以及其他Ajax工具箱中函数的关系。

handleRequest()函数中的其余代码涉及到从XML数据中提取出信息段,然后将它们显示到页面中的每个div元素中。这些代码非常聪明,它们检查章编号和章名称是否同时存在,如果同时存在就会将这两段信息组合起来。否则,只显示实际存在的信息段。这种方法巧妙地解决了有的图书只有章编号,有的只有章名称,而有的既有章编号又有章名称的情况。

在这个网页中我们唯一还没有看到的函数是响应导航按钮单击事件的函数—prevChapter()和nextChapter()。我们从prevChapter()函数开始,该函数的代码如下:

function prevChapter() {
if (curchapIndex > 0) {
curchapIndex-;
document.getElementById("nextButton").disabled = false;
document.getElementById("endButton").disabled = false;
}
if (curchapIndex == 0) {
document.getElementById("homeButton").disabled = true;
document.getElementById("prevButton").disabled = true;
}
loadChapter(document.getElementById('book').options[
document.getElementById('book').selectedIndex].value,
curchapIndex);
}

这个函数中的大部分代码都致力于根据当前章是否是第1章来灵活地启用或者禁用导航按钮。在有关导航按钮的逻辑执行完成后,代码调用了loadChapter()函数,并用当前章索引指定了要加载哪一章。

nextChapter()函数与prevChapter()非常相似,但目标集中在最的一章而不是第1章。换句话说,如果当前章是最后一章,那么nextChapter()函数必须禁用Next按钮。下面的代码显示了如何以totalChapters变量为基础,来决定当前章是不是最后一章:

 function nextChapter() {
if (curchapIndex  < (totalChapters - 1)) {
curchapIndex++;
document.getElementById("homeButton").disabled = false;
document.getElementById("prevButton").disabled = false;
}
if (curchapIndex == (totalChapters - 1)) {
document.getElementById("nextButton").disabled = true;
document.getElementById("endButton").disabled = true;
}
loadChapter(document.getElementById('book').options[
document.getElementById('book').selectedIndex].value,
curchapIndex);
}

以上这些代码构成了改头换面的新Booker应用程序的客户端。现在所剩的只有服务器端脚本了,那是与客户端相对的另外一个主要部分。

Booker的服务器端脚本

在Booker应用程序中,服务器端的PHP脚本负责读取包含整本书的XML文件,然后动态生成只包含客户端网页所需章信息的XML文档。最后,包含章信息的XML文档又通过Ajax响应被传递回客户端。下面就是服务器端PHP脚本booker.php的代码:

<?php
header('Content-Type: text/xml');
// 将电子书的XML数据解析为结构化数据
$rawBook = file_get_contents("book_" . $_REQUEST['title'] .
".xml");
$xml = new SimpleXmlElement($rawBook);
$chap = $xml->chapters->chapter[intval($_REQUEST['chapIndex'])];
$xmlChapter = '<?xml version="1.0" encoding="utf-8"?>';
$xmlChapter .= '<bookData>';
$xmlChapter .= '<chapNum>' . $chap['num'] . '</chapNum>';
$xmlChapter .= '<chapTitle>' . $chap['title'] . '</chapTitle>';
$xmlChapter .= '<chapText>' . $chap . '</chapText>';
$count = 0;
foreach ($xml->chapters->chapter as $chapter) {
$count++;
}
$xmlChapter .= '<totalChapters>' . $count . '</totalChapters>';
$xmlChapter .= '</bookData>';
// 生成包含图书章信息的XML文档
echo $xmlChapter;
?>

如果你没有任何PHP经验,那么这些代码看起来可能很陌生。与其在这里教你一门新语言(当然这肯定超出了本书的范围和领域),不如当一回讲解员。代码在一开始确定了要以XML格式返回数据—这很关键,因为服务器会在通过Ajax响应将数据交付回客户端时,对数据进行适当打包。

脚本中第一处重要的代码块负责从一个XML文件中读取整本电子书,并保存到一个可以进一步处理的数据结构中。其中代码$_REQUEST['title']就是用于取得在Ajax请求的URL中发送的title参数的PHP脚本。回忆一下相应的代码:

booker.php?title=warofworlds&chapIndex=0
PHP脚本$_REQUEST['title']取得的就是在这个URL中发送的title值。类似地,要取得chapIndex参数的值,要使用下面的代码:
$_REQUEST['chapIndex']

回到解析XML电子书的脚本代码中,该代码构建了一个文件名(比如book_warofworlds.xml),然后将其读入到一个XML数据结构中。在此基础上,代码的主要部分深入到这个XML数据结构中,根据脚本取得的chapIndex参数来查找指定的章。然后,有效地读取并写入XML—在整本电子书中查找指定的章信息,将这些章信息写入一个新的XML文档是件乏味的苦差事。最终的结果就是我们在上一节中看到的带有<bookData>标签的简洁的XML响应数据。

要真正理解这些服务器端脚本的工作原理,最好是通过文本编辑器打开其中一本电子书的XML文件,然后在你一行一行地查看脚本中代码的同时研究其中的标签。你会发现一种系统地操作每个标签和属性的模式,而且与这些标签和属性相关的数据会被提取并打包到新XML标签中。

结果,脚本构建起一个包含章信息的新XML文档,又通过下面这一行代码将其返回到客户端:

echo $xmlChapter;

虽然脚本的工作量显得有几分虎头蛇尾的味道,但这正是PHP的工作方式。真正叫绝的还要等到下一节你通过应用程序不停地执行这个脚本块时才会体现出来。不过,在此之前,我们先简单介绍一下如何测试PHP脚本。

我们知道Booker应用程序中的Ajax请求,是由一个向PHP脚本传递参数的URL组成的,PHP脚本负责向请求返回作为响应的XML文档。而在Ajax请求的环境之外研究响应是非常有益的,也就是说我们可以偷看一下PHP脚本在Web浏览器中会直接生成什么内容。为此,我们可以在浏览器中简单地输入一个Ajax请求的URL作为网页地址,像下面这样:

 http://www.yourdomain.com/booker.php?title=warofworlds&chapIndex=0
假设PHP脚本和XML电子书都存储在你的服务器上,你需要将这行代码中的域名修改为你的域名,然后在Web浏览器中输入这个URL。也可以直接在本书附带的Live Linux CD中直接尝试这个技巧。无论采取哪种方式,都会看到如图3-5所示的由PHP脚本生成的XML响应数据。
 
当你在测试本书中其他示例以及你自己的项目时,请记住这个技巧。我在开发这些示例应用程序时,非常频繁地使用了这个技巧,并且有好几次都在PHP脚本中发现了通过其他方式无法轻易发现的错误。
【责任编辑:夏书 TEL:(010)68476606】

回书目   上一节   下一节
专题
程序员如何成长?
解析Ajax开发框架 走进Ajax开发应用
Ajax明天会HOT还是OVER?
微软的Ajax:Atlas(ASP.net AJAX)
AJAX 51CTO技术座谈会
我也说两句

匿名发表

(如果看不清请点击图片进行更换)


中 国 最 大 的 网 络 技 术 网 站 ·
技 术 成 就 梦 想
订阅技术快讯
电子杂志下载
名称:SQL Server数据库管理精品黄皮书
简介:书中文章经过精挑细选,便于用户能根据自己的实际工作和学习,快速在本书寻找到相关资料。内容涵盖了SQL Server的安装与升级、语句查询、数据备份和恢复、自动化任务、数据同步、数据字典、安全和预防、性能和优化、集群等各方面应用信息,以及DBA管理人员在数据库管理工作中
名称:2007路由技术大全
简介:《2007路由技术大全》由51CTO.com网站特别策划制作,该书包括路由器技术、路由器产品、路由器配置、安全设置、路由器故障处理、路由器密码恢复,以及广大网友在实践使用中的心得经验和技巧文章,内容注重实用性,适用于初学者入门,也适合多年从业者提高,是一本实践和理论完
名称:网络安全精品应用黄皮书
简介:《2007精品网络安全黄皮书》包括了9个大类24个小类, 800余篇文章,内容包含了熊猫烧香病毒、DDOS攻击、ARP病等热点问题的介绍及解决方案。从病毒查杀、防范、系统、数据等各方面的安全设置到黑客技术的了解、防范,涉及到了安全应用的全部领域, 由浅至深内容全面。
见证中国网络安全二十年
见证中国网络安全二十年
勇闯IT培训黑色围城
勇闯IT培训黑色围城
技术人求职简历完备手册
技术人求职简历完备手册
· 技术人求职简历完备手册
· 华为员工自杀频频拷问..
· 视频访谈:网管员如何踏..
· 首届中国IT工程师生态..
· 思科全球CEO钱伯斯第七..
· 北漂技术人90天求职纪实
· 2007年互联网大会
· 龙芯要做中国的“奔腾”
· IPv6协议--拓展网络无..
· 国际文档格式标准开战
· 微软出价446亿美元收购..
· 贝恩资本携手华为22亿..
· Linux——从菜鸟到高手
· SOA 面向服务架构
· 2008年4月全国计算机等..
· 微软Forefront企业安全..
ARP攻击防范与解决方案
ARP攻击防范与解决方案
iSCSI应用与发展
iSCSI应用与发展
SQL Server 2008/2005全解
SQL Server 2008/2005全解
· SQL Server 2008/2005..
· SOA 面向服务架构
· SQL Server 2008/2005..
· iSCSI应用与发展
· RAID——磁盘阵列基础
· 中间件应用技术专题
· SQL Server入门到精通
· 病毒查杀专题
· 国际文档格式标准开战
· 路由器设置与口令恢复
· Linux防火墙
· 打造安全服务器
· SOA 面向服务架构
· PHP开发应用手册
· ADSL应用面面俱到
· 入侵防护系统(IPS)初探
ARP攻击防范与解决方案
ARP攻击防范与解决方案
SQL Server 2008/2005全解
SQL Server 2008/2005全解
iSCSI应用与发展
iSCSI应用与发展
· iSCSI应用与发展
· 中间件应用技术专题
· SQL Server入门到精通
· SQL Server 2008/2005..
· SOA 面向服务架构
· iSCSI应用与发展
· RAID——磁盘阵列基础
· 病毒查杀专题
· 路由器设置与口令恢复
· SOA 面向服务架构
· 了解统一威胁管理(UTM)..
· ADSL应用面面俱到
· ADSL应用面面俱到
· 反垃圾邮件技术应用
· PHP开发应用手册
· 中间件应用技术专题