05-MessageConverter和ControllerAdvice

devtools/2024/9/24 0:24:06/

准备对象

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;
}

关键代码
image.png


http://www.ppmy.cn/devtools/36312.html

相关文章

XSS Challenges 靶场通关解析

前言 XSS Challenges&#xff08;跨站脚本攻击挑战&#xff09;是一种用于学习和测试跨站脚本&#xff08;XSS&#xff09;漏洞的实验性平台。这些挑战旨在帮助安全研究人员和开发人员了解XSS漏洞的工作原理、检测方法和防御技巧。 通常&#xff0c;XSS Challenges平台提供一…

揭秘数据可视化:五款利器助力决策

在当今这个数据驱动的时代&#xff0c;数据可视化已成为企业决策、数据分析不可或缺的一部分。通过直观、生动的图形、图像&#xff0c;数据可视化能够更快速、更准确地传达信息&#xff0c;帮助企业洞察数据背后的价值。本文将为您介绍几款优秀的数据可视化工具。 一、山海鲸…

数据库开发关键之与DQL查询语句有关的两个案例

案例 案例1 条件分页查询 查看项目经理提供给我们的需求文档 模糊匹配的含义是 只要包含"张"就可以 use dduo;-- 按照需求完成员工管理的条件分页查询 根据输入条件 查询第一页的数据 每页展示10条记录 -- 输入条件&#xff1a; -- 姓名&#xff1a; 张 -- 年龄&…

代码随想录学习Day 34

62.不同路径 题目链接 讲解链接 动归五部曲&#xff1a; 1.确定dp数组及其下标的含义&#xff1a;dp[i][j]的含义是从(0, 0)走到(i, j)所需的步数&#xff1b; 2.确定递推公式&#xff1a;因为只能往右或者往下&#xff0c;所以dp[i][j] dp[i - 1][j] dp[i][j - 1]。 3.…

2024年小程序视频下载器

2024年&#xff0c;一款全新的视频下载神器——小程序视频下载器横空出世&#xff01;无论你想下载哪个平台的视频&#xff0c;只需简单几步&#xff0c;即可轻松将视频保存到你的手机或电脑中。无论是学习资料还是娱乐内容&#xff0c;我们的下载器都能满足你的需求。无论你在…

基于.NET WinForms 数据CURD功能的实现

使用开发工具 VS 2022 C#&#xff0c;数据库MS SQL SERVER 2019 &#xff0c;基于NET WinForms&#xff0c;实现数据记录的创建(Create)、更新(Update)、读取(Read)和删除(Delete)等功能。主要控件包括&#xff1a;DataGridView&#xff0c;SqlDataApater &#xff0c; DataTab…

LSS (Lift, Splat, Shoot)代码解析

文章目录 论文研究背景算法实现过程梳理一、相关参数设置二、模型相关参数三、算法前向过程 论文研究背景 LSS是一篇发表在ECCV 2020上有关自动驾驶感知方向的论文&#xff0c;具体子任务为object segmentation and map segmentation。论文和官方repo如下&#xff1a; 论文&am…

自己动手写编译器:First 集合,Follow 集合和 Select 集合

在上一节内容&#xff0c;我们手动设计了解析跳转表&#xff0c;表的行对应当前解析堆栈上的非终结符&#xff0c;列对应当前读取的终结符&#xff0c;于是对应的表格数字表示当前应该采取哪个推导表达式。本节我们看看如何自动化构建解析跳转表。首先我们引入一个概念叫 First…