天天看点

Springmvc ModelAndView踩过的坑之HttpServletResponse response

先抛出问题。以下两个方法声明有毛区别:

这是在一个controller里面的接口方法声明,这两个方法,一个声明了

另一个没有,他们看似没有区别,但是spring mvc的套路里面,他们在特殊场景下的区别大的你想哭。

先描述问题的源头:

某天刮风,飘来了一个接口需要处理

http://localhost:8088/1/2/rg.html

这个接口没有什么特殊,get请求,返回json数据,由于习惯使用g.html而不是g.json,再为了兼容jsonp,然而依赖@responsebody注解的方式,对jsonp支持不够完美。

因此,方法g里面,直接操作response,具体处理的地方是另一个地方,利用filter+threadlocal实现的,因此,在g方法中无需声明httpservletresponse就能达到目的

这样处理一下,接口也的确返回了数据,但是reponse.status一直是500。问题描述完毕。

怎么了,你累了,说好的200呢?

首先找到500的原因.

spring mvc里面,我配置了根据客户端的不同的请求决定不同的view进行响应的视图解析器

实验证明,如果我不配置这个解析器,页面会直接404,其实这是同一个问题,因此我去掉这个解析器,页面立即显示了闪花眼镜的tomcat404

Springmvc ModelAndView踩过的坑之HttpServletResponse response

看到错误信息,加上404,联想到/1/2/1/2/rg这个资源没有找到,然而,我们本也没打算给它配资源,get请求回去的,是json数据。

在dispaterserlvet的方法dodispatch中,modelandview被赋值,利用这个入口,可以找到原因。

循序打入断点,到了解析方法参数的地方。

如果mv为null,则不会去寻找资源,因此开始寻找这个void请求,为毛还返回不为null的mv。

往下走,

org.springframework.web.servlet.mvc.method.annotation.requestmappinghandleradapter.invokehandlermethod中,调用getmodelandview

如果

为真,那么我们就达到目的了。(我为什么会这么推测了,因此controller参数含response和不含response的情况下,我分别跟踪了代码。为什么想到需要response参数呢,因为别人家的接口都正确返回了200状态,我家的为什么不按套路,只有对比了。)

往下走

org.springframework.web.servlet.mvc.method.annotation.servletinvocablehandlermethod.invokeandhandle中的判断条件

这是请求controller层接口的实现方法,由于我们的rg方法是void返回类型,因此,这里的returnvalue是null,如果满足

就好,而带response参数的请求

为true。

最终

handlermethodargumentresolver.resolveargument(parameter, mavcontainer, webrequest, binderfactory);

隐藏了我们想要的真相。

对于参数response,他对应的方法参数解析器是

mavcontainer是modelandview的容器,里面存放了很多信息,这里不深究了。

这里

设置了请求已经被处理的标识,这样

就为真了。

最后带了response参数的方法,最终返回的modelandview为null,也就不会找到资源

/1/2/1/2/rg

也就不会出现404了。

总结

httpservletresponse httpservletresponse参数神奇的原因是因为

它做了特殊处理,带上这个参数的接口,都会被认为请求已经被处理了。

在springmvc里面,一个参数声明与否,并不是等价的,即使你没有用到,他也有存在的意义

新博客地址:http://www.cnblogs.com/windliu 

继续阅读