您的位置:首页 > 编程语言 > Java开发

[异常]java.lang.IllegalStateException: Cannot forward after response has been committed 的完美解决 for nutz

2011-06-17 16:38 597 查看
大部分的java.lang.IllegalStateException: Cannot forward after response has been committed

异常都是由于response对象在执行完一次向客户端的写操作后,

response.iscommt()==true

再执行一次写操作就会报这个异常.

我这次是在使用nutz时遇到的,

其实在其他环境遇到也一样能解决,

版本是1.b.37-rc.jar

-------------------------------异常栈

java.lang.IllegalStateException: Cannot forward after response has been committed
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:312)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:302)
at org.nutz.mvc.view.ForwardView.render(ForwardView.java:64)
at org.nutz.mvc.impl.processor.ViewProcessor.process(ViewProcessor.java:35)
at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
at org.nutz.mvc.impl.processor.MethodInvokeProcessor.process(MethodInvokeProcessor.java:23)
at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
at org.nutz.mvc.impl.processor.AdaptorProcessor.process(AdaptorProcessor.java:33)
at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
at org.nutz.mvc.impl.processor.ActionFiltersProcessor.process(ActionFiltersProcessor.java:42)
at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
at org.nutz.mvc.impl.processor.ModuleProcessor.process(ModuleProcessor.java:76)
at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
at org.nutz.mvc.impl.processor.EncodingProcessor.process(EncodingProcessor.java:27)
at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
at org.nutz.mvc.impl.processor.UpdateRequestAttributesProcessor.process(UpdateRequestAttributesProcessor.java:15)
at org.nutz.mvc.impl.NutActionChain.doChain(NutActionChain.java:36)
at org.nutz.mvc.impl.ActionInvoker.invoke(ActionInvoker.java:66)
at org.nutz.mvc.ActionHandler.handle(ActionHandler.java:30)
at org.nutz.mvc.NutFilter.doFilter(NutFilter.java:66)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at cn.com.fanna.managercontroller.web.filter.XFilter.doFilter(XFilter.java:26)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)
at java.lang.Thread.run(Unknown Source)
log4j: 2011-06-17 15:43:46,671 [http-8080-2] DEBUG org.nutz.mvc.impl.UrlMappingImpl - find mapping [null] for path [/img]

-----------------------------------------------------

关键是在调用org.nutz.mvc.impl.processor.*processor的doNext()方法时,

调用了iscommit()为true的response对象造成的,

我们只要在这以环节,

判断下iscommt(),

如==true,什么都不干返回,

否则,进行下个next.process()

org.nutz.mvc.impl.processo.

AbstractProcessor.java

是关键,它是其他processors的超类,

所有就改它就可以了

代码:

关键代码:

/**
* 继续执行下一个Processor
* <p/><b>一般情形下都不应该覆盖这个方法<b>
* @param ac 执行方法的上下文
* @throws Throwable
*/
protected void doNext(ActionContext ac) throws Throwable {
if(ac!=null&&ac.getResponse()!=null&&(!ac.getResponse().isCommitted())){ //就加这个判断就好了
if (null != next)
next.process(ac);
}

}

全部代码:

package org.nutz.mvc.impl.processor;

import org.nutz.mvc.ActionContext;
import org.nutz.mvc.ActionInfo;
import org.nutz.mvc.NutConfig;
import org.nutz.mvc.ObjectInfo;
import org.nutz.mvc.Processor;
import org.nutz.mvc.impl.Loadings;

/**
* 抽象的Processor实现. 任何Processor实现都应该继承这个类,以获取正确的执行逻辑.
* <p/>
* @author zozoh(zozohtnt@gmail.com)
* @author wendal(wendal1985@gmail.com)
*
*/
public abstract class AbstractProcessor implements Processor {

private Processor next;

/**
* 建议覆盖这个方法,以便从NutConfig/ActionInfo获取需要的信息
*/
public void init(NutConfig config, ActionInfo ai) throws Throwable {
}

/**
* 设置下一个Processor
* <p/><b>一般情形下都不应该覆盖这个方法<b>
* @param next 下一个Processor,一般不为null
*/
public void setNext(Processor next) {
this.next = next;
}

/**
* 继续执行下一个Processor
* <p/><b>一般情形下都不应该覆盖这个方法<b>
* @param ac 执行方法的上下文
* @throws Throwable
*/
protected void doNext(ActionContext ac) throws Throwable {
if(ac!=null&&ac.getResponse()!=null&&(!ac.getResponse().isCommitted())){
if (null != next)
next.process(ac);
}

}

protected static <T> T evalObj(NutConfig config, ObjectInfo<T> info) {
return null == info ? null : Loadings.evalObj(config, info.getType(), info.getArgs());
}

}


好了,将这个类单独编译出来,放到nutz的jar包中去,就可以了.

-------------------------------------------------------------------

Thinking:

之后问了nutz的作者兽哥,它说就不该让doNext有机会执行,

再次查看异常栈,

发现直接可以在

NutFilter.java做文章,

也就是nutz的启动类,

手段是一样的,



public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain){}

方法中判断resp的isCommit()状态,做相应修改,应该是这个样子吧

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
if (!skipMode&&(!resp.isCommitted())) {
RequestPath path = Mvcs.getRequestPathObject((HttpServletRequest) req);
if (null == ignorePtn || !ignorePtn.matcher(path.getUrl()).find()) {
if (handler.handle((HttpServletRequest) req, (HttpServletResponse) resp))
return;
}
}
// 如果已经找到对应的action,而且正确处理,并且不是donext模式,那么不会走到这里
//更新 Request 必要的属性
Mvcs.updateRequestAttributes((HttpServletRequest) req);
// 本过滤器没有找到入口函数,继续其他的过滤器
chain.doFilter(req, resp);
}


ok ,这样一来,如果response被提交,直接让容器执行其它filter,

离开nutz的范围,与nutz无关了.

还是要感谢nutz的所有贡献者,让我学到了这个有趣的东西,

尤其是兽哥,每天在qq群里解答大家的各种疑问,

再次膜拜下你们.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐