响应数据转换与渲染
SpringMVC支持多种响应方式,包括JSON/XML数据响应和视图渲染,通过HandlerMethodReturnValueHandler统一处理。
返回值处理器架构
核心接口
Java
public interface HandlerMethodReturnValueHandler {
boolean supportsReturnType(MethodParameter returnType);
void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest);
}
返回值处理器链
Java
// RequestMappingHandlerAdapter初始化返回值处理器
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();
// ModelAndView相关
handlers.add(new ModelAndViewMethodReturnValueHandler());
handlers.add(new ViewMethodReturnValueHandler());
// 响应体相关
handlers.add(new ResponseBodyMethodReturnValueHandler());
// 视图名称
handlers.add(new ViewNameMethodReturnValueHandler());
// 其他类型
handlers.add(new HttpEntityMethodProcessor());
handlers.add(new RequestResponseBodyMethodProcessor());
return handlers;
}
HttpMessageConverter机制
核心接口
Java
public interface HttpMessageConverter<T> {
boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);
boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);
List<MediaType> getSupportedMediaTypes();
T read(Class<? extends T> clazz, HttpInputMessage inputMessage);
void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage);
}
内置转换器
| 转换器 | 支持类型 | MediaType |
|---|---|---|
| StringHttpMessageConverter | String | text/plain |
| MappingJackson2HttpMessageConverter | Object | application/json |
| ByteArrayHttpMessageConverter | byte[] | application/octet-stream |
| FormHttpMessageConverter | MultiValueMap | application/x-www-form-urlencoded |
@ResponseBody处理流程
RequestResponseBodyMethodProcessor
Java
public class RequestResponseBodyMethodProcessor
extends AbstractMessageConverterMethodProcessor {
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) {
mavContainer.setRequestHandled(true);
// 使用MessageConverter写入响应
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
protected <T> void writeWithMessageConverters(T value, MethodParameter returnType,
ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) {
// 获取内容类型
MediaType contentType = outputMessage.getHeaders().getContentType();
// 遍历MessageConverter找到支持的转换器
for (HttpMessageConverter<?> converter : this.messageConverters) {
if (converter.canWrite(valueClass, contentType)) {
((HttpMessageConverter<Object>) converter)
.write(value, contentType, outputMessage);
return;
}
}
}
}
JSON序列化配置
Java
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = new ObjectMapper();
// 日期格式化
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
// 忽略空值
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 驼峰转下划线
objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
converter.setObjectMapper(objectMapper);
converters.add(converter);
}
}
ResponseEntity处理
HttpEntityMethodProcessor
Java
public class HttpEntityMethodProcessor
extends AbstractMessageConverterMethodProcessor {
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) {
HttpEntity<?> httpEntity = (HttpEntity<?>) returnValue;
// 设置响应头
HttpHeaders headers = httpEntity.getHeaders();
outputMessage.getHeaders().putAll(headers);
// 写入响应体
writeWithMessageConverters(httpEntity.getBody(), returnType, outputMessage);
}
}
使用示例
Java
@GetMapping("/users/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
User user = userService.getById(id);
if (user == null) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok()
.header("X-Custom-Header", "value")
.cacheControl(CacheControl.maxAge(3600))
.body(user);
}
视图渲染机制
ViewResolver接口
Java
public interface ViewResolver {
@Nullable
View resolveViewName(String viewName, Locale locale) throws Exception;
}
View接口
Java
public interface View {
void render(@Nullable Map<String, ?> model,
HttpServletRequest request, HttpServletResponse response);
}
内部资源视图解析器
Java
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/views/", ".jsp");
}
}
ContentNegotiatingViewResolver
Java
// 根据请求内容类型选择View
public class ContentNegotiatingViewResolver extends WebMvcConfigurerAdapter {
public View resolveViewName(String viewName, Locale locale) {
// 获取请求的MediaType
List<MediaType> requestedMediaTypes = getMediaTypes(request);
// 查找所有候选View
List<View> candidateViews = getCandidateViews(viewName, locale);
// 选择最佳匹配的View
for (View view : candidateViews) {
for (MediaType mediaType : requestedMediaTypes) {
if (view.getContentType().includes(mediaType)) {
return view;
}
}
}
return null;
}
}
视图渲染流程
Java
// DispatcherServlet
private void processDispatchResult(HttpServletRequest request,
HttpServletResponse response, HandlerExecutionChain handler,
ModelAndView mv, Exception exception) {
// 1. 处理异常情况
if (exception != null) {
mv = processHandlerException(request, response, handler, exception);
}
// 2. 渲染视图
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
}
}
protected void render(ModelAndView mv, HttpServletRequest request,
HttpServletResponse response) {
// 解析View
View view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale);
// 渲染
view.render(mv.getModelInternal(), request, response);
}
Thymeleaf集成
Java
@Configuration
public class ThymeleafConfig {
@Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setPrefix("classpath:/templates/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
return resolver;
}
@Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(templateResolver());
engine.setEnableSpringELCompiler(true);
return engine;
}
@Bean
public ThymeleafViewResolver viewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
resolver.setCharacterEncoding("UTF-8");
return resolver;
}
}
响应处理流程图
text
Handler方法返回值
↓
HandlerMethodReturnValueHandlerComposite
↓
支持@ResponseBody?
↓ Yes ↓ No
ResponseBodyMethodProcessor ViewNameMethodReturnValueHandler
↓ ↓
HttpMessageConverter ViewResolver
↓ ↓
JSON/XML序列化 View.render()
↓ ↓
写入响应体 模板渲染
↓ ↓
└──────── 响应 ─────────┘
返回值处理器统一处理各种响应类型,HttpMessageConverter负责数据序列化,ViewResolver负责视图解析。
要点总结
- HandlerMethodReturnValueHandler统一处理返回值
- HttpMessageConverter负责JSON/XML等数据格式转换
- @ResponseBody直接返回数据,不经过视图解析
- ViewResolver解析视图名称为具体View实现
- ContentNegotiatingViewResolver支持内容协商多视图
jwdev/articles/SPRINGMVC/专家/MVC核心源码执行流程/MVC核心源码执行流程\响应数据转换与渲染.md
📝 发现内容有误?点击此处直接编辑