登入帳戶  | 訂單查詢  | 購物車/收銀台(0) | 在線留言板  | 付款方式  | 聯絡我們  | 運費計算  | 幫助中心 |  加入書簽
會員登入   新用戶註冊
HOME新書上架暢銷書架好書推介特價區會員書架精選月讀2023年度TOP分類閱讀雜誌 香港/國際用戶
最新/最熱/最齊全的簡體書網 品種:超過100萬種書,正品正价,放心網購,悭钱省心 送貨:速遞 / 物流,時效:出貨後2-4日

2024年10月出版新書

2024年09月出版新書

2024年08月出版新書

2024年07月出版新書

2024年06月出版新書

2024年05月出版新書

2024年04月出版新書

2024年03月出版新書

2024年02月出版新書

2024年01月出版新書

2023年12月出版新書

2023年11月出版新書

2023年10月出版新書

2023年09月出版新書

『簡體書』电子商务安全技术

書城自編碼: 2986192
分類: 簡體書→大陸圖書→教材研究生/本科/专科教材
作者: 刘英卓、曹杰、张艳萍
國際書號(ISBN): 9787302467083
出版社: 清华大学出版社
出版日期: 2017-04-01
版次: 1 印次: 1
頁數/字數: 166/238000
書度/開本: 16开 釘裝: 平装

售價:NT$ 202

我要買

share:

** 我創建的書架 **
未登入.



新書推薦:
读书是一辈子的事(2024年新版)
《 读书是一辈子的事(2024年新版) 》

售價:NT$ 352.0
乐道文库·什么是秦汉史
《 乐道文库·什么是秦汉史 》

售價:NT$ 367.0
汉娜·阿伦特与以赛亚·伯林 : 自由、政治与人性
《 汉娜·阿伦特与以赛亚·伯林 : 自由、政治与人性 》

售價:NT$ 500.0
女性与疯狂(女性主义里程碑式著作,全球售出300万册)
《 女性与疯狂(女性主义里程碑式著作,全球售出300万册) 》

售價:NT$ 500.0
药食同源中药鉴别图典
《 药食同源中药鉴别图典 》

售價:NT$ 305.0
设计中的比例密码:建筑与室内设计
《 设计中的比例密码:建筑与室内设计 》

售價:NT$ 398.0
冯友兰和青年谈心系列:看似平淡的坚持
《 冯友兰和青年谈心系列:看似平淡的坚持 》

售價:NT$ 254.0
舍不得星星:全2册
《 舍不得星星:全2册 》

售價:NT$ 356.0

編輯推薦:
本书并不讲述电子商务网站的宏观体系开发,如用户的需求、分析、设计、实现等。本书着眼于战术运用,重点讲述电子商务编码的安全实现环节。本书强调的安全编码技术也不是编程的全部技巧,而是程序员在编码当中*容易忽视的环节,还有电子商务网站独特的安全需求在技术上的解决。尽管就软件本身来说,可重用性、开放性、封闭性都能从一定程度上保证编码本身的生命力更持久,它们当然提高了编码的安全度。但本书并不论述这些编程宏观方法论的东西,本书的目的是让读者理解当前三大编程体系的安全基础和应用技术。因此,本书也不论述加密算法的编程实现问题,也不讨论各种安全漏洞,而是研究对程序员来说编程应如何安全实现。
內容簡介:
电子商务安全编码对于从事电子商务技术开发的人员至关重要,是电子商务安全理论的具体实践。本书划分为三大篇:PHP安全基础、Java安全编码和ASP.NET安全。在每一篇中,按照信息暴露、安全输入过滤、安全输出、安全传输、安全存储几个环节进行了勾勒,精心选择实例素材,尤其对于电子商务中敏感模块的编码实现,做了非常详细的分析。
本书可作为电子商务专业专科生、本科生、研究生的教材,也适合于从事电子商务研究的专业技术人员参考使用。
目錄
目 录
第1篇 PHP安全基础.... 1
1.1 信息暴露... 1
1.1.1 register_globals和错误报告... 1
1.1.2 数据库访问权限暴露... 3
1.1.3 配置选项... 4
1.1.4 引入包含带来的暴露... 6
1.2 输入过滤... 7
1.2.1 过滤基础... 7
1.2.2 过滤表单和URL. 10
1.2.3 SQL注入... 21
1.2.4 动态包含的未过滤问题... 23
1.2.5 文件与命令的未过滤问题... 26
1.2.6 验证过滤与授权... 31
1.2.7 需要关注输入过滤的函数... 38
1.3 输出转义... 40
1.4 安全传输... 41
1.5 安全存储... 50
1.5.1 共享主机... 50
1.5.2 加密... 60
1.5.3 上传文件的安全存储... 66
1.6 安全开发原则... 67
1.7 电子商务PHP开发实例... 71
1.7.1 安全登录... 71
1.7.2 订单签名... 85
第2篇 Java安全编码.... 88
2.1 Java编程陷阱... 90
2.1.1 Java基础编程陷阱... 90
2.1.2 Java客户端方面陷阱... 95
2.1.3 Java服务器端方面陷阱... 103
2.2 商务软件基础开发语言Java的安全... 107
2.2.1 机密性的实现... 107
2.2.2 完整性的实现... 108
2.2.3 认证性的实现... 109
2.2.4 电子商务安全协议SSLTLSHTTPS的实现... 110
2.3 JSP安全... 112
2.4 电子商务框架安全编码... 113
2.5 支付模块的安全编码... 121
第3篇 ASP.NET安全.... 134
3.1 ASP.NET验证和授权机制... 135
3.2 安全配置... 140
3.3 输入过滤... 143
3.4 输出转义... 149
3.5 安全存储... 150
3.6 ASP.NET电子商务安全编码... 155
3.6.1 管理订单... 155
3.6.2 搜索商品... 161
参考文献.... 167
內容試閱
前 言

安全的电子商务Web应用开发首先要从对HTTP协议的深入理解开始,因为HTTP协议是在客户端和服务器端之间运输HTML网页的车辆,这辆车有两种车头:request头和response头。客户端必须获得一个有安全意识的程序员注意,它是典型的Web浏览器、蜘蛛机器人或者其他具有风险的软件比如自动注册提交机。HTTP协议通过TCP的三次握手机制连接到Web服务器。一旦服务器收到请求消息,服务器就开始处理请求和发回带有状态行的响应如HTTP1.1 200 OK。然后,服务器把剩下的响应消息发送出去,其中可能包含HTML、图像、音频、错误消息或任何其他想要发送的信息。浏览器发出的HTTP请求类型有GET、POST,还有用在编程中的HEAD、PUT和TRACE类型。
电子商务程序员编写出一个存在漏洞的Web页面,表面上看起来可能不是什么大问题,但却可以造成非常严重的问题,包括以下内容。
1 盗窃账户或服务。当Web站点使用会话状态时,会话标识符通常存储在用户浏览器的cookie 中,可以通过JavaScript查看和操作站点的cookie。攻击者可以利用此功能把cookie的内容定向到攻击者拥有的另一个站点上,也可以在自己主机的浏览器上重新创建这个cookie,攻击者看上去好像是Web服务的原始用户。根据被攻击站点的不同,对于那些已经被盗取信息的用户,可能会导致身份盗窃、访问机密信息、访问付费内容或DoS攻击等不同的后果。
2 用户重定向。一旦攻击者发现了一个XSS漏洞,他就完全可以使用JavaScript注入重定向整个浏览器。这可能导致安装间谍软件、网络钓鱼或其他常见性的危害。
3 用户跟踪。因为JavaScript可以操作页面内容,所以攻击者可以在服务器托管的存在漏洞的页面中插入图像,这个图像可以被用来跟踪多个存在漏洞的Web站点的用户。此外,攻击者可以利用JavaScript通过添加单击事件脚本来替换页面上所有的链接,以便收集更多的统计信息。
4 错误信息。攻击者可以使用JavaScript重写Web页面内容。如果被攻击的站点是一个金融Web站点,攻击者为了修改特定的股票价格来修改站点中的页面,那么用户没有任何办法辨别显示的价格是不正确的价格,因为浏览器中的URL是相同的。
5 浏览器插件的安装和利用。攻击者可以把标记插入页面中,标记可以启动ActiveX控件、Flash、Java或其他的以这种方式控制的插件,然后利用该插件的漏洞来窃取或公开用户的信息。
6 DoS攻击。攻击者在一个想要发动DoS攻击的站点上插入一个图像标记,并加载最大的图像。由于此站点有足够大的用户浏览量,只加载这些图像就需要占用很大的带宽,因此该站点就无法再很好地提供其他Internet服务了。而且,加载图像属于正常行为,所以此攻击很难被发现。
有鉴于此,开发者必须掌握安全的Web应用编程技能,才能够满足电子商务的需求。
本书并不讲述电子商务网站的宏观体系开发,如用户的需求、分析、设计、实现等。本书着眼于战术运用,重点讲述电子商务编码的安全实现环节。本书强调的安全编码技术也不是编程的全部技巧,而是程序员在编码当中最容易忽视的环节,还有电子商务网站独特的安全需求在技术上的解决。尽管就软件本身来说,可重用性、开放性、封闭性都能从一定程度上保证编码本身的生命力更持久,它们当然提高了编码的安全度。但本书并不论述这些编程宏观方法论的东西,本书的目的是让读者理解当前三大编程体系的安全基础和应用技术。因此,本书也不论述加密算法的编程实现问题,也不讨论各种安全漏洞,而是研究对程序员来说编程应如何安全实现。
安全是一个程度性的词汇,没有绝对的安全,只有相对的安全。安全编码就是在实现基本功能的基础上,增加防护性编码,以保证基本功能编码安全顺利地实现功能。安全编码和风险编码黑客程序是一对矛盾体,由安全编码所建立的软件对抗的是有风险的环境中产生的风险编码。安全性不是一项能够事后添加到现有应用程序的功能,不能等到开发阶段的后期才引入它。安全性是应用程序的固有特性,应作为设计阶段的首要任务来规划。为了确保应用程序的安全,需要开发者、架构师和管理员齐心协力。在电子商务应用系统所处的环境中,恶意用户输入的非正常数据是风险的主要原因。
本书的读者定位是掌握编程基础知识的程序员和学习了安全基础知识后待实践的电子商务专业学生。因此,本书不再讲述安全基础知识、术语,回避了三大编程体系的语法讲解,回避了服务器和数据库管理系统的漏洞讨论,也回避了各种安全算法的实现原理或者它们自身漏洞的讨论。本书侧重于程序员运用编程工具提供的安全API的运用,强调面向电子商务应用,强调网页安全编写技巧、准则,强调编写安全的代码,强调网站整体性安全方案和单页面安全技巧。也就是说,本书仅限于讲解如何开发安全的电子商务应用程序。通过本书的学习,读者能够在编码过程中自觉运用这些技巧和知识,提高编码的健壮性,从而进一步满足电子商务类软件的产出质量。
一个程序员编写的程序如果仅仅考虑了基本功能的实现,那么他的程序就如同一个裸体的婴儿,没有任何抵御外部攻击的能力。安全编码就是在实现了基本功能代码之外,为他穿衣戴帽、披之以铠甲,以实现防护。在什么地方加铠甲,加什么样的铠甲,在什么情形下加,这些是安全编码要研究的地方。从安全实现上来看,安全编码主要分为声明性安全和程序性安全:声明性安全主要针对宏观配置,有利于掌控应用全局的安全;程序性安全代码逻辑上都等价于if已识别风险...then防护...else意外处理语句,有利于程序细节局部的安全防护。写在前面的代码是后面代码执行的前提,前提自然会起到保护后续代码也就是结果的作用。安全外壳保护的永远是脆弱的代码,脆弱的代码会产生脆弱敏感性信息的泄露,归根到底,防护最终要保护的就是敏感数据。开发者在开发网页程序时,头脑中应该首先去想:①这个网页的安全度是什么级别;②是否需要验证用户身份、访问控制权限;③这个网页内有没有需要用户大量提交的数据,如果有就要在设计网页内增加验证码,以防止自动提交式的瘫痪网站攻击;④程序员要保证这个页面和其他网页间的逻辑关系,限制跨页面访问和盗链访问,在页面设置监视量,等等。

本书分为三大篇。第一篇讲述了PHP的安全编程知识,PHP面向电子商务的安全开发。第二篇讲述了Java的安全编程知识,JSP面向电子商务网站的安全编码问题。第三篇讲述了ASP.NET的安全编程知识,ASP.NET面向电子商务网站的安全编码问题。曹杰博士为本书撰写了整体框架,撰写了相应的章节;张艳萍博士为本书的资料收集、汇总给予了很大支持,并撰写了相应的章节。
编写本书的目的是给程序员提供一个安全编程指南。由于本书编者水平有限,书中难免存在错误、瑕疵和其他不足之处,恳请读者批评、指正。


编 者


第2篇 Java安全编码
J2EE体系是企业级电子商务应用开发的首选,这是由于J2EE体系做开发非常灵活,能够给程序员以非常大的发挥空间。但是J2EE体系同时要求程序员掌握大量的知识,这增加了编码出现问题的概率。在行业领域,程序性安全正在向声明性安全转变,目标是通过策略而不是依靠在每个应用程序中散布安全代码来控制保障。
J2EE安全为了实现可移植性和可重用性,其设计主要采用了声明性方法。在J2EE平台上绝大多数的认证、授权、整合、机密性和访问控制策略等行为,都是可以使用配置文件和部署描述符来完成的。而由于这些配置文件和部署描述符是置于应用程序之外的,这就减轻了程序员的负担,并且使得Java企业级程序具有可移植性、可重用性和灵活性。在J2EE环境中,容器支撑着组件,容器的安全基础是安全角色。一个容器可以提供两种安全:声明性的和程序性的。
在声明性安全模型中,一个应用通过应用外部的表单中的安全约束来表达它的安全策略,在J2EE中,安全约束是在部署描述符中指定的。这允许应用成为所谓的安全机制不可知或者安全无意识。不要求应用代码保证安全或者执行应用安全策略。使用声明性安全,应用的逻辑安全要求被定义于部署描述符中,并且随后就被部署者和系统管理员映射到一个部署环境中。部署者使用容器部署工具来处理部署描述符。在运行时,容器使用由部署者和系统管理员配置的安全策略来执行授权。声明性安全提供了更好的应用可移植性,因为与底层容器和操作系统相关的安全事宜都是在应用外部的配置文件中定义的。另外,使用声明性安全的应用更容易开发,因为对安全和策略配置事宜的管理是在应用的外部进行的。应用开发者没有必要同时也是一位安全专家,而基于声明性安全的应用也可以更容易地被扩充。因此,只要声明性安全单独使用仍然可以充分地描述应用的安全需求,那么就要用它来取代程序性安全。
在程序性安全模型中,应用程序员负责显式地编写代码来定义和启用安全。应用安全策略是应用的一个完整部分,一个遵守这个模型的应用被认为是识别安全。程序性安全给应用开发造成了更大的困难,并带来对应用的可移植性和可扩展性的诸多限制,这是因为与指定的应用、容器和应用所运行的操作系统相关的安全事宜必须被硬编码。所以,程序性安全仅仅应该被使用在那些只使用声明性安全不足以表达原因的安全模型的情况。
这两种安全模型一个反映的是宏观一般性的安全策略,一个反映的是具体实现上的安全编码,各自有所侧重。在真正的应用安全实现上,二者应该结合起来使用。
1. 声明性安全
HTTP认证可以是基本认证也可以是摘要认证。在基本认证中,需要用户提供的证书是用户ID和密码,而且两者都是以明文传递的,关键字为BASIC;摘要认证的关键字为DIGEST。


BASICDIGEST
SampleAppReal


表单认证的关键字是FORM,部署描述符如下:


FORM

login.html
login-failed.html




证书认证方式的关键字是CLIENT-CERT,部署描述符如下:


CLIENT-CERT


2. 程序性安全
使用程序性的方法获得用户的身份和特权信息,需要调用如:
javax.servlet.http.HttpServletRequest接口中的isUserInRole
方法,它指示认证用户即客户端是否是指定的安全角色的成员。
javax.servlet.http.HttpServletRequest接口中getUserPrincipal
方法,它返回一个Principal对象,这个对象代表当前的认证用户客户端。
在基础Java语言编程中,程序员往往容易掉进一些陷阱,这些陷阱是一些逻辑错误,是程序员对语言理解不深入造成的。这似乎与安全编码无关,但是可以看成是程序员自己在攻击自己的编码。所以,本书需要讨论一些最容易被开发者忽视的、但最容易犯的错误。

2.1
Java编程陷阱
程序陷阱是指那些能够正常编译,但是在执行时却产生事与愿违的,有时候甚至是灾难性后果的程序代码。广义上任何可能导致程序员把大量的时间浪费在开发工具的使用上而不是最终软件的进展上的语言特性、API或系统,都可以称为陷阱。陷阱能够造成程序员的迷惑,所以要严格分析陷阱。①症状或者问题,首先找到是哪一个代码造成的问题,陷阱的类型是什么。②问题的根源,这个是揭示陷阱最重要的一个部分,要深入底层,了解可能导致程序员绊脚的详细内部工作过程、无效的假设或者API的缺陷。③解决方案,这个是分析陷阱的最后一个步骤,最终给出一个程序实现和运行结果。
2.1.1
Java基础编程陷阱
1. 奇数误判
要判断一个数i是不是奇数,有程序员使用了这样的判别方法:return i % 2==1;,这就产生一个陷阱。这个判别式在判断负数的奇偶性时,会把所有负整数判断为假。这个陷阱的根源是仅仅考虑了正数的情况。应该改为return i % 2!= 0;。
2. 浮点数
浮点数是计算机特有的表示数值的方法,特点是小数点可以浮动,这与人理解数字的方式是不一样的。例如,System.out.printf2.0-1.1;显示出的不是0.9,而是0.8999999999999999,人会认为计算机出错了。但是,计算机并没有出错,仅仅是小数点的浮动方式没有按照人的想象。如果想得到正确答案0.9,应该改为System.out.printf"%.1f", 2.0-1.1,指定小数点后面只有1位;或者System.out.printlnnew
BigDecimal"2.0".subtract new BigDecimal"1.1";。
3. 长整除
下面的代码出现的问题也是与Java表示数值的方式有关的。

public class LongDivision {
public
static void mainString[] args {
final
long MICROS_PER_DAY=24*60*60*1000*1000; 微秒
final
long MILLIS_PER_DAY=24*60*60*1000;毫秒
System.out.printlnMICROS_PER_DAYMILLIS_PER_DAY;
结果并不是1000,而是5。原因是Java把等式右端当作int型,产生了越界。如果要得到正确答案,应该改为final long MICROS_PER_DAY=24L*60*60*1000*1000;
final long MILLIS_PER_DAY=24L*60*60*1000;
}
}

4. 字符串和字符

public class CharAndString {
public
static void mainString[] args {
System.out.println"H"
"a";输出Ha
System.out.println''H''
''a'';输出169,字符被自动提升为int型
}
}

5. 字符数组

public class CharArray {
public
static void mainString[] args {
String letters="ABC";
char[] numbers={''1'', ''2'', ''3''};
System.out.printletters " easy as
" numbers; 输出ABC easy as [C@c17164
System.out.printnumbers;print方法用的是重构,输出的是123
}
}

6. 转义字符

public class UnicodeTest {
public
static void mainString[] args {

\u0022 是双引号的 Unicode转义字符
System.out.println"a\u0022.length
\u0022b".length;
输出为2,明显不合逻辑
System.out.println"a".length
"b".length;
}
}

7. 打印输出类名

public class MyClass {
public
static void mainString[] args {
System.out.println
MyClass.class.getName.

replaceAll".","" ".class"; 要输出包名类名.class,应该改为增加转义字符,replaceAll".",""
".class";正确输出为:包名Myclass.class
}
}

8.随机数

import java.util.Random;

public class RandomTest {
private static Random rnd=new Random;
public
static void mainString[] args {
StringBuffer word=null;
switchrnd.nextInt2 { rnd.nextInt2只能取到0和1,2根本就取不到,应该改为rnd.nextInt3
case 1: word=new StringBuffer''P''; 应该增加break;
''P''应该改为"P",''P''表示字符被StringBuffer转化为ASCII码,表示StringBuffer的容量
case 2: word=new StringBuffer''G''; 应该增加break;
''G''应该改为"G"
default: word=new StringBuffer''M'';
''M''应该改为"M"
}
word.append''a'';
word.append''i'';
word.append''n'';
System.out.printlnword; 结果输出为ain,而非Pain、Gain、Main之一
}
}

9.j=j

public class ForTest {
public
static void mainString[] args {
int j=0;
for int i=0; i
j=j; 应该改为j,或者j=j
}
System.out.printlnj; 输出结果为0,而不是预想中的100,出现错误
}
}

10.整数的边界

public class WhileTest {
public
static final int END=Integer.MAX_VALUE;
public
static final int START=END - 100;
public
static void mainString[] args {
int count=0;
for int i=START; icount;
System.out.printlni;所输出的i变成了负数
}
System.out.printlncount; 出现死循环,程序不能正常执行
}
}

11.计数器的问题

public class Clock {
public
static void mainString[] args {
int minutes=0;
for int ms=0; ms if ms % 60*1000==0 ms % 60*1000==0相当于ms %
60*1000==0,应该修改为ms %60*1000==0
minutes;
System.out.printlnminutes; 输出为60000,不是60,出现错误
}
}


12.try-finally

public class ReturnValue {
public
static void mainString[] args {
System.out.printlndecision; 到底返回什么值呢?返回值为false,最终执行的是finally语句
}

public
static boolean decision {
try {
return true; 此处会出现一个中断,不会真正返回
} finally {
return false;
}
}
}
public class GoodBye {
public
static void mainString[] args {
try {
System.out.println"Hello
world";
System.exit0; 程序退出
} finally {
System.out.println"Goodbye
world";
}
}
}最终输出Hello world,在程序中途退出的情况下,不会进一步去执行finally

13.close

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class IOTest {
public
static void mainString[] args {
}
public
static void copyString src, String dest throws IOException {
InputStream in=null;
OutputStream out=null;
try{
in=new FileInputStreamsrc;
out=new FileOutputStreamdest;
byte[] buf=new byte[1024];
int n;
while n=in.readbuf0
out.writebuf, 0, n;
} finally {
ifin!=null in.close; close方法本身会抛出异常,所以要给其加上try
finally语句
if out!=null out.close;
}
}

}调用close 方法并不保证输入或输出流一定会被关闭,因此,当想使用close方法时,正确的做法是try{in.close;}finally{in=null;}

2.1.2
Java客户端方面陷阱
1. 打开其他进程
错误的做法:

public class ExecJavac {
public
static void mainString[] args {
try{
Runtime rt=Runtime.getRuntime;
Process proc=rt.exec"C:\\Program Files\\Internet Explorer\ iexplore.exe";
int exitVal=proc.EixtValue;会出现process has not
exited异常,因为进程还没有退出。逻辑上,写在后面的程序语句应该等到前面的语句执行完毕才开始执行,这是真实的。但是本例中前面的语句打开了一个进程,后面的语句要以该进程被关闭为执行的前提。在没有获得执行前提的条件下,后面的语句执行时就会产生异常。修改为int exitVal=proc.waitFor; 结果为Process exitValue:1
System.out.println"Process exitValue: " exitVal;
} catch Throwable t{
t.printStackTrace;
}
}
}

正确的做法:

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

public class ExecJavac {
public
static void mainString[] args {
try{
Runtime rt=Runtime.getRuntime;
Process proc=rt.exec"javac";
InputStream stderr=proc.getErrorStream;
InputStreamReader isr=new InputStreamReaderstderr;
BufferedReader br=new BufferedReaderisr;
String line=null;
System.out.println"";
while line=br.readLine!=null
System.out.printlnline;
System.out.println"";
int exitVal=proc.waitFor;
System.out.println"Process exitValue: " exitVal;
} catch Throwable t{
t.printStackTrace;
}
}
}结果为Process exitValue:2

错误信息必须先输出,才能执行后面的。javac进程执行时需要提示使用方式,先输出错误信息。一定不要被阻塞住,要等到上面的代码执行完毕。如果上面的代码有问题,就要先对上面的代码进行处理,下面的代码再等待执行。
2. 日志粒度的控制
错误的做法:

private Logger m_log=null;

public BadLoggerLevel l{
FileHandler fh=null;
m_log=Logger.getLogger"BadLogger.logger";
m_log.setLevell;
}

public void test{
System.out.println"The level for the log is: "
m_log.getLevel;
m_log.finest"This is a test for finest";
m_log.finer"This is a test for finer";
m_log.fine"This is a test for fine";
m_log.info"This is a test for info";
m_log.warning"This is a warning test";
m_log.severe"This is a severe test";
}测试结果仅仅能输入info的情况,其他情况无法输出

正确的做法:

import java.io.IOException;
import java.util.logging.ConsoleHandler;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;

public class BadLogger {
private
Logger m_log=null;

public BadLoggerLevel l{
FileHandler
fh=null;
ConsoleHandler ch=new ConsoleHandler;
m_log=Logger.getLogger"BadLogger.logger";
m_log.addHandlerch;
try
{
fh=new
FileHandler"log.xml";
m_log.addHandlerfh;
}
catch
IOExeption ioexc
{
ioexc.printStackTrace;
}
m_log.setLevell;
m_log.setUseParentHandlersfalse;
fh.setLevell;
ch.setLevell;
}

public void test{
System.out.println"The level for the log is: "
m_log.getLevel;
m_log.finest"This is a test for finest";
m_log.finer"This is a test for finer";
m_log.fine"This is a test for fine";
m_log.info"This is a test for info";
m_log.warning"This is a warning test";
m_log.severe"This is a severe test";
}

public static void mainString[] args{
Level loglevel=Level.INFO;
if args.length!=0 {
if args[0].equals"ALL" {
loglevel=Level.ALL;
}
else if args[0].equals"FINE" {
loglevel=Level.FINE;
}
else if args[0].equals"FINEST" {
loglevel=Level.FINEST;
}
else if args[0].equals"WARNING" {
loglevel=Level.WARNING;
}
else if args[0].equals"SEVERE" {
loglevel=Level.SEVERE;
}
}
BadLogger logex=new BadLoggerloglevel;
logex.test;
}
}要有一个能控制level的东西,否则只能显示info下的,需要增加ConsoleHandler

3.单例模式
错误的做法:

public class Apple {
private
static Apple apple=null;

private
Apple{}

public
static Apple getApple{
ifapple==null
{
apple=new
Apple;
}
return
apple;
}
}

正确的做法:
1 public
class Apple {
private
static Apple apple=new Apple;

private
Apple{}

public
static Apple getApple{
return
apple;
}
}

2 public
class Apple {
private
static Apple apple=null;

private
Apple{}

public
static synchronized Apple getApple{
ifapple==null
{
apple=new
Apple;
}
return
apple;
}
}

public class SingletonTest {
public
static void mainString[] args {
test1;
}

public
static void test1{
Apple
apple1=Apple.getApple;
Apple
apple2=Apple.getApple;
ifapple1==apple2
{
System.out.println"是同一个对象";
}else{
System.out.println"不是同一个对象";
}
}

}单线程不能测试出是否是单例模式。在多线程的情况下,getApple可能同时被引用到,它们都用到getApple方法,就可能创建多个Apple对象,这是懒汉式方法。正确的做法是改为饿汉式,在类加载的时候就创建了一个Apple对象。如果一定要使用饿汉式,要加synchronized

4. 无用的设置大小
错误的做法:

import java.awt.Button;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

class CustomButton extends Button{
public CustomButtonString title{
supertitle;
setSize100,100;
}
}

public class BadSetSize extends Frame{
TextArea status;
public BadSetSize{
super"Bad Set Size";
setLayoutnew GridLayout2,0,2,2;
Panel p=new Panel;
CustomButton button=new CustomButton"Press Me";
p.addbutton;
addp;
status=new TextArea3, 50;
status.append"Button size before display: "
button.getSize "\n";
addstatus;
addWindowListenernew WindowAdapter{
public void
windowClosingWindowEvent we{
System.exit1;
}
};
setLocation100,100;
pack;
setVisibletrue;
status.append"Button size after display: "
button.getSize;
}
public static void mainString args []{
new BadSetSize;
}
}

正确的做法:

class CustomButton extends Button{
public CustomButtonString title{
supertitle;
System.out.println"Size of button is : "this.getSize;
}

public Dimension getMinimumSize{
return new Dimension100,100;
}

public Dimension getPreferredSize{
return getMinimumSize;
}
}
setSize100,100是无用功

5. 遍历容器的一些陷阱
错误的做法:

import java.util.Enumeration;
import java.util.Vector;

public class BadVisitor {
public
static void mainString[] args {
Vector v=new Vector;
v.add"one";
v.add"two";
v.add"three";
v.add"four";
Enumeration enume=v.elements;
while enume.hasMoreElements{
String s=String enume.nextElement;
if s.equals"two"
v.remove"two";
else{
System.out.printlns;
}
}
System.out.println"What''s really there...";
enume=v.elements;
while enume.hasMoreElements{
String s=String enume.nextElement;
System.out.printlns;
}
}
}


正确的做法:

import java.util.Iterator;
import java.util.Vector;

public class GoodVisitor {
public
static void mainString[] args {
Vector v=new Vector;
v.add"one"; v.add"two";
v.add"three"; v.add"four";
Iterator iter=v.iterator;
whileiter.hasNext{
String s=String iter.next;
ifs.equals"two"
iter.remove;
else{
System.out.printlns;
}
}
System.out.println"What''s really there...";
iter=v.iterator;
whileiter.hasNext{
String s=String iter.next;
System.out.printlns;
}
}
}
使用枚举遍历时移除操作会引发异常,应该使用迭代器

 

 

書城介紹  | 合作申請 | 索要書目  | 新手入門 | 聯絡方式  | 幫助中心 | 找書說明  | 送貨方式 | 付款方式 台灣用户 | 香港/海外用户
megBook.com.tw
Copyright (C) 2013 - 2024 (香港)大書城有限公司 All Rights Reserved.