Springmvc-@RequestBody

news2024/11/18 23:45:08

SpringBoot-2.7.12

请求的body参数无法转换,服务端没有报错信息打印,而是响应的状态码是400

@PostMapping("/static/user")
public User userInfo(@RequestBody(required = false) User user){
	user.setAge(19);
	return user;
}

image-20240126215324187

@PostMapping("/static/requiredUser")
public User requiredUserInfo(@RequestBody() User user){
	log.info(gson.toJson(user));
	user.setAge(19);
	return user;
}

image-20240126215757844

SpringBoot-2.1.14.RELEASE

对应springframe一系列版本spring-web、spring-webmvc…版本5.1.15.RELEASE

image-20240126220714423

请求体参数无法接受,没有报错

@PostMapping("/static/requiredUser")
public User requiredUserInfo(@RequestBody() User user){
	log.info(gson.toJson(user));
	user.setAge(19);
	return user;
}

image-20240126221057373

无body及日志输出原因

是因为我这里有一段全局异常处理,但是这里的异常处理返回信息的结果和我上面接口的返回结果不一致。将断点打在这里,也会发现异常并没有进来(进来就会有错误日志了)。是因为我的全局异常类继承了ResponseEntityExceptionHandler这个类导致的。

发现去掉这个全局异常处理,响应结果如下:

@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    private final Log log = LogFactory.getLog(this.getClass());

    @ExceptionHandler(Exception.class)
    @ResponseBody
    ReturnInfo handleControllerException(HttpServletRequest request, Throwable ex) {

        HttpStatus status = getStatus(request);
        //return new ReturnInfo(status.value(), ex.getMessage());
        log.error(status.value(),ex);
        return ReturnInfo.buildErrorInfo(ex.getMessage());
    }

    private HttpStatus getStatus(HttpServletRequest request) {
        Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
        if (statusCode == null) {
            return HttpStatus.INTERNAL_SERVER_ERROR;
        }
        return HttpStatus.valueOf(statusCode);
    }
}

image-20240127093318328

image-20240127093358907

全局异常处理修改

// 只监听这个的下面的异常处理
@ControllerAdvice(assignableTypes = {ExampleController.class})

ResponseEntityExceptionHandler

这个类里面有定义处理HttpMessageNotReadableException异常,这个指定特定异常的优先级可能更高,所以先在这里处理了,但是因为返回的结果类型不匹配,所以最终的响应体是空。

image-20240127100754414

请求体参数属性首字母小写

当出现属性变量名首字母小写时,idea自动生成的get/set格式是set/get[a-z][A-Z].*,首字母会小写,此时你的json的key是属性名,参数是能正常接受的。但是如果将set/get格式换成set/get[A-Z][A-Z].*格式,就会接收不到参数,说明Spring的自动解析参数是set或get方法来的。测试发现,参数接收/响应结果会根据类的get/set中的一个来确定属性的key,例如:

存在一个类中有属性iName,启中只有满足setiName/getiName一项,这个时候使用下面格式就能接收参数

{"iName" : "iName"}

如果都不满从setiName/getiName,而是setIName;getIName,则只能使用下面格式接收参数(并且响应的key和传递一样):

{"iname" : "iname"}


dto1

public class Goods {
    private String name;
    private String iName;
    private String description;
    private String iDescription;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getIName() {
        return iName;
    }

    public void setIName(String iName) {
        this.iName = iName;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getIDescription() {
        return iDescription;
    }

    public void setIDescription(String iDescription) {
        this.iDescription = iDescription;
    }
}

传参格式:

{
    "name": "name",
    "description": "description",
    "iname": "iname",
    "idescription": "idescription"
}

响应结果

{
    "name": "name",
    "description": "description",
    "iname": "iname",
    "idescription": "idescription"
}

dto2

public class Goods {
    private String name;
    private String iName;
    private String description;
    private String iDescription;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getiName() {
        return iName;
    }

    public void setiName(String iName) {
        this.iName = iName;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getiDescription() {
        return iDescription;
    }

    public void setiDescription(String iDescription) {
        this.iDescription = iDescription;
    }
}

接收参数:

{
    "name": "name",
    "description": "description",
    "iName": "iName",
    "iDescription": "iDescription"
}

响应结果:

{
    "name": "name",
    "description": "description",
    "iName": "iName",
    "iDescription": "iDescription"
}

dto3

两种方式都存在,没有属性结果都被返回

public class Goods {
    private String name;
    private String iName;
    private String description;
    private String iDescription;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getIName() {
        return iName;
    }

    public void setIName(String iName) {
        this.iName = iName;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getIDescription() {
        return iDescription;
    }

    public void setIDescription(String iDescription) {
        this.iDescription = iDescription;
    }

    public String getiName() {
        return iName;
    }

    public void setiName(String iName) {
        this.iName = iName;
    }

    public String getiDescription() {
        return iDescription;
    }

    public void setiDescription(String iDescription) {
        this.iDescription = iDescription;
    }
}

image-20240127111037541

请求体解析

在AbstractJackson2HttpMessageConverter调用read(Type type, @Nullable Class<?> contextClass, HttpInputMessage inputMessage)方法解析请求体

  • type:@RequestBody注解的类
  • contextClass:被代理处理的controller接口类
  • inputMessage:HTTP请求体的消息

image-20240128132835031

获取要转换的请求的参数类型Type进行解析

image-20240128133804873

TypeVariable处理逻辑:

  1. 根据这个泛型参数所在的类,new ResolvableType(clazz)对象;
  2. 最终是要获取泛型所代表的具体类型

image-20240128134825773

ParameterizedType支持嵌套处理

image-20240128140440376

根据前面获取到的Type类型,是要ObjectMapper对象构建JavaType对象。

image-20240128140919917

最终使用ObjectMapper结合JavaType和输入流得到对象。默认的解析和转换都是以Jackson的规则来的

Jackson使用测试

public class JacksonUtil {

    private static final ObjectMapper objectMapper = new ObjectMapper();


    public static JavaType getJavaType(Type type){
        return objectMapper.getTypeFactory().constructType(type);
    }

    /**
     * 字符串转Java对象
     * @param json json字符串
     * @param javaType 最终解析的Java对象类Type对应的JavaType
     * @return 泛型对象
     * @param <T>
     */
    public static <T> T stringToObject(String json, JavaType javaType){
        try {
            return objectMapper.readValue(json, javaType);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 输入流json转Java对象
     * @param inputStream json输入流
     * @param javaType 最终解析的Java对象类Type对应的JavaType
     * @return
     */
    public static Object inputStreamToObject(InputStream inputStream, JavaType javaType){
        try {
            return objectMapper.readValue(inputStream, javaType);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     *
     * @param json json字符串
     * @param clazz 结果类
     * @return json解析结果对象
     * @param <T>
     */
    public static <T> T stringToClass(String json, Class<T> clazz){
        try {
            return objectMapper.readValue(json, clazz);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 对象转json字符串
     * @param object 要转成json的对象
     * @param javaType 对象的Type对应的JavaType
     * @return
     */
    public static String objectToJson(Object object, JavaType javaType){

        try {
            return objectMapper.writerFor(javaType).writeValueAsString(object);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 普通对象转输出流
     * @param object 对象
     * @param out 输出流
     * @throws IOException
     */
    public static void objectToPrintStream(Object object, OutputStream out) throws IOException {
        JsonGenerator generator = objectMapper.getFactory().createGenerator(out, JsonEncoding.UTF8);
        ObjectWriter writer = objectMapper.writer();
        writer.writeValue(generator, object);
        generator.flush();
    }
}

public class JacksonExample {

    public static void main(String[] args) throws IOException {
        String json = "{\n" +
                "    \"name\": \"name\",\n" +
                "    \"description\": \"description\",\n" +
                "    \"iName\": \"iName\",\n" +
                "    \"iDescription\": \"iDescription\"\n" +
                "}";
        JavaType javaType = JacksonUtil.getJavaType(Goods.class);

        Goods goods = JacksonUtil.stringToObject(json, javaType);
        Goods goods1 = JacksonUtil.stringToClass(json, Goods.class);

        System.out.println(JacksonUtil.objectToJson(goods, javaType));

        JacksonUtil.objectToPrintStream(goods1,System.out);

    }
}

在json的解析和转换成json的过程中,以对象的set/get方法作为属性的重要依据

image-20240128150445199

可以从下面的测试看出,get方法在解析和转换的过程中占主要地位

image-20240128151805876

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

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

相关文章

05 Redis之Benchmark+简单动态字符串SDS+集合的底层实现

3.8 Benchmark Redis安装完毕后会自动安装一个redis-benchmark测试工具&#xff0c;其是一个压力测试工具&#xff0c;用于测试 Redis 的性能。 src目录下可找到该工具 通过 redis-benchmark –help 命令可以查看到其用法 3.8.1 测试1 3.9 简单动态字符串SDS 无论是 Redis …

【面试】测试开发面试题

帝王之气&#xff0c;定是你和万里江山&#xff0c;我都护得周全 文章目录 前言1. 网络原理get与post的区别TCP/IP各层是如何传输数据的IP头部包含哪些内容TCP头部为什么有浮动网络层协议1. 路由协议2. 路由信息3. OSPF与RIP的区别Cookie与Session&#xff0c;Token的区别http与…

Redis学习——高级篇①

Redis学习——高级篇① Redis7高级之单线程和多线程&#xff08;一&#xff09; 一、Redis单线程VS多线程1.Redis的单线程部分1.1 Redis为什么是单线程&#xff1f;1.2 Redis所谓的“单线程”1.3 Redis演进变化1.3.1 Redis 3.x 单线程时代性能很快的原因1.3.2…

林浩然科学趣谈:妙解麦克斯韦方程的电磁奥秘

林浩然科学趣谈&#xff1a;妙解麦克斯韦方程的电磁奥秘 Lin Haoran’s Scientific Banter: Playful Insights into the Electromagnetic Mysteries of Maxwell’s Equations 在科学的璀璨星河中&#xff0c;林浩然如同一颗热爱探索的行星&#xff0c;以其独特的幽默和严谨的态…

latent-diffusion model环境配置--我转载的

latent-diffusion model环境配置&#xff0c;这可能是你能够找到的最细的博客了_latent diffusion model 训练 autoencoder-CSDN博客 前言 最近在研究diffusion模型&#xff0c;并对目前最火的stable-diffusion模型很感兴趣&#xff0c;又因为stable-diffusion是一种latent-di…

opencv#35 连通域分析

连通域分割原理 像素领域介绍: 4邻域是指中心的像素与它邻近的上下左右一共有4个像素&#xff0c;那么称这4个像素为中心像素的4邻域。 8邻域是以中心像素周围的8个像素分别是上下左右和对角线上的4个像素。 连通域的定义(分割)分为两种:以4邻域为相邻判定条件的连通域分割和…

C++笔记之RTTI、RAII、MVC、MVVM、SOLID在C++中的表现

C++笔记之RTTI、RAII、MVC、MVVM、SOLID在C++中的表现 —— 杭州 2024-01-28 code review! 文章目录 C++笔记之RTTI、RAII、MVC、MVVM、SOLID在C++中的表现1.RTTI、RAII、MVC、MVVM、SOLID简述2.RAII (Resource Acquisition Is Initialization)3.RTTI (Run-Time Type Informat…

steam幻兽帕鲁服务器配置费用报价,4核16G

幻兽帕鲁服务器价格多少钱&#xff1f;4核16G服务器Palworld官方推荐配置&#xff0c;阿里云4核16G服务器32元1个月、96元3个月&#xff0c;腾讯云换手帕服务器服务器4核16G14M带宽66元一个月、277元3个月&#xff0c;8核32G22M配置115元1个月、345元3个月&#xff0c;16核64G3…

某度Pan复活,突破限速,很强大!

软件简介&#xff1a; 软件【下载地址】获取方式见文末。注&#xff1a;推荐使用&#xff0c;更贴合此安装方法&#xff01; 作为国内领先的云存储服务提供商之一&#xff0c;某度Pan为用户提供了一个便捷的文件存储和分享平台。然而&#xff0c;用户普遍反映某度Pan的下载速…

简盒工具箱iapp源码

一款工具箱兼做软件库。 新增远程更新功能 修复了部分失效功能 修复了偶尔会卡在启动页的情况 源码下载&#xff1a;https://download.csdn.net/download/m0_66047725/88776737 更多资源下载&#xff1a;关注我。

漏洞原理MySql注入 Windows中Sqlmap 工具的使用

漏洞原理MySql注入 SQLmap是一款开源的自动化SQL注入工具&#xff0c;用于检测和利用Web应用程序中的SQL注入漏洞。以下是SQLmap工具的使用总结&#xff1a; 安装和配置&#xff1a;首先需要下载并安装SQLmap工具。安装完成后&#xff0c;可以通过命令行界面或图形用户界面来使…

2024幻兽帕鲁服务器,阿里云配置

阿里云幻兽帕鲁服务器Palworld服务器推荐4核16G配置&#xff0c;可以选择通用型g7实例或通用算力型u1实例&#xff0c;ECS通用型g7实例4核16G配置价格是502.32元一个月&#xff0c;算力型u1实例4核16G是432.0元/月&#xff0c;经济型e实例是共享型云服务器&#xff0c;价格是32…

案例分享:长沙红胖子公司内部评估高清内窥镜功能列表流程产出成果鉴赏

若该文为原创文章&#xff0c;转载请注明出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/135898723 红胖子(红模仿)的博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结…

多地多活与单元化架构

多地多活与单元化架构 背景 在业务发展到一定阶段之后&#xff0c;任何因故障而导致的服务中断都会带来巨大的损失。为了提高系统的伸缩能力与高可用能力&#xff0c;我们都不断的在努力消除系统单点瓶颈。如使用应用集群是为了解决服务层的单点问题&#xff0c;使用主从数据…

FreeRTOS任务知识详解

前言 本篇文章旨在记录我学习FreeRTOS实时操作系统中&#xff0c;有关于Free RTOS的任务知识的记录。由于RTOS系统的核心就是任务管理&#xff0c;而且我们大多数人学习RTOS的初衷就是为了使用RTOS的多任务处理功能&#xff01; 初步上手RTOS首先应该掌握的就是任务的创建、删除…

AlmaLinux上安装Docker

AlmaLinux上安装Docker 文章目录 AlmaLinux上安装Docker一、前言二、具体步骤1、Docker 下载更新系统包索引&#xff1a;添加Docker仓库&#xff1a;安装Docker引擎&#xff1a; 2、Docker服务启动启动Docker服务&#xff1a;设置Docker开机自启&#xff1a; 3、Docker 安装验证…

GitLab16.8配置webhooks、Jenkins2.4配置GitLab插件实现持续集成、配置宝塔面板实现持续部署

看本篇文章的前提是已经部署完GItlab和Jenkins服务器&#xff0c;已经可以手动构建成功&#xff0c;并且经过了很多次实践&#xff0c;对这两款软件基本熟悉。 建议大家按以下顺序看 前端自动化&#xff08;其一&#xff09;部署gitlab https://blog.csdn.net/weixin_45062076…

数据中心代理IP:最优性价比业务应用指南

数据中心代理IP在应对高速高并发的业务时&#xff0c;以独特的高速传输&#xff0c;游刃有余地应对多任务处理&#xff0c;适合于特定业务场景的高效加速。理性选用数据中心代理IP&#xff0c;可以为业务将迎来更加稳健和迅速的发展。今天&#xff0c;我们将揭示数据中心代理IP…

QT+VS实现Kmeans++

1、Kmeans的原理如下&#xff1a; &#xff08;1&#xff09;首先选取样本中任一数据点作为第一个聚类中心&#xff1b; &#xff08;2&#xff09;计算样本每一个数据点至现所有聚类中心的最近距离&#xff0c;并记录下来&#xff1b; &#xff08;3&#xff09;逐一挑选所…

ATT汇编

指令后缀 AT&T格式的汇编指令有不同的后缀 其中 b表示byte&#xff0c;字节 w表示word&#xff0c;字/两字节 l表示long&#xff0c;32位系统下的long是4字节 q表示quad&#xff0c;意味四重&#xff0c;表示4个字/8字节 寄存器用途 参见 AT&T的汇编世界 - Gemfield…