前言

主要介绍自己在学习spring mvc过程中踩到的一些坑,涉及到当时遇到这个错误是如何思考的,对思路进行总结,下次遇到类似的错误能够提供一些思路甚至快速解决。

环境准备

jdk8,spring4.3.3.RELEASE,spring mvc与spring版本一致,maven3.2.5,tomcat7

目标:

1.测试spring mvc的json参数绑定功能

2.测试spring mvc的返回json功能

项目目录(已经推送到github:https://github.com/ComingOnuguys/frankwin):

测试1相关代码:
index.jsp

 <%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
<script type="text/javascript"
src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.min.js"></script>
</head>
<body>
<div>
id:<input type="text" id="id" value="123456"><br>
menuName:<input type="text" id="menuName" value="李白"><br>
<input type="button" id="abc" value="test">
</div> <script type="text/javascript">
window.onload = function() {
$("#abc").click(function() {
var menu = {
"id" : $("#id").val(),
"menuName" : $("#menuName").val()
};
var jsonStr = JSON.stringify(menu);
$.ajax({
type : "POST",
async : false,
url : "http://localhost:8080/ssm/getList",
dataType : "json",
contentType : "application/json;charset=UTF-8",
data : jsonStr,
success : function(data) {
alert("123");
}
});
});
}
</script>
</body>
</html>

getList.jsp(为了返回的时候不报404的错)

 <%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
<script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.min.js"></script>
</head>
<body> <h2>陈公告</h2> </body>
</html>

TestSpringMvcController.java

 package com.dg.action;

 import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import com.dg.bean.Menu; @Controller
public class TestSpringMvcController { @RequestMapping("getList")
public void getList(@RequestBody Menu menu){
System.out.println("menu:" + menu);
}
}

Menu.java

 package com.dg.bean;

 import java.io.Serializable;

 public class Menu implements Serializable {

     private static final long serialVersionUID = 410202860691610816L;
private String id;
private String menuCode;
private String menuName;
private String menuUrl;
private String parentMenuId; public String getId() {
return id;
} public void setId(String id) {
this.id = id;
} public String getMenuCode() {
return menuCode;
} public void setMenuCode(String menuCode) {
this.menuCode = menuCode;
} public String getMenuName() {
return menuName;
} public void setMenuName(String menuName) {
this.menuName = menuName;
} public String getMenuUrl() {
return menuUrl;
} public void setMenuUrl(String menuUrl) {
this.menuUrl = menuUrl;
} public String getParentMenuId() {
return parentMenuId;
} public void setParentMenuId(String parentMenuId) {
this.parentMenuId = parentMenuId;
} @Override
public String toString() {
return "Menu [id=" + id + ", menuCode=" + menuCode + ", menuName=" + menuName + ", menuUrl=" + menuUrl
+ ", parentMenuId=" + parentMenuId + "]";
}
}

spring-config.xml(进行了最大程度精简)

 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> </beans>

spring-mvc.xml

 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
">
<!-- 自动扫描该包,使SpringMVC认为包下用了@controller注解的类是控制器 -->
<context:component-scan base-package="com.dg.action" /> <!-- 启动SpringMVC的注解功能,完成请求和注解POJO的映射 -->
<mvc:annotation-driven/> <!-- 定义跳转的文件的前后缀 ,视图模式配置 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean> </beans>

web.xml

 <?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>ssm</display-name>
<!-- Spring和mybatis的配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-config.xml</param-value>
</context-param>
<!-- 编码过滤器 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Spring监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 防止Spring内存溢出监听器 -->
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener> <!-- Spring MVC servlet -->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<!-- 此处可以可以配置成*.do,对应struts的后缀习惯 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 设置静态资源映射 -->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.gif</url-pattern>
</servlet-mapping> <servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.png</url-pattern>
</servlet-mapping> <servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>/index.jsp</welcome-file>
</welcome-file-list> </web-app>

pom.xml

 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion>
<packaging>war</packaging> <name>ssm</name>
<groupId>dg</groupId>
<artifactId>ssm</artifactId>
<version>0.0.1-SNAPSHOT</version> <properties>
<!-- spring版本号 -->
<spring.version>4.3.3.RELEASE</spring.version>
<!-- log4j日志文件管理包版本 -->
<slf4j.version>1.7.7</slf4j.version>
<log4j.version>1.2.17</log4j.version>
</properties> <dependencies>
<!-- spring核心包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- 日志文件管理包 -->
<!-- log start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency> </dependencies>
</project>

坑一:spring mvc的json包
对于测试1,采用以上代码一直返回httpcode415 (Unsupported Media Type)。如下图:

后台报错的日志为:

 [org.springframework.web.servlet.DispatcherServlet] - DispatcherServlet with name 'SpringMVC' processing POST request for [/ssm/getList]
[org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping] - Looking up handler method for path /getList
[org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping] - Returning handler method [public void com.dg.action.TestSpringMvcController.getList(com.dg.bean.Menu)]
[org.springframework.beans.factory.support.DefaultListableBeanFactory] - Returning cached instance of singleton bean 'testSpringMvcController'
[org.springframework.web.cors.DefaultCorsProcessor] - Skip CORS processing: request is from same origin
[org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod] - Error resolving argument [0] [type=com.dg.bean.Menu]
HandlerMethod details:
Controller [com.dg.action.TestSpringMvcController]
Method [public void com.dg.action.TestSpringMvcController.getList(com.dg.bean.Menu)] org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json;charset=UTF-8' not supported
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:235)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:149)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:127)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:161)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:114)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:646)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:504)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:421)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1074)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
[org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver] - Resolving exception from handler [public void com.dg.action.TestSpringMvcController.getList(com.dg.bean.Menu)]: org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json;charset=UTF-8' not supported
[org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver] - Resolving exception from handler [public void com.dg.action.TestSpringMvcController.getList(com.dg.bean.Menu)]: org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json;charset=UTF-8' not supported
[org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver] - Resolving exception from handler [public void com.dg.action.TestSpringMvcController.getList(com.dg.bean.Menu)]: org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json;charset=UTF-8' not supported
[org.springframework.web.servlet.DispatcherServlet] - Null ModelAndView returned to DispatcherServlet with name 'SpringMVC': assuming HandlerAdapter completed request handling
[org.springframework.web.servlet.DispatcherServlet] - Successfully completed request

看到这个报错提示的第一反应是把前台请求index.jsp的contentType这一行注释掉(注:不写默认值是application/x-www-form-urlencoded;charset=UTF-8):
//contentType : "application/json;charset=UTF-8",
报错变成了:Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported
都不支持,这就没法玩了。考虑controller的参数menu不加@RequestBody能不能参数绑定成功,于是去掉@RequestBody,前台请求注释contentType这一行注释掉,发送的参数由jsonStr这个变量改为menu,发现可以正常注入,根据之前学到的知识,String类型和Json的参数绑定是分别由StringHttpMessageConverter和MappingJackson2HttpMessageConverter进行处理,于是把断点分别打在两个类的构造方法上,断点情况如图:

启动tomcat,发现只进到了StringHttpMessageConverter这个类的构造函数里面。报错的原因找到了(没有加载MappingJackson2HttpMessageConverter),但是为什么没有加载,还不知道原因。重新启动tomcat,顺着StringHttpMessageConverter执行下来,发现有这么一段,

看到MappingJackson2HttpMessageConverter非常眼熟,但是很遗憾,这里的jackson2present变量值是false,

看到这里,接着就是去找该变量是false的原因了。Ctrl+Shift+K找到声明这个变量的地方,

选中com.fasterxml.jackson.databind.ObjectMapper,Ctrl+shift+T,没有找到这个类。嗯,问题就处在这了。意思到有可能有什么包没有加进来。查阅资料得知spring mvc从3.2版本开始依赖的json包由原先的jackson-mapper-asl.jar、jackson-core-asl-1.9.13.jar变更为了jackson-core.jar、jackson-dataformat-xml.jar

于是到mavenrepository找到springmvc4.3.3.RELEASE依赖的包的列表,上面的结论得到验证。

接着修改maven依赖json的包,再使用上面的那些代码,终于大功告成~

总结:


1、ajax请求如果不写contentType,则默认是application/x-www-form-urlencoded;charset=UTF-8

2、@RequestBody的作用是将请求参数的json串绑定到实体类上,要实现这个,请求的contentType要设置成contentType : "application/json;charset=UTF-8"

3、更明确spring mvc的这些默认的处理类在tomcat容器启动时就进行初始化。

4、当怀疑是包依赖产生的问题时,可以到mavenrepository找到该框架依赖的jar包。

包依赖的问题解决后,测试2也成功实现目标。

(完)

spring mvc踩坑记的更多相关文章

  1. Spring @Transactional踩坑记

    @Transactional踩坑记 总述 ​ Spring在1.2引入@Transactional注解, 该注解的引入使得我们可以简单地通过在方法或者类上添加@Transactional注解,实现事务 ...

  2. spring boot踩坑记

    Resolved exception caused by handler execution: org.springframework.http.converter.HttpMessageNotWri ...

  3. 记一次 Spring 事务配置踩坑记

    记一次 Spring 事务配置踩坑记 问题描述:(SpringBoot + MyBatisPlus) 业务逻辑伪代码如下.理论上,插入数据 t1 后,xxService.getXxx() 方法的查询条 ...

  4. Spring WebSocket踩坑指南

    Spring WebSocket踩坑指南 本次公司项目中需要在后台与安卓App间建立一个长连接,这里采用了Spring的WebSocket,协议为Stomp. 关于Stomp协议这里就不多介绍了,网上 ...

  5. Spark踩坑记——Spark Streaming+Kafka

    [TOC] 前言 在WeTest舆情项目中,需要对每天千万级的游戏评论信息进行词频统计,在生产者一端,我们将数据按照每天的拉取时间存入了Kafka当中,而在消费者一端,我们利用了spark strea ...

  6. Spark踩坑记——数据库(Hbase+Mysql)

    [TOC] 前言 在使用Spark Streaming的过程中对于计算产生结果的进行持久化时,我们往往需要操作数据库,去统计或者改变一些值.最近一个实时消费者处理任务,在使用spark streami ...

  7. 【踩坑记】从HybridApp到ReactNative

    前言 随着移动互联网的兴起,Webapp开始大行其道.大概在15年下半年的时候我接触到了HybridApp.因为当时还没毕业嘛,所以并不清楚自己未来的方向,所以就投入了HybridApp的怀抱. Hy ...

  8. Spark踩坑记——共享变量

    [TOC] 前言 Spark踩坑记--初试 Spark踩坑记--数据库(Hbase+Mysql) Spark踩坑记--Spark Streaming+kafka应用及调优 在前面总结的几篇spark踩 ...

  9. Spark踩坑记——从RDD看集群调度

    [TOC] 前言 在Spark的使用中,性能的调优配置过程中,查阅了很多资料,之前自己总结过两篇小博文Spark踩坑记--初试和Spark踩坑记--数据库(Hbase+Mysql),第一篇概况的归纳了 ...

随机推荐

  1. select和epoll原理和区别

    对于select和poll,其主要原理跟epoll不同 poll和select的共同点就是,对全部指定设备(fd)都做一次poll,当然这往往都是还没有就绪的,那就会通过回调函数把当前进程注册到设备的 ...

  2. linux 基本概念

    Linux把物理内存分为了固定统一大小的块,称为page(页框),一般为4KB. Linux采用4KB页框大小作为标准的物理内存分配单元,内核用数据结构page描述一个页框的状态信息,其实页是进程的概 ...

  3. 20.包含min函数的栈

    题目描述:   定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1)). 思路分析:   设置两个栈,一个push,一个放置最小元素. 代码: impor ...

  4. Xcode上传appstore 出现 Found an unexpected Mach-O header code: 0x72613c21 错误

    网上说是静态库的问题

  5. POJ1004 Financial Management

    题目来源:http://poj.org/problem?id=1004 题目大意: Larry今年毕业并找到了工作.他开始赚很多的钱,然而他似乎总觉得不够.Larry决定好好掌控他的资产,解决他的财务 ...

  6. c++中STL中的next_permutation函数基本用法

    对于next_permutation函数是针对于排列组合问题的库函数,它的排序方式是按照字典的方式排列的·: 如以下代码对于next_permutation函数的初步解释: #include<c ...

  7. Windows下使用pip安装Python模块

    打开cmd窗口: 找到pip安装路径: 拖动pip.exe到命令行窗口: 空格并输入“install 包名”,回车. ========================================= ...

  8. 为什么 c++中函数模板和类模板的 声明与定义需要放到一起?

    将模板的声明与定义写在一起实在很不优雅.尝试用“传统”方法,及在.h文件里声明,在.cpp文件里定义, 然后在main函数里包含.h头文件,这样会报链接错误.why!!!!!!!!!!!!! 这是因为 ...

  9. Java基础02-变量

    1.为什么要使用变量? 变量就是用来记忆数据的,它是一个记忆系统 2.什么是变量? 变量就是一个容器,用来装数据的,变量是放在内存里的. 比如:内存是酒店,变量名就是房间名,变量值就是住进房间的人 3 ...

  10. 转:Android开源项目推荐之「网络请求哪家强」 Android开源项目推荐之「网络请求哪家强」

    转载自https://zhuanlan.zhihu.com/p/21879931 1. 原则 本篇说的网络请求专指 http 请求,在选择一个框架之前,我个人有个习惯,就是我喜欢选择专注的库,其实在软 ...