本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《
阿里云开发者社区用户服务协议
》和
《
阿里云开发者社区知识产权保护指引
》。如果您发现本社区中有涉嫌抄袭的内容,填写
侵权投诉表单
进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
后台代码:
[2017:05:1709:51:22]:Resolving exception from handler [publicjava.util.Map<java.lang.String, java.lang.Object> com.demo.controller.DemoController.findWxmpType()]:
org.springframework.web.HttpMediaTypeNotAcceptableException: Could not findacceptable representation
项目环境:
spingMVC 4.1.3 + spring + mybatis + jsp + jquery
传输数据格式:
json
debug
调试
【想直接看解决方案的,请直接到文章末尾处】
项目代码及相关配置
spring MVC
部分
配置:
<!--
注解驱动
-->
<
mvc:annotation-driven
>
<!--
如果自定义
message-converters
,默认的
message-converters
将失效
-->
<
mvc:message-converters
>
<!--
定义文本转化器
-->
<
bean
class
=
"org.springframework.http.converter.StringHttpMessageConverter"
>
<
constructor-arg
index
=
"0"
value
=
"UTF-8"
/>
</
bean
>
</
mvc:message-converters
>
</
mvc:annotation-driven
>
<!--
定义
Controller
的扫描包
-->
<
context:component-scan
base-package
=
"com.demo.controller"
/>
<!--
定义视图解析器
-->
class
=
"org.springframework.web.servlet.view.InternalResourceViewResolver"
>
<
property
name
=
"prefix"
value
=
"/WEB-INF/pages/"
/>
<
property
name
=
"suffix"
value
=
".jsp"
/>
</
bean
>
<!--
处理静态资源被
“/”
所拦截的问题
-->
<
mvc:default-servlet-handler
/>
web.xml
部分
配置:
<!--
加载
spring
配置文件
-->
<
context-param
>
<
param-name
>
contextConfigLocation
</
param-name
>
<
param-value
>
classpath:spring/applicationContext*.
xml
</
param-value
>
</
context-param
>
<!--Spring
的
ApplicationContext
载入:
Spring
的监听器
-->
<
listener
>
<
listener-class
>
org.springframework.web.context.ContextLoaderListener
</
listener-class
>
</
listener
>
<!--
加载
SpringMVC
的配置文件
-->
<
servlet
>
<
servlet-name
>
demo
</
servlet-name
>
<
servlet-class
>
org.springframework.web.servlet.DispatcherServlet
</
servlet-class
>
<
init-param
>
<
param-name
>
contextConfigLocation
</
param-name
>
<
param-value
>
classpath:spring/demo-servlet.xml
</
param-value
>
</
init-param
>
<
load-on-startup
>
1
</
load-on-startup
>
</
servlet
>
<!--
配置访问映射的视图路径和后缀
-->
<
servlet-mapping
>
<
servlet-name
>
demo
</
servlet-name
>
<
url-pattern
>
*.
html
</
url-pattern
>
</
servlet-mapping
>
<!—
所有请求
-->
<!--<servlet-mapping>
<servlet-name>demo</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>-->
jsp
页面:
$.post(path+
"/wxmp/findWxmpType.html"
,
function
(data){
alert(data);
console.info("msg:"+data.msg);
if
(data.msg==
"success"
){
alert(data.msg);
Controller
代码:
@RequestMapping
(value =
"/findWxmpType"
, method =RequestMethod.
POST
)
@ResponseBody
public
Map<String, Object> findWxmpType() {
Long
startTime
= System.
currentTimeMillis
();
Map<String,Object>
maps
=
new
HashMap<String, Object>();
try
{
//
微信公众号搜索列表
maps
.put(
"msg"
,
"success"
);
LOGGER
.debug(
"
响应结果:
maps
【
{}
】
"
,
maps
);
}
catch
(Exception
e
) {
LoggerUtil.
errorLog
(
"
执行失败
"
,
startTime
, System.
currentTimeMillis
(),
LOGGER
,
e
);
maps
.put(
"msg"
,
"
加载数据异常,请稍后再试
"
);
return
maps
;
问题跟踪分析
通过
debug
跟踪,
controller
返回
map
集合数据是没有问题的。
问题点出在:
springMVC
在对返回数据进行转换处理的过程中!
网上百度了一下方法:
1,
在
controller
返回的对象中必须包含
getter/setter
方法;(这个并不是问题原因)
2,
在
controller
的
@RequestMapping(value= "/findWxmpType", method = RequestMethod.POST
,produces="application/json"
)
加上红色字体部分。并没有解决问题,
produces
这个属性,大家可以百度下其具体作用是什么。简单来说:就是用于匹配页面的请求头
Accept
信息是否和响应头
Accept
信息(
produces
设置)一致。
3,
配置
jackson
转换器,指定返回数据类型为
text/html;
<bean id="jacksonMessageConverter"
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<!--
解决
HttpMediaTypeNotAcceptableException: Could not findacceptable
representation -->
<propertyname="supportedMediaTypes">
<value>text/html;charset=UTF-8</value>
<!--<value>application/json;charset=UTF-8</value> -->
</list>
</property>
</bean>
这个解决方案,配置后运行效果如下:
数据是可以进行传输了,但已经不是
json
格式,
jsp
无法直接取到
msg
数据。
so,
并没有解决问题!!!删除配置!
springMVC
在处理返回数据的时候是通过转换器
HttpMessageConverter
进行处理的。
org.springframework.web.HttpMediaTypeNotAcceptableException:Could not find acceptable representation
这个错误是:不能找到能接受的
HttpMediaType
协议。也就是说
jsp
页面的请求头
Accept
信息和
controller
返回的响应头
accept
头信息不一致。
前端
jsp
的
Accept
头信息:匹配所有。
指定
MediaTypes
为
json
:
进入
HttpMessageConverter
转换器源码中:
插入一个小话题,
eclipse
跟踪异常源码方法:
点击蓝色部分:弹框:
点击
OK
。
重新访问页面,进入
debug
断点:
跟踪
A
:
@Override
public List<MediaType>resolveMediaTypes(NativeWebRequest webRequest) throwsHttpMediaTypeNotAcceptableException {
for (ContentNegotiationStrategystrategy : this.contentNegotiationStrategies) {
List<MediaType>mediaTypes = strategy.resolveMediaTypes(webRequest);
if (mediaTypes.isEmpty() ||mediaTypes.equals(MEDIA_TYPE_ALL)) {
continue;
return mediaTypes;
return Collections.emptyList();
跟踪
B
:
resolveMediaTypes(webRequest);
@Override
public List<MediaType>resolveMediaTypes(NativeWebRequest webRequest) throwsHttpMediaTypeNotAcceptableException {
String key =getMediaTypeKey(webRequest);
if (StringUtils.hasText(key)) {
MediaType mediaType =lookupMediaType(key);
if (mediaType != null) {
handleMatch(key,mediaType);
returnCollections.singletonList(mediaType);
mediaType =handleNoMatch(webRequest, key);
if (mediaType != null) {
addMapping(key,mediaType);
returnCollections.singletonList(mediaType);
return Collections.emptyList();
跟踪
C
:
getMediaTypeKey(webRequest);
从当前请求
request
当中获取到
MediaType
@Override
protected String getMediaTypeKey(NativeWebRequestwebRequest) {
//
获取
request
对象
HttpServletRequest servletRequest= webRequest.getNativeRequest(HttpServletRequest.class);
if (servletRequest == null) {
logger.warn("AnHttpServletRequest is required to determine the media type key");
return null;
//
获取当前请求路径:
/wxmp/searchWxmps.html
String path =urlPathHelper.getLookupPathForRequest(servletRequest);
//
获取
searchWxmps.html
String filename =WebUtils.extractFullFilenameFromUrlPath(path);
//
获取请求后缀:
html
String extension =StringUtils.getFilenameExtension(filename);
return(StringUtils.hasText(extension)) ? extension.toLowerCase(Locale.ENGLISH) :null;
回到:跟踪
B
:
然后返回
MediaType
。
回到:跟踪
A
:
下一步:直到
ProducesRequestConverter:
@Override
protected booleanmatchMediaType(HttpServletRequest request) throwsHttpMediaTypeNotAcceptableException {
//acceptedMediaTypes=text/html
在经过
springMVC
解析之后的,页面想要的数据头信息
List<MediaType> acceptedMediaTypes =getAcceptedMediaTypes(request);
for (MediaTypeacceptedMediaType : acceptedMediaTypes) {
// getMediaType()=application/json
我们配置的
<value>application/json;charset=UTF8</value>
if(getMediaType().isCompatibleWith(acceptedMediaType)) {
return true;
return false;
结果就是:
在从
jsp
页面发送
ajax
请求的时候,代码是:
$.post(path+"/wxmp/findWxmpType.html",function(data){}
请求路径为:
http://m.demo.com/wxmp/findWxmpType
.html
这个后缀“
.html
”就是问题的根源。
该方法实际上只是为了请求数据,完全可以不带“
.html
”
,但是在
web.xml
里面,进行的伪静态访问配置
<servlet-mapping>
因为该配置,所有的访问,必须加上后缀“
.html
”才能进入后台。
带上这个配置之后,
springMVC
在解析前台请求头信息
Accept
的时候,原本是:
*/*
,却解析成了:
text/html
这样的话,我们在
controller
中加上
@ResponseBody
对返回数据进行
json
转换,设置响应头
Accept=application/json
之后,匹配
matchProduces
异常。
1
,
在
web.xml
中添加这段配置:
<!—
所有请求可进入
-->
<servlet-mapping>
<servlet-name>wupao-mwss</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
也就是放开 前文
web.xml
中最后的注释部分即可。
2
,
jsp
页面请求更改为:
$.post(path+"/wxmp/findWxmpType",function(data){}
去掉
”
.html
”
即可解决问题!!!
本文转自 wyait 51CTO博客,原文链接:http://blog.51cto.com/wyait/1926619,如需转载请自行联系原作者