05-MessageConverter和ControllerAdvice

news2024/11/24 12:48:49

准备对象

@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

@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

@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());
    }
}

序列化优先级

@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中消息转换器的顺序

反序列化

@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

准备对象

@Data
@NoArgsConstructor
@AllArgsConstructor
public static class User {
    private String name;
    private int age;
}

准备控制器与ControllerAdvice

@Controller
public static class MyController {

    @ResponseBody
    public User user() {
        return new User("王五", 30);
    }

}

@ControllerAdvice
public static class MyControllerAdvice implements ResponseBodyAdvice<Object> {

    // 满足条件才转换
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    // 将返回对象转换为统一格式
    @Override
    public 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执行流程


// 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

private static HandlerMethodReturnValueHandlerComposite returnValueHandlerComposite(ApplicationContext applicationContext) {
    MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
    HandlerMethodReturnValueHandlerComposite returnValueHandlerComposite = new HandlerMethodReturnValueHandlerComposite();
    returnValueHandlerComposite.addHandlers(CollUtil.newArrayList(
            // 返回值:ModelAndView
            new ModelAndViewMethodReturnValueHandler(),
            // 返回值字符串:视图名
            new ViewNameMethodReturnValueHandler(),
            // 返回模型数据  带@ModelAttribute注解
            new ServletModelAttributeMethodProcessor(false),
            // 返回值:HttpEntity
            new HttpEntityMethodProcessor(CollUtil.newArrayList(jackson2HttpMessageConverter)),
            // 返回值:HttpHeaders
            new HttpHeadersReturnValueHandler(),
            // 返回值json: 带@ResponseBody注解     添加自定义ControllerAdvice
            new RequestResponseBodyMethodProcessor(CollUtil.newArrayList(jackson2HttpMessageConverter),
                    CollUtil.newArrayList(applicationContext.getBean(WebConfig.MyControllerAdvice.class))),
            // 返回模型数据  不带@ModelAttribute注解
            new ServletModelAttributeMethodProcessor(true)

    ));
    return returnValueHandlerComposite;
}

关键代码
image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1634118.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《21天学通C++》(第十一章)多态

为什么需要多态&#xff1f; 为了最大限度地减少代码&#xff0c;提高可读性 1.虚函数 虚函数是C中的一种特殊成员函数&#xff0c;它允许在派生类&#xff08;也称为子类&#xff09;中重写&#xff08;覆盖&#xff09;基类的实现&#xff0c;使用virtual进行声明 在C中&am…

包装类的基础知识

JAVA 是面向对象编程的 但是基本数据类型没有对象的 基本数据类型 byte------>>Byte short------>>Short int------>>Integer long------>>long char------>>Character double------>>Double boolean------>>Boolean 包装类…

ton-http-api安装部署

1、拉取github代码 mkdir /data git clone https://github.com/toncenter/ton-http-api.git cd ton-http-api2、创建环境变量 ./configure.py cat .env TON_API_CACHE_ENABLED0 TON_API_CACHE_REDIS_ENDPOINTcache_redis TON_API_CACHE_REDIS_PORT6379 TON_API_CACHE_REDIS_T…

【酱浦菌-爬虫项目】爬取百度文库文档

1. 首先&#xff0c;定义了一个变量url&#xff0c;指向百度文库的搜索接口 ‘https://wenku.baidu.com/gsearch/rec/pcviewdocrec’。 2. 然后&#xff0c;设置了请求参数data&#xff0c;包括文档ID&#xff08;docId&#xff09;和查询关键词&#xff08;query&#xff09;。…

Unity镂空图像做法

问题和解决方案 现在要完成一个需求&#xff0c;即镂空中间部分的image&#xff0c;外围image可以定义颜色并可选屏蔽点击&#xff0c;而中间的image需要透明且可以穿透&#xff0c;必须不能屏蔽点击。 由此拆分成了两个问题&#xff1a; 1.定义外围image颜色&#xff0c;内…

政安晨:【Keras机器学习示例演绎】(二十五)—— 使用具有三重损失的连体网络进行图像相似性估计

目录 简介 设置 加载数据集 准备数据 设置嵌入生成器模型 建立连体网络模型 将一切整合在一起 训练 检查网络的学习成果 摘要 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: TensorFlow与Keras机器学习实战 希望政安晨的博客能够…

Django框架之ORM操作

一、选择数据库 1、默认数据库 Django默认的数据库是sqlite3数据库 DATABASES {default: {ENGINE: django.db.backends.sqlite3,NAME: BASE_DIR / db.sqlite3,} }2、指定数据库 修改连接到MySQL数据库 DATABASES {default: {ENGINE: django.db.backends.mysql,# 数据库名…

鸿蒙OpenHarmony【标准系统 烧录】(基于RK3568开发板)

烧录 烧录是指将编译后的程序文件下载到芯片开发板上的动作&#xff0c;为后续的程序调试提供基础。DevEco Device Tool提供一键烧录功能&#xff0c;操作简单&#xff0c;能快捷、高效的完成程序烧录&#xff0c;提升烧录的效率。 RK3568的镜像烧录通过Windows环境进行烧录&…

Oracle-OCR掉盘无法启动集群问题

问题背景&#xff1a; 用户在对一套Oracle11.2.0.4的RAC集群进行OCR掉盘测试&#xff0c;验证NORMAL冗余的OCR磁盘组的可用性。测试通过将udev配置里面的一块OCR盘注释&#xff0c;然后重启服务器集群模拟OCR磁盘组出现掉盘的情况。用户在测试中&#xff0c;注释掉udev配置里面…

嵌入式开发_DMA详解

在嵌入式开发的广阔天地中&#xff0c;MCU是众多开发者手中的利器。而DMA&#xff08;Direct Memory Access&#xff0c;直接内存访问&#xff09;技术&#xff0c;则如同一位高效的快递小哥&#xff0c;穿梭于处理器与外设之间&#xff0c;无需CPU亲自出马&#xff0c;高效地搬…

正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-8.1

前言&#xff1a; 本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM&#xff08;MX6U&#xff09;裸机篇”视频的学习笔记&#xff0c;在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。…

【工具】--- Adobe Illustrator 下载-入门绘图

文章目录 软件下载入门项目可看课程 尝试使用Adobe Illustrator&#xff08;设计师常用软件&#xff09;进行科研绘图。 软件下载 阿里云盘下载 入门项目 绘制一个箭头并保持为SVG&#xff0c; 直线->画线->窗口->描边->选择想要的箭头样式->颜色->改为蓝…

众筹商城源码 众筹商品平台 商城加共识元富之路 网上商城众筹

众筹商城源码 众筹商品平台 商城加共识元富之路 网上商城众筹 前端是编译后的&#xff0c;后端PHP&#xff0c;带商城 源码下载&#xff1a;https://download.csdn.net/download/m0_66047725/89161734 更多资源下载&#xff1a;关注我。

mybatis工程需要的pom.xml,以及@Data 、@BeforeEach、@AfterEach 的使用,简化mybatis

对 “mybatis - XxxMapper.java接口中方法的参数 和 返回值类型&#xff0c;怎样在 XxxMapper.xml 中配置的问题” 这篇文章做一下优化 这个pom.xml文件&#xff0c;就是上面说的这篇文章的父工程的pom.xml&#xff0c;即&#xff1a;下面这个pom.xml 是可以拿来就用的 <?…

Node.js 版本升级方法

在构建vue项目时&#xff0c;依赖npm&#xff08;Node Package Manager&#xff09;工具&#xff0c;类似于Java项目需要maven管理。而npm是node.js的管理工具&#xff0c;npm依赖node.js环境才能执行。 有时候使用voscode或者其他工具安装vue项目依赖&#xff0c;显示一直处于…

【自然语言处理】Word2VecTranE的实现

作业一 Word2Vec&TranE的实现 1 任务目标 1.1 案例简介 Word2Vec是词嵌入的经典模型&#xff0c;它通过词之间的上下文信息来建模词的相似度。TransE是知识表示学习领域的经典模型&#xff0c;它借鉴了Word2Vec的思路&#xff0c;用“头实体关系尾实体”这一简单的训练目…

【Vue3】Ref与Reactive

3.1【ref 创建&#xff1a;基本类型的响应式数据】 作用&#xff1a;定义响应式变量。语法&#xff1a;let xxx ref(初始值)。返回值&#xff1a;一个RefImpl的实例对象&#xff0c;简称ref对象或ref&#xff0c;ref对象的value属性是响应式的。注意点&#xff1a; JS中操作数…

【在线名字作画HTML源码】

在线名字作画HTML源码 效果图部分源码领取源码下期更新预报 效果图 部分源码 index.htm <!DOCTYPE html> <html> <head> <title>在线名字作画|民间花鸟字|多彩花鸟虫鱼组合书法|藏字画|字谜语|飞帛板书|意匠文字</title> <meta http-equiv&…

Profinet转Modbus网关接称重设备与1200PLC通讯

Profinet转Modbus网关&#xff08;XD-MDPN100&#xff09;是一种能够实现Modbus协议和Profinet协议之间转换的设备。Profinet转Modbus网关可提供单个或多个RS485接口&#xff0c;使用Profinet转Modbus网关将称重设备与西门子1200 PLC进行通讯&#xff0c;可以避免繁琐的编程和配…

【C++】深入了解C++内存管理

个人主页&#xff1a;救赎小恶魔 欢迎大家来到小恶魔频道 好久不见&#xff0c;甚是想念 今天我们要深入讲述类与对象的初始化列表以及隐式类型转换 目录 1.C的内存分布 2.C/C言中动态内存管理方式 1.C语言的管理方式 2.C的管理方式 new delete 3.operator new与ope…