知识大全 一次非典型性JSF调试过程

Posted

篇首语:没有加倍的勤奋,就既没有才能,也没有天才。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 一次非典型性JSF调试过程相关的知识,希望对你有一定的参考价值。

一次非典型性JSF调试过程  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  问题

  前一阵子使用JSF开发web应用程序的过程中 碰到一个需求 A页面上存在一个链接 用户点击链接会被重定向B页面 页面B上存在一个单选框 如果是通过A页面的链接过来 会把单选框置为 选择 的状态 这是非常典型的页面转向 根据JSF的页面转向配置 以及对JSF隐含对象param的介绍 下面的代码 貌似 可行

  A页面 <h:mandLink value= Add action= add >

  <f:param name= type value= student />

  </h:mandLink>

  B页面 <h:form>

  <h:selectOneRadio id= type value= #param type >

  <f:selectItem itemlabel= student itemvalue= student />

  <f:selectItem itemlabel= teacher itemvalue= teacher />

  </h:selectOneRadio>

  <h:mandButton id= add action= #backingBean add />

  </h:form>

  编译 部署 重新刷新页面 不错 B页面上单选框的状态能根据是否来自A页面的链接呈现选中或否的状态 一切看上去都很美 似乎已经完成了功能开发 但是 等等 让我们提交表单 浏览器刷新了一遍 又回到了这个页面 通过检查后台数据库以及日志文件 我们发现

  数据库里面并没有添加新的记录

  系统也没有按照配置的navigation转向正确的页面

  glassfish的日志文件中没有add方法执行打印的日志 也没有任何异常信息这三点说明 #backingBean add方法并没有调用 原来可以工作的添加功能出现了bug JSF在处理页面提交请求的过程中发生了什么?让我们来调试一下

  原则

  在软件开发中 调试的目的是解决 如何定位系统问题所在 的问题 一般意义上 解决问题的原则 套用胡适先生的话 就是 大胆假设 小心求证 套用《麦肯锡方法》 则是 以事实为基础 以假设为导向 结构化推理 具体来看 调试是这样一种分析问题的方法 面对复杂的问题 通过逐步确定正确或者错误的事情 缩小问题范围 直到定位问题所在为止 把事情确定化 也可以细分为以下步骤

  提出猜想

  验证猜想or捕获异常

  提出新的猜想

  在调试过程中 上面的步骤周而复始 并借助于严密的逻辑论证来推动 直到定位最终的问题原因为止 同时 因为调试的过程中 开发人员面对的是已经 编码完成 的系统 编码完成 的系统可以从如下两个层面来看分解

  技术层面

  业务层面

  如何高效调试不仅仅是调试工具的问题 更是人对技术和业务领域的理解问题 在面对具体问题的时候 是采用 步步为营 还是 分而治之 都是依赖于当时的具体问题 以及开发人员对问题场景的理解程度和技术熟悉程度 那么 高效地调试应该是什么样子呢?我觉得应该是这样的

  划定问题域边界

  选择确定的出发点

  借助其他已经确定的点走查问题域 缩小问题域好 来看看针对JSF的这个问题如何调试

  步骤

  我们先来划定我们初始的问题域 JSF请求提交后 JSF不能正常调用后台方法进行处理 我们想知道 JSF处理请求过程中哪个地方出问题了 那么我们确定的点是什么呢?JSF规范 因为我们使用的是SUN开发的JSF RI 所以它必然满足JSF规范 在规范中 JSF的请求处理过程一共分成六个阶段

  Restore View

  Apply Request Values

  Process Validations

  Update Model Values

  Invoke Application

  Render Response

  我们可以定义一个PhaseListener 注册到faces configs xml文件里面 看整个请求过程发生了什么?通过查看 glassfish的日志文件 我们发现update model values之后就直接render response 没有 invoke application 如果一切正常 应该是从第一步执行到第六步 但现在跳过了第五步 直接从第四步到了第六步 是哪里出现了问题?好 从 JSF的处理过程 到 第四步 Update Model Values 我们已经缩小了问题域的范围 现在确定的点已经有JSF规范和 Update Model Values 了 继续 从JSF规范对步骤 中寻找 Update Model Values 的说明

  If any of the updateModel() methods that was invoked or an event listener that processed a queued event called renderResponse() on the FacesContext instance for the current request clear the remaining events from the event queue and transfer control to the Render Response phase of the request processing lifecycle Otherwise control must proceed to the Invoke Application phase 这里提到如果我们在updateModel()方法或者事件监听器里面调用了FacesContext的renderResponse()方法 就会从事件队列里面直接清空剩下的事件 转向Render Response步骤 但是我们没有注册任何的事件监听器 也没有自定义任何组件的 updateModel()方法 那就只能是在系统组件的updateModel()方法里面抛出异常被JSF引擎捕获 然后直接 render response 现在进一步缩小范围了 让我们来看看Javaapi doc里面是如何介绍UIInput updateModel() 方法的

  Call setValue() method of the ValueExpression to update the value that the ValueExpression points at 问题转移到javax el ValueExpression的setValue()方法 我们来看看这个方法的API

  Evaluates the expression relative to the provided context and sets the result to the provided value

  Throws:

  PropertyNotFoundException if one of the property resolutions failed because a specified variable or property does not exist or is not readable 再来看看组件的ValueExpression 我们写的是 $param key 从文档里面可以得知param就是 externalContext getRequestParameterMap() 而 ExternalContext getRequestParameterMap()的文档描写是这样的

  Return an immutable Map whose keys are the set of request parameters names included in the current request and whose values (of type String) are the first (or only) value for each parameter name returned by the underlying request 因为表单提交时的request跟之前页面转向时的Request肯定不是一样 那是否由于该ValueExpression导致的问题 让我们来验证一下 把B页面上单选框组件的值改成字符串字面值 student 现在B页面的单选框组件就变成了

  <h:form>

  <h:selectOneRadio id= type value= student >

  <f:selectItem itemLabel= student itemValue= student />

  <f:selectItem itemLabel= teacher itemValue= teacher />

  </h:selectOneRadio>

  <h:mandButton id= add action= #backingBean add />

  </h:form>

  部署 运行 不错 现在的页面组件能保持选中的状态 也能顺利创建新纪录 日志文件中也有add方式的执行信息 说明的确是因为#param key 表达式的求值出错导致异常 这里的#param已经不再是上一步的#param 自然无法从externalContext的 RequestParameterMap里面找到参数名为type的值 因此 JSF运行到这里 因为无法取到参数值去更新页面的单选框组件 所以就跳出了处理过程

  现在 回过头来看一下问题的原因 JSF在处理请求的时候 会对页面组件树上的所有组件进行递归更新 它会根据组件定义的EL表达式来重新计算值 更新组件状态 以保证JSF页面组件的状态性 我们得到的教训是param等JSF隐含对象或许能用 但最好不要放在JSF组件里面 进什么庙 拜什么神 我们还是选择JSF推荐的backingbean来保持组件的值

  结语

cha138/Article/program/Java/hx/201311/26352

相关参考

知识大全 JSF请求处理过程(一) FacesServlet初始化

JSF请求处理过程(一)FacesServlet初始化  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧

知识大全 如何调试oracle存储过程

  PL/SQL中为我们提供了调试存储过程的功能可以帮助你完成存储过程的预编译与测试  点击要调试的存储过程右键选择TEST  如果需要查看变量当然调试都需要在右键菜单中选择Adddebuginfor

知识大全 我的三星galaxy A5手机第一次连电脑,打开USB调试后还是连不上怎么办

我的三星galaxyA5手机第一次连电脑,打开USB调试后还是连不上怎么办?  以下文字资料是由(本站网www.cha138.com)小编为大家搜集整理后发布的内容,让我

知识大全 OraclePL/SQL过程调试的输出方法

OraclePL/SQL过程调试的输出方法  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  最基本

简述9E燃机中、大修后,整套启动调试过程时,热工需进行的常规试验?

简述9E燃机中、大修后,整套启动调试过程时,热工需进行的常规试验?参考答案:一般情况下,9E燃机中、大修后,整套启动调试过程时,热工需进行下列常规试验:1、CO2灭火保护系统实战试验。2、盘车系统检查

简述9E燃机中、大修后,整套启动调试过程时,热工需进行的常规试验?

简述9E燃机中、大修后,整套启动调试过程时,热工需进行的常规试验?参考答案:一般情况下,9E燃机中、大修后,整套启动调试过程时,热工需进行下列常规试验:1、CO2灭火保护系统实战试验。2、盘车系统检查

填埋场渗滤液处理工程调试过程记录

调试方案及操作安全规程一、工程概况城市生活垃圾填埋场日处理城市生活垃圾能力为600吨/日,填埋场有效填埋面积248亩,设计使用年限为12年。本垃圾填埋场渗滤液处理工程是城市垃圾无害化系统工程的配套工程

填埋场渗滤液处理工程调试过程记录

调试方案及操作安全规程一、工程概况城市生活垃圾填埋场日处理城市生活垃圾能力为600吨/日,填埋场有效填埋面积248亩,设计使用年限为12年。本垃圾填埋场渗滤液处理工程是城市垃圾无害化系统工程的配套工程

填埋场渗滤液处理工程调试过程记录

调试方案及操作安全规程一、工程概况城市生活垃圾填埋场日处理城市生活垃圾能力为600吨/日,填埋场有效填埋面积248亩,设计使用年限为12年。本垃圾填埋场渗滤液处理工程是城市垃圾无害化系统工程的配套工程

知识大全 Microsoft SQL Server 7.0储存过程调试指南

MicrosoftSQLServer7.0储存过程调试指南  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一