在代码中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>
构造函C使用 super 会调用类中的构造函数?br>如果在构造函C使用 superQ则必须在构造函数的W一行代码当中,否则~译器会报错?br>注:在我q里的报错信息ؓ Constructor call must be the first statement in a constructor?br> 代码如下Q?br>
初学者可能会有疑问:TestConstructors q没有承Q何类Qؓ什么它会调用父cȝ构造函数呢Q?br>{案是:?Java 中如果没有显C的l承一个类Q则默认为承自 Object cR?br> 如果没有昄的声明一个构造函敎ͼ~译器自动提供一个没有参数的构造函敎ͼ如果一个构造函数没有显C的 super 调用Q编译器自动提供一个没有参数的 super 调用。所以下面的两段代码在功能上是等LQ?br>
]]>正确优雅的解决用户退出问题——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么一大篇。?
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 {
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 />
//...
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); }
//...
?当用户退出后试图点击后退按钮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.
与直接用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 />
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);
上述解决Ҏ(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篇文章讲述了处理退出问题的解决Ҏ(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.