我们先看HttpMessageConverter的示意图,从图片可以看出它是多么的重要。在一条必经之路截道了的感觉。

SpringMvc HttpMessageConverter之@ResponseBody-LMLPHP

先上我的测试例子:

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="<%=request.getContextPath() %>/js/jquery-3.1.1.min.js"></script>
</head>
<body>
<script type="text/javascript">
$(function(){
var args={};
var url="<%=request.getContextPath()%>/testJson";
$.post(url,args,function(result){
alert(result)
})
})
</script>
</body>
</html>

java代码:

@Controller
public class TestJson {
/**
* 如何返回json数据
* 1,加入3个jackson的jar包
* 2,编写对应的方法,使其返回json对应的对象或方法
* 3,在方法中加入@ResponseBody注解
*/ @Autowired
private EmployeeDAO employeeDao; @RequestMapping("testJson")
@ResponseBody
public Collection<Employee> testJson(){
return employeeDao.getAll().values();
}
}

首先我们要知道HttpMessageConverter和@ResponseBody之间有什么联系。

  如果不使用@ResponseBody注解,那么我在业务方法(@RequestMapping注解)的Model中,或者Map中放入的值和我返回的字符串将组成ModelAndView对象。然后渲染视图。

  使用了@ResponseBody之后,会选择适当的处理器,比如json处理器,将我返回的值转换成相应的格式,写入到HttpOutputMessage中,写入到Response的body中去。

下面我们就先看看使用了@ResponseBody时,SpringMvc为我们做了什么?

从DispatcherServlet的handle方法

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

开始-->AbstractHandlerMethodAdapter类的handleInternal方法-->RequestMappingHandlerAdapter类的invokeHandleMethod方法-->ServletInvocableHandlerMethod类的invokeAndHandle方法

public final void invokeAndHandle(ServletWebRequest webRequest,
ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); setResponseStatus(webRequest); if (returnValue == null) {
if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(this.responseReason)) {
mavContainer.setRequestHandled(true);
return;
} mavContainer.setRequestHandled(false); try {
       //处理返回的Map集合
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
}
throw ex;
}
}

从标红部分点进去,

    @Override
public void handleReturnValue(
Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws Exception {
//匹配到的返回值处理器是RequestResponseBodyMethodProcessor
HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType);
Assert.notNull(handler, "Unknown return value type [" + returnType.getParameterType().getName() + "]");
//处理器处理集合
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}

在从标红行点进去,

@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException {
//表示是直接返回页面的body,个人理解,不够准确
mavContainer.setRequestHandled(true);
if (returnValue != null) {
       //把map转为json写到outputMessage
writeWithMessageConverters(returnValue, returnType, webRequest);
}
}

再往后就是调用系统默认处理json的类MappingJackson2HttpMessageConverter来转换成json数据。

至于如何返回给页面,等下回填坑吧。

05-11 16:25
查看更多