【JSF专家Dennis Byrne】JSF反模式与陷井(三)完

终于到本文的最后一节了,本节内容主要讲JSF也是面对接口编程的,作者举了个简单的例子。然后在JSF安全问题上,使用了类似于ASP.NETviewstate概念的东东。最后谈到了头痛的Portlet程序开发问题,作者指出Portlet问题远不止这些,而且问题都出在Portlet本身,非常同情Portlet开发人员。

基于接口编程

JSF鼓励“包含与扩展”的设计原则。因此JSF组件模型广泛基于接口。下面的这个例子中,“ImplementationDependentManagedBean.java”却没有使用接口。好吧,我需要对它做些小小的修正。

import org.apache.myfaces.component.html.ext.HtmlInputHidden;
import org.apache.myfaces.component.html.ext.HtmlInputText;
import org.apache.myfaces.component.html.ext.HtmlOutputText;

public class ImplementationDependentManagedBean {

	private HtmlInputText input ;
	private HtmlInputHidden hidden ;
	private HtmlOutputText output ;

	/* 省略getters和setters方法 */

	public boolean recordTotal(ActionEvent event) {

		long total = ((Long)input.getValue()).longValue();
		total += ((Long)hidden.getValue()).longValue();
		total += ((Long)output.getValue()).longValue();

		return new JmsUtil().broadcastTotal(total);
	}

}

 

   

这个bean绑定了三个组件作为其属性,业务逻辑部分将这三个组件封装到一个action listener里去了。(action listener指的就是这里的recordTotal方法)。这三个类(这里指的是HtmlInputTextHtmlInputHiddenHtmlOutputText)都是MyFaces包自带的。这段代码中需要注意的是这个类的业务逻辑部分recordTotal方法只会调用每个组件的getValue方法。而通过JSFAPI,你又会发现这些组件的getValue方法又承继于它们的父类。因此我决定要重构一下代码,将这几个导入的包给换掉:

import javax.faces.component.ValueHolder;

public class RefactoredManagedBean {

   private ValueHolder input ;
   private ValueHolder hidden ;
   private ValueHolder output ;

   /* getters & setters ommitted */

   public boolean recordTotal(ActionEvent event) {

    long total = 0;

    for(ValueHolder valued : new ValueHolder[] {input, hidden, output})
         total += ((Long)valued.getValue()).longValue();

    return new JmsUtil().broadcastTotal(total);

   }
}

 

 

现在我要说一下,ValueHolderHtmlInputText, HtmlInputHidden HtmlOutputText父类实现的一个接口。通过这次重构,我们只要一个ValueHolder接口就可完成原本需要三个类(上面提到的HtmlInputText, HtmlInputHidden HtmlOutputText)才能完成的工作,代码也干净整洁。你会发现使用Polymorphism(多态)对于基于接口编程的业务逻辑代码整理是相当优雅的。(注:不论是JDK本身还是,目前主流的开源框架,接口,多态运用的非常广泛)

 

请记住,JSF的优点之一就是让你自由自在的在POJO里编写的你的业务逻辑,开发人员并不要实现任何接口或继承任何类!这一点并没有意味着我们失掉了面向对象的编程原则。当你有机会在基于标准的接口上编程的话,大胆去做吧。

 

最后,你有没有注意到recordTotal这个action listener JSF规范规定Actionlistener方法返回值要为void,但咱们这里却返回一个boolean。实际上MyFaces相对规范来说,宽松了点,但允许你这么做,但实际上还是会忽略返回值的。但尽量还是避免这样,因为根据JSF的实现参考来说,有返回值是应该抛异常的,也许别的JSF实现可能与MyFaces不同了吧。

 

 

View State(视图状态)加密

一个普遍的错误观念就是许多开发人员觉得View State加密根本不需要SSL。很显然嘛,SSLView State加密根本没有共同点——它们在各自不同的网络协议中解决属于各自的问题,互不相干。

 

好,我们来再来举个例子。假设Manfred是个银行,Sean是个在线客户,而Mike是媒介。在使用普通的HTTP的情况下,Mike可以截取Sean发送给Mannfred的请求,偷偷记下Sean的密码,然后再转发给Manfred。这一系列动作对于ManfredSean任何一方来说,都是神不知,鬼不觉的。

 

 

 

如果在网络传输层上ManfredSean使用了SSL的话,就可以有效阻止Mike窃取他们之间的信息。

  SSL 提供的是点到点的安全保障,这样从 Sean 发送到 Manfred 的请求就不会被 Mike 截取了。但如果应用程序在客户端保存状态的话, SSL 就法保证一定是安全的了。当使用客户端状态保存时, JSF 会创建一个数据结构,它是一个控件树的序列化 Base64 编码,用来表示绑定组件的响应状态值,这个数据结构就是 view state ,并且此时 view state 是被序列化和加密过的,然后隐藏在的一个 HTML hidden 字段中。  HTML 表单提交时,它会将 view state 的值作为一个 HTTP 参数传到服务器后台。 JSF 利用该参数的值,进行反序列化,解密等逆向操作来还原先前的视图是的状态值。这对所有的 JSF 实现来说都是一个很大安全性挑战,因为 Sean 是可以自由的改变 view state 值的( 因为它只是一个隐藏的 hidden 字段 )。   我强烈推荐在你的产品中使用 view state 加密,因为这样可以防止 web 客户端被恶意篡改 view state 的值。我也建议在开发和功能测试阶段关闭 view state 加密(因为 Base64 编码后的数据量很大,反序列化或解密操作估计有性能损耗)。要想使用 view state 加密,去好好看看你使用的 JSF 实现文档吧。

 

 

Portlet问题

我有点同情Portlet开发人员。确实,他们总是在邮件列表或论坛上不断的提出一个接一个问题,而这些问题本身来自Portlet,与他们无关。如果一定要说有这么一批人不得不对标准低头,被迫屈服的话,那非Portlet开发人员莫属了。(同情中………………

 

有些JSF API在基于Portlet的应用程序中表现的行为是不同的。如果你的Portlet应用程序运行在一个普通的Servlet容器里,那么有一些假设需要去避免。现在假设下面的这段代码在Servlet容器里运行的好好的:

 

FacesContext ctx = FacesContext.getCurrentInstance();
ExternalContext externalContext = ctx.getExternalContext();
ServletRequest request = (ServletRequest) externalContext.getRequest();
String id = request.getParameter("id");

 

 

如果现在你想运行Portlet应用程序,就必须取消显式的对javax.servlet.ServletRequest or javax.servlet.ServletResponse进行转换。在Portlet应用程序中,ExternalContext.getRequest 返回的是一个javax.portlet.PortletRequest,结果可想而知,当然会抛出ClassCastException异常。我这里有一个通用的好办法,也可以获取request中的属性值,请看:

 

FacesContext ctx = FacesContext.getCurrentInstance();
ExternalContext externalContext = ctx.getExternalContext();
externalContext.getRequestParameterMap().get("id");

 

 

 

(全文完)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值