使用springmvc、springboot日常进行restful风格开发时,往往通过 json 数据进行交互,那么前端传入的 json 数据如何被解析成 Java 对象作为 API入参,API 返回结果又如何将 Java 对象解析成 json 格式数据返回给前端?
在开发中这两个注解应该是经常使用:@RequestBody、@ResponseBody,而在整个数据流转的过程中org.springframework.http.converter.HttpMessageConverter接口是重点。
HttpMessageConverter接口有以下五个方法:
public interface HttpMessageConverter<T> {
boolean canRead(Class<?> var1, @Nullable MediaType var2);
boolean canWrite(Class<?> var1, @Nullable MediaType var2);
List<MediaType> getSupportedMediaTypes();
T read(Class<? extends T> var1, HttpInputMessage var2) throws IOException, HttpMessageNotReadableException;
void write(T var1, @Nullable MediaType var2, HttpOutputMessage var3) throws IOException, HttpMessageNotWritableException;
}
1)在前端发起请求,调用后台的方法前,会根据@RequestBody注解选择适当的HttpMessageConverter实现类来将请求参数解析到变量中,它的canRead()方法返回true,然后它的read()方法会从请求中读出请求参数,绑定到方法的变量中。
2)当后端执行方法后,由于返回值标识了@ResponseBody,springmvc/springboot将使用HttpMessageConverter实现类的write()方法,将结果值写入响应报文,当然,此时canWrite()方法返回true。
流程示意图如下:
在对源码分析的过程中,一次请求报文和一次响应报文,分别被抽象为一个请求消息HttpInputMessage和一个响应消息HttpOutputMessage。
MappingJackson2HttpMessageConverter: 负责读取和写入json格式的数据;
ByteArrayHttpMessageConverter: 负责读取二进制格式的数据和写出二进制格式的数据;
StringHttpMessageConverter:负责读取字符串格式的数据和写出二进制格式的数据;
ResourceHttpMessageConverter:负责读取资源文件和写出资源文件数据;
FormHttpMessageConverter:负责读取form提交的数据(能读取的数据格式为 application/x-www-form-urlencoded,不能读取multipart/form-data格式数据);
负责写入application/x-www-from-urlencoded和multipart/form-data格式的数据;
Jaxb2RootElementHttpMessageConverter: 负责读取和写入xml 标签格式的数据;
AtomFeedHttpMessageConverter: 负责读取和写入Atom格式的数据;
RssChannelHttpMessageConverter: 负责读取和写入RSS格式的数据;
该类中有有个方法getMessageConverters获取我们配置的MessageConverter,如果没有配置就调用addDefaultHttpMessageConverters
protected final List<HttpMessageConverter<?>> getMessageConverters() {
if (this.messageConverters == null) {
this.messageConverters = new ArrayList();
this.configureMessageConverters(this.messageConverters);
if (this.messageConverters.isEmpty()) {
this.addDefaultHttpMessageConverters(this.messageConverters);
}
this.extendMessageConverters(this.messageConverters);
}
return this.messageConverters;
}
数据的请求和响应都要经过 DispatcherServlet 类的 doDispatch方法:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
// 这里的 Adapter 实际上是 RequestMappingHandlerAdapter
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 实际处理的handler
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
this.applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}