Sonar的安装很ҎQ按照Sonar官方主页的安装指南解压羃卛_?/p>
Sonar默认使用derby作ؓ数据库,你只需要在sonar.properties文g中去掉对derby数据库属性的注释Q然后启动Apache derby数据库?/p>
按照文档介绍Q启动SonarQ默认的主页地址是http://localhost:9000Q登录用户名和密码是sonar/sonar?/p>
使用Sonar查代码:
要用Sonar查代码,也很Ҏ?/p>
如果待检查项目是maven目Q则只需要安装sonar maven plugin卛_Q如果是非maven目Q则需要在目根目录下创徏pom.xmlQ内Ҏ照文档配|。具体参 见:http://docs.codehaus.org/display/SONAR/Analyzing+Java+Projects
现在只需要项目根目录下,q行mvn sonar:sonar可以运行sonar maven plugin来检查项目中的代码了?/p>
注意Q?/p>
如果目源文件用的~码与系l的默认字符集不同,比如操作pȝ是GBKQ而源文g~码为UTF-8。ؓ了能够正常地查代码,需要在pom.xml的properties元素下增加一w|如:
否则Qsonar在生成checkstyle.xml的时候,不会正的~码传进去,Dcheckstyle在做AST分析的过E中使用了错? 的字W集Q从而提C字W错误:“expecting 'xxx', but got '<EOF>'”。即使是在调用mvn sonar:sonar的时候,增加参数如:
mvn -Dfile.encoding=UTF-8 -DsourceEncoding=UTF-8 sonar:sonar
也无法生效,虽然通过-e开x可以看到pȝ的默认字W集已经Ҏ了UTF-8?/p>
好了Qsonar已经安装完毕Q而且也顺利地完成了代码的分析和检查?/p>
下一步,我们可以分析sonar输出的报告,判断代码的质量,制定改善的措施了?/p>
前一阵子使用JSF开发web应用E序的过E中Q碰C个需求:A面上存在一个链接,用户点击链接会被重定向B面。页面B上存在一个单选框Q如果是通过A面的链接过来,会把单选框|ؓ“选择”的状态。这是非常典型的面转向Q根据JSF的页面{向配|,以及对JSF隐含对象param的介l,下面的代?#8220;貌似”可行Q?
A面Q?<h:commandLink value="Add" action="add">B面Q?
<f:param name="type" value="student" />
</h:commandLink>
<h:form>
<h:selectOneRadio id="type" value="#{param.type}">
<f:selectItem itemlabel="student" itemvalue="student" />
<f:selectItem itemlabel="teacher" itemvalue="teacher" />
</h:selectOneRadio>
<h:commandButton id="add" action="#{backingBean.add}" />
</h:form>
~译、部|Ӏ重新刷新页面。不错,B面上单选框的状态能Ҏ是否来自A面的链接呈现选中或否的状态:一切看上去都很,g已经完成了功能开发。但是,{等Q让我们提交表单。浏览器h了一遍,又回Cq个面。通过查后台数据库以及日志文gQ我们发玎ͼ
在Y件开发中Q调试的目的是解?#8220;如何定位pȝ问题所?#8221;的问题。一般意义上Q解决问题的原则Q套用胡适先生的话,是“大胆假设Q小心求?#8221;Q套用《麦肯锡Ҏ》,则是“以事实ؓ基础Q以假设为导向,l构化推?#8221;。具体来看,调试是这样一U分析问题的ҎQ面对复杂的问题Q通过逐步定正确或者错误的事情Q羃问题范_直到定位问题所在ؓ止。把事情定化,也可以细分ؓ以下步骤Q?
我们先来划定我们初始的问题域QJSFh提交后,JSF不能正常调用后台Ҏq行处理。我们想知道QJSF处理hq程中哪个地方出问题了。那么我们确定的Ҏ什么呢QJSF规范。因为我们用的是SUN开发的JSF RIQ所以它必然满JSF规范。在规范中,JSF的请求处理过E一共分成六个阶D:
我们可以定义一个PhaseListenerQ注册到faces-configs.xml文g里面Q看整个hq程发生了什么?通过查看 glassfish的日志文Ӟ我们发现update model values之后q接render responseQ没?invoke application?如果一切正常,应该是从W一步执行到W六步,但现在蟩q了W五步,直接从第四步CW六步,是哪里出C问题Q好Q从“JSF的处理过E?#8221;?#8220;W四?Update Model Values”Q我们已l羃了问题域的范围Q现在确定的点已l有JSF规范?“Update Model Values”了。l,从JSF规范Ҏ?#8220;”中寻?#8220;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.
q里提到如果我们在updateModel()Ҏ或者事件监听器里面调用了FacesContext的renderResponse()ҎQ就会从事g队列里面直接清空剩下的事Ӟ转向Render Response步骤。但是我们没有注册Q何的事g监听器,也没有自定义Mlg?updateModel()ҎQ那只能是在系l组件的updateModel()Ҏ里面抛出异常被JSF引擎捕获Q然后直?render response。现在进一步羃范围了Q让我们来看看Javaapi doc里面是如何介lUIInput.updateModel() Ҏ的?
Call setValue() method of the ValueExpression to update the value that the ValueExpression points at.
问题转移到javax.el.ValueExpression的setValue()ҎQ我们来看看q个Ҏ的APIQ?/p>
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.
再来看看lg的ValueExpressionQ我们写的是“${param.key}”Q从文档里面可以得知param是 externalContext.getRequestParameterMap()Q?ExternalContext.getRequestParameterMap()的文档描写是q样的:
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肯定不是一P那是否由于该ValueExpressionD的问题。让我们来验证一下,把B面上单选框lg的值改成字W串字面?#8220;student”。现在B面的单选框lg变成了Q?
部vQ运行。不错,现在的页面组件能保持选中的状态,也能利创徏新纪录,日志文g中也有add方式的执行信息:说明的确是因?{param.key} 表达式的求值出错导致异常。这里的#{param}已经不再是上一步的#{param}Q自然无法从externalContext?RequestParameterMap里面扑ֈ参数名ؓtype的倹{因此,JSFq行到这里,因ؓ无法取到参数值去更新面的单选框lgQ所以就跛_了处理过E?/p>
现在Q回q头来看一下问题的原因QJSF在处理请求的时候,会对面lg树上的所有组件进行递归更新Q它会根据组件定义的EL表达式来重新计算|更新lg状态,以保证JSF面lg的状态性。我们得到的教训是param{JSF隐含对象或许能用Q但最好不要放在JSFlg里面?#8220;q什么庙Q拜什么神”Q我们还是选择JSF推荐的backingbean来保持组件的倹{?
软g调试是一很有意思的zdQ常常给开发h员带来解谜般的快感,或者一团ؕȝU结。导入代码、设|断炏V逐步调试q不是最好的办法Q清楚地划分问题域,扑և定点可能会事半功倍。当Ӟ在找出水面下面的暗礁之后Q别忘记l自己、给其他人mark上这块区域的暗礁位置Q能极大减少以后触礁的痛苦?