本人在开发一个使用a4j的jsf项目中,出现了一个奇怪的问题,目前还不知道因为什么,但是根据问题发生的异常找到了一个解决方案,在此抛个石头出来,希望有经验的同志们告诉我为什么会导致那个问题。或许这才是正道。
闲话少说。页面是用一个ajax的注册页面,填充必要的字段,然后利用ajax请求(使用a4j组件来完成)进行判断是否正确。在发送每个ajax请求的时候并没有错,但是问题就出现在如果还有错的情况下强行点击注册,那么就应该返回本页,而不能继续,方式是通过jsf 的 "return null" 返回本页。但是在这里却就会抛出一个鬼异常:
executePhase(RENDER_RESPONSE 6,com.sun.faces.context.FacesContextImpl@1928b7c) threw exception
javax.faces.el.ReferenceSyntaxException: javax.el.ELException: Error Parsing: #{}
at com.sun.faces.application.ApplicationImpl.createValueBinding(ApplicationImpl.java:499)
at com.sun.rave.web.ui.appbase.faces.ViewHandlerImpl.pageBean(ViewHandlerImpl.java:662)
at com.sun.rave.web.ui.appbase.faces.ViewHandlerImpl.pageBean(ViewHandlerImpl.java:641)
at com.sun.rave.web.ui.appbase.faces.ViewHandlerImpl.renderView(ViewHandlerImpl.java:249)
at org.ajax4jsf.framework.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:108)
at org.ajax4jsf.framework.ajax.AjaxViewHandler.renderView(AjaxViewHandler.java:233)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:133)
at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:244)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:140)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:245)
at org.apache.catalina.core.ApplicationFilterChain.servletService(ApplicationFilterChain.java:397)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:184)
at org.ajax4jsf.framework.ajax.xmlfilter.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:127)
at org.ajax4jsf.framework.ajax.xmlfilter.BaseFilter.doFilter(BaseFilter.java:277)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:216)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:184)
at com.sun.rave.web.ui.util.UploadFilter.doFilter(UploadFilter.java:198)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:216)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:184)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:276)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:566)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:536)
at org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContextValve.java:240)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:179)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:566)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:73)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:182)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:566)
at com.sun.enterprise.web.VirtualServerPipeline.invoke(VirtualServerPipeline.java:120)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:939)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:137)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:566)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:536)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:939)
at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:239)
at com.sun.enterprise.web.connector.grizzly.ProcessorTask.invokeAdapter(ProcessorTask.java:667)
at com.sun.enterprise.web.connector.grizzly.ProcessorTask.processNonBlocked(ProcessorTask.java:574)
at com.sun.enterprise.web.connector.grizzly.ProcessorTask.process(ProcessorTask.java:844)
at com.sun.enterprise.web.connector.grizzly.ReadTask.executeProcessorTask(ReadTask.java:287)
at com.sun.enterprise.web.connector.grizzly.ReadTask.doTask(ReadTask.java:212)
at com.sun.enterprise.web.connector.grizzly.TaskBase.run(TaskBase.java:252)
at com.sun.enterprise.web.connector.grizzly.WorkerThread.run(WorkerThread.java:75)
Caused by: javax.el.ELException: Error Parsing: #{}
at com.sun.el.lang.ExpressionBuilder.createNodeInternal(ExpressionBuilder.java:140)
at com.sun.el.lang.ExpressionBuilder.build(ExpressionBuilder.java:157)
at com.sun.el.lang.ExpressionBuilder.createValueExpression(ExpressionBuilder.java:201)
at com.sun.el.ExpressionFactoryImpl.createValueExpression(ExpressionFactoryImpl.java:74)
at com.sun.faces.application.ApplicationImpl.createValueBinding(ApplicationImpl.java:495)
... 42 more
Caused by: com.sun.el.parser.ParseException: Encountered "}" at line 1, column 3.
Was expecting one of:
<INTEGER_LITERAL> ...
<FLOATING_POINT_LITERAL> ...
<STRING_LITERAL> ...
"true" ...
"false" ...
"null" ...
"(" ...
"!" ...
"not" ...
"empty" ...
"-" ...
<IDENTIFIER> ...
at com.sun.el.parser.ELParser.generateParseException(ELParser.java:1651)
at com.sun.el.parser.ELParser.jj_consume_token(ELParser.java:1531)
at com.sun.el.parser.ELParser.Unary(ELParser.java:975)
at com.sun.el.parser.ELParser.Multiplication(ELParser.java:735)
at com.sun.el.parser.ELParser.Math(ELParser.java:655)
at com.sun.el.parser.ELParser.Compare(ELParser.java:467)
at com.sun.el.parser.ELParser.Equality(ELParser.java:361)
at com.sun.el.parser.ELParser.And(ELParser.java:305)
at com.sun.el.parser.ELParser.Or(ELParser.java:249)
at com.sun.el.parser.ELParser.Choice(ELParser.java:203)
at com.sun.el.parser.ELParser.Expression(ELParser.java:195)
at com.sun.el.parser.ELParser.DeferredExpression(ELParser.java:133)
at com.sun.el.parser.ELParser.CompositeExpression(ELParser.java:61)
at com.sun.el.lang.ExpressionBuilder.createNodeInternal(ExpressionBuilder.java:103)
... 46 more
我跟踪调试了这个异常,发现是由于在 context.getViewId 得不到正确页面地址,例如注册页面是:http://server:port/project /register.jsp ,那么应该得到register.jsp ,但是此时会得到 "/" ,于是抛出上述异常,看着十分讨厌。
在网上查找资料等乱七八糟的方式之后,得到目前的解决方式。通过注册自己的一个 PhaseListener来截获这个鬼问题,基本的类源代码贴出,并顺便得到了如何判断一个请求是Ajax请求,从a4j的源代码中偷来借用的,hoho。
package myproject;
import java.util.Iterator;
import java.util.Map;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import org.ajax4jsf.framework.ajax.AjaxContext;
/*
* MyPhaseListener.java
*
* Created on 2007年9月5日, 上午10:18
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
/**
*
* @author rockyzheng
*/
public class MyPhaseListener implements PhaseListener {
/** Creates a new instance of MyPhaseListener */
public MyPhaseListener() {
}
public PhaseId getPhaseId() {
return PhaseId.ANY_PHASE;
}
public void beforePhase(PhaseEvent pe){
/*if (pe.getPhaseId() == PhaseId.RESTORE_VIEW){
System.out.println("===================");
System.out.println("Processing new Request!");
System.out.println("===================/n");
}
System.out.println("before - " + pe.getPhaseId().toString());
ExternalContext externalContext = facesContext.getExternalContext();
Map requestParameterMap = externalContext.getRequestParameterMap();
Iterator parameterNames = externalContext.getRequestParameterNames();*/
FacesContext facesContext = FacesContext.getCurrentInstance();
AjaxContext ajaxContext = AjaxContext.getCurrentInstance(facesContext);
if (ajaxContext.isAjaxRequest()){
// System.out.println("============is ajax request ");
facesContext.renderResponse();
}
if (facesContext.getViewRoot() == null){
//System.out.println("before viewRoot is null");
}else{
//System.out.println("before view id is : " + facesContext.getViewRoot().getViewId());
if (facesContext.getViewRoot().getViewId().equals("/")){
//System.out.println("去tmd 的吧");
facesContext.responseComplete();
}
}
/*if (!parameterNames.hasNext()){
System.out.println("no param");
}
while (parameterNames.hasNext()) {
String parameterName = (String) parameterNames.next();
String parameterValue =(String) requestParameterMap.get(parameterName);
System.out.println("before 参数: " + parameterName + " 值 : " + parameterValue);
}
System.out.println("====before phase done=====");*/
}
public void afterPhase(PhaseEvent pe) {
//System.out.println("after phase - " + pe.getPhaseId().toString());
FacesContext context = pe.getFacesContext();
if (context.getViewRoot() == null){
//System.out.println("after viewRoot is null");
}else{
//System.out.println("after view id is : " + context.getViewRoot().getViewId());
if (context.getViewRoot().getViewId().equals("/")){
// System.out.println("去tmd 的吧");
context.responseComplete();
}
}
AjaxContext ajaxContext = AjaxContext.getCurrentInstance(context);
if (ajaxContext.isAjaxRequest()){
//System.out.println("============is ajax request ");
context.renderResponse();
}
/*
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
Map requestParameterMap = externalContext.getRequestParameterMap();
Iterator parameterNames = externalContext.getRequestParameterNames();
if (!parameterNames.hasNext()){
System.out.println("no param");
}
while (parameterNames.hasNext()) {
String parameterName = (String) parameterNames.next();
String parameterValue =(String) requestParameterMap.get(parameterName);
System.out.println("after 参数: " + parameterName + " 值 : " + parameterValue);
}
if (pe.getPhaseId() == PhaseId.RENDER_RESPONSE){
System.out.println("===================/n");
System.out.println("Done with Request!/n");
System.out.println("===================/n");
}*/
}
}
然后在配置文件 faces-config.xml 中注册
<lifecycle>
<phase-listener>myproject.MyPhaseListener</phase-listener>
</lifecycle>
问题解决。
虽然这样可以解决问题,但是我还是在疑惑为什么会出现这个。