posts - 22, comments - 32, trackbacks - 0, articles - 71
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

2009年4月1日

最近在公司有点时间所以深入研究了下数据库索引btree/b+tree数据结构和原理,由此牵引出了好多问题,请看如下带着问题研究。

1:为什么 btree/b+tree 数据结构适合数据库索引,它到底是怎么样一个原理和结构?

btree/b+tree 数据结构:

在之前的文章中我们介绍过AVL树,红黑树,它们都属于二叉树,即每个节点最多只能拥有2个子节点,而B-tree(B树)的每个节点可以拥有2个以上的子节点,所以我们简单概括一下:B-tree就是一颗多路平衡查找树,它广泛应用于数据库索引和文件系统中。

首先我们介绍一下一颗 m 阶B-tree的特性,那么这个 m 阶是怎么定义的呢?这里我们以一个节点能拥有的最大子节点数来表示这颗树的阶数。举个例子,如果一个节点最多有 n 个key,那么这个节点最多就会有 n+1 个子节点,这棵树就叫做 n+1(m=n+1)阶树。一颗 m 阶B-tree包括以下5条特性:

  1. 每个节点最多有 m 个子节点
  2. 除根节点和叶子节点,其它每个节点至少有 [m/2] (向上取整的意思)个子节点
  3. 若根节点不是叶子节点,则其至少有2个子节点
  4. 所有NULL节点到根节点的高度都一样
  5. 除根节点外,其它节点都包含 n 个key,其中 [m/2] -1 <= n <= m-1

这些特性可能看着不太好理解,下面我们会介绍B-tree的插入,在插入节点的过程中我们就会慢慢理解这些特性了。B-tree的插入比较简单,就是一个节点至下而上的分裂过程。下面我们具体以一颗4阶树来展示B-tree的插入过程。

首先我们 插入 200,300,400,没有什么问题,直接插入就好。

| 200 | 300 | 400 |

现在我们接着插入500,这个时候我们发现有点问题,根据定义及特性1我们知道一颗4阶B-tree的每个节点最多只能有3个key,插入500后这个节点就有4个key了。

| 200 | 300 | 400 | 500 |

这个时候我们就需要分裂,将中间的key上移到父节点,左边的作为左节点,右边的作为右节点,如下图所示:

这个时候我们是不是就明白特性3了,如果根节点不是叶子节点,那么它肯定发生了分裂,所以至少会有2个子节点。同样我们接着插入600,700,800,900插入过程如下图所示:

现在根节点也已经满了,如果我们继续插入910,920,会怎样呢?根节点就会继续分裂,树继续向上生长。看下图:

通过整个的插入过程我们也会发现,B-tree和二叉树的一个显著的区别就是,B-tree是从下往上生长,而二叉树是从上往下生长的。现在我们想想特性2和特性5是为什么?首先我们知道子节点的个数是等于key的数目+1,然后一个节点达到m个key后就会分裂,所以分裂后的节点最少能得到 m/2 - 1个key 。为啥还要减一呢?因为还要拿一个作为父节点。所以这个节点最少回拥有 m/2 - 1 + 1 = m/2 个子节点。同样得到特性5,因为最少有m/2个子节点,所以最少就含有m/2-1个key,m 阶树,每个节点存到了m个key就会分裂,所以最多就有 m-1个key。

根据以上特性我们能推出一棵含有N个总关键字数的m阶的B-tree树的最大高度h的值,

树的高度h: 1, 2, 3 , 4 ,.......... , h

节点个数s: 1, 2, 2*(m/2), 2*(m/2)(m/2), ........ ,2*(m/2)的h-2次方

s = 1 + 2(1 - (m/2)^{h-1} )/(1- (m/2))

N = 1 + s * ((m/2) - 1) = 2 * ((m/2)^{h-1} ) - 1

h = log┌m/2┐((N+1)/2 )+1

2:为什么btree/b+tree 为常用数据库索引结构?

上文说过,红黑树等数据结构也可以用来实现索引,但是文件系统及数据库系统普遍采用B-/+Tree作为索引结构,这一节将结合计算机组成原理相关知识讨论B-/+Tree作为索引的理论基础。

一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上。这样的话,索引查找过程中就要产生磁盘I/O消耗,相对于内存存取,I/O存取的消耗要高几个数量级,所以评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中磁盘I/O操作次数的渐进复杂度。换句话说,索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数。下面先介绍内存和磁盘存取原理,然后再结合这些原理分析B-/+Tree作为索引的效率。

主存存取原理

目前计算机使用的主存基本都是随机读写存储器(RAM),现代RAM的结构和存取原理比较复杂,这里本文抛却具体差别,抽象出一个十分简单的存取模型来说明RAM的工作原理。

图5

从抽象角度看,主存是一系列的存储单元组成的矩阵,每个存储单元存储固定大小的数据。每个存储单元有唯一的地址,现代主存的编址规则比较复杂,这里将其简化成一个二维地址:通过一个行地址和一个列地址可以唯一定位到一个存储单元。图5展示了一个4 x 4的主存模型。

主存的存取过程如下:

当系统需要读取主存时,则将地址信号放到地址总线上传给主存,主存读到地址信号后,解析信号并定位到指定存储单元,然后将此存储单元数据放到数据总线上,供其它部件读取。

写主存的过程类似,系统将要写入单元地址和数据分别放在地址总线和数据总线上,主存读取两个总线的内容,做相应的写操作。

这里可以看出,主存存取的时间仅与存取次数呈线性关系,因为不存在机械操作,两次存取的数据的“距离”不会对时间有任何影响,例如,先取A0再取A1和先取A0再取D3的时间消耗是一样的。

磁盘存取原理

上文说过,索引一般以文件形式存储在磁盘上,索引检索需要磁盘I/O操作。与主存不同,磁盘I/O存在机械运动耗费,因此磁盘I/O的时间消耗是巨大的。

图6是磁盘的整体结构示意图。

图6

一个磁盘由大小相同且同轴的圆形盘片组成,磁盘可以转动(各个磁盘必须同步转动)。在磁盘的一侧有磁头支架,磁头支架固定了一组磁头,每个磁头负责存取一个磁盘的内容。磁头不能转动,但是可以沿磁盘半径方向运动(实际是斜切向运动),每个磁头同一时刻也必须是同轴的,即从正上方向下看,所有磁头任何时候都是重叠的(不过目前已经有多磁头独立技术,可不受此限制)。

图7是磁盘结构的示意图。

图7

盘片被划分成一系列同心环,圆心是盘片中心,每个同心环叫做一个磁道,所有半径相同的磁道组成一个柱面。磁道被沿半径线划分成一个个小的段,每个段叫做一个扇区,每个扇区是磁盘的最小存储单元。为了简单起见,我们下面假设磁盘只有一个盘片和一个磁头。

当需要从磁盘读取数据时,系统会将数据逻辑地址传给磁盘,磁盘的控制电路按照寻址逻辑将逻辑地址翻译成物理地址,即确定要读的数据在哪个磁道,哪个扇区。为了读取这个扇区的数据,需要将磁头放到这个扇区上方,为了实现这一点,磁头需要移动对准相应磁道,这个过程叫做寻道,所耗费时间叫做寻道时间,然后磁盘旋转将目标扇区旋转到磁头下,这个过程耗费的时间叫做旋转时间。

局部性原理与磁盘预读

由于存储介质的特性,磁盘本身存取就比主存慢很多,再加上机械运动耗费,磁盘的存取速度往往是主存的几百分分之一,因此为了提高效率,要尽量减少磁盘I/O。为了达到这个目的,磁盘往往不是严格按需读取,而是每次都会预读,即使只需要一个字节,磁盘也会从这个位置开始,顺序向后读取一定长度的数据放入内存。这样做的理论依据是计算机科学中著名的局部性原理:

当一个数据被用到时,其附近的数据也通常会马上被使用。

程序运行期间所需要的数据通常比较集中。

由于磁盘顺序读取的效率很高(不需要寻道时间,只需很少的旋转时间),因此对于具有局部性的程序来说,预读可以提高I/O效率。

预读的长度一般为页(page)的整倍数。页是计算机管理存储器的逻辑块,硬件及操作系统往往将主存和磁盘存储区分割为连续的大小相等的块,每个存储块称为一页(在许多操作系统中,页得大小通常为4k),主存和磁盘以页为单位交换数据。当程序要读取的数据不在主存中时,会触发一个缺页异常,此时系统会向磁盘发出读盘信号,磁盘会找到数据的起始位置并向后连续读取一页或几页载入内存中,然后异常返回,程序继续运行。

B-/+Tree索引的性能分析

到这里终于可以分析B-/+Tree索引的性能了。

上文说过一般使用磁盘I/O次数评价索引结构的优劣。先从B-Tree分析,根据B-Tree的定义,可知检索一次最多需要访问h个节点。数据库系统的设计者巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入。为了达到这个目的,在实际实现B- Tree还需要使用如下技巧:

每次新建节点时,直接申请一个页的空间,这样就保证一个节点物理上也存储在一个页里,加之计算机存储分配都是按页对齐的,就实现了一个node只需一次I/O。

B-Tree中一次检索最多需要h-1次I/O(根节点常驻内存),渐进复杂度为O(h)=O(logdN)。一般实际应用中,出度d是非常大的数字,通常超过100,因此h非常小(通常不超过3)。

综上所述,用B-Tree作为索引结构效率是非常高的。

而红黑树这种结构,h明显要深的多。由于逻辑上很近的节点(父子)物理上可能很远,无法利用局部性,所以红黑树的I/O渐进复杂度也为O(h),效率明显比B-Tree差很多。

上文还说过,B+Tree更适合外存索引,原因和内节点出度d有关。从上面分析可以看到,d越大索引的性能越好,而出度的上限取决于节点内key和data的大小:

dmax = floor(pagesize / (keysize + datasize + pointsize))  (pagesize – dmax >= pointsize)

dmax = floor(pagesize / (keysize + datasize + pointsize)) - 1  (pagesize – dmax < pointsize)

floor表示向下取整。由于B+Tree内节点去掉了data域,因此可以拥有更大的出度,拥有更好的性能。

这一章从理论角度讨论了与索引相关的数据结构与算法问题,下一章将讨论B+Tree是如何具体实现为MySQL中索引,同时将结合MyISAM和InnDB存储引擎介绍非聚集索引和聚集索引两种不同的索引实现形式。



posted @ 2018-01-25 13:44 为自己代言 阅读(3773) | 评论 (0)编辑 收藏

同事遇到问题是一个java web 工程,依赖了一个jar包,但是jar包中也有自己一套配置文件(例spring 配置文件,资源文件等),这样如果让web工程中的war 包去加载jar 中的配置文件和资源文件呢?
我当时也有一个思想误区,以为web中加载不到jar中的文件,但是经过一番研究,终于明白了,按J2EE规范中web-inf/lib目录下是web工程的classpath 目录,容器会自动去扫描这个目录下所有的配置文件和jar加载到容器中,即:像jar中有自己一套配置文件,war 中又要依赖jar包,这样只需要把这些jar包打成war时候放到web-inf/lib下即可。
注意:1:jar包和war包中配置文件和一些资源文件不能重名。
        
         2:要在war包中的spring 配置文件中引入jar包中的配置文件。



posted @ 2015-04-24 20:42 为自己代言 阅读(6916) | 评论 (0)编辑 收藏

1、不同的tomcat的启动文件startup.sh 中要指定各自的CATALINA_HOME和CATALINA_BASE这两个环境变量。

2、不同的tomcat启动和关闭监听不同的端口

很多人喜欢把CATALINA_HOME和CATALINA_BASE配置到系统环境变量中去,我们不这么做,我们要做的只是把JDK及CLASSPATH配置到环境变量中去即可,因为这个可以通用。
CATALINA_HOME和CATALINA_BASE的区别。简单的说,CATALINA_HOME是Tomcat的安装目 录,CATALINA_BASE是Tomcat的工作目录。如果我们想要运行Tomcat的 多个实例,但是不想安装多个Tomcat软件副本。那么我们可以配置多个工作 目录,每个运行实例独占一个工作目录,但是共享同一个安装目录

下面讲具体的配置方法。

找到Tomcat的startup.sh文件,打开进行编辑。

在文件的开始位置,可以在一大堆注释的后面,加入
export CATALINA_BASE=/usr/ratest/apache-tomcat-7.0.16
export CATALINA_HOME=/usr/ratest/apache-tomcat-7.0.16

/usr/ratest/apache-tomcat-7.0.16这个就是tomcat的安装文件夹位置,不同的tomcat指定相应的文件夹即可。

注意,这两句话一定要在exec “$PRGDIR”/”$EXECUTABLE” start “$@”这句话的前面,我们放在文件的开始位置了,所以,就可以不考虑了。

然后就是要修改shutdown.sh文件,同样在头部加入上面的两行即可,也要在exec “$PRGDIR”/”$EXECUTABLE” stop “$@”的前面。

好了,解决了第一个问题,下面说第二个问题的解决方法。

找到并打开server.xml文件,里面有诸如8080,8009,8443等等端口配置,统一给这些数字加上100,或者1000或者其他什么数字,只要是不跟其他Tomcat或者当前linux上其他服务的端口重复即可。

现在进入Tomcat的bin文件夹,运行./startup.sh看看是不是可以启动多个了。

posted @ 2014-03-28 19:58 为自己代言 阅读(448) | 评论 (0)编辑 收藏

1,设置跟路径时,三种方式

在Tomcat默认安装后,tomcat的主目录是webapps/root目录,所以如果想改变tomcat的主目录的话可以如下所做,所以
第一种方法是:
打开C:/Tomcat/conf/server.xml,在<host></host>之间
加入代码:<Context docBase="d:/Tomcat 5.5/webapps/medi" path="" debug="0" reloadable="true"/>
这样重新启动tomcat,我们的主目录就被设置为dolphin这个项目了。

第二种方法是:
将tomcat安装目录下的ROOT下的所有文件全部删除,然后将工程的解压后的文件全部拷进去。

第三种方法是:
Tomcat5.0以下版本在d:/Tomcat/conf/Catalina/localhost目录下会自动生成了一个ROOT.Xml,
但是5.0以上版本不再生成此文件,所以可以新建个ROOT.xml,在里面加入如下代码:
<?Xml version='1.0' encoding='utf-8'?>
<Context crossContext="true" docBase="d:/Tomcat 5.5/webapps/medi" path="" reloadable="true">
</Context>

2,注意
此时即然配置了 默认访问目录,则不要再tomcat 部署工程了,
比如 在 conf\Catalina\localhost 增加配置文件 指定的工程路径 此文件要去掉, 否则会重复加载工程。

posted @ 2013-11-06 18:44 为自己代言 阅读(660) | 评论 (0)编辑 收藏

很多tomcat进程退出(或者进程假死),都是由于频繁的抛出OutOfMemeoryError导致的。

为了让tomcat退出前或者发生OutOfMemeoryError时自动dump堆栈信息,方便事后排查问题,我们可以做如下操作:

1、 在tomcat启动参数中加入两个参数 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/export/home/tomcat/domains/server2/oom.hprof

2、 重启tomcat

参数说明
(1)-XX:+HeapDumpOnOutOfMemoryError 表示当JVM发生OOM时,自动生成DUMP文件。
(2)-XX:HeapDumpPath=存储文件/目录 表示生成DUMP文件的路径

posted @ 2013-10-30 13:51 为自己代言 阅读(6181) | 评论 (2)编辑 收藏

想从JAVA转到obj-c,看了些基础的东西,感觉很奇怪,可能不太习惯,在网上看到一个不错文章有助理解obj-c的一些核心机制。

Objective-C——消息、Category和Protocol

2012-06-22 20:13 by 池建强, 2627 阅读, 11 评论, 收藏, 编辑

面向对象永远是个可以吐槽的话题,从开始提出到推崇备至,到充满质疑,一路走来让人唏嘘不已。面向对象的思想可谓历史悠久,20世纪70年代的Smalltalk可以说是面向对象语言的经典,直到今天我们依然将这门语言视为面向对象语言的基础。
面向对象是大部分编程语言的基本特性,像 C++、Java、Objective-C这样的静态语言,Ruby、Python这样的动态语言都是面向对象的语言。但是如何编写面向对象的程序却一直是困扰人们的话题,即使是Smalltalk,也有人认为这是一个有缺陷的面向对象的语言实现。
 
我在2010年翻译过的一篇InfoQ的文章,《面向对象编程──走错了路》中提到,面向对象编程的三个原则是:基于消息传递机制,对象分离和多态。文章中还举了Erlang例子,认为Erlang具备了这些原则,“所以可能是唯一的面向对象语言”。除了之前提到的三个特征,单继承和动态类型也被引用为面向对象语言的“绝对需求”。基于这些考虑,文章指出,Smalltalk在实现对象思想时的“错误”──例如,只关注状态和行为,在类和基于映像的语言里缺乏良好的并发模型和消息机制。
 
这篇文章中的核心就是,面向对象思想中除了对象的状态、行为,还应该关注其并发机制、消息机制,后者更为重要。这一点事实上是我在接触了Objective-C之后才有了更深入的体会。
 
Ojbective-C的语法设计主要基于Smalltalk,除了提供传统的面向对象编程特性之外,还增加了很多类似动态语言Ruby、Python才具有的特性,例如动态类型、动态加载、动态绑定等等,同时强化了消息传递机制和表意(Intention Revealing Interface)接口的概念。
 
—消息—
消息传递模型(Message Passing)是Objective-C语言的核心机制。在Objective-C中,没有方法调用这种说法,只有消息传递。在C++或Java中调用某个类的方法,在Objective-C中是给该类发送一个消息。在C++或Java里,类与类的行为方法之间的关系非常紧密,一个方法必定属于一个类,且于编译时就已经绑定在一起,所以你不可能调用一个类里没有的方法。而在Objective-C中就比较简单了,类和消息之间是松耦合的,方法调用只是向某个类发送一个消息,该类可以在运行时再确定怎么处理接受到的消息。也就是说,一个类不保证一定会响应接收到的消息,如果收到了一个无法处理的消息,那么程序就是简单报一个错。甚至你可以向一个值为nil的空对象发送消息,系统都不会出错或宕掉。这种设计本身也比较符合软件的隐喻。
 
在表意接口(Intention Revealing Interface)方面,Objective-C也是设计的比较出色的语言。面向对象语言的特性之一就是通过API把实现封装起来,为上层建筑提供服务。但是需要注意的一点就是,你封装的API最好能够让调用者看到接口描述就知道怎么使用。如果为了使用一个API必须要去研究它的实现,那么就失去了封装的意义。Objective-C通过显式的API描述,让开发者不自觉的写出满足表意接口的API,比如下图中的API描述。

 
上图中描述了一个传统意义的实例方法,但和Java或C++不同的是,其方法关键字由多个字符串组成,在这个例子是insertObject和atIndex,(id)anObject和 (NSUInterger)index分别表示参数类型和参数名称。整个方法看上去就像一个英语句子,我们可以很容易的知道,这个方法就是在索引为 index处插入一个对象。如果你是从其他语言转到Objective-C,那么开始的时候会感觉这种写法有些繁复,但是一旦理解并习惯了你会感受到其巨大的好处,这种写法会强制你写出优美易读的代码和API,而且有了XCode强大的提示功能,再长的方法也是一蹴而就。
 
下面我们来说说多态和继承。
 与Java一样,Objective-C一样不支持多重继承,但是通过类别(Category)和协议(Protocol)可以很好的实现代码复用和扩展。
 
—Category—
首先我们来谈谈Category。
 
Objective-C提供了一种与众不同的方式——Catagory,可以动态的为已经存在的类添加新的行为。这样可以保证类的原始设计规模较小,功能增加时再逐步扩展。使用Category 对类进行扩展时,不需要访问其源代码,也不需要创建子类。Category使用简单的方式,实现了类的相关方法的模块化,把不同的类方法分配到不同的分类文件中。
 
实现起来很简单,我们举例说明。
SomeClass.h
@interface SomeClass : NSObject{
}
-(void) print;
@end 
 
这是类SomeClass的声明文件,其中包含一个实例方法print。如果我们想在不修改原始类、不增加子类的情况下,为该类增加一个hello的方法,只需要简单的定义两个文件 SomeClass+Hello.h和SomeClass+Hello.m,在声明文件和实现文件中用“()”把Category的名称括起来即可。声明文件代码如下:
 
#import "SomeClass.h"
 
@interface SomeClass (Hello)
-(void)hello;
@end
实现文件代码如下
#import "SomeClass+Hello.h"
@implementationSomeClass (Hello)
-(void)hello{
    NSLog (@"name:%@ ", @"Jacky");
}
@end 
其中Hello是Category的名称,如果你用XCode创建Category,那么需要填写的内容包括名称和要扩展的类的名称。这里还有一个约定成俗的习惯,将声明文件和实现文件名称统一采用“原类名+Category”的方式命名。
调用也非常简单,毫无压力,如下:
首先引入Category的声明文件,然后正常调用即可。
#import "SomeClass+Hello.h"
 
SomeClass * sc =[[SomeClass alloc] init];
[sc hello] 
执行结果是:
nameJacky 
 
Category的使用场景:
1、当你在定义类的时候,在某些情况下(例如需求变更),你可能想要为其中的某个或几个类中添加方法。
2、一个类中包含了许多不同的方法需要实现,而这些方法需要不同团队的成员实现
3、当你在使用基础类库中的类时,你可能希望这些类实现一些你需要的方法。
 
遇到以上这些需求,Category可以帮助你解决问题。当然,使用Category也有些问题需要注意,
1、Category可以访问原始类的实例变量,但不能添加变量,如果想添加变量,可以考虑通过继承创建子类。
2、Category可以重载原始类的方法,但不推荐这么做,这么做的后果是你再也不能访问原来的方法。如果确实要重载,正确的选择是创建子类。
3、和普通接口有所区别的是,在分类的实现文件中可以不必实现所有声明的方法,只要你不去调用它。
 
用好Category可以充分利用Objective-C的动态特性,编写出灵活简洁的代码。
 
—Protocol— 
下面我们再来看Protocol。
Protocol,简单来说就是一系列不属于任何类的方法列表,其中声明的方法可以被任何类实现。这种模式一般称为代理(delegation)模式。你通过Protocol定义各种行为,在不同的场景采用不同的实现方式。在iOS和OS X开发中,Apple采用了大量的代理模式来实现MVC中View和Controller的解耦。
 
定义Protocol很简单,在声明文件(h文件)中通过关键字@protocol定义,然后给出Protocol的名称,方法列表,然后用@end表示Protocol结束。在@end指令结束之前定义的方法,都属于这个Protocol。例如:
@protocol ProcessDataDelegate <NSObject>
@required
- (void) processSuccessful: (BOOL)success;

@optional
- (id) submitOrder: (NSNumber *) orderid;
@end
 
以上代码可以单独放在一个h文件中,也可以写在相关类的h文件中,可以视具体情况而定。该Protocol包含两个方法,processSuccessful和submitOrder。这里还有两个关键字,@required和@optional,表示如果要实现这个协议,那么processSuccessful方法是必须要实现的,submitOrder则是可选的,这两个注解关键字是在Objective-C 2.0之后加入的语法特性。如果不注明,那么方法默认是@required的,必须实现。
 
那么如何实现这个Protocol呢,很简单,创建一个普通的Objective-C类,取名为TestAppDelegate,这时会生成一个h文件和m文件。在h文件中引入包含Protocol的h文件,之后声明采用这个Protocol即可,如下:
@interface TestAppDelegate : NSObject<ProcessDataDelegate>;

@end
用尖括号(<...>)括起来的ProcessDataDelegate就是我们创建的Protocol。如果要采用多个Protocol,可以在尖括号内引入多个Protocol 名称,并用逗号隔开即可。例如<ProcessDataDelegate,xxxDelegate>
 
m文件如下:
@implementation TestAppDelegate

- (void) processSuccessful: (BOOL)success{
    if (success) {
        NSLog(@"成功");
    }else {
        NSLog(@"失败");
    }
}

@end 
由于submitOrder方法是可选的,所以我们可以只实现processSuccessful。
 
Protocol一般使用在哪些场景呢?Objective-C里的Protocol和Java语言中的接口很类似,如果一些类之间没有继承关系,但是又具备某些相同的行为,则可以使用 Protocol来描述它们的关系。不同的类,可以遵守同一个Protocol,在不同的场景下注入不同的实例,实现不同的功能。其中最常用的就是委托代理模式,Cocoa框架中大量采用了这种模式实现数据和UI的分离。例如UIView产生的所有事件,都是通过委托的方式交给Controller完成。根据约定,框架中后缀为Delegate的都是Protocol,例如UIApplicationDelegate,UIWebViewDelegate 等,使用时大家可以留意一下,体会其用法。
 
使用Protocol时还需要注意的是:
1、Protocol本身是可以继承的,比如:
@protocol A
     -(void)methodA;
@end
@protocol B <A>
     -(void)methodB;
@end

如果你要实现B,那么methodA和methodB都需要实现。 

2、Protocol是类无关的,任何类都可以实现定义好的Protocol。如果我们想知道某个类是否实现了某个Protocol,还可以使用conformsToProtocol进行判断,如下:
[obj conformsToProtocol:@protocol(ProcessDataDelegate)] 
 
好吧,具体的语言特性这次就介绍这么多。从某种意义上来说,Objective-C是一门古老的语言,发明于1980年。1988年,乔布斯的Next公司获得了Objective-C语言的授权,并开发出了Objective-C的语言库和NEXTSTEP的开发环境。NextStep是以Mach和BSD为基础,Objective-C是其语言和运行库,后来的事大家都清楚,苹果买了Next,乔布斯回归苹果,开始神奇的苹果振兴之路,NextStep成了Max OS X的基础。以后发展越来越好,Objctive-C成了Apple的当家语言,现在基本上是Apple在维护Objctive-C的发展。
 
在苹果的AppStore推出之前,Objective-C一直相对小众,但是其优秀的语言特性似乎一直在为后面的爆发积蓄力量,当苹果平台级的应用出现之后,Objective-C开始大放异彩,静态语言的效率和动态语言的特性得到众多程序员的喜爱,目前它已经以火箭般的速度蹿升TIOBE语言排行版第四位。
 
对于喜爱苹果技术的技术人员来说,Objective-C是你必须深入了解和值得学习的一门语言,希望以后有机会多写一些相关的文章。

转载于:http://www.cnblogs.com/chijianqiang/archive/2012/06/22/objc-category-protocol.html

 

posted @ 2012-10-17 13:49 为自己代言 阅读(342) | 评论 (0)编辑 收藏

     摘要: 我们大部分情况使用默认的或者chain或者redirect,其实struts2还有很多其他类型的,今天我们就来看一下都有哪些类型。 struts2的源码中struts-default.xml文件有全部类型下边解释下: 类型 chain 描述 用来处理Action链,被跳转的action中仍能获取上个页面的值,如request信息。 使用的类...  阅读全文

posted @ 2012-06-01 12:56 为自己代言 阅读(406) | 评论 (0)编辑 收藏

 org.apache.cxf.binding.soap.SoapFault: "http://schemas.xmlsoap.org/wsdl/" is  not a valid SOAP version.

在写好服务器端测试没有问题,在客户端调用时候出现上面错误,经过分析原面如下:

1:CXF 有两种客户端调用,一种是动态工厂形式, 第二种是通过CXF 中wsdl2java 命令先把客户端类生成到本地,在调用;

第一种: 1:  用org.apache.cxf.jaxws.JaxWsProxyFactoryBean配置

<bean id="msgWebServiceSoap" class="com.jd.sms.MsgWebServiceSoap" factory-bean="msgClientFactory"
          factory-method="create"/>
    <bean id="msgClientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
        <property name="serviceClass" value="com.jd.sms.MsgWebServiceSoap"/>
        <property name="address" value="http://127.0.0.1/services/AlarmInformationServices"/>
    </bean>


第二种: 2:  

   用标签<jaxws:client直接配置:

<jaxws:client id="orderClient" serviceClass=

                "demo.order.OrderProcess" address=

                 "http://localhost:8080/orderapp/OrderProcess" />

以上两种webService 的接口地址都不需要在后面加上?wsdl这个后缀,因为这样spring 调用时候要先通过 CXF/bin 命令行wsdl2java 这个命令生成本地客户端调用,把生成的本地客户端代码复制到客户端工程中去,在spring 配置文件中通过上面的任意一种配置方式选择配置,即可调用。
以上CXF异常,就是用这种方式调用,但是接口URL 多了?wsdl后缀的原面;
附wsdl2java 使用方式cd CXF/bin目录下:

例输入:wsdl2java -p com.jd.ws.all  -d F://src - client http://localhost:9000/helloWorld?wsdl
其作用上面的build.xml作用一样。
附加:wsdl2java用法:
wsdl2java -p com -d src -all aa.wsdl
-p 指定其wsdl的命名空间,也就是要生成代码的包名:
-d 指定要产生代码所在目录
-client 生成客户端测试web service的代码
-server 生成服务器启动web service的代码
-impl 生成web service的实现代码
-ant 生成build.xml文件


posted @ 2012-05-22 14:00 为自己代言 阅读(2597) | 评论 (0)编辑 收藏

首先在web工程src目录下新建一个database.properties 文件
内容如下:

user=root
password=root
databaseType=com.mysql.jdbc.Driver
url=jdbc:mysql://192.168.2.232:3306/oa? seUnicode=true&amp;characterEncoding=UTF8&amp;zeroDateTimeBehavior=convertToNull

 这里的内容随自己的合适而变化,这里不多说了;

在新建一个读取.properties文件新类:

package com.junhai.tamsys.util;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

public class DatabaseConfigure {
 private Properties property;
 private FileInputStream inputFile;
 private FileOutputStream outputFile;

 public DatabaseConfigure() {
  property = new Properties();
 }

 public DatabaseConfigure(String filePath) {
  property = new Properties();
  try {
   inputFile = new FileInputStream(filePath);
   property.load(inputFile);
   inputFile.close();
  } catch (FileNotFoundException e) {
   System.out.println("读取属性文件--->失败!- 原因:文件路径错误或者文件不存在");
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  }
 }

 /*
  * 重载函数,得到key的值 @param key 取得其值的键 @return key的值
  */
 public String getValue(String key) {
  if (property.containsKey(key)) {
   return property.getProperty(key);

  } else
   return "";
 }

 /*
  * 重载函数,得到key的值
  *
  * @param fileName propertys文件的路径+文件名 @param key 取得其值的键 @return key的值
  */
 public String getValue(String fileName, String key) {
  try {
   String value = "";
   inputFile = new FileInputStream(fileName);
   property.load(inputFile);
   inputFile.close();
   if (property.containsKey(key)) {
    value = property.getProperty(key);
    return value;
   } else
    return value;
  } catch (FileNotFoundException e) {
   e.printStackTrace();
   return "";
  } catch (IOException e) {
   e.printStackTrace();
   return "";
  } catch (Exception ex) {
   ex.printStackTrace();
   return "";
  }
 }

 /*
  * 清除properties文件中所有的key和其值
  */
 public void clear() {
  property.clear();
 }

 /*
  * 改变或添加一个key的值,当key存在于properties文件中时该key的值被value所代替, 当key不存在时,该key的值是value
  * @param key 要存入的键 @param value 要存入的值
  */
 public void setValue(String key, String value) {
  property.setProperty(key, value);
 }

 /*
  * 将更改后的文件数据存入指定的文件中,该文件可以事先不存在。 @param fileName 文件路径+文件名称 @param
  * description 对该文件的描述
  */
 public void saveFile(String fileName, String description) {
  try {
   outputFile = new FileOutputStream(fileName);
   property.store(outputFile, description);
   outputFile.close();
  } catch (FileNotFoundException e) {
   e.printStackTrace();
  } catch (IOException ioe) {
   ioe.printStackTrace();
  }
 }

 public static void main(String[] args) {
  DatabaseConfigure test=new DatabaseConfigure("./src/database.properties");
  System.out.println(test.getValue("user"));
  System.out.println(test.getValue("databaseType")+";"+test.getValue("url"));
  
 }
}


这样就可以通过key得到相应的value了;
想在这里多说一点是路径问题,java工程和web 工程读取.properties路径是不一样的,我在这里就花了不少时间。
JAVA工程: DatabaseConfigure test=new DatabaseConfigure("./src/database.properties");这样读取就可以了:
web工程这样读取:DatabaseConfigure  dc = new DatabaseConfigure(Thread.currentThread().getContextClassLoader()
                                                .getResource("").getPath()+"database.properties");
 
因为当服务器启动后工程里面东西会编译后加到\WEB-INF\classes这个目录,服务也是从这个目录下读取信息的。所以先取到这个路径,才能正确读取到database.properties这里边的内容。

posted @ 2010-01-28 15:46 为自己代言 阅读(2970) | 评论 (0)编辑 收藏

     摘要:   Struts2 拦截器详细配置过程 1:所有拦截器的超级接口Interceptor ,Action去实现这个接口;  Interceptor 它其中有三个方法(init(),destroy() ,interceptor()):       Init()方法:在服务器起动的时候加载一次,并且只加载一次;  ...  阅读全文

posted @ 2009-10-12 22:41 为自己代言 阅读(33073) | 评论 (6)编辑 收藏

 

Hiberante3 一级缓存总结

1.             Session 级别的缓存,它同session邦定。它的生命周期和session相同。Session消毁,它也同时消毁;管理一级缓存,一级缓存无法取消,用两个方法管理,clear(),evict()

2.             两个session 不能共享一级缓存,因它会伴随session的生命周期的创建和消毁;

3.             Session缓存是实体级别的缓存,就是只有在查询对象级别的时候才使用,如果

使用HQLSQL是查询属性级别的,是不使用一级缓存的!切记!!!!

4 .  iterate 查询使用缓存,会发出查询IdSQLHQL语句,但不会发出查实体的,

它查询完会把相应的实体放到缓存里边,一些实体查询如果缓存里边有,就从缓存中查询,但还是会发出查询idSQLHQL语句。如果缓存中没有它会数据库中查询,然后将查询到的实体一个一个放到缓存中去,所以会有N+1问题出现。

5 . List()iterate 查询区别:

使用iterate,list查询实体对象*N+1问题,在默认情况下,使用query.iterate查询,有可以能出现N+1问题

所谓的N+1是在查询的时候发出了N+1sql语句1:首先发出一条查询对象id列表的sqlN:

根据id列表到缓存中查询,如果缓存中不存在与之匹配的数据,那么会根据id发出相应的sql语句listiterate的区别?

list每次都会发出sql语句,list会向缓存中放入数据,而不利用缓存中的数据

iterate:在默认情况下iterate利用缓存数据,但如果缓存中不存在数据有可以能出现N+1问题

6Get()load(),iterate方法都会使用一级缓存,

 

7.hiberate3 session 存储过程如下:

       例如 object 对象

       Session.save(object);

       这时候不会把数据放到数据库,会先放到session缓存中去,数据库中没有相应记录,session.flush();才发SQLHQL语句,数据库中有了相应记录,

       但是数据库用select查不到,这是跟数据库事物级别有关系,(这里在说下数据库的事务隔离级别一共四种如下:)
    数据库隔离级别:
        隔离级别                       是否存在脏读  是否存在不可重复读     是否存在幻读;
    Read UnCommited(未提交读)               Y            Y                     Y
    Read Commited (提交读 oraclel默认)      N            Y                     Y
    Repeatable Read(不可重复读(Msql默认))  N            N                     Y 
    Serializable(使用很少)                  N            N                     N

    


       Session.beginTrransaction().commit();

       事物提交后可以查询到了。

Session.flush()语句但是为什么不写呢,因为commit()会默认调用flush();


Hiberante3 二级缓存总结

1.Hibernate3的(sessionFactory)二级缓存和session级别的缓存一样都只对实体对象做缓存,不对属性级别的查询做缓存;二级缓存的生命周期和sessionFactory的生命周期是一样的,sessionFactory可以管理二级缓存;

2.sessionFactory级别的缓存,需要手动配置;所有的session可以共享sessionFactory 级别的缓存;(一般把一些不经常变化的实体对象放到sessionFactory级别的缓存中,适合放不经常变化的实体对象。)

3.Hiberante3二级缓存的配置和使用方法如下:

1. 必须把ehcache.jar包导入,然后到Hibernate3.2etc文件下把ehcache.xml复制到工程src目录下(ehcache.xml里边的参数里边有详细英文说明);

(说明:ehcache.jar是第三方法的缓存产品,hiberante只是把它做了集成,还有好多第三方hibernate集成的缓存产品,相关说明请查阅hiberante3开发手册;ehcache支持分布应用的(这个和Hibernate3.2开发手册有出入,经过官网查证确实支持了),如果有分布式需求,请换成支持分布式的二级缓存产品,hiberate3开发手册都有相头说明。配置方法都类似);

4.Hibernate3的二级缓存默认是开起的,也可以指定开起。在hibernate.cfg.xml 文件下配置如下:

*修改hibernate.cfg.xml文件,开户二级缓存;

                     <property name=”hibernate.cache.use_second_level_cache”>true</property>

                     *指定二级缓存产品的提供商;

<property name=”hibernate.cache.provider_class”> org.hibernate.cache.EhCacheProvider

</property>

要让那些实体使用二级缓存,在hibernate.cfg.xml配置文件中加入:

<!—

让这个实体用二级缓存 也可以在实体中映射文件去配置即:

<cache usage="read-only"/>

-->

<class-cache class=”com.zzz.hibernate.ClassT” usage=”read-only”/>

Read-only一般使用这个策略,其它的hibernate3开发手册中也有详细介绍;

CacheModehibernate3开发手册中搜索这个关键字,可以找到一级缓存和二级缓存交互使用的问题;

posted @ 2009-08-11 23:01 为自己代言 阅读(7877) | 评论 (3)编辑 收藏

这里为什么使用struts2.0.14这个版本呢??请看官网的文章如下:

24 November 2008 - Struts 2.0.14 General Availability Release

The latest release of Struts 2 is Struts 2.0.14, which was promoted to "General Availability" on 24 November 2008.

For changes included in Struts 2.0.14, see the release notes. Struts 2.0.14 is a bugfix release for version 2.0.12, which provided important security fixes. Struts 2.0.14 addresses two major bugs introduced with these security fixes, keeping the FilterDispatcher from serving built in static resources, and keeping conversion error messages from being displayed. All developers are strongly encouraged to update existing Struts 2 applications to Struts 2.0.14.

如果你的英语不差的话,自己去看下吧.这段英语的大概意思是,Struts 2.0.14修正了Struts 2.0.12 的两个主要的bug ;并且建议开发者更新到Struts 2.0.14
这个版本.Struts 2.0.14 General Availability Release 这是个通用的开发版本.
其实我在整合这个S2SH时,struts2 的最新版本是struts2.1.16 这个也是稳家版本,不过最新的版本网上资料很少.所以...........! 如果自己学的话可以选择这个两个版本.
下边是整合的全过程:
主要是jar包的引入,我个人比较不喜欢用IDE 工具自动引入jar包,所以下边是自己用的jar的引入,这样可以省去相关jar 的冲突;

1:首先struts2.0.14所需要的jar包如下:
commons-logging-1.0.4  ;
freemarker-2.3.8
 ognl-2.6.11
struts2-core-2.0.14
xwork-2.0.7
struts2-spring-plugin-2.0.14  这是整合spring 必需的jar 包,从它的名字就可以看出来了!   

2:hiberante3.2 jar 包如下 这是我的工程必需的,如果你的工程要用到其它的jar包可以去看一看hibernate 的必读文件那里有很详细的解释;
            这个是做一般的工程,引入最少的jar 了,一般的项目都可以了!

antlr-2.7.6         cglib-2.1.3     commons-collections-2.1.1    commons-logging-1.0.4      dom4j-1.6.1  
ehcache-1.2.3    hibernate3     jaas        jaxen-1.1-beta-7     jdbc2_0-stdext     jta    log4j-1.2.11  
xml-apis             asm             asm-attrs 

如果你自己不做整合的,就是单独做hibernate 学习,本人建议你把所有jar 都导入项目的lib目录下!这里不在做任何解释了!

3:  spring 2.5.6  相关的jar 也是做项目最少引入的jar包了,如果自己还需要特定的自己去引入;

    aspectjrt    aspectjweaver   ( 这两个是AOP 相关的jar包,因为spring  2.5的AOP实现,没有自己去做,也用到了第三方组件,分开了,这好像和2.0版本有出入!有关细节,请自己去查阅相关文档)
    spring

好的,这三个框架所有jar 包,都介绍完了,(不要奇怪我的所有jar 包没有后缀名,是我自己给隐藏了)

好的进入主题了(顺序最好 hibernate --->spring---->struts)

1:把相关的hibernate  jar 包导入项目lib 目录下!
2: 把spring  相关jar   包导入项目lib 目录下!
3: 把struts2相关jar   包导入项目lib 目录下!

三者整合:
web.xml文件如下里边都有解释自己看吧:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

 <!-- 配置spring监听器和上下文变量 -->
 <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/applicationContext-*.xml</param-value>
 </context-param>

 <listener>
  <listener-class>
   org.springframework.web.context.ContextLoaderListener
  </listener-class>
 </listener>
 <!-- spring end -->

<!-- 配置字符过滤器-->
 <filter>
  <filter-name>encodingFilter</filter-name>
  <filter-class>
   org.springframework.web.filter.CharacterEncodingFilter
  </filter-class>
  <init-param>
   <param-name>encoding</param-name>
   <param-value>GBK</param-value>
  </init-param>
 </filter>
 <filter-mapping>
  <filter-name>encodingFilter</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>

 <!--让spring来过滤管理Hiberante中的session-->
 <filter>
  <filter-name>lazyLoadingFilter</filter-name>
  <filter-class>
   org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
  </filter-class>
 </filter>

 <!-- spring end -->

 <!-- 增加struts2所需要的过滤器,以便在服务器启动时,拦截URL请求 -->
 <filter>
  <filter-name>struts2</filter-name>
  <filter-class>
   org.apache.struts2.dispatcher.FilterDispatcher
  </filter-class>
 </filter>

 <filter-mapping>
  <filter-name>lazyLoadingFilter</filter-name>
  <url-pattern>*.action</url-pattern>
 </filter-mapping>


 <filter-mapping>
  <filter-name>struts2</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>
  </web-app>


applicationContext-common.xml 文件:其中我使用了,DBCP数据库连接波,如果你自己想用,
                           还的去下载相关的jar 包( commons-dbcp-1.2.2   commons-pool-1.3)记着引入哦!

我下边注释掉的就是没有用数据库连接池的,也就是不把src目录下的hibernate.cfg.xml删除.上边用到的数据库连接池的,就不用这个文件了,直接都用spring来管理啦!!!!

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
 <!-- 用DBCP数据库连接波来配置hibernate数据库连接 -->
 
  <bean id="dataSource"
  class="org.apache.commons.dbcp.BasicDataSource">
  <property name="driverClassName"
  value="com.mysql.jdbc.Driver">
  </property>
  <property name="url" value="jdbc:mysql://localhost/oa"></property>
  <property name="username" value="root"></property>
  <property name="password" value="root"></property>
  </bean>
 
 <!-- 配置sessionFactory -->
  
  <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
  <property name="dataSource">
  <ref bean="dataSource" />
  </property>
  <property name="hibernateProperties">
  <props>
  <prop key="hibernate.dialect">
  org.hibernate.dialect.MySQLDialect
  </prop>
  <prop key="hibernate.show_sql">true</prop>
  <prop key="format_sql">true</prop>
  <prop key="hibernate.hbm2ddl.auto">update</prop>
  </props>
  </property>
  <property name="mappingResources">
  <list>
  <value>com/oa/model/Person.hbm.xml</value>
  <value>com/oa/model/Organization.hbm.xml</value>
  </list>
  </property>
  </bean>
  
<!-- 让spring管理sessionFactory的加一种方法 ,就是不删除hibernate.cfg.xml文件;
 <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
  <property name="configLocation">
   <value>classpath:hibernate.cfg.xml</value>
  </property>
 </bean>
--> 
  
 <!-- 配置hibernate事物让spring来管理 -->
 <bean id="transactionManager"
  class="org.springframework.orm.hibernate3.HibernateTransactionManager">
  <property name="sessionFactory">
   <ref bean="sessionFactory" />
  </property>
 </bean>
 <!-- 配置事物的传播特性 -->
 <tx:advice id="txAdvice" transaction-manager="transactionManager">
  <tx:attributes>
   <tx:method name="add*" propagation="REQUIRED" />
   <tx:method name="delete*" propagation="REQUIRED" />
   <tx:method name="update*" propagation="REQUIRED" />
   <tx:method name="*" read-only="true" />
  </tx:attributes>
 </tx:advice>
 <!-- 那些类的那些方法需要事物; -->
 <aop:config>
  <aop:pointcut id="allManagerMethod"
   expression="execution(* com.oa.manager.*.*(..))" />
  <aop:advisor pointcut-ref="allManagerMethod"
   advice-ref="txAdvice" />
 </aop:config>
</beans>

对了还需要注意的一个地方就是如果用了,我这种数据库连接池技术,得把你的数据库驱动类,复制tomcat lib 目录下.不然会报错的!

好了三个东西整合好,我也是费了九牛二虎之力才整合成功的.
如果有什么问题发我的邮箱一起交流:zzzlyr@163.com



posted @ 2009-07-11 00:03 为自己代言 阅读(1637) | 评论 (1)编辑 收藏

下面以三个页面分别命名为framedemo.html,left.html,right.html为例来具体说明如何做。

其中framedemo.html由左右两个页面组成,代码如下:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> frameDemo </TITLE>
</HEAD>
<frameset cols="200,*">
<frame name=top src="left.html">
<frame name=button src="right.html">
</frameset>
</HTML>

现在假设left.html即上面的页面有一个button来实现对下面页面的刷新,可以用以下七种语句,哪个好用自己看着办了。

语句1. window.parent.frames[1].location.reload();

语句2. window.parent.frames.bottom.location.reload();

语句3. window.parent.frames["bottom"].location.reload();

语句4. window.parent.frames.item(1).location.reload();

语句5. window.parent.frames.item('bottom').location.reload();

语句6. window.parent.bottom.location.reload();

语句7. window.parent['bottom'].location.reload();

解释一下:

1.window指代的是当前页面,例如对于此例它指的是top.html页面。

2.parent指的是当前页面的父页面,也就是包含它的框架页面。例如对于此例它指的是framedemo.html。

3.frames是window对象,是一个数组。代表着该框架内所有子页面。

4.item是方法。返回数组里面的元素。

5.如果子页面也是个框架页面,里面还是其它的子页面,那么上面的有些方法可能不行。
top.html源代码;(页面上有七个按钮,功能都是刷新下面的框架页面)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
</HEAD>
<BODY>
<input type=button value="刷新1" onclick="window.parent.frames[1].location.reload()"><br>
<input type=button value="刷新2" onclick="window.parent.frames.bottom.location.reload()"><br>
<input type=button value="刷新3" onclick="window.parent.frames['bottom'].location.reload()"><br>
<input type=button value="刷新4" onclick="window.parent.frames.item(1).location.reload()"><br>
<input type=button value="刷新5" onclick="window.parent.frames.item('bottom').location.reload()"><br>
<input type=button value="刷新6" onclick="window.parent.bottom.location.reload()"><br>
<input type=button value="刷新7" onclick="window.parent['bottom'].location.reload()"><br>
</BODY>
</HTML>

下面是right.html页面源代码,为了证明下方页面的确被刷新了,在装载完页面弹出一个对话框。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
</HEAD>
<BODY onload="alert('我被加载了!')">
<h1>This is the content in button.html.</h1>
</BODY>
</HTML>

经我测试,只能1 和4 显示效果,别的好像不对哟
============================

附:
Javascript刷新页面的几种方法:
1    history.go(0)
2    location.reload()
3    location=location
4    location.assign(location)
5    document.execCommand('Refresh')
6    window.navigate(location)
7    location.replace(location)
8    document.URL=location.href

 

 

 

自动刷新页面的方法:
1.页面自动刷新:把如下代码加入<head>区域中
<meta http-equiv="refresh" content="20">
其中20指每隔20秒刷新一次页面.

2.页面自动跳转:把如下代码加入<head>区域中
<meta http-equiv="refresh" content="20;url=http://www.wyxg.com">
其中20指隔20秒后跳转到http://www.wyxg.com页面

3.页面自动刷新js版
<script language="JavaScript">
function myrefresh()
{
       window.location.reload();
}
setTimeout('myrefresh()',1000); //指定1秒刷新一次
</script>

ASP.NET如何输出刷新父窗口脚本语句
1.   this.response.write("<script>opener.location.reload();</script>");  

2.   this.response.write("<script>opener.window.location.href = opener.window.location.href;</script>");   

3.   Response.Write("<script language=javascript>opener.window.navigate(''你要刷新的页.asp'');</script>")


JS刷新框架的脚本语句

//如何刷新包含该框架的页面用   
<script language=JavaScript>
   parent.location.reload();
</script>   

//子窗口刷新父窗口
<script language=JavaScript>
    self.opener.location.reload();
</script>

( 或 <a href="javascript:opener.location.reload()">刷新</a>   )

//如何刷新另一个框架的页面用   
<script language=JavaScript>
   parent.另一FrameID.location.reload();
</script>

如果想关闭窗口时刷新或者想开窗时刷新的话,在<body>中调用以下语句即可。

<body onload="opener.location.reload()">
开窗时刷新
<body onUnload="opener.location.reload()">
关闭时刷新

<script language="javascript">
window.opener.document.location.reload()
</script>

posted @ 2009-05-22 22:55 为自己代言 阅读(4584) | 评论 (0)编辑 收藏

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>js退出使用!</title>
 <script language="javascript">
  function logout(){
  if( confirm("你确实要退出吗??")){
   window.parent.location.href="http://www.163.com";
  }
  else{
   return;
  }
 }
 </script>
</head>
 <p> <a href="javascript:logout()"> 退出</a></p>
<a href="javascript:history.back();">返回</a>
<body>
</body>
</html>

posted @ 2009-05-22 22:44 为自己代言 阅读(5087) | 评论 (0)编辑 收藏

<%@include file="/common/taglib.jsp"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>网站后台管理系统</title>
 <%@include file="/common/metadata.jsp"%>
 <link href="${ctx}/admin/style/css_body.css" rel="stylesheet" type="text/css" />
 <script type="text/javascript">
      function del(id){
        if(confirm("您确认要删除该项吗?")){
          document.location.href="${ctx}/NewsManage?action=deleteNews&id="+id;
        }else{
          return;
        }
      }
      function pagging(pageNo){
         document.location.href="${ctx}/MemeberRegisterServlet?action=list&pageNo="+pageNo;
     }
    </script>
</head>
<body>
 
  <div class="bodytitle">
    <div>
      <span class="bodytitletxt">新闻列表</span>
    </div>
  </div>
 
  <div class="list-div">
  <table border="0" cellpadding="10" cellspacing="1">
   <tr>
    <td align="center"><a href="${ctx}/NewsManage?action=refresh">刷新新闻列表</a></td>
    </tr>
  </table>
 
    <table border="0" cellpadding="10" cellspacing="1">
  
      <tr>
        <th>新闻编号</th>
        <th>新闻名称</th>
        <th>发布者</th>
        <th>发布时间</th>
        <th>修改时间</th>
        <th>浏览次数</th>
        <th>操作</th>
      </tr>
      <c:forEach items="${newsList}" var="news">
      <tr>
        <td align="center">${news.id}</td>
        <td align="center"><a href="${ctx}/BrowerNewsServlet?action=browerNews&id=${news.id}">${news.topic}</a></td>
        <td align="center">${news.publishuser}</td>
        <td align="center">${news.publishtimes}</td>
        <td align="center">${news.modifytimes}</td>
        <td align="center">${news.hits}</td>
       <td align="center">
          <a href="${ctx}/NewsManage?action=modifyNews&id=${news.id}"><img src="${ctx}/icons/icon_edit.gif"></a>
          &nbsp;&nbsp;|&nbsp;&nbsp;
          <a href="javascript:del(${news.id})"><img src="${ctx}/icons/icon_drop.gif"></a>
        </td>
      </tr>
      </c:forEach>
      <tr>
        <td align="right" bgcolor="#f9ffe6" colspan="7"><%@include file="/common/paggingDiv.jsp" %></td>
      </tr>
    </table>
   
  </div>
 
  <div id="footer"><br />版权所有 &copy; 2005-2008 Onest's Studio 工作室,并保留所有权利。</div>

</body>
</html>

posted @ 2009-05-22 22:18 为自己代言 阅读(1853) | 评论 (0)编辑 收藏

今天去面试了问我最简单的JS对话框的使用,我竟然没有回答上来!丢人,回来看了一个晚上的JS!好像懂点了。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>三种弹出对话框的用法实例</title>
<script language="javascript">
function ale()
{//这个基本没有什么说的,就是弹出一个提醒的对话框 ,这个方法也可以带参数的
    alert("提示对话框!");
}
function firm()
{//利用对话框返回的值 (true 或者 false)
    if(confirm("你确信要转去 天轰穿的博客?"))
    {//如果是true ,那么就把页面转向thcjp.cnblogs.com
        location.href="http://www.xiaonei.com";
    }
    else
    {//否则说明下了,赫赫
        alert("你按了取消,那就是返回false");
    }
}
function prom()
{
    var name=prompt("请输入您的名字","");//将输入的内容赋给变量 name ,
    //这里需要注意的是,prompt有两个参数,前面是提示的话,后面是当对话框出来后,在对话框里的默认值
    if(name)//如果返回的有内容
    {
        alert("欢迎您:"+ name)
    }
}
</script>
</head>

<body>
<p>对话框有三种</p>
<p>1:只是提醒,不能对脚本产生任何改变;</p>
<p>2:一般用于确认,返回 true 或者 false ,所以可以轻松用于 ifelse判断 </p>
<p>3: 一个带输入的对话框,可以返回用户填入的字符串,常见于某些留言本或者论坛输入内容那里的 插入UBB格式图片 </p>
<p>下面我们分别演示:</p>
<p>演示一:提醒 对话框</p>
<p>
  <input type="submit" name="Submit" value="提交" onclick="ale()" />
</p>
<p>演示二 :确认对话框 </p>
<p>
  <input type="submit" name="Submit2" value="提交" onclick="firm()" />
</p>
<p>演示三 :要求用户输入,然后给个结果</p>
<p>
  <input type="submit" name="Submit3" value="提交" onclick="prom()" />
</p>
</body>
</html>

posted @ 2009-05-22 22:15 为自己代言 阅读(2573) | 评论 (0)编辑 收藏

一、抽象类:

抽象类是特殊的类,只是不能被实例化;除此以外,具有类的其他特性;重要的是抽象类可以包括抽象方法,这是普通类所不能的。抽象方法只能声明于抽象类中,且不包含任何实现,派生类必须覆盖它们。另外,抽象类可以派生自一个抽象类,可以覆盖基类的抽象方法也可以不覆盖,如果不覆盖,则其派生类必须覆盖它们。

二、接口:

接口是引用类型的,类似于类,和抽象类的相似之处有三点:

1、不能实例化;

2、包含未实现的方法声明;

3、派生类必须实现未实现的方法,抽象类是抽象方法,接口则是所有成员(不仅是方法包括其他成员);

另外,接口有如下特性:
接口除了可以包含方法之外,还可以包含属性、索引器、事件,而且这些成员都被定义为公有的。除此之外,不能包含任何其他的成员,例如:常量、域、构造函数、析构函数、静态成员。一个类可以直接继承多个接口,但只能直接继承一个类(包括抽象类)。

三、抽象类和接口的区别:

1.类是对对象的抽象,可以把抽象类理解为把类当作对象,抽象成的类叫做抽象类.而接口只是一个行为的规范或规定,微软的自定义接口总是后带able字段,证明其是表述一类类“我能做。。。”.抽象类更多的是定义在一系列紧密相关的类间,而接口大多数是关系疏松但都实现某一功能的类中.

2.接口基本上不具备继承的任何具体特点,它仅仅承诺了能够调用的方法;    

3.一个类一次可以实现若干个接口,但是只能扩展一个父类    

4.接口可以用于支持回调,而继承并不具备这个特点.    

5.抽象类不能被密封。  

6.抽象类实现的具体方法默认为虚的,但实现接口的类中的接口方法却默认为非虚的,当然您也可以声明为虚的.

7.(接口)与非抽象类类似,抽象类也必须为在该类的基类列表中列出的接口的所有成员提供它自己的实现。但是,允许抽象类将接口方法映射到抽象方法上。  

8.抽象类实现了oop中的一个原则,把可变的与不可变的分离。抽象类和接口就是定义为不可变的,而把可变的座位子类去实现。

9.好的接口定义应该是具有专一功能性的,而不是多功能的,否则造成接口污染。如果一个类只是实现了这个接口的中一个功能,而不得不去实现接口中的其他方法,就叫接口污染。  

10.尽量避免使用继承来实现组建功能,而是使用黑箱复用,即对象组合。因为继承的层次增多,造成最直接的后果就是当你调用这个类群中某一类,就必须把他们全部加载到栈中!后果可想而知.(结合堆栈原理理解)。同时,有心的朋友可以留意到微软在构建一个类时,很多时候用到了对象组合的方法。比如asp.net中,Page类,有Server Request等属性,但其实他们都是某个类的对象。使用Page类的这个对象来调用另外的类的方法和属性,这个是非常基本的一个设计原则。  

11.如果抽象类实现接口,则可以把接口中方法映射到抽象类中作为抽象方法而不必实现,而在抽象类的子类中实现接口中方法.

四、抽象类和接口的使用:

1. 如果预计要创建组件的多个版本,则创建抽象类。抽象类提供简单的方法来控制组件版本。

2.如果创建的功能将在大范围的全异对象间使用,则使用接口。如果要设计小而简练的功能块,则使用接口。

3.如果要设计大的功能单元,则使用抽象类.如果要在组件的所有实现间提供通用的已实现功能,则使用抽象类。  

4.抽象类主要用于关系密切的对象;而接口适合为不相关的类提供通用功能。

以下是我在网上看到的几个形象比喻,真的非常不错,呵呵:

1.飞机会飞,鸟会飞,他们都继承了同一个接口“飞”;但是F22属于飞机抽象类,鸽子属于鸟抽象类。

2. 就像铁门木门都是门(抽象类),你想要个门我给不了(不能实例化),但我可以给你个具体的铁门或木门(多态);而且只能是门,你不能说它是窗(单继承);一个门可以有锁(接口)也可以有门铃(多实现)。 门(抽象类)定义了你是什么,接口(锁)规定了你能做什么(一个接口最好只能做一件事,你不能要求锁也能发出声音吧(接口污染)

posted @ 2009-05-12 11:06 为自己代言 阅读(1450) | 评论 (0)编辑 收藏

     摘要:   阅读全文

posted @ 2009-05-11 09:09 为自己代言 阅读(478) | 评论 (1)编辑 收藏

     摘要:   阅读全文

posted @ 2009-04-01 11:18 为自己代言 阅读(2447) | 评论 (5)编辑 收藏