准备对象
java">@Data
static class User {private String name;private int age;@JsonCreator // 默认jackson会使用无参构造器反序列化 这里强制使用当前带参构造器public User(@JsonProperty("name") String name, @JsonProperty("age") int age) {this.name = name;this.age = age;}
}
MessageConverter
序列化-JSON
java">@SneakyThrows
private static void test1() {MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();if (converter.canWrite(User.class, MediaType.APPLICATION_JSON)) {converter.write(new User("张三", 30), MediaType.APPLICATION_JSON, outputMessage);System.out.println("outputMessage.getBodyAsString() = " + outputMessage.getBodyAsString());}
}
序列化-XML
java">@SneakyThrows
private static void test2() {MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();MappingJackson2XmlHttpMessageConverter converter = new MappingJackson2XmlHttpMessageConverter();if (converter.canWrite(User.class, MediaType.APPLICATION_XML)) {converter.write(new User("张三", 30), MediaType.APPLICATION_XML, outputMessage);System.out.println("outputMessage.getBodyAsString() = " + outputMessage.getBodyAsString());}
}
序列化优先级
java">@ResponseBody
// @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public User user() {return null;
}@SneakyThrows
public static void test4() {// 模拟请求MockHttpServletRequest request = new MockHttpServletRequest();MockHttpServletResponse response = new MockHttpServletResponse();ServletWebRequest servletWebRequest = new ServletWebRequest(request, response);// 配置请求头 以及 响应类型request.addHeader("Accept", "application/xml");response.setContentType("application/json");// 设置ResponseBody处理的类型转换器RequestResponseBodyMethodProcessor requestResponseBodyMethodProcessor = new RequestResponseBodyMethodProcessor(CollUtil.newArrayList(new MappingJackson2HttpMessageConverter(),new MappingJackson2XmlHttpMessageConverter()));requestResponseBodyMethodProcessor.handleReturnValue(new User("张三", 30),new MethodParameter(TestMessageConverter.class.getMethod("user"), -1),new ModelAndViewContainer(),servletWebRequest);System.out.println(new String(response.getContentAsByteArray(), StandardCharsets.UTF_8));
}
@ResponseBody 是由返回值类型处理器完成解析的,具体转换工作有消息转换器完成 MappingJackson2HttpMessageConverter
具体转换为json还是xml?
- 响应头里有没有设置response.setContentType 或者 @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
- request的请求头里Accept参数
- RequestResponseBodyMethodProcessor中消息转换器的顺序
反序列化
java">@SneakyThrows
public static void test3() {MockHttpInputMessage inputMessage = new MockHttpInputMessage("{\"name\":\"张三\", \"age\": 30}".getBytes(StandardCharsets.UTF_8));MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();if (converter.canRead(User.class, MediaType.APPLICATION_JSON)) {User readUser = (User) converter.read(User.class, inputMessage);System.out.println(readUser);}}
ControllerAdvice
准备对象
java">@Data
@NoArgsConstructor
@AllArgsConstructor
public static class User {private String name;private int age;
}
准备控制器与ControllerAdvice
java">@Controller
public static class MyController {@ResponseBodypublic User user() {return new User("王五", 30);}}@ControllerAdvice
public static class MyControllerAdvice implements ResponseBodyAdvice<Object> {// 满足条件才转换@Overridepublic boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {return true;}// 将返回对象转换为统一格式@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {if (body instanceof JsonResponse) {return body;}return JsonResponse.ok(body);}
}
MVC执行流程
java">
// 1. 准备容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(WebConfig.class);// 2. 准备请求
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
ServletWebRequest servletWebRequest = new ServletWebRequest(request, response);// 3. 准备servletInvocableHandlerMethod
ServletInvocableHandlerMethod servletInvocableHandlerMethod = new ServletInvocableHandlerMethod(applicationContext.getBean(WebConfig.MyController.class),WebConfig.MyController.class.getDeclaredMethod("user"));
// 这里没有特殊参数绑定 入参传null
ServletRequestDataBinderFactory servletRequestDataBinderFactory = new ServletRequestDataBinderFactory(Collections.emptyList(), null);
servletInvocableHandlerMethod.setDataBinderFactory(servletRequestDataBinderFactory);
servletInvocableHandlerMethod.setParameterNameDiscoverer(new DefaultParameterNameDiscoverer());
servletInvocableHandlerMethod.setHandlerMethodArgumentResolvers(argumentResolverComposite(applicationContext));
servletInvocableHandlerMethod.setHandlerMethodReturnValueHandlers(returnValueHandlerComposite(applicationContext));// 4. 准备ModelAndViewContainer容器
ModelAndViewContainer modelAndViewContainer = new ModelAndViewContainer();// 5. 方法执行
servletInvocableHandlerMethod.invokeAndHandle(servletWebRequest,modelAndViewContainer);System.out.println(new String(response.getContentAsByteArray(), StandardCharsets.UTF_8));// 6. 关闭容器
applicationContext.close();
参数解析器与之前一致,主要是返回值处理器中的RequestResponseBodyMethodProcessor添加自定义ControllerAdvice
java">private static HandlerMethodReturnValueHandlerComposite returnValueHandlerComposite(ApplicationContext applicationContext) {MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();HandlerMethodReturnValueHandlerComposite returnValueHandlerComposite = new HandlerMethodReturnValueHandlerComposite();returnValueHandlerComposite.addHandlers(CollUtil.newArrayList(// 返回值:ModelAndViewnew ModelAndViewMethodReturnValueHandler(),// 返回值字符串:视图名new ViewNameMethodReturnValueHandler(),// 返回模型数据 带@ModelAttribute注解new ServletModelAttributeMethodProcessor(false),// 返回值:HttpEntitynew HttpEntityMethodProcessor(CollUtil.newArrayList(jackson2HttpMessageConverter)),// 返回值:HttpHeadersnew HttpHeadersReturnValueHandler(),// 返回值json: 带@ResponseBody注解 添加自定义ControllerAdvicenew RequestResponseBodyMethodProcessor(CollUtil.newArrayList(jackson2HttpMessageConverter),CollUtil.newArrayList(applicationContext.getBean(WebConfig.MyControllerAdvice.class))),// 返回模型数据 不带@ModelAttribute注解new ServletModelAttributeMethodProcessor(true)));return returnValueHandlerComposite;
}
关键代码