• spring mvc踩坑记


    前言

    主要介绍自己在学习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

     1 <%@ page language="java" contentType="text/html; charset=utf-8"
     2     pageEncoding="utf-8"%>
     3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
     4 <html>
     5 <head>
     6 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
     7 <title>Insert title here</title>
     8 <script type="text/javascript"
     9     src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.min.js"></script>
    10 </head>
    11 <body>
    12     <div>
    13         id:<input type="text" id="id" value="123456"><br>
    14         menuName:<input type="text" id="menuName" value="李白"><br>
    15         <input type="button" id="abc" value="test">
    16     </div>
    17 
    18     <script type="text/javascript">
    19         window.onload = function() {
    20             $("#abc").click(function() {
    21                 var menu = {
    22                     "id" : $("#id").val(),
    23                     "menuName" : $("#menuName").val()
    24                 };
    25                 var jsonStr = JSON.stringify(menu);
    26                 $.ajax({
    27                     type : "POST",
    28                     async : false,
    29                     url : "http://localhost:8080/ssm/getList",
    30                     dataType : "json",
    31                     contentType : "application/json;charset=UTF-8",
    32                     data : jsonStr,
    33                     success : function(data) {
    34                         alert("123");
    35                     }
    36                 });
    37             });
    38         }
    39     </script>
    40 </body>
    41 </html>


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

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


    TestSpringMvcController.java

     1 package com.dg.action;
     2 
     3 import org.springframework.stereotype.Controller;
     4 import org.springframework.web.bind.annotation.RequestBody;
     5 import org.springframework.web.bind.annotation.RequestMapping;
     6 
     7 import com.dg.bean.Menu;
     8 
     9 @Controller
    10 public class TestSpringMvcController {
    11 
    12     @RequestMapping("getList")
    13     public void getList(@RequestBody Menu menu){
    14         System.out.println("menu:" + menu);
    15     }
    16 }


    Menu.java

     1 package com.dg.bean;
     2 
     3 import java.io.Serializable;
     4 
     5 public class Menu implements Serializable {
     6 
     7     private static final long serialVersionUID = 410202860691610816L;
     8     private String id;
     9     private String menuCode;
    10     private String menuName;
    11     private String menuUrl;
    12     private String parentMenuId;
    13 
    14     public String getId() {
    15         return id;
    16     }
    17 
    18     public void setId(String id) {
    19         this.id = id;
    20     }
    21 
    22     public String getMenuCode() {
    23         return menuCode;
    24     }
    25 
    26     public void setMenuCode(String menuCode) {
    27         this.menuCode = menuCode;
    28     }
    29 
    30     public String getMenuName() {
    31         return menuName;
    32     }
    33 
    34     public void setMenuName(String menuName) {
    35         this.menuName = menuName;
    36     }
    37 
    38     public String getMenuUrl() {
    39         return menuUrl;
    40     }
    41 
    42     public void setMenuUrl(String menuUrl) {
    43         this.menuUrl = menuUrl;
    44     }
    45 
    46     public String getParentMenuId() {
    47         return parentMenuId;
    48     }
    49 
    50     public void setParentMenuId(String parentMenuId) {
    51         this.parentMenuId = parentMenuId;
    52     }
    53 
    54     @Override
    55     public String toString() {
    56         return "Menu [id=" + id + ", menuCode=" + menuCode + ", menuName=" + menuName + ", menuUrl=" + menuUrl
    57                 + ", parentMenuId=" + parentMenuId + "]";
    58     }
    59 }

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

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

    spring-mvc.xml

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

    web.xml

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     3     xmlns="http://java.sun.com/xml/ns/javaee"
     4     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
     5     version="3.0">
     6     <display-name>ssm</display-name>
     7     <!-- Spring和mybatis的配置文件 -->
     8     <context-param>
     9         <param-name>contextConfigLocation</param-name>
    10         <param-value>classpath:spring-config.xml</param-value>
    11     </context-param>
    12     <!-- 编码过滤器 -->
    13     <filter>
    14         <filter-name>encodingFilter</filter-name>
    15         <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    16         <async-supported>true</async-supported>
    17         <init-param>
    18             <param-name>encoding</param-name>
    19             <param-value>UTF-8</param-value>
    20         </init-param>
    21     </filter>
    22     <filter-mapping>
    23         <filter-name>encodingFilter</filter-name>
    24         <url-pattern>/*</url-pattern>
    25     </filter-mapping>
    26     <!-- Spring监听器 -->
    27     <listener>
    28         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    29     </listener>
    30     <!-- 防止Spring内存溢出监听器 -->
    31     <listener>
    32         <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
    33     </listener>
    34 
    35     <!-- Spring MVC servlet -->
    36     <servlet>
    37         <servlet-name>SpringMVC</servlet-name>
    38         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    39         <init-param>
    40             <param-name>contextConfigLocation</param-name>
    41             <param-value>classpath:spring-mvc.xml</param-value>
    42         </init-param>
    43         <load-on-startup>1</load-on-startup>
    44         <async-supported>true</async-supported>
    45     </servlet>
    46     <servlet-mapping>
    47         <servlet-name>SpringMVC</servlet-name>
    48         <!-- 此处可以可以配置成*.do,对应struts的后缀习惯 -->
    49         <url-pattern>/</url-pattern>
    50     </servlet-mapping>
    51     <!-- 设置静态资源映射 -->
    52     <servlet-mapping>
    53         <servlet-name>default</servlet-name>
    54         <url-pattern>*.jpg</url-pattern>
    55     </servlet-mapping>
    56     <servlet-mapping>
    57         <servlet-name>default</servlet-name>
    58         <url-pattern>*.gif</url-pattern>
    59     </servlet-mapping>
    60     
    61     <servlet-mapping>
    62         <servlet-name>default</servlet-name>
    63         <url-pattern>*.png</url-pattern>
    64     </servlet-mapping>
    65     
    66     <servlet-mapping>
    67         <servlet-name>default</servlet-name>
    68         <url-pattern>*.js</url-pattern>
    69     </servlet-mapping>
    70     <servlet-mapping>
    71         <servlet-name>default</servlet-name>
    72         <url-pattern>*.css</url-pattern>
    73     </servlet-mapping>
    74     <welcome-file-list>
    75         <welcome-file>/index.jsp</welcome-file>
    76     </welcome-file-list>
    77 
    78 </web-app> 

    pom.xml

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     3     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
     4 
     5     <modelVersion>4.0.0</modelVersion>
     6     <packaging>war</packaging>
     7 
     8     <name>ssm</name>
     9     <groupId>dg</groupId>
    10     <artifactId>ssm</artifactId>
    11     <version>0.0.1-SNAPSHOT</version>
    12 
    13     <properties>
    14         <!-- spring版本号 -->
    15         <spring.version>4.3.3.RELEASE</spring.version>
    16         <!-- log4j日志文件管理包版本 -->
    17         <slf4j.version>1.7.7</slf4j.version>
    18         <log4j.version>1.2.17</log4j.version>
    19     </properties>
    20 
    21     <dependencies>
    22         <!-- spring核心包 -->
    23         <dependency>
    24             <groupId>org.springframework</groupId>
    25             <artifactId>spring-core</artifactId>
    26             <version>${spring.version}</version>
    27         </dependency>
    28         <dependency>
    29             <groupId>org.springframework</groupId>
    30             <artifactId>spring-web</artifactId>
    31             <version>${spring.version}</version>
    32         </dependency>
    33         <dependency>
    34             <groupId>org.springframework</groupId>
    35             <artifactId>spring-webmvc</artifactId>
    36             <version>${spring.version}</version>
    37         </dependency>
    38         <!-- 日志文件管理包 -->
    39         <!-- log start -->
    40         <dependency>
    41             <groupId>log4j</groupId>
    42             <artifactId>log4j</artifactId>
    43             <version>${log4j.version}</version>
    44         </dependency>
    45         <dependency>
    46             <groupId>org.codehaus.jackson</groupId>
    47             <artifactId>jackson-mapper-asl</artifactId>
    48             <version>1.9.13</version>
    49         </dependency>
    50     
    51     </dependencies>
    52 </project>

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

    后台报错的日志为:

     1 [org.springframework.web.servlet.DispatcherServlet] - DispatcherServlet with name 'SpringMVC' processing POST request for [/ssm/getList]
     2   [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping] - Looking up handler method for path /getList
     3   [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping] - Returning handler method [public void com.dg.action.TestSpringMvcController.getList(com.dg.bean.Menu)]
     4   [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Returning cached instance of singleton bean 'testSpringMvcController'
     5   [org.springframework.web.cors.DefaultCorsProcessor] - Skip CORS processing: request is from same origin
     6   [org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod] - Error resolving argument [0] [type=com.dg.bean.Menu]
     7 HandlerMethod details: 
     8 Controller [com.dg.action.TestSpringMvcController]
     9 Method [public void com.dg.action.TestSpringMvcController.getList(com.dg.bean.Menu)]
    10 
    11   org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json;charset=UTF-8' not supported
    12     at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:235)
    13     at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:149)
    14     at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:127)
    15     at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
    16     at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:161)
    17     at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128)
    18     at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:114)
    19     at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
    20     at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
    21     at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    22     at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
    23     at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
    24     at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
    25     at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
    26     at javax.servlet.http.HttpServlet.service(HttpServlet.java:646)
    27     at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
    28     at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    29     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    30     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    31     at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    32     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    33     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    34     at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
    35     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    36     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    37     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    38     at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
    39     at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    40     at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:504)
    41     at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
    42     at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    43     at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
    44     at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    45     at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:421)
    46     at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1074)
    47     at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611)
    48     at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
    49     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    50     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    51     at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    52     at java.lang.Thread.run(Thread.java:745)
    53 [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
    54   [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
    55   [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
    56   [org.springframework.web.servlet.DispatcherServlet] - Null ModelAndView returned to DispatcherServlet with name 'SpringMVC': assuming HandlerAdapter completed request handling
    57   [org.springframework.web.servlet.DispatcherServlet] - Successfully completed request
    58   

    看到这个报错提示的第一反应是把前台请求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也成功实现目标。

     (完)

  • 相关阅读:
    Selenium开发环境搭建
    如何抓取移动端崩溃日志?
    html+ashx + NPOI 实现导出Excel文件并且预览和下载
    oss 文件上传:Web端上传介绍
    事务控制和锁定语句
    索引的设计和使用
    最近几年读过的书籍
    053.NET5_EFCoreMigration
    052.NET5_EFCoreDbFirst
    051.NET5_中间件的多种引用方式
  • 原文地址:https://www.cnblogs.com/frankwin608/p/spring-mvc.html
Copyright © 2020-2023  润新知