今天在做ssm项目的时候,写了一个ssm整合测试,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_2_5.xsd" version="2.5">
<!-- needed for ContextLoaderListener -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-persist-*.xml</param-value>
</context-param>
<!-- Bootstraps the root web application context before servlet initialization -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- The front controller of this Spring Web application, responsible for handling all application requests -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-web-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Map all requests to the DispatcherServlet for handling -->
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>*.html</url-pattern>
<url-pattern>*.json</url-pattern>
</servlet-mapping>
</web-app>
前端index.jsp的代码如下
<%@ page language="java" contentType="text/html; charset=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>
<base href="http://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/">
<script type="text/javascript" src="jquery/jquery-2.1.1.min.js"></script>
<script type="text/javascript">
$(function(){
$("#btn4").click(function(){
var student={
"stuId":5,
"stuName":"孙培养",
"address":{
"province":"河南",
"city":"南阳",
"street":"淅川县金河镇"
},
"subjectList":[
{
"subjectName":"Java",
"subjectScore":"100"
},{
"subjectName":"Android",
"subjectScore":"90"
}
],
"map":{
"k1":"v1",
"k2":"v2",
}
};
var requestBody=JSON.stringify(student);
$.ajax({
"url":"send/compose/object.html",
"type":"post",
"data":requestBody,
"contentType":"application/json;charset=UTF=8",
"dataType":"json",
"success":function(response){
console.log(response);
},
"error":function(response){
console.log(response);
}
});
});
});
</script>
</head>
<body>
<br><br>
<button id="btn4">send student</button>
</body>
</html>
后端controller层的代码如下
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.atguigu.crowd.entity.Admin;
import com.atguigu.crowd.entity.ParamData;
import com.atguigu.crowd.entity.Student;
import com.atguigu.crowd.service.api.AdminService;
import com.atguigu.crowd.util.ResultEntity;
@Controller
public class TestHandler {
private static Logger logger=LoggerFactory.getLogger(TestHandler.class);
@ResponseBody
@RequestMapping(value="/send/compose/object.html")
public ResultEntity<Student> receiveComposeObject(@RequestBody Student student){
logger.info(student.toString());
return ResultEntity.successWithData(student);
}
}
启动Tomcat之后,访问index.jsp
点击按钮之后,发现结果出人意料
下面是ajax请求返回的响应
406错误出现的原因大多是因为前端设置接收的数据类型与后端返回的数据类型不匹配导致的,但是怪就怪在我的ajax请求设置的dataType为json格式,而后端同样是通过@ResponseBody注解返回了json格式,前后端的格式很显然是相互匹配的,那么又为什么会造成406错误呢?
根据下面这张图可以看出前端请求头中的数据格式均为json,而后台响应的“Content-Type”为“text/html;charset=utf-8”,所以很可能就是后台没有成功返回json格式数据造成的。
于是我首先想到了给responsebody对象设置content-type
resp.setContentType("application/json;charset=UTF-8");
然而运行之后406报错依旧,百度了一下,几乎所有的经验都是告诉我使用response没用,需要设置一下后端RequestMapping注解中的produces(为了以防万一,我并没有去掉resp.setContentType)
@ResponseBody
@RequestMapping(value="/send/compose/object.html",produces= "application/json;charset=UTF-8")
public ResultEntity<Student> receiveComposeObject(@RequestBody Student student,HttpServletResponse resp){
resp.setContentType("application/json;charset=UTF-8");
logger.info(student.toString());
return ResultEntity.successWithData(student);
}
本以为就这样大功告成了,结果运行之后还是406错误!!!看了下响应头信息,发现“Content-Type”依然为“text/html;charset=utf-8”,整个人就很懵逼了,看来不能根据以往的经验来确定前后端交互的效果了。想了一下,觉得还是因为响应Content-Type的原因,既然返回一直固定为html格式,那么肯定跟请求路径的后缀多少有些关系,难道是因为后缀是html?于是我试着把ajax请求地址和controller映射地址的后缀都改成了json
重新启动项目,点击按钮,响应成功!响应信息的“Content-Type”变成了“application/json;charset=UTF-8”,也间接证明了之前的猜想是正确的
再看后台日志,成功打印出前端请求数据
虽然问题算是就此解决了,也知道了是由于请求路径后缀造成这次的问题,但更深入的原因,查了很多资料后还是不清楚,可能跟浏览器的底层有关系吧。但是到此还没有完,既然知道了跟后缀有关,或许可以改一下web.xml配置的后缀来更优雅的解决该问题,而不是每次ajax请求后都要用json做后缀。我这里在web.xml中将spring的分发拦截映射的后缀改为"*.do"
接着将前后台代码的路径也改过来
重启项目,点击按钮
大功告成,打完收工!