它能帮我们解析客户端(移动设备、浏览器等)发送过来的json数据,并封装到实体类中。
常用的http请求MIME类型有application/json、text/html、text/xml、image/jpeg等,这些都是对应固定格式的Content-Type类型。
在网页中表单form元素的语法中,EncType表明提交数据的格式 用 Enctype 属性指定将数据回发到服务器时浏览器使用的编码类型。
例如:
常用来处理content-type不是默认的application/x-www-form-urlcoded编码的内容,比如:application/json或者是application/xml等,常常用来其来处理application/json类型。
注意:@requestBody接收的是前端传过来的json字符串,而不是JSON对象,在http协议中只能传输字符串,对象只能在前端或者后端语言中存在,所以前端的Json对象必须使用javascript提供的JSON.stringify()方法去转成json字符串。
另外使用JQuery的ajax时,默认的content-type类型为application/x-www-form-urlcoded。
一个JQuery的ajax代码例子
// Jquery Ajax请求
$.ajax({
url : "doindex.action",
type : "POST",
contentType : "application/json;charset=UTF-8",
data :JSON.stringify(json),
dataType : "json",
success : function(data) {
}
});
注意,ajax中contentType : “application/json;charset=UTF-8”,这里面一定要写入charset=UTF-8类型,否则后端容易出现中文乱码,tomcat默认的字符集不是utf-8
在后端方法签名中使用@RequestBody注解,来读取前段传入的json字符串,看个例子
@RequestMapping("/doindex.action")
public @ResponseBody Customer getPages(@RequestBody(required=true) Map map , HttpServletRequest request)throws Exception{
Customer cust=new Customer();
cust.setLcname("马雷");
cust.setCreatetime(new Timestamp(System.currentTimeMillis()));
//mv.addObject(cust);
//Map map=new HashMap();
//map.put("cust",cust);
ObjectMapper om=new ObjectMapper();
om.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
//ModelAndView mv=new ModelAndView(new MappingJackson2JsonView(om),cust);
return cust;
}
不用管方法体中具体代码的意义,前端传来的json字符串参数信息自动就填充到@RequestBody(required=true) 标注的Map
Spring 为我们内置了大量的HttpMessageConverter,例如, MappingJackson2HttpMessageConverter 、StringHttpMessageConverter 等。主要是为了配合@RequestBody和@ResponsetBody。
HttpMessageConverter接口是 Spring3.0 新添加的一个接 口,负责 1、将请求信息转换为一个对象(类型为 T),2、将对象( 类型为 T)输出为响应信息。
看一下接口代码
public interface HttpMessageConverter {
//指定转换器 可以读取的对象类型,即转换器是否可将请求信息转换为clazz类型的对象,同时指定支持 MIME 类型(text/html,applaiction/json等)
boolean canRead(Class> var1, MediaType var2);
//指定转换器 是否可将 clazz类型的对象写到响应流中,响应流支持的媒体类型在MediaType 中定义。–LIst getSupportMediaTypes():该转换器支持的媒体类型
boolean canWrite(Class> var1, MediaType var2);
List getSupportedMediaTypes();
//将请求信息流转换为 T 类型的对象
T read(Class extends T> var1, HttpInputMessage var2) throws IOException, HttpMessageNotReadableException;
//将T类型的对象写到响应流中,同时指定相应的媒体类型为contentType
void write(T var1, MediaType var2, HttpOutputMessage var3) throws IOException, HttpMessageNotWritableException;
}
通过上面接口代码可以看出转换器中可以将请求信息进行转换,也可以将响应信息进行自动转换,所以基于前面的那个ajax请求的例子,后端代码接收方式可以是
//以下三种方法头都可以接收前段ajax传入的非application/x-www-form-urlcoded类型信息
//将传入的json参数自动封装到map里,参数名成是key,参数值时value
public @ResponseBody Customer getPages(@RequestBody(required=true) Map map , HttpServletRequest request)
//将传入的json字符串直接复制给username字段
public @ResponseBody Customer getPages(@RequestBody(required=true) String username, HttpServletRequest request)
//将传入的json字符串中每个字段的值赋给user对象实例对应名称的属性
public @ResponseBody Customer getPages(@RequestBody(required=true) User user , HttpServletRequest request)
注意:上面是使用SpringMVC默认转换器,如果自己在springmvc配置文件中指定了其他的转换器后,不保证上面自动封装能实现,具体看指定的转换器功能。
用于将Controller的方法返回的对象,通过HttpMessageConverter接口转换为指定格式的数据如:json,xml等,通过Response响应给客户端.
注意:不一定只能传递字符串,若有对应的java类,springMVC会自动帮忙转换成符合要求的数据格式(json/xml)
下面就介绍几种实测后的可以实现返回给前段json相应类型的方法:
在web.xml中,在DispatcherServlet请求拦截中配置增加一个*.action的拦截,用来处理json返回的,如果不增加的话默认会调用已经配置的视图解析器去解析,解析失败就会报错406,所以添加一个新的映射类型后专门处理json返回。
miniappservice
/
miniappservice
*.action
当增加了请求拦截后
miniappservice
*.action
所有前段的需要返回json的请求,必须是以action为后缀的,当然action可以更改成任何名称比如do
由于在springmvc中处理json格式需要一些jar的包的支持,先在pom单中加入以下依赖:
com.fasterxml.jackson.core
jackson-core
2.10.1
com.fasterxml.jackson.core
jackson-annotations
2.10.1
com.fasterxml.jackson.core
jackson-databind
2.10.1
使用MappingJackson2JsonView视图返回json
springmvc的配置文件(-servlet.xml)中配置jsp的视图解析器即可;
springmvc的配置文件(-servlet.xml)中配置mvc:annotation-driven/;
方法使用@ResponseBody标注;
在返回的ModelAndView中配置MappingJackson2JsonView视图,并将要返回json的实体实例、集合或map类型直接复制给ModelAndView,此处要注意以下,如果要返回的实体实例、集合或map类型加入ModelAndView时指定了名称则返回的json名称就是指定名称,如果没有指定名称则返回的json名称就是实体实例、集合或map类型名称的小写名称。看个例子
@RequestMapping("/test1.action")
@ResponseBody
public ModelAndView getDo1(@RequestBody(required=true) String username , HttpServletRequest request){
Customer cust=new Customer();
cust.setLcname("测试");
cust.setCreatetime(new Timestamp(System.currentTimeMillis()));
ModelAndView mv=new ModelAndView(new MappingJackson2JsonView());
mv.addObject(cust);
return mv;
}
前端请求过来的参数为json字符串{“username”:“测试”,“password”:“123456fg”},方法中标注@RequestBody字符串类型参数username获取的注入值为前端传过来的json字符串。
getDo1方法执行后返回给前段的响应输出为:
{"customer":{"sysId":null,"createtime":1577084421101,,"lcname":"马雷"}}
可以看出来,输出到前端的json是将cust实例的小写类名作为json字符串的key输出的,且日期createtime是按照时间戳类型输出的,如果要将时间输出是格式化,则需要使用com.fasterxml.jackson.databind.ObjectMapper类,此时将上面的代码修改一下如下:
@RequestMapping("/test2.action")
@ResponseBody
public ModelAndView getDo2(@RequestBody(required=true) String username , HttpServletRequest request){
Customer cust=new Customer();
cust.setLcname("马雷");
cust.setCreatetime(new Timestamp(System.currentTimeMillis()));
//引入格式化
ObjectMapper om=new ObjectMapper();
om.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
ModelAndView mv=new ModelAndView(new MappingJackson2JsonView(om));
mv.addObject(cust);
return mv;
}
请求参数不变,相应结果如下:
{"customer":{"sysId":null,"2019-12-23 15:10:41","lcname":"马雷"}}
@RequestMapping("/test3.action")
public @ResponseBody Map getDo3(@RequestBody(required=true) String username , HttpServletRequest request){
Customer cust=new Customer();
cust.setLcname("测试");
cust.setCreatetime(new Timestamp(System.currentTimeMillis()));
Map map=new HashMap<>();
map.put("customer",cust);
return map;
}
@ResponseBody可以标注在方法上也可以标注在方法签名上;
前端请求过来的参数依然为json字符串{“username”:“测试”,“password”:“123456fg”},下面的介绍中前端每次请求参数都是这个字符串,就不单独赘述了。
向前端相应输出结果为:
{"customer":{"sysId":null,"createtime":1577085315542,"lcname":"测试"}}
可以看出来,createtime依然是输出的时间戳,没有好的办法转化成日期时间格式。
注意:以上两中方法的区别
1、要格式化日期只能使用第一种;
2、如果输出的json需要{“key”:“value”,“key”:“value”}格式的可以使用第二种或者第一种、第二种使用map封装;
上面代码替换mvc:annotation-driven;
第二步在方法中或方法上使用@ResponseBody标注即可,看代码
@RequestMapping("/test4.action")
public @ResponseBody Customer getDo4(String username,String password, HttpServletRequest request){
Customer cust=new Customer();
cust.setLcname("测试");
cust.setCreatetime(new Timestamp(System.currentTimeMillis()));
return cust;
}
前端使用application/x-www-form-urlcoded格式,url为test4.action?username=测试&password=123456fg;
响应输出为
{
"sysId": null,
"createtime": "2019-12-23 16:08:17",
"lcname": "测试"
}
前端也可以使用application/json;charset=UTF-8格式,此时后端方法如下:
@RequestMapping("/test4.action")
public @ResponseBody List getDo4(@RequestBody(required=true) Map map1 , HttpServletRequest request){
Customer cust=new Customer();
cust.setLcname("测试");
cust.setCreatetime(new Timestamp(System.currentTimeMillis()));
List map=new ArrayList<>();
map.add(cust);
return map;
}
这里要着重强调一下,当使用@RequestBody签名时,可以封装map接收前端传来的json字符串,也可以使用实体类接收前端传来的json字符串,不能直接使用string字符串去接收前端传来的json,使用就报400的错误,另外如果使用实体类接收前端串类的json字符串,实体类的属性少于传来的字符串的属性则也会报400错误。
用本种方法输出json的好处,可以将日期格式化;