??xml version="1.0" encoding="utf-8" standalone="yes"?>国产大陆亚洲精品国产,亚洲成a∧人片在线观看无码,久久噜噜噜久久亚洲va久http://www.tkk7.com/majianan/category/14510.html<br> <div align=center > <img width=200 height=50 src="http://www.tkk7.com/images/blogjava_net/majianan/14891/r_5858488902000cu2.gif" name="welcome"> </div> <br> <script language="JavaScript"> <!-- Begin text = "人本是hQ不必刻意去做hQ世本是世,无须_ֿd世;自然的才是快乐的?; color1 = "blue"; color2 = "red"; fontsize = "2"; speed = 100; i = 0; if (navigator.appName == "Netscape") { document.write("<layer id=a visibility=show></layer><br><br><br>"); } else { document.write("<div id=a></div>"); } function changeCharColor() { if (navigator.appName == "Netscape") { document.a.document.write("<center><font face=arial size =" + fontsize + "><font color=" + color1 + ">"); for (var j = 0; j < text.length; j++) { if(j == i) { document.a.document.write("<font face=arial color=" + color2 + ">" + Text.charAt(i) + "</font>"); } else { document.a.document.write(text.charAt(j)); } } document.a.document.write('</font></font></center>'); document.a.document.close(); } if (navigator.appName == "Microsoft Internet Explorer") { str = "<center><font face=arial size=" + fontsize + "><font color=" + color1 + ">"; for (var j = 0; j < text.length; j++) { if( j == i) { str += "<font face=arial color=" + color2 + ">" + text.charAt(i) + "</font>"; } else { str += text.charAt(j); } } str += "</font></font></center>"; a.innerHTML = str; } (i == text.length) ? i=0 : i++; } setInterval("changeCharColor()", speed); // End --> </script> zh-cnFri, 20 Apr 2007 11:41:23 GMTFri, 20 Apr 2007 11:41:23 GMT60[译]understanding constructorshttp://www.tkk7.com/majianan/archive/2007/04/20/112198.html马嘉?/dc:creator>马嘉?/author>Fri, 20 Apr 2007 10:01:00 GMThttp://www.tkk7.com/majianan/archive/2007/04/20/112198.htmlhttp://www.tkk7.com/majianan/comments/112198.htmlhttp://www.tkk7.com/majianan/archive/2007/04/20/112198.html#Feedback2http://www.tkk7.com/majianan/comments/commentRss/112198.htmlhttp://www.tkk7.com/majianan/services/trackbacks/112198.htmlunderstanding constructors

                  --How constructors differ from methods

                                               By Robert Nielsen, JavaWorld.com, 10/13/00

                                               [译] 马嘉?/a>       2007.04.20


key words:

constructor      构造函?nbsp;        method        Ҏ(gu)            instance          实例
object             对象              modifier         修饰W?nbsp;        return type      q回cd
static method   静态方?nbsp;        superclass      类           Inheritance      l承
platypus          鸭嘴?br>

我们说一个构造函数是Ҏ(gu)好比说x鸭嘴兽是另一个哺乛_物一栗?Z了解鸭嘴兽,知道其与其他的哺乛_物的差别Ҏ(gu)们来说非帔R要。同理,了解构造函敎ͼ知道构造函C其他Ҏ(gu)的区别对我们同样重要。对于Q何学习JavaQ尤其是Z获得资格证书的学生来_都需要知道这些区别。在q篇文章中,我将会一一道来。在文章l尾QTable1 ȝ了constructorQ构造函敎ͼ和methodQ方法)的重要区别?br>


Purpose and Function Q目的与功能Q?/span>


构造函数都有一个目的:创徏一个类的实例。也可以叫做创徏一个对象,如下Q?br>

Platypus p1 = new Platypus();


相比之下,Ҏ(gu)QmethodQ的目的昑־更ؓ普? 一个方法的基本功能是Z执行Java的代?




Signature differencesQ签名区别)Q?/span>Signature 不知道怎么译好)


构造函敎ͼconstructorsQ和Ҏ(gu)QmethodsQ在以下三个斚w存在差别Q?br>
·   修饰W?nbsp;  QmodifiersQ?br>·   q回cdQreturn typeQ?br>·   名字     QnameQ?br>
像方法一P构造函数可以有L一U访问修饰符Qaccess modifiersQ:公共的(publicQ,保护的(protectedQ,U有的(privateQ或者没有(常被UCؓpackage或者f(xi)riendlyQ。不同于Ҏ(gu)的是Q构造函数只能被讉K修饰W进行限定。因此,构造函C能是abstract, static, final, natice or synchronized的?nbsp;

两者的q回cdQreturn typeQ也是截然不同的。方法可以拥有Q何有效的q回cdQ或者方法没有返回|q种情况下方法的q回cd为void。构造函数没有返回类型,也没有void?br>
最后,构造函数和Ҏ(gu)在取名方面也有很大的不同。构造函数名字与其类名(class nameQ相同;按照惯例Q方法用其他与cd不相同的名字。如果JavaE序员遵循通常惯例Q方法名会以小写字母开_构造函数名字以大写字母开头。ƈ且,因ؓ与类名相同,构造函数名字通常是个名词Q方法名字是个动词?br>



The use of "this" Qthis的用)


构造函数和Ҏ(gu)使用关键?this 差别很大?br>
Ҏ(gu)中的 this 指的是执行该Ҏ(gu)的类的实例(instanceQ。静态方法(static methodQ不使用 this 。因为静态方法不属于M一个类的实例,所?this 无所指向。静态方法M上属于一个类而非一个类的实例?br>
构造函C?this 指的是,在同一个类中拥有不同的参数列表的另一个构造函数。代码如下:

public class Platypus {
       String name;
       Platypus(String input) {
               name 
= input;
       }
       Platypus() {
               
this("John/Mary Doe");
       }
       
public static void main(String args[]) {
               Platypus p1 
= new Platypus("digger");
               Platypus p2 
= new Platypus();
       }
}


在代码中Q有两个构造函数?br>W一个构造函数通过一个String参数inputlnameq行赋倹{?br>W二个构造函数没有参敎ͼ通过默认的名?John/Mary Doe"来调用第一个构造函数?br>
如果在构造函C使用 thisQ则必须在构造函数的W一行代码当中,否则~译器会报错?br>注:在我q里的报错信息ؓ Constructor call must be the first statement in a constructor?br>



The use of "super"Qsuper的用)


Ҏ(gu)和构造函C?super 的时候,指的都是类QsuperclassQ,但也有所不同?br>
Ҏ(gu)中?super 会执行类中被覆盖的方法,如下所C:

class Mammal {
       
void getBirthInfo() {
               System.out.println(
"born alive.");
       }
}
class Platypus extends Mammal {
       
void getBirthInfo() {
               System.out.println(
"hatch from eggs");
               System.out.print(
"a mammal normally is ");
               
super.getBirthInfo();
       }
}


在上面代码中Qsuper.getBirthInfo() 会调用类 Mammal 中被覆盖的方?getBirthInfo().


构造函C使用 super 会调用类中的构造函数?br>如果在构造函C使用 superQ则必须在构造函数的W一行代码当中,否则~译器会报错?br>注:在我q里的报错信息ؓ Constructor call must be the first statement in a constructor?br>
代码如下Q?br>

public class SuperClassDemo {
        SuperClassDemo() {}
}
class Child extends SuperClassDemo {
       Child() {
               
super();
       }
}





Complier -- supplied codeQ编译器提供的代码)


当编译器自动为构造函数提供代码的时候,Java初学者可能会感到困惑。如果你的类中没有构造函敎ͼ~译器将会ؓ你自动提供一个没有参数的构造函数。如果你的代码如下:

public class Example {}


功能上它{同于如下代码:

public class Example {
       Example() {}
}


如果在你的构造函数的W一行代码当中没有?superQ那么编译器会自动ؓ你提供代码,插入 super?br>如果你的代码如下Q?br>

public class TestConstructors {
       TestConstructors() {}
}


功能上它{同于如下代码:

public class TestConstructors {
       TestConstructors() {
               
super();       
         }
}


初学者可能会有疑问:TestConstructors q没有承Q何类Qؓ什么它会调用父cȝ构造函数呢Q?br>{案是:?Java 中如果没有显C的l承一个类Q则默认为承自 Object cR?br>
如果没有昄的声明一个构造函敎ͼ~译器自动提供一个没有参数的构造函敎ͼ如果一个构造函数没有显C的 super 调用Q编译器自动提供一个没有参数的 super 调用。所以下面的两段代码在功能上是等LQ?br>

public class Example {} 


?br>

public class Example {
       Example() {
             
super();
       }
}





InheritanceQ承)


下面情况有什么不对?

律师阅读cA的遗嘱。所有家庭成员围坐在大会议桌旁,q且有些人在d呜咽。律师说刎ͼ“我,cAQ头脑清楚n体健P我所有的构造函数留l我的孩?#8221;?br>
问题是构造函C是通过l承得到的。然而幸q的是,子类可以自动的承父cL有的Ҏ(gu)Q所以子cdƈ不是一无所有?br>
CQJava Ҏ(gu)可以通过l承得到Q而构造函C行。看下面代码Q?br>

public class Example {
        
public void sayHi {
                system.out.println(
"Hi");
        }
        Example() {}
}
public class SubClass extends Example {
}


c?SubClass 自动l承父类?sayHi Ҏ(gu)。然而,构造函?Example() 不会被类 SubClass 所l承?br>



Summarizing the differences


构造函CҎ(gu)的区别就像鸭嘴兽与典型的Z^动物一栗尤其是在目的(purposeQ,{֐QsignatureQ,?this ?super 的用方面。另外,在承和~译器提供代码方面也有很大差异。记住所有的区别可能会非常辛苦,所以下面提供的一个表|单的概括了重要的差异斚w?br>

Topic Constructors Methods
Purpose Create an instance of a class Group Java statements
Modifiers Cannot be abstract, final, native, static, or synchronized Can be abstract, final, native, static, or synchronized
Return type No return type, not even void void or a valid return type
Name Same name as the class (first letter is capitalized by convention) -- usually a noun Any name except the class. Method names begin with a lowercase letter by convention -- usually the name of an action
this Refers to another constructor in the same class. If used, it must be the first line of the constructor Refers to an instance of the owning class. Cannot be used by static methods
super Calls the constructor of the parent class. If used, must be the first line of the constructor Calls an overridden method in the parent class
Inheritance Constructors are not inherited Methods are inherited
Compiler automatically supplies a default constructor If the class has no constructor, a no-argument constructor is automatically supplied Does not apply
Compiler automatically supplies a default call to the superclass constructor If the constructor makes no zero-or-more argument calls to super, a no-argument call to super is made Does not apply




原文Q?a >http://www.javaworld.com/jw-10-2000/jw-1013-constructors.html



]]>
正确优雅的解决用户退出问题——JSP和Struts解决Ҏ(gu)http://www.tkk7.com/majianan/archive/2006/08/24/65147.html马嘉?/dc:creator>马嘉?/author>Thu, 24 Aug 2006 03:01:00 GMThttp://www.tkk7.com/majianan/archive/2006/08/24/65147.htmlhttp://www.tkk7.com/majianan/comments/65147.htmlhttp://www.tkk7.com/majianan/archive/2006/08/24/65147.html#Feedback2http://www.tkk7.com/majianan/comments/commentRss/65147.htmlhttp://www.tkk7.com/majianan/services/trackbacks/65147.html 注:本文是由 马嘉? 译的javaworld.com上的一名为《Solving the logout problem properly and elegantly》的文章Q原文请参看 Solving the logout problem properly and elegantly ?br />
׃2天翻译过后才发现wolfmanchen已经捯先登了,而且译得很准确Q比我的好,^+^Q我q行了修改,在此谢谢wolfmanchen?br />
文中所有示例程序的代码可以从javaworld.com中下载,文章后面有资源链接?br />
我看q之后觉得很好,希望对你也有所帮助Q?br />
其实文中ȝh也就是几行代码的事情Q?
只不q问了把问题的来龙去脉说清楚Q作者才扬扬z洒写了q么一大篇。?

如果性子急,那你直接看代码,有问题在L章里面找{案可以了^+^


                             正确优雅的解决用户退出问?br />                                           ------JSP和Struts解决Ҏ(gu)

摘要

在一个有密码保护的Web应用当中Q正妥善的处理用户退Eƈ不仅仅只需要调用HttpSession对象的invalidate()Ҏ(gu)Q因为现在大部分览器上都有后退(Back)和前q?Forward)按钮Q允许用户后退或前q到一个页面。在用户退Z个Web应用之后Q如果按了后退按钮Q浏览器把缓存中的页面呈现给用户Q这会用户产生疑惑Q他们会开始担心他们的个h数据是否安全?br />
实际上,许多Web应用会弹Z个页面,警告用户退出时关闭整个览器,以此来阻止用Ld退按钮。还有一些用JavaScriptQ但在某些客L览器中q却不一定v作用。这些解x案大多数实现都很W拙Q且不能保证在Q何情况下?00%有效Q同Ӟ它还要求用户有一定的操作l验?br />
q篇文章以简单的E序CZ阐述了正解决用户退出问题的Ҏ(gu)。作者Kevin Le首先描述了一个理想的密码保护Web应用Q然后以CZE序解释问题如何产生q讨决问题的Ҏ(gu)。文章虽然是针对JSPq行讨论阐述Q但作者所阐述的概念很Ҏ(gu)理解而且能够为其他Web技术所采用。最后最后,作者Kevin Le用Jakarta Struts更ؓ优雅地解决用户退出问题。文中包含JSP和Struts的示例程?(3,700 words; September 27, 2004)




大部分Web应用不会包含像银行̎h信用卡资料那h密的信息Q但是一旦涉及到敏感数据Q就需要我们提供某些密码保护机制。例如,在一个工厂当中,工h必须通过Web应用E序讉K他们的时间安排、进入他们的培训评以及查看他们的薪金等{。此时应用SSL(Secure Socket Layer)有些大材小用了(SSL面不会在缓存中保存Q关于SSL的讨论已l超出本文的范围)。但是这些应用又实需要某U密码保护措施,否则Q工人(在这U情况下Q也是Web应用的用者)可以发现工厂中所有员工的Uh机密信息?br />
cM上面的情况还包括位于公共图书馆、医院?font color="#000000">|吧
{公共场所的计机。在q些地方Q许多用户共同用几台计机Q此时保护用L个h数据显得至关重要?
同时应用E序的良好设计与实现对用户专业知识以及相兛_训要求少之又?

让我们来看一下现实世界中一个完的Web应用是怎样工作的:
1. 用户在浏览器中输入URLQ访问一个页面?br />2. Web应用昄一个登陆页面,要求用户输入有效的验证信息?br />3. 用户输入用户名和密码?br />4. 假设用户提供的验证信息是正确的,l过了验证过E,Web应用允许用户览他有权访问的区域?br />5. 退出时Q用L击页面的退出按钮,Web应用昄认面Q询问用h否真的需要退出。一旦用Lȝ定按钮,Sessionl束QWeb应用重新定位到登陆页面。用L在可以放心的d而不用担心他的信息会被泄霌Ӏ?br />6. 另一个用户坐C同一台电(sh)脑前。他点击后退按钮QWeb应用不应该显CZ一个用戯问过的Q何一个页面?br />事实上,Web应用一直停留在登陆面上,除非W二个用h供正的验证信息Q之后才可以讉K他有权限的区域?br />
通过CZE序Q文章向(zhn)阐qC如何在一个Web应用中实C面的功能?br />



一. JSP samples

Z更ؓ有效地向(zhn)说明这个解x案,本文从展示一个Web应用logoutSampleJSP1中碰到的问题开始。这个示例代表了许多没有正确解决退E的Web应用。logoutSampleJSP1包含一下JSP面Qlogin.jsp,  home.jsp,  secure1.jsp,  secure2.jsp,  logout.jsp,  loginAction.jsp, ?logoutAction.jsp。其中页面home.jsp,  secure1.jsp,  secure2.jsp, ?logout.jsp是不允许未经认证的用戯问的Q也是_q些面包含了重要信息,在用L陆之前或者退Z后都不应该显C在览器中。login.jsp面包含了用于用戯入用户名和密码的form。logout.jsp面包含了要求用L认是否退出的form。loginAction.jsp和logoutAction.jsp作ؓ控制器分别包含了登陆和退出动作的代码?br />
W二个WebCZ应用logoutSampleJSP2展示了如何纠正示例logoutSampleJSP1中的问题。但是第二个CZlogoutSampleJSP2自n也是有问题的。在特定情况下,退出问题依然存在?br />
W三个WebCZ应用logoutSampleJSP3对logoutSampleJSP2q行了改q,比较妥善地解决了退出问题?br />
最后一个WebCZlogoutSampleStruts展示了JakartaStruts如何优雅地解决退出问题?br />
注意Q本文所附示例在最新版本的Microsoft Internet Explorer (IE), Netscape Navigator, Mozilla, FireFox和Avant览器上试通过?br />


? Login action

Brian Pontarelli的经典文?
《J2EE Security: Container Versus Custom? 讨论了不同的J2EE认证Ҏ(gu)。文章同时指出,HTTP协议和基于form的认证方法ƈ不能提供处理用户退出问题的机制。因此,解决Ҏ(gu)便是引入用户自定义的安全实现机制Q这提供了更大的灵zL?br />
在用戯定义的认证方法中Q普遍采用的Ҏ(gu)是从用户提交的form中获得用戯入的认证信息Q然后到诸如LDAP (lightweight directory access protocol)或关pL据库(relational database management system, RDBMS)的安全域中进行认证。如果用h供的认证信息是有效的Q登陆动作在HttpSession对象中保存某个对象。HttpSession存在着保存的对象则表示用户已经登陆到Web应用当中。ؓ了方便v见,本文所附的CZ只在HttpSession中保存一个用户名以表明用户已l登陆。清?是从loginAction.jsp面中节选的一D代码以此讲解登陆动作:




Listing 1
//...

//initialize RequestDispatcher object; set forward to home page by default
RequestDispatcher rd = request.getRequestDispatcher(
"home.jsp" );

//Prepare connection and statement

rs = stmt.executeQuery(
"select password from USER where userName = '" + userName + "'" );
if (rs.next()) {
//Query only returns 1 record in the result set;
//Only 1
password per userName which is also the primary key
    if (rs.getString(
"password" ).equals(password)) { //If valid password

        session.setAttribute(
"User" , userName); //Saves username string in the session object
    }
    else {
//Password does not match, i.e., invalid user password
        request.setAttribute(
"Error" , "Invalid password." );

        rd = request.getRequestDispatcher(
"login.jsp"
);
    }
}
//No record in the result set, i.e., invalid username

    else {

        request.setAttribute(
"Error" , "Invalid user name." );
        rd = request.getRequestDispatcher(
"login.jsp"
);
    }
}

//As a controller, loginAction.jsp finally either forwards to "login.jsp" or "home.jsp"

rd.forward(request, response);
//...

				
				
		


本文当中所附Web应用CZ均以关系型数据库作ؓ安全域,但本问所讲述的内容同样适用于其他Q何类型的安全域?br />


? Logout action

退出动作包含删除用户名以及调用用户的HttpSession对象的invalidate()Ҏ(gu)。清?是从loginoutAction.jsp中节选的一D代码,以此说明退出动作:



Listing 2
//...

session.removeAttribute(
"User" );
session.invalidate();
//...

						
						
				


? L未经认证讉K受保护的JSP面

从提交的form中获取用h交的认证信息q经q验证后Q登陆动作仅仅在HttpSession对象中写入一个用户名。退出动作则刚好相反Q它从HttpSession中删除用户名q调用HttpSession对象的invalidate()Ҏ(gu)。ؓ了登陆和退出动作真正发挥作用,所有受保护的JSP面必须首先验证HttpSession中包含的用户名,以便认用户当前是否已经登陆。如果HttpSession中包含了用户名,p明用户已l登陆,Web应用会将剩余的JSP中的动态内容发送给览器。否则,JSP将跌{到登陆页面,login.jsp。页面home.jsp,  secure1.jsp,  secure2.jsp?logout.jsp均包含清?中的代码D:


Listing 3
//...
String userName = (String) session.getAttribute(
"User" );
if (null == userName) {
    request.setAttribute(
"Error" , "Session has ended. Please login."
);
    RequestDispatcher rd = request.getRequestDispatcher(
"login.jsp"
);
    rd.forward(request, response);
}
//...

//Allow the rest of the dynamic content in this JSP to be served to the browser
//...
						
						
				


在这个代码段中,E序从HttpSession?font color="#000000">?/font>username字符丌Ӏ如果username字符串ؓI,Web应用则自动中止执行当前页面ƈ跌{到登陆页Q同时给出错误信息“Session has ended. Please log in.”;如果不ؓI,Web应用l箋执行Q把剩余的页面提供给用户Q从而JSP面的动态内Ҏ(gu)为服务对象?br />


?q行logoutSampleJSP1

q行logoutSampleJSP1会出现如下几种情ŞQ?br />
?如果用户没有登陆QWeb应用会正确中止受保护页面home.jsp,  secure1.jsp,  secure2.jsp和logout.jsp中动态内容的执行。也是_假如用户q没有登陆,但是在浏览器地址栏中直接敲入受保护JSP늚地址试图讉KQWeb应用自动蟩转到登陆面Q同时显C错误信息“Session has ended.Please log in.?br />
?同样的,当一个用户已l退出,Web应用会正确中止受保护页面home.jsp,  secure1.jsp,  secure2.jsp和logout.jsp中动态内容的执行。也是_用户退Z后,如果在浏览器地址栏中直接敲入受保护JSP늚地址试图讉KQWeb应用自动蟩转到登陆面Q同时显C错误信息“Session has ended.Please log in.?br />
?用户退Z后,如果点击览器上的后退按钮q回到先前的面QWeb应用不能正保护受保护的JSP面——在Session销毁后Q用户退出)受保护的JSP会重新昄在浏览器中。然而,点击该页面上的Q何链接,Web应用都会跌{到登陆页面,同时昄错误信息“Session has ended.Please log in.?br />


? L览器缓?/font>
 
上述问题的根源就在于C大部分浏览器都有一个后退按钮。当点击后退按钮Ӟ默认情况下浏览器不会从Web服务器上重新获取面Q而是单的从浏览器~存中重新蝲入页面。这个问题ƈ不仅限于ZJava(JSP/servlets/Struts) 的Web应用当中Q在ZPHP (Hypertext Preprocessor)、ASP?Active Server Pages)、和.NET的Web应用中也同样存在?br />
在用Ld退按钮之后Q浏览器到Web服务器(一般来_或者应用服务器Q在java的情况下Q再从服务器到浏览器q样通常意义上的HTTP回\q没有徏立。仅仅只是用P览器和~存之间q行了交互。所以即使受保护的JSP面Q例如home.jsp,  secure1.jsp,  secure2.jsp和logout.jsp包含了清?上的代码Q当点击后退按钮Ӟq些代码也永q不会执行的?br />
~存的好坏,真是仁者见仁智者见智。缓存事实上的确提供了一些便利,但这些便利通常只存在于静态的HTML面或基于图形或影像的页面。而另一斚wQWeb应用通常是面向数据的。由于Web应用中的数据频繁变更Q所以与Z节省旉从缓存中dq显C期的数据相比Q提供最新的数据昑־ؓ重要Q?br />
q运的是QHTTP头信息“Expires”和“Cache-Control”ؓ应用E序服务器提供了一个控制浏览器和代理服务器上缓存的机制。HTTP头信息Expires告诉代理服务器它的缓存页面何时将q期。HTTP1.1规范中新定义的头信息Cache-Control在Web应用当中可以通知览器不~存M面。当点击后退按钮Ӟ览器发送Httph道应用服务器以便获取该页面的最新拷贝。如下是使用Cache-Control的基本方法:

?no-cache:强制~存从服务器上获取该面的最新拷?br />?no-store: 在Q何情况下~存不保存该面

HTTP1.0规范中的Pragma:no-cache{同于HTTP1.1规范中的Cache-Control:no-cacheQ同样可以包含在头信息中?

通过使用HTTP头信息的cache控制Q第二个CZ应用logoutSampleJSP2解决了logoutSampleJSP1的问题。logoutSampleJSP2与logoutSampleJSP1不同表现在如下代码段中,q一代码D加入进所有受保护的页面中Q?br />



//...
response.setHeader(
"Cache-Control" , "no-cache" ); //Forces caches to obtain a new copy of the page from the origin server
response.setHeader(
"Cache-Control" , "no-store" ); //Directs caches not to store the page under any circumstance
response.setDateHeader(
"Expires" , 0); //Causes the proxy cache to see the page as "stale"
response.setHeader(
"Pragma" , "no-cache" ); //HTTP 1.0 backward compatibility
String userName = (String) session.getAttribute(
"User" );
if (null == userName) {
    request.setAttribute(
"Error" , "Session has ended. Please login."
);
    RequestDispatcher rd = request.getRequestDispatcher(
"login.jsp"
);
    rd.forward(request, response);
}
//...

						
						
				


通过讄头信息和查HttpSession对象中的用户名来保览器不会缓存JSP面。同Ӟ如果用户未登陆,JSP面的动态内容不会发送到览器,取而代之的是登陆面login.jsp?br />


? q行logoutSampleJSP2

q行WebCZ应用logoutSampleJSP2后将会看到如下结果:

?当用户退出后试图点击后退按钮Q浏览器不会重新昄受保护的面Q它只会昄登陆login.jsp同时l出提示信息Session has ended. Please log in.

?然而,当按了后退按钮q回的页是处理用h交数据的面ӞIE和Avant览器将弹出如下信息提示Q?br />
           警告Q页面已q期
           The page you requested was created using information you submitted in a form. This page is no longer available. As a security precaution, Internet Explorer does not automatically  resubmit your information for you.

Mozilla和FireFox览器将会显CZ个对话框Q提CZ息如下:

            The page you are trying to view contains POSTDATA that has expired from cache. If you  resend the data, any action from the form carried out (such as a search or online purchase) will be repeated. To resend the data, click OK. Otherwise, click Cancel.

在IE和Avant览器中选择h或者在Mozilla和FireFox览器中选择重新发送数据后Q前一个JSP面重新显C在览器中。显然的Q这病不是我们所想看到的因ؓ它违背了logout动作的目的。发生这一现象Ӟ很可能是一个恶意用户在试获取其他用户的数据。然而,q个问题仅仅出现在点d退按钮后,览器返回到一个处理POSTh的页面?br />


? 记录最后登陆时?

上述问题的发生是因ؓ览器重新提交了其缓存中的数据。这本文的例子中Q数据包含了用户名和密码。尽IE览器给Z安全警告信息Q但事实上浏览器此时起到了负面作用?br />
Z解决logoutSampleJSP2中出现的问题QlogoutSampleJSP3的login.jsp除了包含username和password的之外,q增加了一个称作lastLogon的隐藏表单域Q此表单域将会动态的被初始化Z个long型倹{这个long型值是通过调用System.currentTimeMillis()获取到的?970q??日以来的毫秒数。当login.jsp中的form提交ӞloginAction.jsp首先隐藏域中的g用户数据库中的lastLogonD行比较。只有当lastLogon表单域中的值大于数据库中的值时Web应用才认是个有效的登陆?br />
Z验证登陆Q数据库中lastLogon字段必须用表单中的lastLogonD行更新。上例中Q当览器重复提交缓存中的数据时Q表单中的lastLogong比数据库中的lastLogon值大Q因此,loginAction蟩转到l(f)ogin.jsp面Qƈ昄如下错误信息“Session has ended.Please log in.”清?是loginAction中节选的代码D:




清单5
//...
RequestDispatcher rd = request.getRequestDispatcher(
"home.jsp" ); //Forward to homepage by default
//...
if (rs.getString(
"password" ).equals(password)) { //If valid password
    long lastLogonDB = rs.getLong(
"lastLogon" );
    if (lastLogonForm > lastLogonDB) {
        session.setAttribute(
"User" , userName); //Saves username string in the session object

        stmt.executeUpdate(
"update USER set lastLogon= " + lastLogonForm + " where userName = '" + userName + "'" );
    }
    else {
        request.setAttribute(
"Error" , "Session has ended. Please login."
);
        rd = request.getRequestDispatcher(
"login.jsp"
); }
    }
else {
//Password does not match, i.e., invalid user password

    request.setAttribute(
"Error" , "Invalid password." );
    rd = request.getRequestDispatcher(
"login.jsp"
);
}
//...

rd.forward(request, response);
//...
						
						
				


Z实现上述Ҏ(gu)Q你必须记录每个用户的最后登陆时间。对于采用关pd数据库安全域来说Q这点可以可以通过在某个表中加上lastLogin字段L实现。虽然对LDAP以及其他的安全域来说需要稍微动下脑{,但最后登陆方法很昄是可以实现的?br />
表示最后登陆时间的Ҏ(gu)有很多。示例logoutSampleJSP3利用了自1970q??日以来的毫秒数。这个方法即使在许多人在不同览器中用一个用戯̎L陆时也是可行的?br />


? q行logoutSampleJSP3

q行CZlogoutSampleJSP3展C如何正处理退出问题。一旦用户退出,点击览器上的后退按钮在Q何情况下都不会在览器中昄受保护的JSP面。这个示例展CZ如何正确处理退出问题而不需要对用户q行额外的培训?br />
Z使代码更l有效,一些冗余的代码可以剔除。一U途径是把清?中的代码写到一个单独的JSP中Q其他JSP面可以通过标签 <jsp:include>q行使用
?br />


? Struts框架下的退出实?/font>

与直接用JSP或JSP/servletsq行Web应用开发相比,另一个更好的可选方案是使用Struts。对于一个基于Struts的Web应用来说Q添加一个处理退出问题的框架可以优雅CҎ(gu)力的实现。这归功于Struts是采用MVC设计模式的,因此可以模型和视图代码清晰的分R另外,Java是一个面向对象的语言Q支持承,可以比JSP中的脚本更ؓҎ(gu)地实C码重用。对于Struts来说Q清?中的代码可以从JSP面中移植到Actioncȝexecute()Ҏ(gu)中?br />
此外Q我们还可以定义一个承Struts ActioncȝAction基类Q其execute()Ҏ(gu)中包含了cM清单4中的代码。通过l承Q其他Actioncd以承基本类中的通用逻辑来设|HTTP头信息以及检索HttpSession对象中的username字符丌Ӏ这个Action基类是一个抽象类q定义了一个抽象方法executeAction()。所有承自Action基类的子c都必须实现exectuteAction()Ҏ(gu)而不是覆盖它。通过l承q一机制Q所有承自Action基类的子c都不必再担心退Z码接口。(plumbing实在不知道怎么译了,^+^Q高手帮帮忙啊!原文QWith this inheritance hierarchy in place, all of the base Action's subclasses no longer need to worry about any plumbing logout code.Q。他们将只包含正常的业务逻辑代码。清?是基cȝ部分代码Q?br />


清单6
publicabstractclass BaseAction extends Action {
    public ActionForward execute(ActionMapping mapping, ActionForm form,
                                                 HttpServletRequest request, HttpServletResponse response) 
               throws IOException, ServletException {

response.setHeader(
"Cache-Control" , "no-cache" ); //Forces caches to obtain a new copy of the page from the origin server
response.setHeader(
"Cache-Control" , "no-store" ); //Directs caches not to store the page under any circumstance
response.setDateHeader(
"Expires" , 0); //Causes the proxy cache to see the page as "stale"
response.setHeader(
"Pragma" , "no-cache" ); //HTTP 1.0 backward compatibility

if (!this.userIsLoggedIn(request)) {
    ActionErrors errors = new ActionErrors();

    errors.add(
"error" , new ActionError( "logon.sessionEnded" ));
    this.saveErrors(request, errors);

    return mapping.findForward(
"sessionEnded"
);
}

return executeAction(mapping, form, request, response);
}

protectedabstract ActionForward executeAction(ActionMapping mapping,  ActionForm form, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException;

privateboolean userIsLoggedIn(HttpServletRequest request) {
if (request.getSession().getAttribute(
"User"
) == null) {
    return false;
}

return true;
}
}
						
						
				


清单6中的代码与清?中的很相像,唯一区别是用ActionMapping findForward替代了RequestDispatcher forward。清?中,如果在HttpSession中未扑ֈusername字符ԌActionMapping对象找到名为sessionEnded的forward元素q蟩转到对应的path。如果找CQ子c通过实现executeAction()Ҏ(gu)Q将执行他们自己的业务逻辑。因此,在struts-web.xml配置文g中ؓ所有承自Action基类的子cd明个一名ؓsessionEnded的forward元素q将其指向login.jsp是至关重要的。清?以secure1 action阐明了这样一个声明:


清单7
<action path=
"/secure1"
type=
"com.kevinhle.logoutSampleStruts.Secure1Action"
scope=
"request" >
<forward name=
"success" path= "/WEB-INF/jsps/secure1.jsp"
/>
<forward name=
"sessionEnded" path= "/login.jsp"
/>
</action>

						
						
				


l承自BaseActioncȝ子类Secure1Action实现了executeAction()Ҏ(gu)而不是覆盖它。Secure1ActioncM需要执行Q何退Z码,如清?Q?br />


清单8
publicclass Secure1Action extends BaseAction {
    public ActionForward executeAction(ActionMapping mapping, ActionForm form,
                                                           HttpServletRequest request, HttpServletResponse response)
               throws IOException, ServletException {

               HttpSession session = request.getSession(); 
               return (mapping.findForward(
"success" ));
         }
}
						
						
				


上面的解x案是如此的优雅有效,它仅仅只需要定义一个基c而不需要额外的代码工作。将通用的行为方法写成一个承StrutsAction的基cL者的推荐的,而且q是许多Struts目的共同经验?br />



十一. 局限?/font>

上述解决Ҏ(gu)对JSP或基于Struts的Web应用都是非常单而实用的Q但它还是有某些局限。在我看来,q些局限ƈ不是臛_紧要的?br />
• ?通过取消与浏览器后退按钮有关的缓存机Ӟ一旦用L开面而没有对数据q行提交Q那么页面将会丢失所有输入的数据。即使点L览器的后退按钮q回到刚才的面也无于事,因ؓ览器会从服务器获取新的I白面昄出来。一U可能的Ҏ(gu)q不是阻止这些JSP面包含数据数据表格。在ZJSP的解x案当中,那些JSP面可以删除在清?中的代码。在ZStruts的解x案当中,Actionc需要承自Struts的Actionc而非BaseActioncR?br />
•  上面讲q的Ҏ(gu)在Opera览器中不能工作。事实上没有适用于Opera览器的解决Ҏ(gu)Q因为Opera览器与2616 Hypertext Transfer Protocol—HTTP/1.1紧密相关。Section 13.13 of RFC 2616 states:          
User agents often have history mechanisms, such as "Back" buttons and history lists, which can be used to redisplay an entity retrieved earlier in a session.

History mechanisms and caches are different. In particular history mechanisms SHOULD NOT try to show a semantically transparent view of the current state of a resource. Rather, a history mechanism is meant to show exactly what the user saw at the time when the resource was retrieved.

q运的是Q用微软的IE和基于Mozilla的浏览器用户多余Opera览器。上面讲q的解决Ҏ(gu)对大多数用户来说q是有帮助的。另外,无论是否使用上述的解x案,Opera览器仍然存在用户退出问题,O(jin)pera来说没有M改变。然而,正如RFC2616中所_通过像上面一栯|头文g指oQ当用户点击一个链接时QOpera览器不会从~存中获取页面?br />



十二. l论

q篇文章讲述了处理退出问题的解决Ҏ(gu)Q尽方案简单的令h惊讶Q但在所有情况下都能有效地工作。无论是对JSPq是StrutsQ所要做的不q是写一D不过50行的代码以及一个记录用h后登陆时间的Ҏ(gu)。在有密码保护的Web应用中用这些方案能够确保在M情况下用LUh数据不致泄露Q同Ӟ也能增加用户的经验?br />
About the author
[i]Kevin H. Le[/i] has more than 12 years of experience in software development. In the first half of his career, his programming language of choice was C++. In 1997, he shifted his focus to Java. He has engaged in and successfully completed several J2EE and EAI projects as both developer and architect. In addition to J2EE, his current interests now include Web services and SOA. More information on Kevin can be found on his Website http://kevinhle.com.




]]>
վ֩ģ壺 йchina[ձ| ĻmvѸƵ7| ߹ۿվ| ƷAVһ| ձƵһ߹ۿ| ޹˾þۺ3d| Դ߹ۿѰ| ޹þþþƷС˵| ߻ɫӰ| ޸Ƶ| ר˿ŵƵ| ˳ӰԺҹվ| ˻ƶվƵ| ˳վѲ| Ļѵַվ| һëƬƵѹۿ| ƷƬ| 91ƷѲ| AVվ| Ƭѿ| ɫۺϽѹۿ| þþƷ鶹| 13һ14ëƬ| ɫͼƬС˵| պAvĻþþ޸ | պƷר| ޾ƷŮһ | þþþAVۿ | ѿ۳ҹվ| ձ޸߹ۿ| AVרպ| ձɫͼ߹ۿ| a߹ۿ| ޳AƬ߹ۿ| ձһ| ޾Ʒɫһ| պ߾Ʒһ| VAһ| ŷ߹ۿ| þþŷղũ| 97޳|