背景
涛哥最近跟我提了个需求,要求在http请求的过程中直接传输json字符串,问spring mvc在后端能不能直接拿到参数,一开始笔者第一想法是在spring mvc的Controller层的方法里把@PathVariable注解去掉,就能正常读取到传递过来的值,后来想想不太对,如果请求体里是正常的key=value形式,去掉@PathVariable是有效的,直接在body里面放个json好像不太行吧;然后涛哥把前端ajax请求代码发给我看,上面指明了request的content-type是application/json!
关键的Content-Type
平时在处理post请求的时候并没有太留意,大部分post都是来自表单提交和ajax的post请求,默认情况下,请求体里的格式都是key=value&key=value形式,这种编码方式其实就是最常用的application/x-www-form-urlencoded,只是平时我们不会主动去写这个content-type而已;现在主动指明body里面的数据以json格式传输,即可指明content-type为application/json。注意:jQuery的ajax方法指定的dataType=json是指明接收json格式的返回数据,对应http header中accept:application/json.
$(function(){
$.ajax({
url: "http://localhost:8080/demo",
type: "POST",
dataType: "json",
contentType : "application/json",
data : JSON.stringify({username:'1', password:'2'}),
success : function(data){
console.log("success");
console.log(data);
},
error: function(e){
console.log("error");
console.log(e);
}
});
});
@RequestBody注解
一开始并不知道Spring MVC提供了这个注解,涛哥说不想用这个注解,我看走眼以为是@ResponseBody,这个注解会直接把返回的对象以json形式写在body里;而@RequestBody注解的含义就是读取请求body里面的值映射成参数。之后自己动手实验了一把,后端代码如下:
@RequestMapping(value = "/demo", method = RequestMethod.POST)
@ResponseBody
public Map index(HttpServletRequest request, @RequestBody UserEntity user) {
Map<String, String> map = new HashMap<String, String>();
map.put("username", user.getUsername());
map.put("password", user.getPassword());
return map;
}
其实一开始并不顺利,总是报“415 Unsupported Media Type”这种错,debug输出的log显示不支持application/json这种media-type
[DEBUG] Resolving exception from handler [com.yuanwhy.fantasy.controller.HomeController@6ea53502]: org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json' not supported - org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.resolveException(AbstractHandlerExceptionResolver.java:132)
后来发现没有使用<mvc:annotation-driven/>明确指明使用注解驱动,加上后就好了,所以这里<mvc:annotation-driven/>有时不加虽然也能使用@Controller这种注解,但是最好还是一开始就加上,否则总有一些让人抓狂的默认行为。
调试时控制台打印结果显示成功读取到服务端返回的正确参数,其实直接从httpServletRequest里也是能读取到body信息的,只是太麻烦而已。
网友评论