<< 九月 2013 | 首页 | 十一月 2013 >>

Oracle 高水位(HWM: High Water Mark) 说明 - David Dai -- Focus on Oracle - 博客频道 - CSDN.NET

Oracle表段中的高水位线HWM      

Oracle数据的存储中,可以把存储空间想象为一个水库,数据想象为水库中的水。水库中的水的位置有一条线叫做水位线,在Oracle中,这条线被称为高水位线High-warter mark, HWM)。在数据库表刚建立的时候,由于没有任何数据,所以这个时候水位线是空的,也就是说HWM为最低值。当插入了数据以后,高水位线就会上涨,但是这里也有一个特性,就是如果你采用delete语句删除数据的话,数据虽然被删除了,但是高水位线却没有降低,还是你刚才删除数据以前那么高的水位。也就是说,这条高水位线在日常的增删操作中只会上涨,不会下跌。HWM通常增长的幅度为一次5个数据块.

 

Select语句会对表中的数据进行一次扫描,但是究竟扫描多少数据存储块呢,这个并不是说数据库中有多少数据,Oracle就扫描这么大的数据块,而是Oracle会扫描高水位线以下的数据块。现在来想象一下,如果刚才是一张刚刚建立的空表,你进行了一次Select操作,那么由于高水位线HWM在最低的0位置上,所以没有数据块需要被扫描,扫描时间会极短。而如果这个时候你首先插入了一千万条数据,然后再用delete语句删除这一千万条数据。由于插入了一千万条数据,所以这个时候的高水位线就在一千万条数据这里。后来删除这一千万条数据的时候,由于delete语句不影响高水位线,所以高水位线依然在一千万条数据这里。这个时候再一次用select语句进行扫描,虽然这个时候表中没有数据,但是由于扫描是按照高水位线来的,所以需要把一千万条数据的存储空间都要扫描一次,也就是说这次扫描所需要的时间和扫描一千万条数据所需要的时间是一样多的。所以有时候有人总是经常说,怎么我的表中没有几条数据,但是还是这么慢呢,这个时候其实奥秘就是这里的高水位线了。

 

    那有没有办法让高水位线下降呢,其实有一种比较简单的方法,那就是采用TRUNCATE语句进行删除数据。采用TRUNCATE语句删除一个表的数据的时候,类似于重新建立了表,不仅把数据都删除了,还把HWM给清空恢复为0。所以如果需要把表清空,在有可能利用TRUNCATE语句来删除数据的时候就利用TRUNCATE语句来删除表,特别是那种数据量有可能很大的临时存储表。

 

    在手动段空间管理(Manual Segment Space Management)中,段中只有一个HWM,但是在Oracle 9i Release1才添加的自动段空间管理(Automatic Segment Space Management)中,又有了一个HWM的概念出来。为什么有了HWM还又有一个低HWM呢,这个是因为自动段空间管理的特性造成的。在手段段空间管理中,当数据插入以后,如果是插入到新的数据块中,数据块就会被自动格式化等待数据访问。而在自动段空间管理中,数据插入到新的数据块以后,数据块并没有被格式化,而是在第一次访问这个数据块的时候才格式化这个块。所以我们又需要一条水位线,用来标示已经被格式化的块。这条水位线就叫做HWM。一般来说,低HWM肯定是低于等于HWM的。

 

2.3. 修正ORACLE表的高水位线

       ORACLE中,执行对表的删除操作不会降低该表的高水位线。而全表扫描将始终读取一个段(extent)中所有低于高水位线标记的块。如果在执行删除操作后不降低高水位线标记,则将导致查询语句的性能低下。rebuild, truncate, shrink,move  等操作会降低高水位。

 

2.3.1 执行表重建指令 alter table table_name move;

       在线转移表空间ALTER TABLE ... MOVE TABLESPACE ..

当你创建了一个对象如表以后,不管你有没有插入数据,它都会占用一些块,ORACLE也会给它分配必要的空间.同样,ALTER TABLE MOVE释放自由空间后,还是保留了一些空间给这个表.  

ALTER TABLE ...  MOVE 后面不跟参数也行,不跟参数表还是在原来的表空间,Move后记住重建索引.alter index index_name rebuild. 如果以后还要继续向这个表增加数据,没有必要move 只是释放出来的空间,只能这个表用,其他的表或者segment无法使用该空间。

 

2.3.2 执行alter table table_name shrink space;

       此命令为Oracle 10g新增功能,再执行该指令之前必须允许行移动 alter table table_name enable row movement;

 

2.3.3 重建表

       复制要保留的数据到临时表tdrop原表,然后rename临时表t为原表

 

2.3.4 用逻辑导入导出: Emp/Imp

 

2.3.5. Alter  table table_name deallocate unused  

       DEALLOCATE UNUSED为释放HWM上面的未使用空间,但是并不会释放HWM下面的自由空间,也不会移动HWM的位置.

 

2.3.6 推荐使用truncate.

阅读全文……

标签 : ,

香港有哪些特色小店? - 知乎

香港的小清新都在楼上,那就是香港人口中的“上樓店”。所以说小清新這件事在香港雖然沒有什麼群聚效應,但零零散散還是有的。


“上樓店”,是相對于街鋪而言的,即店鋪開設于一般樓宇的二樓或更高。這樣的店鋪租金低,人流少,不少小規模經營的店鋪都選擇以“上樓店”的方式經營。


大家都聽說過那個悲慘的故事吧,2008年,香港一位書店老闆被倒下的書砸死。事情發生在除夕前夜,這位老闆的書店由於多年經營困難,剛剛申請破產,但他仍積極籌備重新開業。那天他獨自在倉庫點貨,從下邊抽取書記,導致九尺高的書堆轟然一聲坍塌。事發十四天後,腐爛的屍體才由工厦管理员发现。而這位被自己的書砸死的老闆,正是香港著名的二樓書店“青文書屋”的主人羅志華


過往最常見的樓上店就是這種二樓書店了。咖啡、茶座、服飾店也常常以上樓店的方式經營。近年來通貨膨脹,越來越多店都棄街上樓,其中不乏你所說的“独特的小店”(原创设计,服饰,家居,书籍,古物...)什麼的


這些樓上鋪在香港幾個購物旺區分佈零散,並無特別集中之地。非要說的話,上樓店數量比較多的街道有:銅鑼灣軒尼詩道、駱克道,旺角彌頓道、西洋菜街,尖沙咀加連威老路、柯士甸路

阅读全文……

标签 : ,

胆囊息肉并不可怕!-仁者医术-搜狐博客

     胆囊息肉(Polypoid lesion of gallbladder PLG)大多数没有症状,85%是通过例行体检才发现的。现代人本来就怕查出点什么问题,一旦查出有胆囊息肉就忧心忡忡,惶惶不可终日。那是因为人们对胆囊息肉的不了解而无端地害怕。

    胆囊息肉为何会让人觉得如此可怕呢?我们来看看平时医生是怎么说的:“你的息肉有一厘米了,赶快切掉胆囊吧,要不会癌变的!”;我们再看看网络查询到的一些信息:“胆囊息肉平均癌变率由1~2%提升到8~12%,成为现代都市的一大杀手。”;还有诸如“胆囊息肉具备潜在攻击性强,癌变率高的特点”等。对于一个刚查出有胆囊息肉的人,当他听到这些、查询到这些、看到这些时,他能不害怕吗?以上所说就完全不对吗?当然不是,胆囊息肉的相关知识中确实包含有这些。但我们不能一叶障目。作为病人,要主动的较全面的了解胆囊息肉(但信息量太多,复杂,斟酌谁是谁非确实不容易!),当医生的也应该有义务简要介绍胆囊息肉。其实,胆囊息肉本身并没有太多的症状,而能癌变的息肉并不太多,如果不会癌变,它应该算不上是什么疾病。这样大家是不是觉得胆囊息肉并不可怕吗?关键是哪些息肉会癌变。下面我就根据病人最为关注的热点来介绍 。

1 胆囊息肉究竟是不是一种疾病?息肉就是赘生物,通俗的讲息肉就是多余的不应该存在的东西。胆囊壁向胆囊腔内生长的多余的不应该存在的东西,我们就称之为胆囊息肉也称为胆囊隆起样病变(Polypoid lesion of gallbladder PLG),是一种常见的胆囊良性疾病。文献报道其发病率为3%~6% ,胆囊息肉绝大多数没有任何症状,85%是通过例行体检中超声发现。胆囊息肉类似于皮肤上的赘生物,俗称“瘊子”,只是它不在皮肤上而在胆囊粘膜上。胆囊息肉即没有症状又不会影响胆囊的功能,如果它不会癌变,那么它严格的来说,它算不上是一种真正的疾病。

2 什么样的胆囊息肉要手术呢?胆囊息肉是不是一定要等到它癌变了再做手术呢?要回答这两个问题首先要理解胆囊息肉的临床分类与治疗对策。临床上所谓胆囊息肉或者胆囊隆起样病变实为一组包含很多不同病理状态的胆囊疾病。目前通用的病理分类是分为非肿瘤性病变(假性息肉)与肿瘤性病变(真性息肉)两大类。胆囊息肉的临床分类如下:

第一类:胆固醇性息肉(占50%)。又称它为假性息肉。迄今未发现有癌变的报导。它外观呈桑葚状,脆而易碎,蒂细如棉线,极易脱落,多在10mm以内,以多发为主,位于胆囊体部。大多数胆固醇性息肉病人没有症状或者症状轻微,而胆囊功能良好,故可以每3-6月定期B超复查,观察其大小变化。如果有明显症状或者短期内增大明显时才考虑手术治疗。对于胆囊功能良好且胆囊没有急慢性炎症的可以首选胆道镜、腹腔镜联合胆囊内镜检查、活检及治疗(又称之为“腹腔镜胆道镜联合保胆息肉摘除活检术”),如果胆囊功能差,或伴有急慢性炎症者可首选腹腔镜胆囊切除术(LC)。

第二类:良性非胆固醇性息肉(占40%)。又称为真性息肉。主要是指:胆囊腺瘤、腺肌瘤、炎性息肉、腺瘤样增生,其中腺瘤是公认的癌前病变,癌变率在10%左右,腺肌增生症也有潜在癌变危险。因此,这类病变应该行预防性胆囊切除,首选腹腔镜胆囊切除术。

第三类:息肉型早期胆囊癌(约占10%)。目前对于混杂在胆囊息肉中的息肉型早期胆囊癌主要靠B超来侦别。必要时加作增强CT。癌性息肉的B超特征为:大于10mm(88%);单发(82%);多位于胆囊颈部(70%);约有50%伴有胆囊结石;病变回声强度以中低回声为主。一旦怀疑此类病变时应限期行根治性胆囊切除。

通过以上的介绍,我们可以这样简单理解:胆囊息肉有真假之分。假性息肉是不会癌变的,可以观察;而真性息肉有癌变的可能性,建议行预防性将胆囊切除,这样就可以减少胆囊癌的发生。如何判断息肉的真假就尤为重要了。

3 胆囊息肉中有多少可以癌变呢?据统计:如此众多的胆囊息肉中也只有12%可以癌变。鉴于目前胆囊癌的手术疗效较好的也只局限于胆囊粘膜的早期癌,而胆囊癌的总体疗效极差,它对放疗、化疗均不敏感。所以胆囊癌在目前医学界仍是一个很棘手的疾病,唯一提高治疗效果的方法就是早期发现,早期切除胆囊。这就要求医生对如此众多的胆囊息肉病人做出比较正确客观的判断--即可以早期发现胆囊癌,又可以避免大量的不必要胆囊切除。尽最大可能保留一部分病人的胆囊。息肉有可能癌变就是胆囊息肉最为可怕之处。医生也认为:胆囊息肉样病变仍然是一种癌前疾病,应定期B超复查,动态观察息肉大小形态的变化。应该引起高度重视。据国内健康查体统计表明:正常人群中有5%的胆囊息肉检出率。也就是说在各个单位组织的例行身体检查中有5%的人能可能会查出胆囊息肉。

4 有没有什么办法来侦别可以癌变的息肉呢?从上述胆囊息肉的临床分类和不同类型的胆囊息肉的治疗方法中,我们不难看出:胆囊息肉有真假之分,治疗上可以简单地说“胆囊假性息肉可以保留胆囊,而真性息肉要预防性切除胆囊,息肉样癌要行胆囊根治性切除。”然而,目前的医学检查不能准确确定息肉的性质,故将怀疑真性息肉的胆囊一律切除,做以绝后患。这样就不可避免地造成半数以上的胆囊被冤枉切除。也许有人会问:有没有不手术就能知道胆囊息肉的真假?能不能将胆囊内的息肉取出来然后再将胆囊缝上?我们都知道,肿瘤的性质其最高诊断依据是组织学诊断(也叫病理诊断)。临床上经常有通过经皮穿刺或内镜活检等手段取得活体组织,然而,胆囊是一个储存胆汁的盲袋状空腔器官,它没有自然腔首来供内镜进入,也无法经皮穿刺,故我们无法取到组织。而各种检查手段均只能对息肉外形进行描述,而这些外形描述仅只能作为参考,无法指导临床。所以,不想通过手术就能获得胆囊息肉的性质就成为不可能的事。如果我们将在外科建议切除胆囊的这部分病人,在手术中取到息肉的组织,并进行快速冰冻活检,最后依据组织学结果,对假性息肉的胆囊给予保留,真性息肉的胆囊酌情给予预防性切除。这样即能保留部分有功能的胆囊,又切除有癌变倾向的胆囊,实为一种严谨的态度下获得的新的治疗方法。目前医疗水平能否达到这种设想呢?答案是肯定的,确实有这样的方法,我们称之为“腹腔镜胆道镜联合保胆息肉摘除活检术”。它是通过腹腔镜来了解腹腔内情况及胆囊的外观,初步判断胆囊是否正常及腹腔内是否有癌的病灶,然后在腹腔镜直视下将胆囊底部夹住并将其拖出一小部分到腹壁切口外,再将胆囊底部切开一个很小的口,通过这个口我们再用胆道镜观察胆囊腔内的情况,包括胆囊粘膜是否有胆固醇沉积、息肉的外观数目、胆汁是否清亮、胆囊管开口是否通畅等,最后通过胆道镜用活检钳将息肉一一夹取,取出的息肉进行术中快速冰冻切片活检,如果快速冰冻切片活检报告为属于胆固醇性等良性息肉,那我们就尽力取净胆囊内息肉后再将胆囊小口缝合。胆囊就这样保留在你的身体里了。此手术技术相当成熟,很少有严重的并发症。但目前医学界对此手术也有争议,其原因就是此手术不能改变胆囊的内环境,息肉的复发将是不可能避免的。所以,当你有胆囊息肉时,在就诊的时候医生会给出不同的建议意见。这一点,希望大家能理解。

5 胆囊的良性疾病保留胆囊是否有必要?众所周知:中华民族是一个注重孝道的民族。《孝经》第一章就言:“身体发肤,受之父母,不敢毁伤,孝之始也;立身行道,扬名于后世,以显父母,孝之终也。……”。传统文化要求中国人保持完整的身体,这是孝道的开始。这样我们就不难理解为什么有这么多的胆囊结石和胆囊息肉的病人有着强烈的保留胆囊的愿望,甚至喊出“誓与胆共存亡”的心声。此举并非愚昧。从现代医学生理上来讲,也是有很强的理论依据的。只可惜现代西医在胆囊切除术诞生的120余年里,一直没能找到替代胆囊切除的更好方法。因此,在上个世纪里,中国人一直在忍受着不得以毁伤源于父母的身体。当然,单纯从传统文化方面来说保留胆囊的意义是有点偏颇。但病人有强烈的保留胆的要求是可以从文化中寻求到根源的。目前我们能够通过胆道镜来观察胆囊内息肉的外观,对真假息肉进行准确判断。并可以将息肉取出做快速切片活检,最终根据病理结果来决定胆囊的去留。如此,我们能够做到保留假性息肉的胆囊,去除真性息肉的胆囊,即能解除胆囊癌的后顾之忧,又能保留正常的胆囊。这样在不增加病人痛苦和费用的情况下,极大可能保留了一部胆囊,这也是人类人文医学的具体表现。所以,我认为适当保留胆囊还是很有必要的。

6 胆囊息肉治疗建议对比:外科教材对胆囊息肉的指导性建议:一 观察 胆囊内多发息肉,直径在1.0cm以下无症状者,应定期B超复查,动态观察息肉大小形态的变化。2预防性胆囊切除。二 预防性胆囊切除:① 1单发息肉;② 大于1.0cm广基或基底部宽大者; ③ 病变有增大者; ④ 合并有胆囊结石者;⑤ 年龄在60岁以上者,伴有症状。以上均可以视为恶性病变的高危因素。目前新观念:一 观察(内容同上)。二 假性息肉可以保留胆囊,真性息肉要行预防性胆囊切除。随着现代影像诊断技术的不断发展以及国家重视国民的身体素质大力提倡健康体检,使胆囊息肉的检出数量日益增多,胆囊息肉已成为最常见的胆道疾病之一。然而,对胆囊息肉应该如何治疗的问题,一直存在一些争论或分歧。首先,胆囊息肉目前尚无针对强的药物来预防与治疗。对于小于10mm的息肉,可以不做任何治疗,建议每三到六月复查一次超声,以监测胆囊息肉大小的动态变化。对于接近或者超过10mm的息肉,建议行预防性胆囊切除,首选腹腔镜胆囊切除术(LC)。如果病人有保留胆囊的愿望且年龄在60岁以下又达到预防性切除胆囊标准时,对于这部分病人可以试行腹腔镜胆道镜联合保胆息肉摘除活检术,最后视术中息肉的病理性质而决定胆囊的去与留。这样就能最大可能的保留一部分病人的胆囊。

综上所述,胆囊息肉确实并不可怕,一味地担忧肯定是自找烦恼,将息肉任其不管肯定也不正确。只有科学客观地待胆囊息肉,才是最为明智的选择。

阅读全文……

标签 :

有胆囊息肉饮食应该注意什么?不能吃什么?什么要少吃?

胆囊息肉是一种多发病 ,分为单发性胆囊息肉和多发性胆囊息肉两种 ,得了此病 ,一般需要手术治疗。对于单发性胆囊息肉来说 ,如果息肉较小 ,手术切除后可能仅为胆固醇结晶。但假如确诊为多发性胆囊息肉 ,或体积较大的息肉 ,一般应考虑手术切除胆囊。否则 ,假如息肉恶变 ,成为胆囊癌 ,其预后极差 ,多数病人在发病数月内死亡。对于息肉较小 ,又不愿意手术者 ,应当严密随访 ,定期复查B超 ,如发生变化应尽早手术 ,现在胆囊切除可以做腹腔镜手术 ,创伤小恢复快 ,术后第二天即可下床活动。 胆囊息肉是胆囊黏膜向胆囊腔内生长出一种突起的局限性病变。患者一般没有什么症状 ,有的患者只是感到右胁下不适 ,通过B超检查可被发现。近几年 ,随着B超检查的普及 ,临床发现的胆囊息肉样病变呈现出越来越多的趋势。同时 ,因为胆囊息肉样病变可包含良性、恶性病变共 20余种 ,患者常由于担心癌变而四处求医问药。那么 ,胆囊息肉到底是什么样的疾病呢 ?

胆囊息肉的易发人群

大样本调查资料统计结果表明 ,胆囊息肉的人群发病率为 5%以上 ,且男性居多。国外19 9 9年对 19 4767例日本】等俗鳔超普查 ,查出胆囊息肉样病变 109 26例 ,占 5. 6%,其中男性发病率为 5. 9 %,最多见于 30~ 40岁人群 ;女性发病率为 4. 5%,最多见于 40~ 50岁。多项调查研究发现 ,胆囊息肉样病变与性别、葡萄糖不耐受等有关。此外 ,男性肥胖与其也存在一定的相关性 ,而女性则无此相关性。

胆囊息肉的类型及分类

胆囊息肉样病变的表现形式包含很多病理类型 ,病理分类为非肿瘤与肿瘤性病变两大类 ,肿瘤性病变又分为良性和恶性。

1.非肿瘤性病变 :其中以胆固醇息肉最为多见。国外 19 9 5年报告 ,胆固醇息肉占胆囊息肉样病变的 65%,国内报告的 288例患者中胆固醇息肉占 62. 5%。其次为炎症性息肉、腺瘤样增生及腺肌瘤等。

(1)胆固醇息肉 :胆固醇沉着是胆囊息肉的重要病因 ,胆固醇沉着于胆囊黏膜固有膜的巨噬细胞内 ,逐步向黏膜表面突起 ,促使黏膜上皮增生、罗 -阿窦增多及肌层增厚而形成息肉。胆固醇息肉的病理特点为多发性小息肉 ,曾有胆固醇息肉 74例病例报告显示 :直径小于10mm者占 9 7%, 50%为多发性 ,平均 3. 09±3. 31个 (肿瘤性息肉多为单个病变 ,有临床鉴别意义 )。胆固醇息肉质脆带细 ,易与黏膜分离 ,不伴有肠化生及不典型增生 ,也不含其他基质成分 ,即便伴有炎症也很轻微 ,到目前为止未见有癌变报道。

(2)炎症性息肉 :为炎症刺激所致的一种肉芽肿 ,直径约 5mm ,单发或多发的广基性结节。其组成成分有毛细血管、成纤维细胞及慢性炎症细胞 ,息肉周围的胆囊壁有明显炎症 ,至今尚无癌变报道。

(3)腺瘤样增生 :既非炎症也非肿瘤的增生性病变 ,为黄色质软的疣状物 ,直径约 5mm ,单发或多发。其组成成分为丰富的结缔组织中含平滑肌束及杯状细胞 ,其表面有上皮增生并伴有肠化生。腺样增生因黏膜上皮伸入肌层形成的罗 -阿窦明显增多 ,窦口上常有狭窄 ,致窦内常有胆汁淤积、炎症或胆石嵌入 ,有癌变可能。

(4)腺肌瘤 :存在黏膜上皮局部变化、肌纤维增生与局限性腺肌增生 ,故医学上又称为腺肌增生症 ,有弥漫型、节段型与局限性三种。腺肌瘤也是既非炎症、也非肿瘤的增生性病变 ,也可能癌变。

2.肿瘤性病变 :此类病变中以良性的腺瘤为主 ,恶性主要为胆囊癌。

(1)腺瘤 :多为单发的有蒂息肉 ,外形可呈乳头状或非乳头状 ,恶变率约 30%,癌变机会与腺瘤大小呈正相关。 19 9 8年国外学者观察良性胆囊息肉样病变时发现 ,其中 9 4%直径 <10mm , 66%的患者年龄 <60岁 ;而恶性胆囊息肉样病变 88%直径 >10mm , 75%的患者年龄>60岁。研究认为 ,胆囊腺瘤的发病率很低 ,在 1 0年内施行的 12 153例胆囊切除中 ,仅 81例为胆囊息肉样病变 ,只占 0. 7%,而其中是腺瘤的仅为 9 . 6%;而同期人群中发现胆囊癌 225例 ,占 1. 85%,可见本病虽有癌变的可能性 ,但对人群构成的威胁并不太大。

(2)腺癌 :分为乳头型、结节型及浸润型。前两者为隆起性病变 ,直径约 <20mm ;而浸润型不属于胆囊息肉样病变 ,绝大多数直径 >20mm。因此表现为胆囊息肉样病变的胆囊癌往往为早期 ,其中乳头型癌绝大多数限于黏膜和肌肉内 ,预后良好。

胆囊息肉的诊断和治疗

1.胆囊息肉样病变的诊断 :由于此类患者往往无症状或症状轻微 ,主要靠影像带诊断 ,以B超为首选。国内专家报告B超的检出率为9 2. 7%,特异性为 9 4. 8%,假阳性率为 5. 2%,准确性明显高于CT。专家认为B超能清晰地显示息肉病变的部位、大小、数目和局部胆囊的变化 ,既简便又可靠。国外研究认为内镜超声比B超更准确 ,提供的图像更清晰。CT检查胆囊息肉是否有蒂比较敏感 ,增强CT能鉴别肿瘤与非肿瘤样胆囊息肉样病变 ,能可靠地筛选出应予手术的肿瘤性病变。

2.胆囊息肉样病变的治疗要根据息肉大小 ,良性和恶性等不同 ,给予手术治疗。

(1)胆固醇息肉 :大多数人无症状 ,且胆囊功能良好。患者在平时应每 3~ 6个月予以B超随访 ,一旦出现明显症状或息肉迅速增大才考虑手术。如胆囊功能良好 ,可行经皮胆囊镜息肉摘除。此类息肉直径往往 <10mm(82%),并以多发性为主 (75%),外观呈桑椹状 ,蒂细如线 ,质脆易落 ,很容易摘除。如胆囊功能不良可行腹腔镜胆囊切除。

(2)良性非胆固醇性胆囊息肉 :包括腺瘤与腺肌瘤病、炎症性息肉及腺瘤样增生罕见的间叶组织肿瘤等。其中炎症性息肉虽无恶变报道 ,但均伴有程度不等的胆囊炎症 ,且多有临床症状 ,其余类型则均有恶变可能 ,因此一经查实应及时手术切除同时做病理切片以明确病变的性质。

胆囊息肉样病变易发生肿瘤的高危因素主要有 6个方面 :①单发 ;②直径 >10mm ;③广基或蒂粗大 ;④病变增长 ;⑤年龄 >50岁 ;⑥合并胆石。但有专家强调 ,对直径 <10mm的息肉也不能放松警惕 ,必须定期随访。对胆囊息肉样病变可采用 3种不同的胆囊切除术 :即在胆囊周围结缔组织中剥离的单纯胆囊的除术、切除全部胆囊结缔组织的全厚胆囊切除术及加做胆囊床部分肝组织切除的扩大胆囊切除术 ,根据术前判断胆囊息肉性质加以选择。就癌肿而言 ,直径 <18mm者仍有早期癌的可能 ,仍可经膜腔镜胆囊切除行全厚胆囊切除 ,若术后病理证实已浸润至浆膜层下 ,则可行二次探查术。但若直径 >18mm ,即有晚期癌的可能 ,可直接开腹行扩大胆囊切除术 ,甚至要做广泛淋巴结清扫。

可采用非手术及中药治疗。
平时应注意:
禁酒及含酒精类饮料
饮食要规律、早餐要吃好
低胆固醇饮食
胆固醇摄入过多,可加重肝胆的代谢、清理负担,并引起多余的胆固醇在胆囊壁结晶、积聚和沉淀,从而形成息肉,所以,胆囊息肉患者应降低胆固醇摄入量,尤其是晚上,应避免进食高胆固醇类食品如:鸡蛋(尤其是蛋黄)、肥肉、海鲜、无鳞鱼类、动物内脏等食品。
其它饮食注意事项

1、宜多食各种新鲜水果、蔬菜,进低脂肪、低胆固醇食品如:香菇、木耳、芹菜、豆芽、海带、藕、鱼肉、兔肉、鸡肉、鲜豆类等。

2、宜多食干豆类及其制品。

3、宜选用植物油,不用动物油。

4、少吃辣椒、生蒜等刺激性食物或辛辣食品

5、宜用煮、蒸、烩、炒、拌、氽、炖的烹调方法,不用油煎、炸、烤、熏的烹调方法。

6、山楂10克,杭菊花10克,决明子15克,煎汤代茶饮或饮用绿茶。

7、平时喝水时,捏少许山楂、沙棘、银杏、绞股蓝草放入水杯中当茶饮用

阅读全文……

标签 :

总胆固醇高是怎么回事,后果?吃什么?

胆固醇是一种脂质,是每个人不可缺少的,尤其在细胞膜的成份和激素的合成中起重要作用。武警湖南总队医院肝病专家介绍,我们的身体可以在肝脏合成胆固醇。
饮食中的胆固醇主要来自蛋黄、动物脂肪、动物内脏、鱿鱼、虾等。在身体里,胆固醇与蛋白质结合,以脂蛋白的形式在身体内进行转运。
“坏”胆固醇与“好”胆固醇,认识“坏”胆固醇与“好”胆固醇非常重要。

“坏”胆固醇——(低密度脂蛋白胆固醇LDL-C)占总胆固醇的60%,尽管身体需要一定的LDL-C,但多余的LDL-C会钻入动脉血管内皮,形成斑块,堵塞血管引起冠心病、脑梗塞,或者随着斑块破裂引起心肌梗死、猝死等严重后果。
“好”胆固醇——(高密度脂蛋白胆固醇HDL-C)占总胆固醇的1/3,可以将多余的胆固醇转运出动脉,运回肝脏。
血里还有一种血脂叫甘油三酯,血中甘油三酯升高可以使“坏”胆固醇LDL-C升高,所以它是“坏”胆固醇的帮凶。
总胆固醇正常参考值:为3.12 ~5.98 mmol/L;
吃的食物中摄入的胆固醇多了,此时也可以引起高胆固醇血症,此外像一些疾病如:高脂血症、糖尿病、甲状腺功能减退、高血压、冠心病、动脉粥样硬化、胆总管阻塞等一些疾病都可以引起总胆固醇偏高。

总胆固醇偏高的危害
    动脉在人体非常重要,它们把血液和氧输送到身体的各个重要器官。如果“坏”胆固醇增加,一旦高血压、糖尿病、吸烟等因素使内皮有漏洞,它们就会钻到动脉的内皮下面,
形成动脉粥样硬化斑块。这种斑块就象潜伏在在动脉壁里的肿瘤,它的外面是一层包膜,内部就是许多聚集在一起的“坏”胆固醇。血液里的“坏”胆固醇越多,聚集在动脉
壁里的就越多,斑块不断长大,使动脉逐渐狭窄甚至阻塞,影响血液和氧的输送,就会引起心绞痛、心肌缺血、脑梗死、脑软化等疾病。更可怕的是,这些斑块象“定时炸弹”
一样会在没有任何先兆时爆炸。由于胆固醇是一种脂质,它在斑块里越多,就象饺子馅里有很多油汤,容易破裂。另外,“坏”胆固醇越高还会引起内皮的炎症,使斑块的
外膜变薄并且很脆弱,就象一个皮薄馅里又有很多油汤的饺子,很容易破裂。一旦斑块破裂,“爆炸物”(从斑块内涌出的物质)会引发一连串的反应,使动脉迅速堵塞,
引起急性心肌梗死甚至猝死。
生活中的注意事项:
   建议平时低糖低脂低胆固醇饮食,少吃含糖量高的食物和水果,少食油腻食物,少吃蛋黄,动物内脏等含胆固醇高的食物,控制饮食,饮食定时定量,适量运动,保持乐观的心态.祝您早日康复.
一个月后可以复诊一下,观察病情如果没事了就不用吃药。

 
母亲总胆固醇、低密度脂蛋白偏高,请问应该吃什么降脂药?
最佳答案
    这与老年人代谢较慢有关,在控制饮食前特下还要适量运动,以身体能够耐受为度,也不要运动量太大造成劳损;在运动越1个月后再复查血脂,如果仍然较高,则需要药物治疗了。
选择他汀类药物,如辛伐他汀;阿托伐他汀,立普妥片等,均需晚睡前服药,服药后1个月监测肝功。另外可以服用中药汤剂也是不错的选择。
 
随着现代人生活节奏加快,饮食习惯改变尤其是快餐文化的出现,高胆固醇、高脂肪、高热量食物引起的血脂升高等相关疾病正日益成为威胁人类健康的“隐形杀手”,根据2002年全国营养与健康调查数据,我国成人血脂异常患病率为18.6%,估计全国血脂异常现患人数16亿,高血脂患者也呈年轻化的趋势。

1、什么是血脂
    血脂是血液中所含有的脂质成分的总称,这些脂质是一大类营养物质和对身体有用的化合物,如胆固醇、甘油三酯、磷脂、脂肪酸等,但可引起动脉粥样硬化的脂质主要是胆固醇和甘油三酯。

2、什么是总胆固醇(TC)
    众所周知,胆固醇异常与心脑血管疾病的发生密切相关,然而胆固醇到底是一种什么样的物质呢?胆固醇可以说是一种“油”,是不溶于水的物质,但实际上血液中没有单独存在的胆固醇,胆固醇必须与载脂蛋白(一种蛋白质)和磷脂结合后,才能在血液中自由流动,因此,总胆固醇(TC)就是血液中各种脂蛋白所含胆固醇的总和。

3、胆固醇载体——载脂蛋白

(1)、分类

    血液中的载脂蛋白包括高密度脂蛋白(HDL)与低密度脂蛋白(LDL)等,其中密度高、颗粒小的称为高密度脂蛋白,而密度低、颗粒稍大的称为低密度脂蛋白。

(2)、不同载脂蛋白的差异

   许多人一提到胆固醇,大有谈虎色变的恐惧,其实这是一种误解。我们知道任何事物具有两面性,就胆固醇而言,它本身是具有重要作用的生命物质。

   研究发现,血中的脂蛋白也有好坏之分。前面提到的低密度脂蛋白(LDL)从肝脏携带胆固醇到周围血管,特别是到心脏上的血管(医学上称冠状动脉),可造成过多的胆固醇在血管壁上存积,引起动脉粥样硬化。现已证实,LDL及其所携带的胆固醇(LDL-C)升高是引起冠心病等心脑血管疾病的罪魁祸首,所以我们称LDL-C为坏胆固醇。

  相反,高密度脂蛋白(HDL)能将血管壁多余的胆固醇运送回肝脏进行代谢,从而保护血管免受侵害。所以,HDL及HDL-C升高有益健康。

  如果摄入太多饱和脂肪和胆固醇,体内的LDL增高,过多的胆固醇会粘附在血管壁上,长期作用可引起动脉粥样硬化,HDL可以防止游离胆固醇积累在动脉壁和其他组织,所以血液中HDL含量高的人,动脉粥样硬化的危险性较低。

(3)、低密度脂蛋白与动脉粥样硬化

   血脂异常(包括高甘油三酯、高总胆固醇、高密度脂蛋白和低密度脂蛋白)或许更能反映血脂与动脉粥样硬化的关系,但人们通常都用高血脂来表示血脂与动脉粥样硬化的关系。

   大量研究表明,氧化LDL和巨噬细胞在动脉粥样硬化的发病过程中起着主要作用:
A、沉积在动脉粥样斑块上的脂质来源于血浆中的LDL,而胆固醇及其酯在血管壁没的聚集很可能与两条途径有关:一是依靠血管壁内的内皮细胞膜上的特异性受体进行主动摄取;二是经过非受体途径被动性进入,如在严重细胞内皮损伤时。

B、血管壁内和动脉粥样硬化损伤处的所有主要细胞都能产生导致氧化LDL的自由基,产生氧化LDL(ox-LDL),而在动脉粥样硬化的早期阶段,损伤处内皮细胞导致LDL的轻度氧化可能是至关重要的。

C、轻度氧化的LDL或微小修饰的LDL在引起巨噬细胞聚集方面具有启动因子的作用,也就是说氧化的LDL促进巨噬细胞在受损内皮细胞附近聚集。

D、巨噬细胞吞噬大量的ox-LDL后衍变成泡沫细胞,巨噬细胞或泡沫细胞内的脂质饱和后,无论破裂与否,都可释放大量的活性物质,加速病变的进展。泡沫细胞逐渐增多并融合,形成脂质条纹,继而发展为成熟的粥样斑块。

血脂升高的原因

  脂肪来源于体内和体外两个途径,前者主要在肝内合成,而后者从饮食中摄取。脂肪主要通过肝脏代谢清除,所以体内脂肪来源过多和肝脏清除减少都可导致血脂升高。遗传、某些疾病的影响及环境因素等原因,都可能引起血脂升高而患上高胆固醇症。

1、遗传与某些疾病

  少数病人是由遗传性因素决定的,或继发某些疾病如肾病综合症、肝胆疾病、糖尿病等后出现,绝大多数病人属遗传缺陷加上环境因素影响而患病。

2、环境因素

  环境因素包括生理因素、饮食不当以及某些药物的影响等,其中饮食不当可能是最普遍的因素。

·生理因素

  妊娠、绝经、进入老年期

·饮食不当

A、高胆固醇和高饱和脂肪酸的摄入。例如有些人喜欢吃肥肉和动物内脏,时间长了,血脂就悄悄地升了上去。

  人体中有60%的胆固醇来源于肝脏的合成,有的病人即使在相当长的时间内不摄取胆固醇,血浆胆固醇的浓度也只能下降10-25%,所以要想使血浆胆固醇下降不能仅仅靠限制膳食胆固醇的办法,还必须抑制胆固醇的合成,但对于动脉粥样硬化的预防,对膳食中胆固醇的摄入还是有必要进行限制,尤其是对高胆固醇血症病情较轻的人,限制膳食胆固醇的摄入有更大的意义。此外,还应限制饱和脂肪酸的摄入,人类血浆胆固醇浓度随饱和脂肪酸摄入的增加而升高,原因除了饱和脂肪酸本身会影响胆固醇的代谢外,富含饱和脂肪酸的食物,胆固醇含量也较高。

B、从饮食中摄取过多的热量,引起肥胖或超重,是高血脂、高血压、糖尿病和心脏病常见的危险因素之一。

  由于某些原因引起体内脂肪过分堆积而造成体重超过正常标准20%以上者称为肥胖。肥胖的人不仅体内脂肪组织增加,而且血液中脂质也明显增加,尤其是甘油三酯、游离脂肪酸和胆固醇水平多高出正常。

  由于引起血脂升高的原因很多,包括遗传和多种环境因素,体重只是众多影响血脂高低的因素之一,不是唯一决定性的。所以较瘦的人同样可存在脂质代谢异常。因此,体态苗条的人也不可对高血脂症掉以轻心,尤其是中老年人容易发生心脑血管疾病者,定期检查血脂是很有必要的。

3、不良生活方式

  不良生活方式也是重要的影响因素,如长期不运动或少运动、酗酒、吸烟、精神紧张或焦虑等,都可能引起血脂升高。

血脂升高对健康的危害

  血液中的胆固醇在正常情况下可以保持一定的份量,但不规律的生活或进食过量饱和脂肪和胆固醇等会令血中总胆固醇增加,过多的LDL好象废物般积聚在血管壁内,导致内皮细胞受损。如前所述,这些LDL会被自由基氧化,产生氧化LDL、氧化LDL具有很高的细胞毒性,进一步损伤内皮细胞,形成恶性循环。

  由内皮细胞层受损吸引而来的巨噬细胞对氧化LDL的吞噬远远多于对原型LDL的吞噬,而且氧化LDL还将吸引更多的巨噬细胞在受损内皮细胞附近的聚集,形成另一个恶性循环。巨噬细胞吞噬LDL后形成泡沫细胞,是动脉粥样硬化的标志。

  一个又一个恶性循环带来的越来越多的泡沫细胞与胆固醇、受损坏死的细胞等,在血管壁内形成肉眼可见、形状类似小米粥的块状物,即动脉粥样硬化斑块。

血脂升高的科学预防

   高血脂的发病率高,危害性大,高脂血症和动脉粥样硬化在发病早期可能没有不舒服的症状,多数患者在发生了冠心病、脑中风后才发现血脂异常,因此应当居安思危,早发现早治疗,将疾病隐患消灭在萌芽状态。主要以防止结合,重点在防;无病防病,有病防进展。同时,不仅要重视预防高血脂本身的出现,更要重视防治高血脂所带来的危害性。首先需要强调对病因的预防,去除或控制其可能病因、诱因及其它影响因素,即:
1、合理饮食

   简单说来,高血脂病人的饮食应注意“一个平衡”和“五个原则”。

“一个平衡”即平衡饮食;很多人患上高血脂后就完全素食、偏食,这是个误区,对身体是很不利的。首先应从饮食中获得的各种营养素,确保种类齐全,比例适当,可按照中国居民膳食指南的建议进行均衡饮食。

“五个原则”包括低热量、低胆固醇、低脂肪、低糖、高纤维饮食。

 低热量:控制饮食中的热量,旨在达到和维持理想体重。所谓理想体重通常是以“体质指数”表示。其计算公式为:体重指数=体重(公斤)/[身高(米)]2,其理想值为18.5-23.9。体重超过理想体重之10%表示过重,超过理想体重之20%表示肥胖。对于体型肥胖的高血脂患者,通常是每周降低体重0.5-1公斤为合适。

  低胆固醇:每日总摄取量应低于300毫克,然而,我们饮食中胆固醇却常常超量。以北京人膳食结构为例,胆固醇摄入量平均为412.4毫克。所以应少吃含胆固醇高的食物(见附表)

 低脂肪:尽量少吃含饱和脂肪酸多的食物,如肥肉、奶油、猪油、牛油、肉类外皮等动物性食品,烹调用油宜选择含较多不饱和脂肪酸的油,例如:大豆油、玉米油、红花籽油、葵花仔油、橄榄油、花生油、茶油;另外,鱼类及豆类饱和脂肪酸含量较少。亦可多考虑用以取代其它肉类,作为蛋白质的来源。

 低糖:少吃糖分高的饮料或甜食如糕点、巧克力、冰淇淋等

 高纤维:多吃含纤维多的食物如豆类、燕麦、菇类、韭菜、芹菜等蔬菜和水果。

 另外还可多选择一些具有降血脂作用的食物:如茶、大豆、大蒜、升姜、茄子、山查、柿子、香菇、黑木耳、海藻等。

2、加强运动

  每周至少进行3次有氧运动,每次30分钟以上。体力活动能够消耗体内大量的能量,既可以降低血浆中胆固醇的甘油三酯的含量,又可以使高密度脂蛋白的水平升高。而最新的实验结果也证明了这一点,研究发现血脂水平升高的小白鼠每天进行运动,6-8周后,它们的血脂显著改善,高密度脂蛋白胆固醇水平显著增高,动脉粥样硬化斑块的形成也受到了明显的抑制。

3、戒除吸烟习惯

  研究发现,吸烟会引起或加重血脂异常。实验观察,吸烟者的血清总胆固醇水平显著高于非吸烟者。吸烟降低血清高密度脂蛋白胆固醇水平,并且吸烟量越大,血清高密度脂蛋白胆固醇水平越低。暴露于烟雾中的低密度脂蛋白容易被氧化修饰,形成对血管危害更大的氧化型低密度脂蛋白颗粒。因此吸烟是冠状动脉粥样硬化的主要危险因素之一。及早戒烟可将其危害大为降低。研究表明戒烟一年,患动脉粥样硬化的危险性降低一半,血中高密度脂蛋白胆固醇可增加至非吸烟者的水平。需特别指出的是,长期受吸烟者影响的被动吸烟者,血清高密度脂蛋白胆固醇水平也会下降,而总胆固醇水平则升高,所以说,吸烟不但害己,也害及旁人。下定决心戒烟,于自己和别人都有利。

4、预防与控制可能继发高血脂的其它疾病;如肾病综合症、肝胆疾病、糖尿病等

5、定期检查

  高血脂、高血压、糖尿病患者或40岁以上男性、绝经后女性等属危险人群,均应定期化验血脂,以期早防早治。

  由于血脂增高是一个缓慢的过程,血脂的调节特别是消除血脂不良影响也同样需要一个持续作用的过程。因此患者应根据自身的不同情况,采用适合自己的防治方法。

6、Omega-3与血脂调节

  很早以前科学家们便发现,生活在冰岛上的爱斯基摩人,冠心病发病率很低,进一步研究显示,这些以渔猎为生的人们,多以海鱼为主要食物。所以,学者们联想到进食鱼类可能有预防冠心病的作用,鱼的这种作用可能与其能降低血脂有关,后来的研究也证实,鱼油尤其是深海鱼油含有Omega-3可转化成EPA和DHA,即二十碳五烯酸和二十二碳六烯酸,有降低甘油三酯的作用。

  另外,经调查发现深海鱼油产品质量悬殊,劣势的鱼油进入人体易导致过多自由基产生,而自由基是机体衰老和诸多疾病之源。鉴于目前鱼油市场的现状,消费者在选择鱼油时应更加注重生产厂家的技术和信誉。

茶与心血管健康 
  “茶”不仅作为日常饮品存在于我们的生活之中,且以一种传统文化的形式,深深地植根于我们的意识中。俗话说,开门七件事柴米油盐酱醋茶。“茶”作为中国国粹之一,是中国文化的组成部分。

1、茶的保健作用

  喝茶在我国已有数千年的历史,其不仅作为一种饮料,有解渴提神之功效,而且还有较强的保健功效,已经成为一种风靡全球的保健饮料。《神农本草》中记载“神农尝百草,日遇七十毒,得茶而解之”。《本草拾遗》上说:“诸药为各病之药,茶为万病之药。”可见在古代就已经知道茶具有许多疗效作用,因此常把茶当作药饮。茶具有提神醒脑、消炎解毒、抗衰老、降血脂等功效。

  喝茶能降血脂,国内外已有大量报道。长期喝茶可以帮助降低人体血液中总胆固醇、低密度脂蛋白胆固醇和甘油三酯,同时可以增加高密度脂蛋白胆固醇,加速脂肪和胆固醇的代谢。在我国古代文献中就有茶可“解油腻”、“去人脂”的记载。用茶叶中的茶多酚进行降血脂的实验研究显示茶多酚对降血脂和预防动脉粥样硬化的有十分明显的效果。 
 
          

阅读全文……

标签 :

Web安全测试之XSS - 小坦克 - 博客园

XSS 漏洞修复

原则: 不相信客户输入的数据
注意:  攻击代码不一定在<script></script>中

  1. 将重要的cookie标记为http only,   这样的话Javascript 中的document.cookie语句就不能获取到cookie了.
  2. 只允许用户输入我们期望的数据。 例如: 年龄的textbox中,只允许用户输入数字。 而数字之外的字符都过滤掉。
  3. 对数据进行Html Encode 处理
  4. 过滤或移除特殊的Html标签, 例如: <script>, <iframe> ,  &lt; for <, &gt; for >, &quot for
  5. 过滤JavaScript 事件的标签。例如 "onclick=", "onfocus" 等等。

如何测试XSS漏洞

方法一:  查看代码,查找关键的变量,   客户端将数据传送给Web 服务端一般通过三种方式 Querystring, Form表单,以及cookie.  例如在ASP的程序中,通过Request对象获取客户端的变量

<%
strUserCode = Request.QueryString(“code”);
strUser = Request.Form(“USER”);
strID = Request.Cookies(“ID”);
%>

假如变量没有经过htmlEncode处理, 那么这个变量就存在一个XSS漏洞

 

 方法二: 准备测试脚本,

"/><script>alert(document.cookie)</script><!--
<script>alert(document.cookie)</script><!--
"onclick="alert(document.cookie)

 在网页中的Textbox或者其他能输入数据的地方,输入这些测试脚本, 看能不能弹出对话框,能弹出的话说明存在XSS漏洞

 在URL中查看有那些变量通过URL把值传给Web服务器, 把这些变量的值退换成我们的测试的脚本。  然后看我们的脚本是否能执行

 

方法三:  自动化测试XSS漏洞
现在已经有很多XSS扫描工具了。 实现XSS自动化测试非常简单,只需要用HttpWebRequest类。 把包含xss 测试脚本。发送给Web服务器。 然后查看HttpWebResponse中,我们的XSS测试脚本是否已经注入进去了。

阅读全文……

标签 : ,

Spring MVC防止XSS、SQL注入漏洞攻击方法 - windows9834的日志 - 网易博客

XSS漏洞攻击主要分为两种途径:
1、URL参数传递
2、表单提交参数

先说第一种,这种一般都是做为查询条件传递到后端的,来需要保存到数据库中的,处理方法也简单,只要进行转码或过滤就可以了。但是具体方法也有很多,如
1)直接对参数进行编码:StringEscapeUtils.escapeHtml(searchWords);在传递可页面显示的时候都可以进行。
2)在Spring的控制器中注册属性编辑器
下面是一个简单的Spring命令控制器,扩展AbstractCommandController:

public class AbstractFrontCommandController extends AbstractCommandController{

public AbstractFrontCommandController(){

//只是为满足AbstractCommandController的要求
this.setCommandClass(String.class);
}

@Override
protected final void initBinder(HttpServletRequest request,

ServletRequestDataBinder binder) throws Exception {
super.initBinder(request, binder);
binder.registerCustomEditor(

String.class,new StringEscapeEditor(true, false, false));
}

@Override
protected ModelAndView handle(HttpServletRequest request,
HttpServletResponse response, Object command, BindException errors)
throws Exception {
return null;
}
}

 

public class StringEscapeEditor extends PropertyEditorSupport {

private boolean escapeHTML;
private boolean escapeJavaScript;
private boolean escapeSQL;

public StringEscapeEditor() {
super();
}

public StringEscapeEditor(boolean escapeHTML, boolean escapeJavaScript, boolean escapeSQL) {
super();
this.escapeHTML = escapeHTML;
this.escapeJavaScript = escapeJavaScript;
this.escapeSQL = escapeSQL;
}

public void setAsText(String text) {
if (text == null) {
setValue(null);
} else {
String value = text;
if (escapeHTML) {
value = StringEscapeUtils.escapeHtml(value);
}
if (escapeJavaScript) {
value = StringEscapeUtils.escapeJavaScript(value);
}
if (escapeSQL) {
value = StringEscapeUtils.escapeSql(value);
}
setValue(value);
}
}

public String getAsText() {
Object value = getValue();
return (value != null ? value.toString() : "");
}
}

这两个类都比较简单,还有其它的控制器都可以这么做,如SimpleFormController等。
3)直接写一个XSS Filter的过滤器,在期间进行编码,这样更简单,但牺牲性能。

public class CrossScriptingFilter implements Filter {


/* (non-Javadoc)
* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
CrossScriptingRequestWrapper xssRequest = new CrossScriptingRequestWrapper((HttpServletRequest) request);
filterChain.doFilter(xssRequest, response);
}

@Override
public void destroy() {
// TODO Auto-generated method stub
}


@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}

}

 

 

package net.eprow.b2b.web.filter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;

/**
* <code>{@link CrossScriptingRequestWrapper}</code>
*
* @author wqf
*/
public class CrossScriptingRequestWrapper extends HttpServletRequestWrapper {
HttpServletRequest orgRequest = null;

public CrossScriptingRequestWrapper(HttpServletRequest request) {
super(request);
orgRequest = request;
}

/**
* 覆盖getParameter方法,将参数名和参数值都做xss过滤。<br/>
* 如果需要获得原始的值,则通过super.getParameterValues(name)来获取<br/>
* getParameterNames,getParameterValues和getParameterMap也可能需要覆盖
*/
@Override
public String getParameter(String name) {
String value = super.getParameter(xssEncode(name));
if (value != null) {
value = xssEncode(value);
}
return value;
}

public String[] getParameterValues(String parameter) {
String[] values = super.getParameterValues(parameter);
if (values==null) {
return null;
}
int count = values.length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = xssEncode(values[i]);
}
return encodedValues;
}

/**
* 覆盖getHeader方法,将参数名和参数值都做xss过滤。<br/>
* 如果需要获得原始的值,则通过super.getHeaders(name)来获取<br/>
* getHeaderNames 也可能需要覆盖
*/
@Override
public String getHeader(String name) {
String value = super.getHeader(xssEncode(name));
if (value != null) {
value = xssEncode(value);
}
return value;
}

/**
* 将容易引起xss漏洞的半角字符直接替换成全角字符
*
* @param s
* @return
*/
private static String xssEncode(String value) {
if(StringUtils.isBlank(value)) return value;
return StringEscapeUtils.escapeHtml(value);
//或者下面的方法直接过滤特殊字符,但有时候不能这么做。
// value = value.replace('<',' ');
// value = value.replace('>',' ');
// value = value.replace('"',' ');
// value = value.replace('\'',' ');
// value = value.replace('/',' ');
// value = value.replace('%',' ');
// value = value.replace(';',' ');
// value = value.replace('(',' ');
// value = value.replace(')',' ');
// value = value.replace('&',' ');
// value = value.replace('+','_');

//或者直接转换成全角字符,有时候也不适用。
// StringBuilder sb = new StringBuilder(s.length() + 16);
// for (int i = 0; i < s.length(); i++) {
// char c = s.charAt(i);
// switch (c) {
// case '>':
// sb.append('>');//全角大于号
// break;
// case '<':
// sb.append('<');//全角小于号
// break;
// case '\'':
// sb.append('‘');//全角单引号
// break;
// case '\"':
// sb.append('“');//全角双引号
// break;
// case '&':
// sb.append('&');//全角
// break;
// case '\\':
// sb.append('\');//全角斜线
// break;
// case '#':
// sb.append('#');//全角井号
// break;
// default:
// sb.append(c);
// break;
// }
// }
// return sb.toString();
}

/**
* 获取最原始的request
*
* @return
*/
public HttpServletRequest getOrgRequest() {
return orgRequest;
}

/**
* 获取最原始的request的静态方法
*
* @return
*/
public static HttpServletRequest getOrgRequest(HttpServletRequest req) {
if (req instanceof CrossScriptingRequestWrapper) {
return ((CrossScriptingRequestWrapper) req).getOrgRequest();
}
return req;
}

}

 

每二种方式就比较麻烦了,Spring也自带了一些处理方法:
1)web.xml中添加

         <context-param>
<param-name>defaultHtmlEscape</param-name>
<param-value>true</param-value>
</context-param>

 

2)在包含form的jsp页面中添加

<spring:htmlEscape defaultHtmlEscape="true" />

3)直接在form中的元素中添加

<form:input path="someFormField" htmlEscape="true" />

<form:form htmlEscape="true">

4)JSTL输出

<c:out value="${formulario}" escapeXml="true" />默认escapeXml就为true

${fn:escapeXml(param.nextUrl)}


值得注意的是,不要在后台处理的时候进行编码或过滤,因为后台处理需要真实的数据,真正到页面输出的时候才需要做转义。

阅读全文……

标签 : ,

Spring MVC防御CSRF、XSS和SQL注入攻击 - Mainz - 博客园

本文说一下SpringMVC如何防御CSRF(Cross-site request forgery跨站请求伪造)和XSS(Cross site script跨站脚本攻击)。

说说CSRF

CSRF来说,其实Spring3.1ASP.NET MVC3RailsDjango等都已经支持自动在涉及POST的地方添加Token(包括FORM表单和AJAX POST等),似乎是一个tag的事情,但如果了解一些实现原理,手工来处理,也是有好处的。因为其实很多人做web开发,但涉及到web安全方面的都是比较资深的开发人员,很多人安全意识非常薄弱,CSRF是什么根本没有听说过。所以对他们来说,CSRF已经是比较高深的东西了。先说说什么是CSRF?你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......造成的问题包括:个人隐私泄露以及财产安全。CSRF一般都是利用你的已登录已验证的身份来发送恶意请求。比较著名的一个例子就是2009年黑客利用Gmail的一个CSRF漏洞成功获取好莱坞明星Vanessa Hudgens的独家艳照。其攻击过程非常简单,给该明星的gmail账户发了一封email,标题是某大导演邀请你来看看这个电影,里面有个图片:<img src="https://mail.google.com/mail?ui=2&fw=true&[email protected]">,结果她登录Gmail,打开邮件就默默无闻的中招了,所有邮件被转发到黑客的账号。因为当时Gmail设置转发的设置页面有漏洞,其设置方法是打开一个窗口,点击确定后实际URL是https://mail.google.com/mail?ui=2&fw=true&[email protected]:

 

其实即使不是在同一个页面打开,在不同的tab打开也是一样可以通过网站登录验证的,因为受害者首先已经登录了网站,在浏览网站的过程中,若网站设置了Session cookie,那么在浏览器进程的生命周期内,即使浏览器同一个窗口打开了新的tab页面,Session cookie也都是有效的,他们在浏览器同一个窗口的多个tab页面里面是共享的(注:现在Gmail支持多个tab同时持有多个SessionID)。所以攻击步骤是,第一,受害者必须在同一浏览器窗口(即使不是同一tab)内访问并登陆目标站点;第二,这使得Session cookie有效,从而利用受害者的身份进行恶意操作。 

再举个实际的例子,假设我们界面上有删除某一项的链接,例如:<a href="javascript:void(0)" onclick="region_del.do?name=0000001">Delete</a>;

其Java Spring MVC后台有个函数是删除某个item,注意是GET不是POST:

复制代码
@RequestMapping(value = "region_del.do", method = RequestMethod.GET)
public String regionDel(@RequestParam String name, Locale locale)
{
    //Delete region name=@name....
        
    return "redirect:/region.html";
}
复制代码

点击界面上那个<a href="javascript:void(0)" onclick="region_del.do?name=0000001">Delete</a>链接,就后台删除某项,看起来非常正常啊。 

好,现在你登录你的网站,然后在另外一个tab打开这个html文件:

复制代码
<!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" xml:lang="en" lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>hack</title>
</head>
<body>
  <img src="http://localhost/testsite/region_del.do?name=0000001"/>
 </body>
</html>
复制代码

发现同样被删除了某项。试想,如果是网银,你的钱已经被转账......(除了referer不一样,session cookie被利用)

 

好了,现在 后台改成POST(写操作尽量用POST),前台界面那个删除的链接改成Form提交:

<form action="region_del.do" method="POST">
 <input type="hidden" name="name" value="0000001">
        <input type="submit" value="Delete" />
</form>

看起来安全多了。OK,现在你登录你的网站,然后在另外一个tab打开这个html文件:

复制代码
<!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" xml:lang="en" lang="en">
<head>
    <title>Hack</title>
    <script>
      
function steal(){
        
var mySubmit = document.getElementById('steal_form');
        mySubmit.submit();
      }
    
</script>
  </head>
  <body onload='steal()'>
<form id = "steal_form" method="POST" action="http://localhost/testsite/region_del.do">
   <input type="hidden" name="func" value="post">
<input type="hidden" name="name" value="0000001">
</form>
  </body>
</html>
复制代码

 

发现同样被删除了某项。试想,如果是网银,你的钱已经被转账......

当然,你如果前台还是用链接,但改成js,用AJAX POST提交,也是一样的效果:

 

$.ajax({
 type: "POST",
 url:....
});

解决办法就是在Form表单加一个hidden field,里面是服务端生成的足够随机数的一个Token,使得黑客猜不到也无法仿照Token。 

先写一个类,生成足够随机数的Token(注:Java的Random UUID已经足够随机了,参考这个这个) 

复制代码
package com.ibm.cn.web.beans;

import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
* A manager for the CSRF token for a given session. The {
@link #getTokenForSession(HttpSession)} should used to
* obtain the token value for the current session (and this should be the only way to obtain the token value).
* **
*/

public final class CSRFTokenManager {

    /**
     * The token parameter name
     
*/
    static final String CSRF_PARAM_NAME = "CSRFToken";

    /**
     * The location on the session which stores the token
     
*/
    public static final  String CSRF_TOKEN_FOR_SESSION_ATTR_NAME = CSRFTokenManager.class
            .getName() + ".tokenval";

    public static String getTokenForSession(HttpSession session) {
        String token = null;
        
        // I cannot allow more than one token on a session - in the case of two
        
// requests trying to
        
// init the token concurrently
        synchronized (session) {
            token = (String) session
                    .getAttribute(CSRF_TOKEN_FOR_SESSION_ATTR_NAME);
            if (null == token) {
                token = UUID.randomUUID().toString();
                session.setAttribute(CSRF_TOKEN_FOR_SESSION_ATTR_NAME, token);
            }
        }
        return token;
    }

    /**
     * Extracts the token value from the session
     * 
     * 
@param request
     * 
@return
     
*/
    public static String getTokenFromRequest(HttpServletRequest request) {
        return request.getParameter(CSRF_PARAM_NAME);
    }

    private CSRFTokenManager() {
    };

}
复制代码

打开Form页面的时候在服务端生成Token并保存到Session中,例如:model.addAttribute("csrf", CSRFTokenManager.getTokenForSession(this.session));

然后在Form中添加Hidden field: 

<input type="hidden" name="CSRFToken" value="${csrf}" />

然后在后台提交的时候验证token :

 

复制代码
@RequestMapping(value = "region_del.do", method = RequestMethod.GET)
public String regionDel(@RequestParam String name, @RequestParam String CSRFToken, Locale locale)
    {
        if(CSRFToken == null || !CSRFToken.equals(session.getAttribute(CSRFTokenManager.CSRF_TOKEN_FOR_SESSION_ATTR_NAME).toString())){
                logger.debug("CSRF attack detected. URL: region_edit.do");
                return "redirect:/login.form";
        } 
                
    //Delete region name=@name....
        
    return "redirect:/region.html";
}
复制代码

 

你还可以把上面的步骤写到BaseController里面,或者写到拦截器里面,拦截所有POST请求,验证CSRF Token。这里掠过....

如果你用AJAX POST的方法,那么后台一样,前台也要有Hidden field保存Token,然后在提交AJAX POST的时候加上该csrf参数即可。(更多csrf参考这个这个。)

 

AJAX POST的CSRF防御

 

首先在页面进入的时候从后台生成一个Token(每个session),放到一个Hidden input(用Spring tag或freemarker可以写) 。然后在ajax post提交的时候放到http请求的header里面:

复制代码
    var headers = {};
    headers['__RequestVerificationToken'] = $("#CSRFToken").val();
    
    $.ajax({
        type: "POST",
        headers: headers,
        cache: false,
        url: base + "ajax/domain/delete.do",
        data: "id=123",
        dataType:"json",
        async: true,
        error: function(data, error) {},
        success: function(data)
        {
            
        }
    });
复制代码

然后在后台controller里面校验header里面这个token,也可以把这个函数放到baseController里面:

复制代码
protected boolean isValidCsrfHeaderToken() {
        if (getRequest().getHeader("__RequestVerificationToken") == null
                || session
                        .getAttribute(CSRFTokenManager.CSRF_TOKEN_FOR_SESSION_ATTR_NAME) == null
                || !this.getRequest()
                        .getHeader("__RequestVerificationToken")
                        .equals(session
                                .getAttribute(
                                        CSRFTokenManager.CSRF_TOKEN_FOR_SESSION_ATTR_NAME)
                                .toString())) {
            return false;
        }
        return true;
    }
复制代码

 

xss

关于xss的介绍可以看这个这个网页,具体我就讲讲Spring MVC里面的预防:

web.xml加上:

<context-param>
   <param-name>defaultHtmlEscape</param-name>
   <param-value>true</param-value>
</context-param>

Forms加上:

 

<spring:htmlEscape defaultHtmlEscape="true" />

 

更多信息查看OWASP页面

 

第二种方法是手动escape,例如用户可以输入:<script>alert()</script> 或者输入<h2>abc<h2>,如果有异常,显然有xss漏洞。

首先添加一个jar包:commons-lang-2.5.jar ,然后在后台调用这些函数:StringEscapeUtils.escapeHtml(string); StringEscapeUtils.escapeJavaScript(string); StringEscapeUtils.escapeSql(string);

前台js调用escape函数即可。

 

第三种方法是后台加Filter,对每个post请求的参数过滤一些关键字,替换成安全的,例如:< > ' " \ /  # & 

方法是实现一个自定义的HttpServletRequestWrapper,然后在Filter里面调用它,替换掉getParameter函数即可。

首先添加一个XssHttpServletRequestWrapper:

复制代码
package com.ibm.web.beans;

import java.util.Enumeration;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {  
    public XssHttpServletRequestWrapper(HttpServletRequest servletRequest) {
        super(servletRequest);
    }
    public String[] getParameterValues(String parameter) {
      String[] values = super.getParameterValues(parameter);
      if (values==null)  {
                  return null;
          }
      int count = values.length;
      String[] encodedValues = new String[count];
      for (int i = 0; i < count; i++) {
                 encodedValues[i] = cleanXSS(values[i]);
       }
      return encodedValues;
    }
    public String getParameter(String parameter) {
          String value = super.getParameter(parameter);
          if (value == null) {
                 return null;
                  }
          return cleanXSS(value);
    }
    public String getHeader(String name) {
        String value = super.getHeader(name);
        if (value == null)
            return null;
        return cleanXSS(value);
    }
    private String cleanXSS(String value) {
                //You'll need to remove the spaces from the html entities below
        value = value.replaceAll("<", "& lt;").replaceAll(">", "& gt;");
        value = value.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41;");
        value = value.replaceAll("'", "& #39;");
        value = value.replaceAll("eval\\((.*)\\)", "");
        value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
        value = value.replaceAll("script", "");
        return value;
    }

复制代码

然后添加一个过滤器XssFilter :

复制代码
package com.ibm.web.beans;

import java.io.IOException;  

import javax.servlet.Filter;  
import javax.servlet.FilterChain;  
import javax.servlet.FilterConfig;  
import javax.servlet.ServletException;  
import javax.servlet.ServletRequest;  
import javax.servlet.ServletResponse;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;

public class XssFilter implements Filter {
    FilterConfig filterConfig = null;

    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }

    public void destroy() {
        this.filterConfig = null;
    }

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        chain.doFilter(new XssHttpServletRequestWrapper(
                (HttpServletRequest) request), response);
    }
}
复制代码

最后在web.xml里面配置一下,所有的请求的getParameter会被替换,如果参数里面 含有敏感词会被替换掉:

复制代码
  <filter>
     <filter-name>XssSqlFilter</filter-name>
     <filter-class>com.ibm.web.beans.XssFilter</filter-class>
  </filter>
  <filter-mapping>
     <filter-name>XssSqlFilter</filter-name>
     <url-pattern>/*</url-pattern>
     <dispatcher>REQUEST</dispatcher>
  </filter-mapping>
复制代码

 (这个Filter也可以防止SQL注入攻击) 

 

登录页面的攻击例子

假设登录页面有个输入用户名和密码的输入框,可以有很多Xss/csrf/注入钓鱼网站/SQL等的攻击手段,例如:

 

 输入用户名 :    >"'><script>alert(1779)</script>
 输入用户名:     usera>"'><img src="javascript:alert(23664)">
 输入用户名:     "'><IMG SRC="/WF_XSRF.html--end_hig--begin_highlight_tag--hlight_tag--">
 输入用户名:     usera'"><iframe src=http://demo.testfire.net--en--begin_highlight_tag--d_highlight_tag-->

 

 

Web安全漏洞检测工具

推荐使用IBM Rational AppScan(IBM Rational AppScan下载、版权购买和破解、注册码自己解决)

 

可以录制脚本,设置URL,如果网站需要登录,可以设置自动登录:

 

检测结果还可以保持为专业的pdf检测报告 

 

 

业界安全编程标准最佳实践

阅读全文……

标签 : ,

XSS CSRF 攻击 - siqiniao - 博客园

XSS:跨站脚本(Cross-site scripting)

CSRF:跨站请求伪造(Cross-site request forgery)定义:

跨网站脚本Cross-site scripting,通常简称为XSS跨站脚本跨站脚本攻击),为了与层叠样式表(Cascading Style Sheets)区分,故命名为XSS

XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java, VBScript, ActiveX, Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。

 

XSS成因概括 :

 

 
XSS其实就是Html的注入问题,攻击者的输入没有经过严格的控制进入了数据库,最终显示给来访的用户,导致可以在来访用户的浏览器里以浏览用户的身份执行Html代码,数据流程如下:攻击者的Html输入—>web程序—>进入数据库—>web程序—>用户浏览器。

 

检测方法:

//通常有一些方式可以测试网站是否有正确处理特殊字符:

><script>alert(document.cookie)</script>
='><script>alert(document.cookie)</script>
"><script>alert(document.cookie)</script>
<script>alert(document.cookie)</script>
<script>alert(vulnerable)</script>
%3Cscript%3Ealert('XSS')%3C/script%3E
<script>alert('XSS')</script>
<img src="javascript:alert('XSS')">
<img src="http://xxx.com/yyy.png" onerror="alert('XSS')">
<div style="height:expression(alert('XSS'),1)" />(这个仅限 IE 有效)

 

 

攻击手段和目的:

攻击者使被攻击者在浏览器中执行脚本后,如果需要收集来自被攻击者的数据(如cookie或其他敏感信息),可以自行架设一个网站,让被攻击者通过JavaScript等方式把收集好的数据作为参数提交,随后以数据库等形式记录在攻击者自己的服务器上。 

a. 盗用 cookie ,获取敏感信息。

b.利用植入 Flash ,通过 crossdomain 权限设置进一步获取更高权限;或者利用Java等得到类似的操作。 

c.利用 iframe、frame、XMLHttpRequest或上述Flash等方式,以(被攻击)用户的身份执行一些管理动作,或执行一些一般的如发微博、加好友、发私信等操作。 

d.利用可被攻击的域受到其他域信任的特点,以受信任来源的身份请求一些平时不允许的操作,如进行不当的投票活动。

  e.在访问量极大的一些页面上的XSS可以攻击一些小型网站,实现DDoS攻击的效果。

 

漏洞的防御和利用:

避免XSS的方法之一主要是将用户所提供的内容进行过滤,许多语言都有提供对HTML的过滤:
PHP的htmlentities()或是htmlspecialchars()。
Python的cgi.escape()。
ASP的Server.HTMLEncode()。
ASP.NET的Server.HtmlEncode()或功能更强的Microsoft Anti-Cross Site Scripting Library
Java的xssprotect(Open Source Library)。

Node.js的node-validator。 

 

使用HTTP头指定类型:

很多时候可以使用HTTP头指定内容的类型,使得输出的内容避免被作为HTML解析。如在PHP语言中使用以下代码: 

  header('Content-Type: text/javascript; charset=utf-8');

 即可强行指定输出内容为文本/JavaScript脚本(顺便指定了内容编码),而非可以引发攻击的HTML。

 

CSRF:冒充用户之手:

XSS:跨站脚本(Cross-site scripting)

CSRF:跨站请求伪造(Cross-site request forgery)

示意图:

 图片引用来源:http://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html

XSS 是实现 CSRF 的诸多途径中的一条,但绝对不是唯一的一条。一般习惯上把通过 XSS 来实现的 CSRF 称为 XSRF。

CSRF 顾名思义,是伪造请求冒充用户在站内的正常操作。我们知道,绝大多数网站是通过 cookie 等方式辨识用户身份(包括使用服务器端 Session 的网站,因为 Session ID 也是大多保存在 cookie 里面的),再予以授权的。所以要伪造用户的正常操作,最好的方法是通过 XSS 或链接欺骗等途径,让用户在本机(即拥有身份 cookie 的浏览器端)发起用户所不知道的请求。 

请求令牌(一种简单有效的防御方法):

首先服务器端要以某种策略生成随机字符串,作为令牌(token),保存在 Session 里。然后在发出请求的页面,把该令牌以隐藏域一类的形式,与其他信息一并发出。在接收请求的页面,把接收到的信息中的令牌与 Session 中的令牌比较,只有一致的时候才处理请求,处理完成后清理session中的值,否则返回 HTTP 403 拒绝请求或者要求用户重新登陆验证身份 

 

令牌来防止 CSRF 有以下几点要注意:

a.虽然请求令牌原理和验证码有相似之处,但不应该像验证码一样,全局使用一个 Session Key。因为请求令牌的方法在理论上是可破解的,破解方式是解析来源页面的文本,获取令牌内容。如果全局使用一个 Session Key,那么危险系数会上升。原则上来说,每个页面的请求令牌都应该放在独立的 Session Key 中。我们在设计服务器端的时候,可以稍加封装,编写一个令牌工具包,将页面的标识作为 Session 中保存令牌的键。

b.在 ajax 技术应用较多的场合,因为很有请求是 JavaScript 发起的,使用静态的模版输出令牌值或多或少有些不方便。但无论如何,请不要提供直接获取令牌值的 API。这么做无疑是锁上了大门,却又把钥匙放在门口,让我们的请求令牌退化为同步令牌。

c.第一点说了请求令牌理论上是可破解的,所以非常重要的场合,应该考虑使用验证码(令牌的一种升级,目前来看破解难度极大),或者要求用户再次输入密码(亚马逊、淘宝的做法)。但这两种方式用户体验都不好,所以需要产品开发者权衡。

d.无论是普通的请求令牌还是验证码,服务器端验证过一定记得销毁。忘记销毁用过的令牌是个很低级但是杀伤力很大的错误。我们学校的选课系统就有这个问题,验证码用完并未销毁,故只要获取一次验证码图片,其中的验证码可以在多次请求中使用(只要不再次刷新验证码图片),一直用到 

如下也列出一些据说能有效防范 CSRF,其实效果甚微或甚至无效的做法:

a.通过 referer 判定来源页面:referer 是在 HTTP Request Head 里面的,也就是由请求的发送者决定的。如果我喜欢,可以给 referer 任何值。当然这个做法并不是毫无作用,起码可以防小白。但我觉得性价比不如令牌。

b.过滤所有用户发布的链接:这个是最无效的做法,因为首先攻击者不一定要从站内发起请求(上面提到过了),而且就算从站内发起请求,途径也远远不知链接一条。比如 <img src="./create_post.php" /> 就是个不错的选择,还不需要用户去点击,只要用户的浏览器会自动加载图片,就会自动发起请求。

c.在请求发起页面用 alert 弹窗提醒用户:这个方法看上去能干扰站外通过 iframe 发起的 CSRF,但攻击者也可以考虑用 window.alert = function(){}; 把 alert 弄哑,或者干脆脱离 iframe,使用 Flash 来达到目的。 

 

阅读全文……

标签 : ,

如何修改浏览器Cookie | 开心e点

网站通过 Cookie 保存了我们访问网站的信息,在不同的浏览器中修改 Cookie 可以如下操作:

Firefox:
安装 Web Developer 插件,装完重启之后会出现一排新的工具栏,点击 Cookies -> Add Cookie… 即可增加/修改一个Cookie了。

Opera:
Opera 可以在 菜单 -> 工具 -> 高级 -> Cookie… 对话框中找到当前的页面的 Cookie 项,选中以后点“编辑…”即可修改。如果修改不成功的话,有可能是因为启用了 Opera Turbo 加速器导致的,可以检查 菜单 -> 工具 -> 快速参数(F12) -> 启动Opera Turbo 是否开启,如开启着的话,把它关闭以后再试试是不是可以了。

Chrome:
安装 Edit This Cookie 插件,之后点击插件图标即可操作 Cookie。

IE:
可以用 IECookiesView 碰碰运气,如果有其他更好的办法也请告知。

除上述工具之外,免费工具Fiddler 和商业软件 HttpWatch 可以通过设置断点,跨浏览器调试所有的 HTTP(S)流量,很好很强大。只是需要写脚本,就改 Cookie 这个功能没有上述专门的工具来的方便,有杀鸡用牛刀之嫌。

 

阅读全文……

Fiddler (二) Script 用法 - 小坦克 - 博客园

Fiddler 包含了一个脚本文件可以自动修改Http Request 和Response.这样我们就不需要手动地下"断点"去修改了,

实际上它是一个脚本文件CustomRules.js 

位于: C:\Documents and Settings\[your user]\My Documents\Fiddler2\Scripts\CustomRules.js 下

你也可以在Fiddler 中打开CustomRules.js 文件,  启动Fiddler, 点击菜单Rules->Customize Rules...

Fiddler Script 的官方帮助文档必须认真阅读, 地址是:http://www.fiddler2.com/Fiddler/dev/ScriptSamples.asp

 

如何在Fiddler Script中修改Cookie

cookie其实就是request 中的一个header.

// 删除所有的cookie

oSession.oRequest.headers.Remove("Cookie");

 

// 新建cookie

oSession.oRequest.headers.Add("Cookie", "username=testname;testpassword=P@ssword1");


注意: Fiddler script不能直接删除或者编辑单独的一个cookie, 你需要用replace方法或者正则表达式的方法去操作cookie的string

复制代码
static function OnBeforeRequest(oSession: Session)  {       if (oSession.HostnameIs('www.example.com') &&            oSession.uriContains('pagewithCookie') &&  oSession.oRequest.headers.Contains("Cookie"))       {        var sCookie = oSession.oRequest["Cookie"];        //  用replace方法或者正则表达式的方法去操作cookie的string
     sCookie = sCookie.Replace("cookieName=", "ignoreme=");        oSession.oRequest["Cookie"] = sCookie;      } 
复制代码

 

阅读全文……

JavaScript性能优化的30个技巧

Tip #1 – Evaluate Local Variables

(http://blogs.msdn.com/b/ie/archive/2006/08/28/728654.aspx)

Primarily, specific to IE, because local variables are found based on the most to the least specific scope and can pass through multiple levels of scope, the look-ups can result in generic queries. When defining the function scope, within a local variable without a preceding var declaration, it is important to precede each variable with var in order to define the current scope in order to prevent the look-up and to speed up the code.

Tip #2 – Create shortcut codes to speed up coding

(http://www.spoonfeddesign.com/4-easy-tips-to-improve-javascript-efficiency)

For useful codes that are constantly being used, speeding up the coding process can be achieved by creating shortcuts for longer codes, for example, document.getElementById. By creating a shortcut, longer scripts will not take as long to code and will save time in the overall process.

Tip #3 –Manipulate element fragments before adding them to DOM

(http://www.jquery4u.com/dom-modification/improve-javascript-performance)

Before placing the elements to the DOM, ensure that all tweaks have been performed in order to improve JavaScript performance. This will eliminate the need to set aside Prepend or Append jQuery APIs.

Tip #4 – Save bytes by using Minification

(http://sixrevisions.com/web-development/10-ways-to-improve-your-web-page-performance)

Reduce the file size of your JavaScript documents by removing characters (tabs, source code documents, spaces etc.) without changing the functionality of the file.

There are a number of minification tools that can assist in this process, and have the ability to reverse the minification. Minification is the process of removing all unnecessary characters from source code, without changing its functionality.

Tip #5 –Don’t use nested loops if not required

(http://www.techstrut.com/2009/08/04/10-javascript-performance-tips)

Avoid unwanted loops, such as for/while, in order to keep the JavaScript linear and to prevent from having to go through thousands of objects. Unwanted loops can cause the browser to work harder to process the codes and can slow down the process.

Tip #6 – Cache objects to increase performance

(http://www.techstrut.com/2009/08/04/10-javascript-performance-tips)

Many times, scripts will be repeatedly used to access a certain object. By storing a repeated access object inside a user defined variable, as well as using a variable in subsequent references to that object, performance improvement can be achieved immediately.

Tip #7 – Use a .js file to cache scripts

(http://www.javascriptkit.com/javatutors/efficientjs.shtml)

By using this technique, increased performance can be achieved because it allows the browser to load the script once and will only recall it from cache should the page be reloaded or revisited.

Tip #8 – Place JavaScript at the bottom of the page

(http://developer.yahoo.com/blogs/ydn/posts/2007/07/high_performanc_5)

Placing the scripts as low as possible in the page will increase the rendering progress, and also increase download parallelization. The result is that the page will seem to load faster, and in some cases it can also save on the total amount of code needed.

Tip #9 – Use jQuery as a framework

(http://www.techstrut.com/2009/08/04/10-javascript-performance-tips)

Used for the scripting of HTML, jQuery is an easy to use JavaScript library that can help to speed up any website. jQuery provides a large number of plug-ins that can quickly be used, by even novice programmers.

Tip #10 – Compress your files with GZip

(http://devmoose.com/coding/10-ways-to-instantly-speed-up-your-website)

GZip can reduce a JavaScript file considerably, saving bandwidth, and accelerate the response time. JavaScript files can be very large, and without compression, it can bog down any website. Smaller files provide a faster and more satisfying web experience.

Tip #11- Don’t use “With” keyword

(http://blogs.msdn.com/b/ie/archive/2006/08/28/728654.aspx)

The “With” keyword is considered a black-sheep because it suffers from several flaws that can be very frustrating. Although it makes the process of working with local properties simpler, “With” can make looking up variables in other scopes more expensive.

Tip #12 – Minimize requests for HTTP

(http://www.websiteoptimization.com/speed/tweak/http)

Minimize HTTP requests to render pages by combining external files and including JavaScript directly within XHTML pages. Each time a unique HTTP takes a trip to a server, the result is a large number of delays.

Tip #13 – Implement Event Delegation

(http://www.djavaweb.com/blog/75-speed-up-your-webdevelop-smart-event-handlers.html)

With Event Delegation, it becomes easier to use a single event handler to manage a type of event for the entire page. Without using Event Delegation, large web applications can grind to a halt because of too many event handlers. Benefits of Event Delegation include; less functionality to manage, fewer ties between code and DOM, and less memory required to process.

Tip #14 – Don’t use the same script twice

(http://www.abhishekbharadwaj.com/2010/12/speed-up-your-website-avoid-duplicate-scripts)

Duplicate scripts will have a significant impact on performance. Duplicate scripts will create unnecessary requests on HTTP, especially in the IE browser. Using a SCRIPT tag, in an HTML page, will help to avoid accidentally duplicating scripts.

Tip #15 – Remove Double Dollar $$

(http://www.mellowmorning.com/2008/05/18/javascript-optimization-high-performance-js-apps)

Using “double dollar $$” function is not necessarily needed, when it comes to improving the speed of a website.

Tip #16 – Creating reference variables

(http://mondaybynoon.com/2009/04/27/a-couple-of-quick-tips-for-javascript-optimization)

When working with a specific node repeatedly, it is best to define a variable with that particular note, instead of switching to it repeatedly. This is not a significant enhancement but it can have a bigger impact on a large scale.

Tip #17 – Increase speed of Object Detection

(http://dean.edwards.name/weblog/2005/12/js-tip1)

A more efficient method to using Object Detection is to use a code created dynamically based off of object detection, rather than performing object detection inside of a function.

Tip #18 – Write effective Loops

(http://robertnyman.com/2008/04/11/javascript-loop-performance)

Depending on the browser, the method used to write Loops can have a great effect on the performance of a site. Improper writing of loops can slow down pages with lots of queries and running a number of loops in parallel.

Tip #19 – Shorten Scope Chains

(http://homepage.mac.com/rue/JS_Optimization_Techniques)

Global scopes can be slow, because each time a function executes, it cause a temporary calling scope to be created. JavaScript searchers for the first item in the scope chain, and if it doesn’t find the variable, it swells up the chain until it hits the global object.

Tip #20 – Index directly to NodeLists

(http://homepage.mac.com/rue/JS_Optimization_Techniques)

NodeLists are live and can take up a lot of memory, as they are updated when an underlying document changes. Its quicker to index directly into a list, as a browser will not need to create a node list object.

Tip #21 – Don’t use ‘eval’

(http://www.javascripttoolbox.com/bestpractices/#eval)

Although the “eval” function is a good method to run arbitrary code, each string that is passed to the eval function has to be parsed and executed on-the-fly. This cost has to be paid every time the execution reaches an eval function call.

Tip #22 – Use Function Inlining

(http://portal.acm.org/citation.cfm?id=844097)

Function Inlining helps to eliminate call costs, and replaces a function call with the body of the called function. In JavaScript, performing a function call is an expensive operation because it takes several preparatory steps to perform: allocating space for parameters, copying the parameters, and resolving the function name.

Tip #23 – Implement Common Sub-expression Elimination (CSE)

(http://sunilkumarn.wordpress.com/2010/10/19/common-subexpression-elimination-cse)

Common sub-expression elimination (CSE) is a performance-targeted compiler optimization technique that searches for instances of identical expressions and replaces them with a single variable holding the computed value. You can expect that using a single local variable for a common sub-expression will always be faster than leaving the code unchanged.

Tip #24 – Build DOM node and all its sub-nodes offline

(http://archive.devwebpro.com/devwebpro-39-0030514OptimizingJavaScriptforExecutionSpeed.html)

When adding complex content such as tables to a site, performance is improved by adding complex sub-trees offline.

Tip #25 – Try not to use global variables

(http://wiki.forum.nokia.com/index.php/JavaScript_Performance_Best_Practices#JavaScript_Performace_Best_Practices)

Because the scripting engine needs to look through the scope, when referencing global variables from within function or another scope, the variable will be destroyed when the local scope is lost. If variables in global scope cannot persist through the lifetime of the script, the performance will be improved.

Tip #26 – Use primitive functions operations vs. function calls

(http://wiki.forum.nokia.com/index.php/JavaScript_Performance_Best_Practices#JavaScript_Performace_Best_Practices)

Improved speed can be achieved in performance critical loops and functions by using equivalent primitive functions instead of function calls.

Tip #27 – Don’t retain alive references of other documents

(http://dev.opera.com/articles/view/efficient-javascript/?page=4#docreferences)

By not retaining alive references of other documents after the script has finished with them, faster performance will be achieved. This is because any references to those objects from that document are not to be kept in its entire DOM tree, and the scripting environment will not be kept alive in RAM. Thus the document itself is no longer loaded.

Tip #28 – Use XMLHttpRequest

(http://dev.opera.com/articles/view/efficient-javascript/?page=4#docreferences)

XMLHttpRequest helps to reduce the amount of content coming from the server, and avoids the performance impact of destroying and recreating the scripting environment in between page loads. Its is important to ensure that XMLHttpRequest is supported, or otherwise it can lead to problems and confusion.

Tip #29 – Avoid using try-catch-finally

(http://dev.opera.com/articles/view/efficient-javascript/?page=2)

Whenever the catch clause is executed, where the caught exception object is assigned to a variable, “try-catch-finally” creates a new variable in the current scope at runtime. A number of browsers do not handle this process efficiently because the variable is created and destroyed at runtime. Avoid it!

Tip #30 – Don’t misuse for-in

(http://dev.opera.com/articles/view/efficient-javascript/?page=2)

Because the “for-in” loop requires the script engine to build a list of all the enumerable properties, coding inside for loop does not modify the array. It iterates pre-compute the length of the array into a variable len inside for loop scope.

阅读全文……

回流与重绘:CSS性能让JavaScript变慢? « 张鑫旭-鑫空间-鑫生活

关于回流(reflows)与重绘(repaints),我已经在twitterdelicious上发布,但是并没有在演讲中提到或是以文章形式发布。

第一次让我开始思考关于回流(reflows)与重绘(repaints)的问题是在和ParisWeb上的Mr. Glazman做一个firey交换的时候。我可能有一些顽固,但是我确实听了他的一些理论。:)Stoyan和我开始讨论如何量化这个问题。

展望性能社区,除了一些典型的黑盒实验外,需要与浏览器厂商有更多的合作。对于性能,浏览器制造者知道哪些是重要的,哪些是不相干的。Opera列出“reflow和repaint是减缓JavaScript的三大主要原因之一”一文,所以其肯定值得一看。// zxx: Firefox浏览器相关内容可以看这里;Safari可以看这里

让我们从一些背景资料开始,当一个元素的外观的可见性visibility发生改变的时候,重绘(repaint)也随之发生,但是不影响布局。类似的例子包括:outline, visibility, or background color。根据Opera浏览器,重绘的代价是高昂的,因为浏览器必须验证DOM树上其他节点元素的可见性。而回流更是性能的关键因为其变化涉及到部分页面(或是整个页面)的布局。一个元素的回流导致了其所有子元素以及DOM中紧随其后的祖先元素的随后的回流。

 

例如:

<body>
<div class="error">
	<h4>我的组件</h4>
	<p><strong>错误:</strong>错误的描述…</p>
	<h5>错误纠正</h5>
	<ol>
		<li>第一步</li>
		<li>第二步</li>
	</ol>
</div>
</body>

在上面的HTML片段中,对该段落(<p>标签)回流将会引发强烈的回流,因为它是一个子节点。这也导致了祖先的回流(div.error和body – 视浏览器而定)。此外,h5和ol也会有简单的回流,因为其在DOM中在回流元素之后。就Opera而言,大部分的回流将导致页面的重新渲染。

Opera原文:Reflows are very expensive in terms of performance, and is one of the main causes of slow DOM scripts, especially on devices with low processing power, such as phones. In many cases, they are equivalent to laying out the entire page again.

既然它们对性能影响如此可怕,那什么会导致回流呢?

不幸的是,很多的东西,其中一些还与CSS的书写特别相关。

  1. 调整窗口大小(Resizing the window)
  2. 改变字体(Changing the font)
  3. 增加或者移除样式表(Adding or removing a stylesheet)
  4. 内容变化,比如用户在input框中输入文字(Content changes, such as a user typing text in
    an input box)
  5. 激活 CSS 伪类,比如 :hover (IE 中为兄弟结点伪类的激活)(Activation of CSS pseudo classes such as :hover (in IE the activation of the pseudo class of a sibling))
  6. 操作 class 属性(Manipulating the class attribute)
  7. 脚本操作 DOM(A script manipulating the DOM)
  8. 计算 offsetWidth 和 offsetHeight 属性(Calculating offsetWidth and offsetHeight)
  9. 设置 style 属性的值 (Setting a property of the style attribute)

Mozilla关于回流的文章罗列了导致回流的要点以及何时可以减少他们。

如何避免回流或将它们对性能的影响降到最低?

注意:这里我限定了自己只能讨论CSS对回流的影响,如果您是一位JavaScript程序员,我是推荐您读一下我的reflow链接(zxx: 原作者收藏标记的一些关于reflow的一些文章或页面链接),有一些非常好的东西,没有直接关系到CSS。

  1. 如果想设定元素的样式,通过改变元素的 class 名 (尽可能在 DOM 树的最末端)(Change classes on the element you wish to style (as low in the dom tree as possible))
  2. 避免设置多项内联样式(Avoid setting multiple inline styles)
  3. 应用元素的动画,使用 position 属性的 fixed 值或 absolute 值(Apply animations to elements that are position fixed or absolute)
  4. 权衡平滑和速度(Trade smoothness for speed)
  5. 避免使用table布局(Avoid tables for layout)
  6. 避免使用CSS的JavaScript表达式 (仅 IE 浏览器)(Avoid JavaScript expressions in the CSS (IE only))

 

尽可能在DOM树的最末端改变class

 

回流可以自上而下,或自下而上的回流的信息传递给周围的节点。回流是不可避免的,但可以减少其影响。尽可能在DOM树的里面改变class,可以限制了回流的范围,使其影响尽可能少的节点。例如,你应该避免通过改变对包装元素类去影响子节点的显示。面向对象的CSS始终尝试获得它们影响的类对象(DOM节点或节点),但在这种情况下,它已尽可能的减少了回流的影响,增加性能优势。

 

避免设置多层内联样式

 

我们都知道与DOM交互很慢。我们尝试在一种无形的DOM树片段组进行更改,然后整个改变应用到DOM上时仅导致了一个回流。同样,通过style属性设置样式导致回流。避免设置多级内联样式,因为每个都会造成回流,样式应该合并在一个外部类,这样当该元素的class属性可被操控时仅会产生一个reflow。

 

动画效果应用到position属性为absolute或fixed的元素上

 

动画效果应用到position属性为absolute或fixed的元素上,它们不影响其他元素的布局,所它他们只会导致重新绘制,而不是一个完整回流。这样消耗会更低。

牺牲平滑度换取速度

Opera还建议我们牺牲平滑度换取速度,其意思是指您可能想每次1像素移动一个动画,但是如果此动画及随后的回流使用了100%的CPU,动画就会看上去是跳动的,因为浏览器正在与更新回流做斗争。动画元素每次移动3像素可能在非常快的机器上看起来平滑度低了,但它不会导致CPU在较慢的机器和移动设备中抖动。

避免使用table布局

避免使用table布局。可能您需要其它些避免使用table的理由,在布局完全建立之前,table经常需要多个关口,因为table是个和罕见的可以影响在它们之前已经进入的DOM元素的显示的元素。想象一下,因为表格最后一个单元格的内容过宽而导致纵列大小完全改变。这就是为什么所有的浏览器都逐步地不支持table表格的渲染(感谢Bill Scott提供)。然而有另外一个原因为什么表格布局时很糟糕的主意,根据Mozilla,即使一些小的变化将导致表格(table)中的所有其他节点回流。

Jenny Donnelly, YUI 数据表格 widget的所有者,建议使用数据表格的固定布局以便更有效的布局算法,任何表格-布局的值除了”auto”将引发一个固定布局,根据CSS2.1规范,这将允许表格一行一行的呈递。Quirksmode显示,大部分的浏览器对表格布局属性支持良好。

In this manner, the user agent can begin to lay out the table once the entire first row has been received. Cells in subsequent rows do not affect column widths. Any cell that has content that overflows uses the ‘overflow’ property to determine whether to clip the overflow content.

固定布局, CSS 2.1 规范

This algorithm may be inefficient since it requires the user agent to have access to all the content in the table before determining the final layout and may demand more than one pass.

自动布局, CSS 2.1 规范

避免使用CSS的JavaScript表达式

这项规则较过时,但确实是个好的主意。主要的原因,这些表现是如此昂贵,是因为他们每次重新计算文档,或部分文档、回流。正如我们从所有的很多事情看到的:引发回流,它可以每秒产生成千上万次。当心!

进一步的学习

Yahoo!出色的性能团队做了一个实验,以确定最佳的方法引入外部的样式表文件。我们建议把链接标记放在头部,尽管其比所有其他阻碍进一步渲染的方法慢一秒(6.3至7.3秒)。虽然逐步地渲染不可改变的(用户讨厌盯着一个空白屏幕),但它使我对下载组件和整体响应时间的渲染,重画,回流和CPU的颠簸造成的影响感到好奇。如果我们可以减少加载过程中的回流个数我们可以夺回了失去的时间的十分之一(100毫秒)吗?如果它是多达一半呢?

在SXSW我试图说服史蒂夫的回流是很重要的。我告诉他一个我已经做了很长一段时间的实验,只是没有时间。我希望有人能在我留下来的那个地方继续(提示!提示!)。虽然加载页面我想故意引发不同程度的回流。这或许可以通过切换一个body(实验)标签的class名称来改变body的最后一个child(没有子节点)完成。比较这两者情况,并增加每秒回流的数目,我们可以关联回流反应时间。衡量JS反应对回流的影响将会更难,因为我们所做能够引发回流的事情都可能会影响实验。

最后,量化影响的趣味只有那么一点点,因为浏览器厂商会告诉我们它的问题。或许更有趣的是把注意力集中在回流的原因以及如何避免它们。这将需要更好的工具,所以我需要浏览器厂商和性能社区共同努力,使之成为现实!

事实说话

也许你是一个视觉关注者,这些视频通过很酷的方式将回流过程可视化展示出来。//zxx: youtube视频,想看,需翻墙。

  1. http://www.youtube.com/watch?v=nJtBUHyNBxs
  2. http://www.youtube.com/watch?v=ZTnIxIA5KGw
  3. http://www.youtube.com/watch?v=dndeRnzkJDU

回流消失的疯狂

为了改进性能,浏览器厂商可能限制回流影响临近的节点或者联合其他几个回流形成一次大的改变,就如Mozilla的这篇文章中展示的。这可以提高性能,但有时也可能导致显示问题。您可以使用我们所了解到的关于回流的知识,在必要纠正相关显示问题的时候触发它们。

例如,我们改变图片优化网站上的选项卡,http://smush.it,随着选项卡的不同,内容区域的高度是不断变化的,有时候,下面的投影会被留下,这是因为内容区域上的父节点被切换而其容器可能没有回流,下面这张图是模拟的,因为这个bug很难用相机捕捉,任何试图获取操作都会导致回流而纠正显示。如果你自己发现类似的bug,移动背景图片到下面切换的DOM元素上。

模拟图 >> 张鑫旭-鑫空间-鑫生活

另外一个例子是动态添加列表项,当您将列表项从9个增加到10个或是从99个增加到100个,列表的数字将不会正确的排队显示,这在所有浏览器都是。当总数按数量的顺序增加且浏览器不回流兄弟节点时,队列被打破。快速切换整个列表的显示或是增加添加一个class类,即使没有相关联的样式,也会导致回流和正确的队列显示。

工具

最近有小部分工具产生了一些波澜,Stoyan Stefanov和我已经一直在寻找好的方法来测量回流与重绘,这里有一些(尽管比较早)。要当心,有的在我正确使用之前把浏览器给搞跛了。大部分情况下,你需要每晚安装下最新的版本。

当Mozilla公开MozAfterPaint Firefox API时,互联网界议论纷纷。

  • 更新:Google的Lindsey Simon写了个可以在任意浏览器下测试回流时间的书签工具。非常的赞,注意:所有的震动都是正常的。//zxx: 我测试此链接为500错误
  • John Resig写了个书签工具来可视化绘制事件。
  • Kyle Scholz创建了一个工具用来在页面加载之前可视化绘制事件
  • Yoono的Alex创建了XUL分析工具

是否其他人见到过好的关于回流评估的工具?请发送告知我。

还有其他一对不是直接用来处理回流的工具。

最后,我们需要一个跨浏览器的工具来量化并减少回流和重绘。我希望性能社区能够与浏览器厂商合作,使这一工具成为现实。浏览器厂商已经告诉我们有一段时间了,这是我们未来需要看到的,希望在我们手中。

阅读全文……

标签 : , ,

JVM GC日志和内存DUMP参数配置 - Java实践 - ITeye技术网站

在JVM出现内存溢出或泄露时,为便于排查和定位,需要JVM的启动上增加相应的参数。主要是GC日志和内存DUMP参数。详细如下。 
1.GC日志和内存DUMP参数配置 
    
    本文参数配置基于各厂商的JDK 6.0版本,低版本或高版本的参数有可能不同。各厂商JVM GC日志和内存DUMP参数配置如下: 
(1)Oracle  JVM
-Xloggc:${目录}/managed1_gc.log 
-XX:+HeapDumpOnOutOfMemoryError 
-XX:HeapDumpPath=${目录} 
(2)HP JVM
-Xverbosegc:file=${目录}/mananged1_gc.log 
-XX:+HeapDumpOnOutOfMemoryError  -XX:+HeapDumpOnCtrlBreak   
-XX:HeapDumpPath=${目录} 
(3)IBM JVM 
-XverboseGClog: ${目录}/mananged1_gc.log 
-Xdump:heap:events=user,file=${目录}/pid%uid%pid.phd 

阅读全文……

标签 :

电信/联通 三户关系模型 - abc123def - 博客园

三户关系

 

2.1.4.1. 三户模型联通总部营业系统定义了以客户,用户,帐户为主的三户模型

三户的关系如图:
 
客户、帐户与用户。它将客户的基本信息,客户消费的信息和与运营商某个业务的契约信息分开。
这三者之间的关系可以想象成是一棵树,客户位于树的根部,帐户在中间,用户是第三层叶节点。一个客户拥有多个帐户,一个帐户下可以有多个用户,用户是最细的单位,在经营分析中,目前的统计分析大多都是针对用户进行统计,但是由于术语定义的不严格,在很多场合下,将客户和用户混为一谈,例如经常说的客户数通常是用户数(不是绝对),用户级别其实是客户级别。

2.1.4.2. 用户
 用户是系统的基础。
在营业系统中,用户对应的就是业务号码(即手机号码),也就是说一个号码对应一个用户。用户包含于客户,一个客户可能有多个用户,用户和帐户通过帐务关系对应,一个帐户也可能有多个用户。一个用户有一个私人帐户和一个集团帐户。
由于用户有可能被销户,手机号码在冻结一段时间以后重新拿出来使用,因此目前也存在一个手机号码对应多个用户的情况,但是同时有效在使用的,只有一个用户。
一个用户通过唯一的用户标识来确定。
用户信息描述一个用户使用联通业务的业务信息,用户信息里面存放和业务相关的信息,包括手机号码,开户时间,开户地点,所选套餐,用户状态,用户类型,用户级别,用户停机时间,用户销户时间等等和使用联通业务相关的信息,只有使用联通业务,才存在用户信息。
当一个客户入网时,例如选定CDMA业务,一般情况下会为这个客户建立一套三户关系,当然如果一个客户申请一项新业务,例如193长途,如果想用已有的帐户缴费,可以只需建一个新用户,如果它想在另一个帐户缴费,则再建一个新的帐户。在客户信息,我们关注的信息是客户类型、客户级别、性别、年龄、职业等。在帐户中,我们通常关注的是帐户的缴费类型、预存款等,用户入网时可以首先指定他是用现金缴费还是银行代扣等信息,对于银行代扣等类型,还记录银行名称、帐号等。用户信息中,有用户的手机号、服务状态、入网时间、是否有效等契约信息。
关于用户,还有一个子业务信息,或称特服,例如来电显示、移动秘书台、三方通话,这些信息表明该用户除了基本的通话功能外,还有哪些特殊的服务,它们通常和服务属性存储在一块(其实特服本身就是一种服务属性),例如漫游级别、长途级别等。有的系统通过掩码来表明用户订购了哪些特服或是哪些服务属性(如东软、神码的营帐),有的是通过单独的表来维护用户开通了哪些特服(如亚信的营帐)。
2.1.4.3. 客户
客户可分为个人客户,单位客户,集团客户。一个客户可以包含多个用户,客户通过唯一的客户标识来确定。
客户描述一个客户的自然属性,客户可以和用户一一对应,也可以和用户一对多。即使不使用联通业务,也可能存在客户,因为客户是自然存在的。
客户信息包含客户名,地址,邮政编码,性别,年龄,职业,证件号码等等信息,是自然存在的信息。
2.1.4.4. 帐户
帐户是用户缴费的依据,用户的费用信息是与帐户对应的。一个用户可以对应多个帐户,一个帐户也可能由多个用户使用。
在用户进行缴费,充值,消费,销帐的时候,所依据的标识是帐户标识。

阅读全文……

标签 : ,

cxf学习笔记之传递附件 - ll_feng - ITeye技术网站

注意事项 
1、服务端和客户端的数据对象中,用来存储附件的属性都要用“@XmlMimeType("application/octet-stream")”进行注解,如下: 
Java代码  收藏代码
  1. @XmlMimeType("application/octet-stream")  
  2. private DataHandler photo;  


2、服务端和客户端的web服务配置都要声明mtom-enabled=true 
服务端如果在spring中配置,如下: 
Java代码  收藏代码
  1. <jaxws:endpoint id="register"  implementor="cn.ibeans.ws.impl.RegisterWebServiceImpl" address="/ws/register">  
  2.     <jaxws:properties>  
  3.         <entry key="mtom-enabled" value="true"/>    
  4.     </jaxws:properties>  
  5. </jaxws:endpoint>  


客户端,如果用代码配置(也可用spring配置,类似服务端),如下: 
Java代码  收藏代码
  1. Map<String,Object> map = new HashMap<String,Object>();  
  2. map.put("mtom-enabled"true);  
  3. factory = new JaxWsProxyFactoryBean();  
  4. factory.setProperties(map);  

 

 

 

阅读全文……

标签 :

3 ways to read files using Java NIO | How to do in JAVA

New I/O, usually called NIO, is a collection of APIs that offer additional capabilities for intensive I/O operations. It was introduced with the Java 1.4 release by Sun Microsystems to complement an existing standard I/O. The extended NIO that offers further new file system APIs, called NIO2, was released with Java SE 7 (“Dolphin”).

NIO related questions are very popular in java interviews now-a-days.

NIO2 provides two major methods of reading a file:

  • Using buffer and channel classes
  • Using Path and Files classes

In this post, I am showing a couple of ways to read a file from file system. So lets start them by first showing old famous approach first, so that we can see what really changed.

Old famous I/O way

This example shows how we have been reading a text file using old I/O library APIs. It uses a BufferedReader object for reading. Another way can be using InputStream implementation.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.howtodoinjava.test.nio;
 
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
 
public class WithoutNIOExample
{
    public static void main(String[] args)
    {
        BufferedReader br = null;
        String sCurrentLine = null;
        try
        {
            br = new BufferedReader(
            new FileReader("test.txt"));
            while ((sCurrentLine = br.readLine()) != null)
            {
                System.out.println(sCurrentLine);
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                if (br != null)
                br.close();
            } catch (IOException ex)
            {
                ex.printStackTrace();
            }
        }
    }
}

1) Read a small file in buffer of file size

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.howtodoinjava.test.nio;
 
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
 
public class ReadFileWithFileSizeBuffer
{
    public static void main(String args[])
    {
        try
        {
            RandomAccessFile aFile = new RandomAccessFile(
                            "test.txt","r");
            FileChannel inChannel = aFile.getChannel();
            long fileSize = inChannel.size();
            ByteBuffer buffer = ByteBuffer.allocate((int) fileSize);
            inChannel.read(buffer);
            buffer.rewind();
            buffer.flip();
            for (int i = 0; i < fileSize; i++)
            {
                System.out.print((char) buffer.get());
            }
            inChannel.close();
            aFile.close();
        }
        catch (IOException exc)
        {
            System.out.println(exc);
            System.exit(1);
        }
    }
}

2) Read a large file in chunks with fixed size buffer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.howtodoinjava.test.nio;
 
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
 
public class ReadFileWithFixedSizeBuffer
{
    public static void main(String[] args) throws IOException
    {
        RandomAccessFile aFile = new RandomAccessFile
                ("test.txt", "r");
        FileChannel inChannel = aFile.getChannel();
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        while(inChannel.read(buffer) > 0)
        {
            buffer.flip();
            for (int i = 0; i < buffer.limit(); i++)
            {
                System.out.print((char) buffer.get());
            }
            buffer.clear(); // do something with the data and clear/compact it.
        }
        inChannel.close();
        aFile.close();
    }
}

3) Faster file copy with mapped byte buffer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.howtodoinjava.test.nio;
 
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
 
public class ReadFileWithMappedByteBuffer
{
    public static void main(String[] args) throws IOException
    {
        RandomAccessFile aFile = new RandomAccessFile
                ("test.txt", "r");
        FileChannel inChannel = aFile.getChannel();
        MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
        buffer.load(); 
        for (int i = 0; i < buffer.limit(); i++)
        {
            System.out.print((char) buffer.get());
        }
        buffer.clear(); // do something with the data and clear/compact it.
        inChannel.close();
        aFile.close();
    }
}

All above techniques will read the content of file and print it to console. You can do whatever you want once you have read it.

阅读全文……

标签 :

Java DES文件加密解密 javax.crypto.BadPaddingException: Given final block not properly padded - ice world - BlogJava

Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded
    at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
    at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
    at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
    at javax.crypto.Cipher.doFinal(DashoA13*..)

除了在Windows,Linux,Solaris不同操作系统下随机数生成机制不同问题导致key初始化问题,另外,

需要使用CipherInputStream和CipherOutputStream进行加密解密文件流

 

阅读全文……

标签 :

一步步DIY: OSM-Web服务器(一) PostgreSql 配置以及osm2pgsql原始PBF数据导入 - 流浪小狗的窝 - 博客频道 - CSDN.NET

<1>安装PostgreSQL

 

[plain] view plaincopy
 
  1. sudo apt-get update  
  2. sudo apt-get dist-upgrade  
  3. sudo apt-get install postgresql  
  4. sudo apt-get install postgresql-9.1-postgis postgresql-contrib-9.1 postgresql-server-dev-9.1  
  5. sudo apt-get install libpq-dev   

当然,也可以直接在X下新立得软件管理器中安装,顺便把pgAdminIII 给安上

 

下面进行配置。

 

<2>更改Linux  用户和PostgreSQL 的用户密码,创建用于数据访问的用户

为了用自己的postgres账户在 pgAdminIII中登录,以及远程访问数据库,我们要修改postgres的管理员密码

 

[plain] view plaincopy
 
  1. sudo passwd postgres  


输入两遍自己的密码, 就更改了Linux下用户postgres的口令。而后,在数据库中修改 postgres 的密码,一般与上面操作系统中postgres用户的密码取一致。

 

[plain] view plaincopy
 
  1. sudo su postgres  
  2.   
  3. psql -dpostgres  
  4.   
  5. ALTER USER postgres WITH PASSWORD '你的密码';  

 

为了安全,创建一个用户,用于数据访问。为了和后面渲染契合,用户名 www-data,分别在console以及psql下执行:

[plain] view plaincopy
 
  1. sudo passwd www-data  
  2. 在psql或者pgAminIII 中  
  3. CREATE ROLE "www-data" LOGIN  
  4.   PASSWORD '你想设置给www-data的密码'  
  5.   SUPERUSER INHERIT CREATEDB NOCREATEROLE REPLICATION;  

 

<3>adminPack 安装

     如果安装了pgAdminIII,则会提示您没有安装服务器端adminpack,postgresql 9.1下,这个东西不再是 contrb,而是“扩展”extension,直接点击“修复repair”或执行

 

[plain] view plaincopy
 
  1. create extension adminpack;  

 

以安装服务器管理员拓展包,否则,很多pgAdmin的功能用不了。

 

 

<4>建立PostGIS数据库

首先,我们要在2TB的分区文件夹下建立表空间。本例中, 2TB分区位于 /hugecargo

 

[plain] view plaincopy
 
  1. cd /hugecargo  
  2. sudo mkdir pgtbs_osmgis  
  3. sudo chown postgres ./pgtbs_osmgis  

而后,在psql或者pgAdmin下创建表空间

 

 

[plain] view plaincopy
 
  1. CREATE TABLESPACE pgtbs_osmgis  
  2.   OWNER "www-data"  
  3.   LOCATION '/hugecargo/pgtbs_osmgis';  


接着,创建数据库。由于中文Mint 下,postgresql默认采用 zh_cn.UTF-8 locale, 这种字符排序对后面的导入工作会造成一定的麻烦,保险起见,采用Locale "C"

 

 

[plain] view plaincopy
 
  1. CREATE DATABASE osmgis  
  2.   WITH OWNER = "www-data"  
  3.        ENCODING = 'UTF8'  
  4.        TABLESPACE = pgtbs_osmgis  
  5.        LC_COLLATE = 'C'  
  6.        LC_CTYPE = 'C'  
  7.        CONNECTION LIMIT = -1;  
  8. GRANT ALL ON DATABASE osmgis TO public;  
  9. GRANT ALL ON DATABASE osmgis TO "www-data";  

添加 postgis 功能,以及hstore(类似C++的map)。

 

 

[plain] view plaincopy
 
  1. sudo su postgres -c "psql -dosmgis </usr/share/postgresql/9.1/contrib/postgis-1.5/postgis.sql"  
  2. sudo su postgres -c "psql -dosmgis </usr/share/postgresql/9.1/contrib/postgis-1.5/spatial_ref_sys.sql"  
  3. sudo su postgres -c "psql -dosmgis </usr/share/postgresql/9.1/contrib/postgis_comments.sql"  
  4. sudo su postgres  
  5. psql -dosmgis  
  6. create extension hstore  

这样,postgis数据库就建立好了。

 

<5> 对postgresql性能进行优化

首先,编辑 /etc/postgresql/9.1/main/postgresql.conf

sudo nano /etc/postgresql/9.1/main/postgresql.conf

修改缓存,关闭自动资源释放,否则,等着导入的时候硬盘over吧!

 

[plain] view plaincopy
 
  1. shared_buffers = 256MB  
  2. checkpoint_segments = 20  
  3. maintenance_work_mem = 256MB  
  4. autovacuum = off  

小内存机器,不要设置太大。

 

 

[plain] view plaincopy
 
  1. shared_buffers = 128MB  


注意,把前面的"#"去掉,否则那一行只是注释而已,我这个粗心鬼不止一次忘了。

 

而后,要同步修改系统的最大共享内存数

 

[plain] view plaincopy
 
  1. sudo nano /etc/sysctl.conf   


在尾部补上

 

 

[plain] view plaincopy
 
  1. #128MB shared_buffer对应256MB shmmax   
  2. kernel.shmmax=268435456   
  3. #256MB shared_buffer对应512MB   
  4. shmmax kernel.shmmax=536870912  

 

最后,重启机器,确定postgresql服务运行正常,就ok了。

 

至此,postgresql设置完毕。

----------------------------------------- 

 

<6> 编译支持pbd文件格式的 osm2pgsql

为了导入数据,需要osm2pgsql这个工具。安装一些依赖

 

[plain] view plaincopy
 
  1. sudo apt-get install subversion git-core tar unzip wget bzip2   
  2. sudo apt-get install build-essential autoconf libtool libxml2-dev libgeos-dev libbz2-dev   
  3. sudo apt-get install proj libprotobuf-c0-dev protobuf-c-compiler   
  4. sudo apt-get install libfreetype6-dev libpng12-dev libtiff4-dev libicu-dev libboost-all-dev   
  5. sudo apt-get install libgdal-dev libcairo-dev libcairomm-1.0-dev apache2 apache2-dev libagg-dev  

我在自己的文档文件夹下建立bin, src  两个文件夹,bin用于存放直接运行的程序,src用于存放编译后 make install 到系统路径中的程序。

 

[plain] view plaincopy
 
  1. mkdir ~/src  
  2. mkdir ~/bin  
  3. cd ~/bin  
  4. svn co http://svn.openstreetmap.org/applications/utils/export/osm2pgsql/  

 

而后,进入目录,编译,如果需要多线程支持,安装pThread

sudo apt-get install libpthread-stubs0-dev libevent-pthreads-2.0-5  libzthread-dev

 

[plain] view plaincopy
 
  1. cd osm2pgsql  
  2. ./autogen.sh  
  3. ./configure  
  4. make  
  5. sudo make install  

 

就ok了

请注意一下configure的时候,有没有提示protobuf 是yes,是的话,才能认 pbf文件,从而节约大量的下载时间(pbf比 osm.bz2小了7-8个GB)

 

<7> 开始导入测试用中国数据(全球数据最后一步导入,那是去和老板请假休息的时候)

准备好后,直接运行

 

[plain] view plaincopy
 
  1. ./osm2pgsql -dosmgis -s -S"./default.style" -C384 -Uwww-data -W -Hlocalhost -v ~/downloaded/china.osm.pbf  

 

即可导入。china.osm.pbf 的数据导入很快。

阅读全文……

标签 : ,

A Generic Iterator for Tree Traversal | Dr Dobb's

 

 

 

 

Alexander works as a system architect at PricewaterhouseCoopers. He specializes in designing and developing object-oriented frameworks. He can be reached at [email protected].

 


 

Tree-like structures can be implemented in a variety of ways. For example, nodes (siblings) of one level of a tree can be linked using different types of collection, such as java.util.vector or java.util.list. These collections (or rather, their iterators) may provide different methods for collection traversal. Another way is that the link between a parent node and its child nodes can be one-way (from parent to children) or bidirectional. Bidirectional links simplify traversal logic.

The most notable difference among tree-like structures is in the public interfaces of tree nodes. For example, the javax.swing.tree.TreeNode interface (TreeNode is used for TreeModel, which is in turn used by JTree) provides the methods children() and isLeaf(). Node interfaces that employ the XML DOM tree (org.w3c.dom.Node; see http://sundev .natural.com/docs/java/oracle_xml_ parser2.0.2.4/org.w3c.dom.Node.html) define the methodsgetChildNodes() and hasChildNodes(), which essentially mean the same as children() andisLeaf() (they negate hasChildNodes()).

 

Normally, code performing tree traversal should be adjusted for each type of tree-like structure. Generic tree traversal logic, on the other hand, can be used with any type of tree-like structure or tree node, which lets you focus on the application logic rather than the internals of the tree structure organization.

 

Recursion is probably the best known and most frequently used way of traversing a tree. Recursive algorithms use the method call stack to keep the state of the traversal for every level of a tree. Listing One includes a class using recursion to traverse an XML DOM tree. Alternatively, traversing algorithms can utilize a separate stack object to store the tree level's state, as in Listing Two.

 

You can avoid using stack objects for tree-like structures that provide support for child-parent links. Once the child level has been processed, this link can be used to return back to the parent level; see Listing Three.

 

The important design decision for any generic algorithm is how to encapsulate its logic within a reusable class. There are two basic choices available for tree traversal -- visitor patterns and iterator patterns (see Design Patterns: Elements of Reusable Object-Oriented Software, by Erich Gamma et al., Addison-Wesley 1995).

 

Visitor patterns use two classes -- the visitor itself and the class performing the traversal. Traversal classes call the visitor for every node they traverse. The visitor applies its logic to a node it receives from the traversal class. Traversal classes are initialized with concrete visitor objects before the beginning of traversals. (This implementation of the visitor pattern is slightly different from the one described in Design Patterns, which assumes that the collection itself traverses its elements.)

 

The downside of the visitor pattern is that the visitor's interface is not extensible. It is fully controlled by the traversal class and takes only those parameters that the traversal class passes. So, if the logic of tree processing requires additional information not provided by a traversal class or a tree node itself, the visitor class needs to have state (member) objects that should be initialized before the traversal begins. Because the visitor interface is usually implemented by a separate class, encapsulation may potentially be weakened. The "one class for each distinct type of tree processing" requirement can also lead to the creation of numerous classes that are too granular.

 

The iterator pattern is simpler and its pervasive use in collection class libraries makes it one of the best-known design patterns. Tree iterators do not impose limitations on calling programs. The calling program only needs to call the iterator's next (sometimes called "advance") method.

 

Another advantage of the iterator pattern is that tree-like structures can be viewed simply as another type of collection, similar to the list or Java Vector class. The iterator pattern, not visitor, is the easiest way to traverse a collection. After all, a visitor is not normally used with lists, so why use it for a tree? Given that, iterator is a better choice of a design pattern for generic algorithms.

 

To make it even more consistent with how collections operate, the tree iterator can implement the abstract iterator interface provided by a collection class library. For Java, this is java.util.Iterator interface, which comes with the Java collection framework. This interface requires the implementation of three methods -- nexthasNext, and removeremove has to be defined, but it doesn't need to be coded; instead, it can simply throwUnsupportedOperationExceptionListing Four illustrates the use of the iterator for traversing XML DOM tree structure.

 

It is obvious that recursion can't be used with the iterator pattern. Using the child-parent link seems to be the most elegant alternative. This link effectively simulates stack structure, so there is no need for a separate stack object.

 

Another option is to introduce an auxiliary class, LevelIterator, which provides tree-level abstraction to the tree iterator. The task of traversing nodes of the same level is also delegated to this class. Another LevelIterator task is to maintain the link back to the parent level, which lets the tree iterator rely on the child-parent link even if it is not supported natively by the tree structure. Example 1 illustrates how the tree iterator's next method can be implemented using LevelIterator. The LevelIterator.toParent method simply returns the parent's LevelIterator object, while LevelIterator.nextLevel creates a new LevelIterator object for the child level. Creating a new object for every nextLevel call could be expensive for complex trees, so it is desirable to use object pooling to minimize the number of new objects. Object pool implementation for a tree-like structure is straightforward since the number of objects always equals the number of tree levels and the object is always returned to the pool before it can be allocated again. So a simple stack structure can be adapted for use as an object pool of LevelIterator objects. (The complete source code of my tree iterator and implementation of the object pool is available electronically; see "Resource Center," page 5).LevelIterator also runs some other chores, such as maintaining a node index within the level and a level index within the tree (depth).

 

After the public interface and implementation aspects of the algorithm are defined, you need to decide how the iterator deals with different kinds of tree nodes (org.w3c.dom.Node or javax.swing.tree .TreeNode, for example).

 

In situations where there are no common interfaces that can be used by an algorithm, the adapter pattern is handy. The adapter converts calls to its generic methods into the calls to methods used by the particular Node class. In fact, just two methods are needed to implement the adapter for the tree iterator -- getChildren and hasChildren (see Example 2).

 

The adapter class is usually trivial and doesn't do much. Listing Five is a trivial adapter for swing.tree.TreeNode. The simplicity of the adapter's code stems from TreeNode's native support of the enumeration interface for child nodes. When there is no such support, implementation is trickier. The adapter for org.w3c.dom.Node includes an additional nested adapter class for enumeration. This class uses the Node.getNextSibling() method to enumerate over the list of children; see Listing Six.

 

In Java, enumeration seems to be the natural interface for the collection of nodes, so additional enumeration adapters are rarely required. The DOM specification, being language independent, does not natively support enumeration; however, vendors of XML parsers usually extend the basic interface of org.w3c.dom by adding enumeration support. Therefore, it makes sense to use the DOM adapter in Listing Six only if there is a need to keep the adapter class generic so it can work with any XML parser. Otherwise, an additional enumeration adapter is not needed. Listing Seven contains the adapter's code for IBM's XML4J parser, which does support enumeration natively. This approach is also preferred from the performance standpoint, since creating new enumeration objects for every level of a tree adds some overhead, especially for deep trees with a low number of nodes at most of the levels. Because DOM trees usually fall under this category, their terminal levels frequently contain only one node.

 

Adapter objects should be passed to the tree iterator constructor along with the tree's root, for example:

 

Document xdoc = parser.readStream(new FileReader(fileName));

 

TIterator tIterator = new TIterator (xdoc,new DOMAdapter());

 

 

In addition to being generic, the implementation of the tree iterator presented here includes capabilities that allow for improving traversal performance in certain situations.

 

 

Limiting the Depth of Traversal

 

Tree traversal algorithms usually go over all nodes of a tree, assuming that full traversal is required by the calling code. However, the calling code occasionally needs to process only the subset of the tree's levels, meaning that it doesn't need to go all the way to the leaf level of a tree. In this case, full traversal carries significant overhead, since it traverses nodes that are ignored by the calling code. Tree traversal is a linear algorithm (O(n), where n is the number of nodes), so it is important to be able to limit the number of traversed nodes.

 

Consider the XML tree in Figure 1 (this example comes with IBM's XML4J parser). Suppose you want to process the IDs of all people in this file, but at the same time, are not interested in a person's name, e-mail, or other attribute. Full traversal is not what you want, since it traverses levels with name and e-mail, thus increasing the overall processing time.

 

Tree iterators should be able to stop at the second level and not go any deeper. To accomplish this, the iterator accepts the additional parameter maxDepth. This parameter is checked in the iterator's next method before moving to the children of the current node; seeExample 3(a). So, for ID processing, the iterator should be created with the maxDepthparameter, as in Example 3(b). The only disadvantage of this approach is that the idLevelvalue will have to be changed if the structure (schema) of the XML document changes. To avoid this problem, the idLevel can be dynamically found by performing an additional loop, as inListing Eight. This extra loop is lightweight, because the iterator only traverses the first node of each level and exits right after the required level is found.

 

 

Implementation of Selective Traversal

 

Oftentimes, there is a need to process nodes selectively based on conditions applied to one of the parent nodes. In other words, the condition is checked against the parent node (control node); if the condition is met, the entire branch that originates from this node should be processed. Otherwise, children of this node should be ignored.

 

It is expensive to use full traversal in situations like this, especially if the selectivity of the condition is high. In the extreme case, when search criteria contain a unique key (for example, "print all information about an employee with a given SSN"), the cost of full traversal could be prohibitive for large trees. Also, if the control node is located close to the root of the tree, the number of redundant steps for full traversal will be extremely high. In any event, full traversal overhead directly depends on the number of child nodes with control nodes that don't meet selection criteria.

 

On the other hand, it is desirable to be able to use generic traversal algorithms even when full traversal is not needed, since the rules of navigating through levels of a tree still apply. For example, suppose the traversing program needs to print all information about K.TAMURA. The easiest way to do this is to implement a nested loop that uses its own iterator. Maximum depth for the outer loop iterator should be limited to the level of the "person" node (second level); see Listing Nine.

 

The disadvantage of this approach is the need to have multiple nested loops and multiple iterators, which could lead to complicated code in cases of complex selection criteria.

 

You can do all processing in a single loop using the same iterator. But it requires additional intelligence on the iterator's side. One way to do it is to make the iterator implement a specialskipChildren method. When this method is called, the iterator sets its skipChildren flag. The flag is reset after the iterator advances to the first child:

 

if (! skipChildren and node.has Children()) {

 

// move to child's level ...

 

}

 

skipChildren = false;

 

 

Listing Ten prints all nodes for the K.TAMURA control node, this time using the skipChildrenmethod.

 

The most flexible approach for selective traversal is to make the handling of the maximum depth by the iterator more sophisticated. Indeed, selective traversal can be accomplished by dynamically changing the maximum depth for different nodes (branches). In the example with the node printing for K.TAMURA, the initial maximum depth is two (depth of idLevel). For selected nodes (ID=''K.TAMURA''), the depth should be adjusted to "unlimited," so the tree iterator can process children of the node. With this approach, maximum depth can't remain just a static parameter applied to the entire tree. Instead, the original depth should be restored when the iterator returns to the level of the parent node. In other words, depth becomes an attribute of a level and should be kept in the stack along with other level information (such as the current node). For the tree iterator I present here, an instance of LevelIterator class represents the tree level, so the current maximum depth value is kept there.

 

The calling program calls the setLevelDepth method of the iterator to change maximum depth value for the current node (control node). This method creates a new LevelIterator object for the child level and sets the new maximum depth on it. When next is called, the iterator navigates to the first node of the child level. The new maximum depth becomes current and is used for all child levels of the node -- unless setLevelDepth is called again. When all children are processed and the iterator returns to the control node level, the corresponding maximum depth is restored (that is, the control node's LevelIterator object becomes current). Listing Eleven prints the required nodes using the setLevelDepth method.

 

The logic for the traversal with the dynamically changed maximum depth is similar to theskipChildren flag approach. It is somewhat more elegant because it doesn't require using negative logic, but in terms of functionality, it does the same thing. The variable maximum depth approach, however, provides much greater flexibility when it comes to more complex selective processing. It allows for applying a different maximum depth to different branches of the tree. Some branches can be processed fully and some partially, up to the required depth. For example, you might need to process all levels for managers and only some levels for other entries in a personnel file.

 

This approach also allows for depth nesting. setLevelDepth can be called multiple times, first for the top-most control node, then for the node within the same branch that meets some additional criteria, and so on. In other words, coverage of the tree during traversal is defined by the combination of depths specified for the given set of criteria. Every criterion in the set can impose its own depth limitation on the tree. And no matter how complex these criteria are, the traversal is still performed within one loop. So the increased complexity of the tree iterator code (because of the handling of the maximum depth setting for each level) is justified by the gained flexibility in selective traversal.

 

DDJ

Listing One

 

package aan.treexamples;
import org.w3c.dom.*;
public class RecursiveTraversal implements ITraversal {
  /* Performs full tree traversal using recursion. */
  public void traverse( Node parentNode ) {
    // traverse all nodes that belong to the parent
    for(Node node=parentNode.getFirstChild(); node!=null; 
                                              node=node.getNextSibling()) {
      // print node information
      System.out.println( node.getNodeName()+"="+node.getNodeValue());
      // traverse children
      traverse(node);
    } 
  } 
} 

 

Back to Article

Listing Two

 

package aan.treexamples;
import org.w3c.dom.*;
import java.util.*;
public class StackTraversal implements ITraversal {
  /* Performs full tree traversal using stack. */
  public void traverse( Node rootNode ) {
    Stack stack = new Stack();
    // ignore root -- root acts as a container
    Node node=rootNode.getFirstChild();
    while (node!=null) {
      // print node information
      System.out.println( node.getNodeName()+"="+node.getNodeValue());
      if ( node.hasChildNodes()) {
        // store next sibling in stack. Return to it after all children 
        //                                                     are processed.
        if (node.getNextSibling()!=null)
          stack.push( node.getNextSibling() );
        node = node.getFirstChild();
      } 
      else {
        node = node.getNextSibling();
        if (node==null && !stack.isEmpty())
          // return to the parent's level.
          // some levels can be skipped if parent's node was the last one.
          node=(Node) stack.pop();
      } 
    } 
  } 
} 

 

Back to Article

Listing Three

 

package aan.treexamples;
import org.w3c.dom.*;
public class LinkTraversal implements ITraversal {
  /* Performs full tree traversal usingchild-parent link. */
  public void traverse( Node rootNode ) {
    // ignore root -- root acts as a container
    Node node=rootNode.getFirstChild();
    while (node!=null) {
      // print node information
      System.out.println( node.getNodeName()+"="+node.getNodeValue());
      if ( node.hasChildNodes()) {
        node = node.getFirstChild();
      } 
      else {    // leaf
        // find the parent level 
        while (node.getNextSibling()==null && node != rootNode)
            // use child-parent link to get to the parent level
            node=node.getParentNode();
        node = node.getNextSibling();
      } 
    } 
  } 
} 

 

Back to Article

Listing Four

 

package aan.treexamples;
import aan.tree.*;
import org.w3c.dom.*;
public class IterFullTraversal implements ITraversal {
  /* Performs full tree traversal using tree iterator. */
  public void traverse ( Node rootNode ) {
    // create iterator
    TIterator tIterator = new TIterator ( rootNode , new DOMAdapter() );
    Node node = null;
    while( (node=(Node)tIterator.next()) != null )  {
      // print node information
      System.out.println( node.getNodeName()+"="+node.getNodeValue());
    } 
  } 
} 

 

Back to Article

Listing Five

 

package aan.tree;
import java.util.Enumeration;
import javax.swing.tree.TreeNode;
/* This adapter maps <code>javax.swing.tree.TreeNode</code> interface to
 * generic methods required by <code>TIterator</code>. */
public class SwingAdapter implements TNodeAdapter {
  public Enumeration getChildren( Object node ) {
    return ((TreeNode)node).children();
  } 
  public boolean hasChildren( Object node ) {
    return ! ((TreeNode)node).isLeaf();
  } 
} 

 

Back to Article

Listing Six

 

package aan.tree;
import java.util.Enumeration;
import org.w3c.dom.*;
/** This adapter maps <code>org.w3c.dom.Node</code> interface to generic 
 * methods required by <code>TIterator</code>. Enumeration provided by the 
 * nested class in order to conforom to w3c spec. */
public class DOMAdapter implements TNodeAdapter {
  public Enumeration getChildren( Object node ) {
    return new Enumerator( ((Node)node).getFirstChild() );
  } 
  public boolean hasChildren( Object node ) {
    return ((Node)node).hasChildNodes();
  } 
  /* Maps <code>org.w3c.dom.Node</code> methods to <code>Enumeration<code>.
   * Inner class <code>HeadNode</code> provides dummy impelmemtation for
   * <code>Node</code>, it is used as the head of the list. This is needed 
   * to advance to the first element after the <code>next()</code> */
  static public class Enumerator implements Enumeration {
    private Node node;
    Enumerator( Node node) {
      // empty node is the head of the list
      this.node = new HeadNode( node );
    } 
    public Object nextElement() {
      node = node.getNextSibling();
      return node;
    } 
    public boolean hasMoreElements() {
      return (node.getNextSibling() != null);
    } 
    /* Dummy implementation of the <code>Node</code>.
     * It returns its node after the <code>nextSibling</code> call */
    private class HeadNode  implements Node {
      private Node nextNode;
      /* Creates the node and initiates with the current node */
      private HeadNode( Node node){
        nextNode = node;
      } 
      /* Returns current node as the next. This is the only method that's 
       * used out of <code>Node</code> interface.  @return current node */
      public Node getNextSibling() {
        return nextNode;
      } 
      // all these methods are not used
      public String getNodeName(){ return null;} 
      public String getNodeValue() throws DOMException { return null;} 
      public void setNodeValue(String nodeValue) throws DOMException {} 
      public short getNodeType() {return 0;} 
      public Node getParentNode() {return null;} 
      public NodeList getChildNodes() {return null;} 
      public Node getFirstChild()  {return null;} 
      public Node getLastChild()  {return null;} 
      public Node getPreviousSibling()  {return null;} 
      public NamedNodeMap getAttributes(){return null;} 
      public Document getOwnerDocument(){return null;} 
      public Node insertBefore(Node newChild, Node refChild)
        throws DOMException {return null;} 
      public Node replaceChild(Node newChild, Node oldChild)
        throws DOMException {return null;} 
      public Node removeChild(Node oldChild)
        throws DOMException {return null;} 
      public Node appendChild(Node newChild)
        throws DOMException {return null;} 
      public boolean hasChildNodes() {return false;} 
      public Node cloneNode(boolean deep) {return null;} 
    }  // end of HeadNode
  }  // end of Enumerator
} 

 

Back to Article

Listing Seven

 

package aan.tree;
import java.util.Enumeration;
import org.w3c.dom.Node;
import com.ibm.xml.parser.Parent;
/* Maps <code>org.w3c.dom.Node</code> and 
 * <code>com.ibm.xml.parser.Parent</code> to generic methods required 
 * by <code>TIterator</code>. */
public class XML4JAdapter implements TNodeAdapter {
  public Enumeration getChildren( Object node ) {
    return ((Parent)node).elements();
  } 
  public boolean hasChildren( Object node ) {
    return ((Node)node).hasChildNodes();
  } 
} 

 

Back to Article

Listing Eight

 

package aan.treexamples;
import aan.tree.*;
import org.w3c.dom.*;
public class IterMaxDepthTraversal implements ITraversal {
  /* Traverses tree with traversal depth set to depth of the "person" level */
  public void traverse ( Node rootNode ) {
    // create iterator
    TIterator tIterator = new TIterator ( rootNode, new DOMAdapter() );
    // find the depth of the required level
    int targetDepth = -1;
    Node node = null;
    while( (node=(Node)tIterator.next()) != null )  
      if (node.getNodeName().equals("person")) {
        targetDepth = tIterator.getDepth();
        break;
      } 
    // we can reuse the same iterator
    tIterator.setRoot(rootNode);
    // limit the depth of traversal
    tIterator.setMaxDepth( targetDepth );
    while( (node=(Node)tIterator.next()) != null )  {
      // print node information
      System.out.println( node.getNodeName()+"="+node.getNodeValue());
    } 
  } 
} 

 

Back to Article

Listing Nine

 

package aan.treexamples;
import aan.tree.*;
import org.w3c.dom.*;
public class SelectiveNestedTraversal implements ITraversal {
  /* Selectively traverses the tree ising nested loops. */
  public void traverse ( Node rootNode ) {
    // create 1st iterator. depth should be limited to ID's level
    DOMAdapter domAdapter = new DOMAdapter();
    TIterator tIterator = new TIterator ( rootNode, domAdapter, 2 );
    Node node = null;
    while( ( node=(Node)tIterator.next() )!=null ){
      // print node information
      System.out.println( node.getNodeName()+"="+node.getNodeValue());
      if  (node instanceof Element && ((Element)node).getAttribute( "id" ).
        equalsIgnoreCase( "K.TAMURA" )) {
        // create 2nd iterator, perform nested loop to process the branch.
        TIterator branchIterator =  new TIterator ( node, domAdapter);
        Node branchNode = null;
        while( (branchNode=(Node)branchIterator.next()) != null )
          // print node information
          System.out.println( branchNode.getNodeName()+"=" 			+branchNode.getNodeValue());
      } 
    } 
  } 
} 

 

Back to Article

Listing Ten

 

package aan.treexamples;
import aan.tree.*;
import org.w3c.dom.*;
public class SelectiveSkipTraversal implements ITraversal {
  /* Selectively traverses the tree ising skip flag. */
  public void traverse ( Node rootNode ) {
    // create an iterator.
    int idLevel = 2;
    TIterator tIterator = new TIterator ( rootNode, new DOMAdapter());
    Node node = null;
    while( ( node=(Node)tIterator.next() )!=null ){
      // print node information
      System.out.println( node.getNodeName()+"="+node.getNodeValue());
      if  ( tIterator.getDepth() == idLevel && ! (node instanceof Element &&
        ((Element)node).getAttribute( "id").equalsIgnoreCase("K.TAMURA" ))) {
        // allow parsing all children of the node -- applies  				only to the current node
        tIterator.skipChildren();
      } 
    } 
  } 
} 

 

Back to Article

Listing Eleven

 

package aan.treexamples;
import aan.tree.*;
import org.w3c.dom.*;
public class SelectiveSetDepthTraversal implements ITraversal {
  /* Selectively traverses the tree using <code>setLevelDepth</code> */
  public void traverse (Node rootNode) {
    // create iterator, initially it is limited to the ID level
    int idLevel =2;
    TIterator tIterator = new TIterator (rootNode,new DOMAdapter(),idLevel);
    Node node = null;
    while( ( node=(Node)tIterator.next() )!=null ){
      // print node information
      System.out.println( node.getNodeName()+"="+node.getNodeValue());
      if  ( tIterator.getDepth() == idLevel && (node instanceof Element &&
        ((Element)node).getAttribute( "id").equalsIgnoreCase("K.TAMURA" ))) {
        // this allows iterator to traverse children of the current  node
        tIterator.setLevelDepth( TIterator.DEPTH_UNLIMITED);
      } 
    } 
  } 
} 

 

Back to Article

阅读全文……

OpenLayers中地图缩放级别的设置方法 - 心帆 - 博客园

一、概述

在OpenLayers中,地图必须具有一个缩放级别的范围,缩放级别可以用比例尺(scale)或者分辨率(resolution)表示。

比例尺——屏幕上1米代表多少地图坐标单位;分辨率——屏幕上一个像素代表多少地图坐标单位。
两者的转换关系是:scale = resolution * 72 * 39.3701(1米=39.3701英寸,1英寸=72像素)

地图具有一个总的缩放级别,每个图层可以有各自的缩放级别,这样可以控制图层只在合适的级别上显示。

二、缩放级别范围的确定方法

1、比例尺数组或者分辨率数组来确定(相邻两级之间不一定是2倍的关系,可以是任意值)。示例:

resolutions: [1.40625,0.703125,0.3515625,0.17578125,0.087890625,0.0439453125]
scales: [
5000000030000000100000005000000]

 

2、用最大分辨率(maxResolution)和缩放级别总数(numZoomLevels)确定,相邻两级是2倍关系

2.1最大分辨率的确定方法:

a. 直接指定maxResolution,例如:

maxResolution: 0.17578125

b. 直接指定minScale,例如:

minScale: 50000000

c. 由maxExtent确定(maxResolution需设置为‘auto’),例如:

maxExtent: new OpenLayers.Bounds(-180-9018090),
maxResolution: 
"auto"

2.2 缩放级别总数的确定方法:

a.  直接指定numZoomLevels,例如:numZoomLevels: 5
b.  由最大分辨率和最小分辨率的比值确定,最小分辨率同2.1有三种方法可以确定:

    b.1 直接指定minResolution
    b.2 直接指定maxScale
    b.3 由minExtent确定(minResolution需设置为‘auto’)

 

如果指定的参数过多,导致缩放级别范围不一致时,上述方法顺序决定了OpenLayers确定缩放级别范围的优先级。

阅读全文……

配置Openlayers中的缩放级别 - JenMinZhang - 博客园

OpenLayers Map可以在不同的比例尺或解析度下显示他的每一个layer
map对象含有缩放级别的引用,即ZoomLevels,而且允许他的每一个layer去自定义他们自己的缩放级别,使之看起来合适
可以通过在构造函数中设置options属性来配置openlayers layer的缩放级别

== 正常图层==
对于基于openlayers.layer的正常layer,和能够在任何解析度下显示的layer,存在多种不同的方式去配置缩放级别和他们各自的比例尺和解析度

“解析度数组”:
要是转化缩放级别成为解析度,需要一个{{{resolutions}}}数组,他是这个图层所支持的不同解析度的列表,缩放级别就仅仅是一个解析度数组的索引,解析度数组始于0终于缩放级别-1

比如:
一个图层的解析度为[a,b,c],那么缩放级别的0就是a ,1就是b。。。


=== 配置解析度数组的方式 ===

可选项:
{{{scales}}} - ''Array'' -- 预先设置比例尺值的数组
{{{resolutions}}} - ''Array'' -- 预先设置解析度值的数组
{{{minScale}}} - ''float'' --layer能够显示的最小比例尺
{{{maxScale}}} - ''float'' --layer能够显示的最大比例尺
{{{maxResolution}}} - ''float'' --layer能够显示的最大解析度
{{{minResolution}}} - ''float'' -- layer能够显示的最小解析度
{{{minExtent}}} - ''!OpenLayers.Bounds'' --layer能显示出的最小范围
{{{maxExtent}}} - ''!OpenLayers.Bounds'' -- layer能显示出的最大范围
{{{numZoomLevels}}} - ''int'' -- 缩放级别的总数
{{{units}}} - ''String'' - layer显示的单位,作用于比例尺-解析度换算

Example Declarations:
{{{
    var options = { scales: [50000000, 30000000, 10000000, 5000000],
                    resolutions: [1.40625,0.703125,0.3515625,0.17578125,0.087890625,0.0439453125],
                    minScale: 50000000,
                    maxResolution: "auto",
                    maxExtent: new OpenLayers.Bounds(-180, -90, 180, 90),
                    maxResolution: 0.17578125,
                    maxScale: 10000000,
                    minResolution: "auto",
                    minExtent: new OpenLayers.Bounds(-1, -1, 1, 1),
                    minResolution: 0.0439453125,
                    numZoomLevels: 5,
                    units: "degrees"
                  };
    map = new OpenLayers.Map( $('map') , options);
}}}


显然所有的配置项不能在一次设置中全都用上,因为他们可能相互冲突,他们会按照下面的优先级起作用:

[A]【预设的缩放级别列表】缩放级别由预先设置的比例尺或解析度决定

{{{scales}}} -解析度的数组由这些比例尺直接转化而来
{{{resolutions}}} - 解析度数组直接从初始化函数的option参数中带来
Examples:
{{{
    var options = { scales: [50000000, 30000000, 10000000, 5000000] };
    map = new OpenLayers.Map( $('map') , options);
}}}

{{{
    var options = { resolutions: [1.40625,0.703125,0.3515625,0.17578125,0.087890625,0.0439453125] };
    map = new OpenLayers.Map( $('map') , options);
}}}

* '''maxResolution and numZoomLevels''' - ''!ZoomLevels are determined based on a maximum resolution and the number of desired !ZoomLevels''


[B]【最大解析度 &缩放级别的总数】缩放级别在最大解析度和缩放级别的总数上被决定
B1 最大解析度的确定
{{{minScale}}} --解析度的值从比例尺由单位{{{units}}}转化来
{{{maxExtent}}} AND {{{maxResolution == "auto"}}} --解析度由地图的div尺寸和maxExtent属性计算而来。若maxExtent属性未指定,默认从map继承,即全世界
{{{maxResolution}}}--解析度的值直接从layer的options参数中带来,若没指定,则默认为从map的options中带来
B2 缩放级别的总数确定
    B2_a基于最大和最小解析度的比值来计算--确定最小解析度:
{{{maxScale}}} --解析度的值从比例尺由单位{{{units}}}转化来
{{{minExtent}}} AND {{{minResolution == "auto"}}}--解析度的值基于地图div尺寸和minExtent属性来计算。minExtent属性必须被指定,默认不从map继承
{{{minResolution}}} --解析度的值从layer指定的option参数中直接带来,若没指定,最小解析度保持为空,缩放级别数直接接受
    B2_b {{{numZoomLevels}}}缩放级别数直接从layer指定的option参数带来,若没有指定默认从map的option带来

Examples:

||maxResolution||Converted from minScale using specified units||
||numZoomLevels||Default from map||
{{{
    var options = { minScale: 50000000,
                    units: "degrees"
                  };
    map = new OpenLayers.Map( $('map') , options);
}}}
[[BR]]

||maxResolution||Calculated based on div size and default maxExtent from map||基于div的尺寸和地图最大范围计算
||numZoomLevels||Calculated using ratio of maxResolution/minResolution||用最大最小分辨率的比值计算
{{{
    var options = { maxResolution: "auto",
                    maxExtent: new OpenLayers.Bounds(-180, -90, 180, 90),
                    minResolution: 0.0439453125
                  };
    map = new OpenLayers.Map( $('map') , options);
}}}
[[BR]]

||maxResolution||Specified||
||numZoomLevels||Specified||
{{{
    var options = { maxResolution: 0.17578125,
                    numZoomLevels: 15
                  };
            map = new OpenLayers.Map( $('map') , options);
}}}
[[BR]]

||maxResolution||Default from map||
||numZoomLevels||Converted maxScale (using default units from map) to minResolution, then uses ratio of maxResolution/minResolution to calculate numZoomLevels||
{{{
    var options = { maxScale: 10000000 };
    map = new OpenLayers.Map( $('map') , options);
}}}
[[BR]]

||maxResolution||Specified||
||numZoomLevels||Calculated minResolution based on div size and default minExtent from map, then uses ratio of maxResolution/minResolution to calculate numZoomLevels||
{{{
    var options = { maxResolution: 0.17578125,
                    minResolution: "auto",
                    minExtent: new OpenLayers.Bounds(-1, -1, 1, 1),
                  };
    map = new OpenLayers.Map( $('map') , options);
}}}

 

 

阅读全文……