Springmvc-@RequestBody

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

算法设计与分析实验一:二分查找

目录 一、有序数组中的单一元素 1.1思路 1.2 代码实现 1.3 运行结果 二、长度最小的子数组 2.1思路 2.2 代码 2.3 运行结果 三、 山脉数组中查找目标值 3.1 思路 3.2 代码 3.3 运行结果 四、寻找旋转排序数组中的最小值 4.1思路 4.2代码 4.3 运行结果 一、有…

超越 Node.js:Bun 的创新与突破

1. Bun Bun 是一个全新的 JavaScript 运行时&#xff0c;类似于 Node.js 和 Deno&#xff0c;它专注于提供出色的性能和开发者体验。Bun 的一些特点包括&#xff1a; 快速的性能&#xff1a;Bun 旨在提供高性能&#xff0c;无论是启动时间、执行速度还是安装依赖包的速度。 兼…

ORM-02-Hibernate 对象关系映射(ORM)框架

拓展阅读 The jdbc pool for java.(java 手写 jdbc 数据库连接池实现) The simple mybatis.&#xff08;手写简易版 mybatis&#xff09; Hibernate Hibernate ORM 允许开发者更轻松地编写那些数据在应用程序进程结束后仍然存在的应用程序。 作为一个对象关系映射&#xff08…

蓝桥杯省赛无忧 编程14 肖恩的投球游戏加强版

#include <stdio.h> #define MAX_N 1003 int a[MAX_N][MAX_N], d[MAX_N][MAX_N]; // 差分数组的初始化 void init_diff(int n, int m) {for (int i 1; i < n; i) {for (int j 1; j < m; j) {d[i][j] a[i][j] - a[i-1][j] - a[i][j-1] a[i-1][j-1];}} } // 对差…

【王道数据结构】【chapter2线性表】【P44t17~t20】【统考真题】

目录 2009年统考 2012年统考 2015年统考 2019年统考 2009年统考 #include <iostream>typedef struct node{int data;node* next; }node,*list;list Init() {list head(list) malloc(sizeof (node));head->next nullptr;head->data-1;return head; }list Buyne…

QA-GNN: 使用语言模型和知识图谱的推理问答

Abstract 使用预训练语言模型&#xff08;LMs&#xff09;和知识图谱&#xff08;KGs&#xff09;的知识回答问题的问题涉及两个挑战&#xff1a;在给定的问答上下文&#xff08;问题和答案选择&#xff09;中&#xff0c;方法需要&#xff08;i&#xff09;从大型知识图谱中识…

C++:auto 关键字 范围for

目录 auto 关键字&#xff1a; 起源&#xff1a; auto的使用细则&#xff1a; auto不能推导的场景&#xff1a; 范围for&#xff1a; 范围for的使用条件&#xff1a; C的空指针&#xff1a; 注意&#xff1a; auto 关键字&#xff1a; 起源&#xff1a; 随着程序越…

蜡烛图采用PictureBox控件绘制是实现量化的第一步

股票软件中的蜡烛图是非常重要的一个东西&#xff0c;这里用VB6.0自带的Picture1控件的Line方法就可以实现绘制。 关于PictureBox 中的line 用法 msdn 上的说明为如下所示 object.Line [Step] (x1, y1) [Step] - (x2, y2), [color], [B][F] 然…

【Axure教程0基础入门】02高保真基础

02高保真基础 1.高保真原型的要素 &#xff08;1&#xff09;静态高保真原型图 尺寸&#xff1a;严格按照截图比例&#xff0c;参考线 色彩&#xff1a;使用吸取颜色&#xff0c;注意渐变色 贴图&#xff1a;矢量图/位图&#xff0c;截取&#xff0c;覆盖等 &#xff08;…

【Java Kubernates】Java调用kubernates提交Yaml到SparkOperator

背景 目前查询框架使用的是trino&#xff0c;但是trino也有其局限性&#xff0c;需要准备一个备用的查询框架。考虑使用spark&#xff0c;spark operator也已经部署到k8s&#xff0c;现在需要定向提交spark sql到k8s的sparkoperator上&#xff0c;使用k8s资源执行sql。 对比 …

【linux】查看进程和子进程

在Linux系统中&#xff0c;可以使用多个命令来查看进程及其子进程。以下是一些常用的方法&#xff1a; 1. ps 命令 ps 命令用于显示当前进程的状态。可以结合不同的选项来查看进程及其子进程。 查看进程树&#xff1a; ps -auxf - -a 显示所有进程。 - -u 显示进程的用户/所…

2024年最适合开Palworld的游戏服务器

如果要开Palworld服务器&#xff0c;当然要选大内存的服务器 在雨云&#xff0c;你不仅可以 链接&#xff1a;雨云 - 新一代云服务提供商欢迎来到以用户体验为优先的雨云&#xff0c;我们提供稳定高速的国际虚拟主机&#xff0c;云服务器产品&#xff0c;强大的功能&#xff…

MySQL中使用percona-xtrabackup工具 三种备份及恢复 (超详细教程)

CSDN 成就一亿技术人&#xff01; 今天讲讲再MySQL中使用percona-xtrabackup这个开源工具来实现在线备份。 CSDN 成就一亿技术人&#xff01; 目录 介绍percona-xtrabackup 安装Percona 完整备份 备份流程 恢复流程 1.模拟文件损坏 2.滚回日志 3.恢复数据目录 4.授权…

复现五 LMDeploy 的量化和部署

0基础知识 一步一步跟着教程复现第五&#xff1a;LMDeploy 的量化和部署 复现一&#xff1a; 轻松玩转书生浦语大模型internlm-demo 配置验证过程_ssh -cng -l 7860:127.0.0.1:6006 rootssh.intern-ai-CSDN博客文章浏览阅读827次&#xff0c;点赞17次&#xff0c;收藏24次。…

BTC的数据结构Merkle Tree和Hash pointer

比特币是一种基于区块链技术的加密数字货币&#xff0c;其底层数据结构被设计为分布式&#xff0c;去中心化的。它的核心数据结构是一个链式的区块&#xff0c;每个区块都包含了多笔交易记录和一个散列值。 比特币的底层数据结构使用了两个关键概念&#xff1a;hash pointer和…

01 Redis的特性+下载安装启动+Redis自动启动+客户端连接

1.1 NoSQL NoSQL&#xff08;“non-relational”&#xff0c; “Not Only SQL”&#xff09;&#xff0c;泛指非关系型的数据库。 键值存储数据库 &#xff1a; 就像 Map 一样的 key-value 对。如Redis文档数据库 &#xff1a; NoSQL 与关系型数据的结合&#xff0c;最像关系…

AP3464 车充 适配器IC 4-30V 2.4A 同步降压驱动器

AP3464 是一款支持宽电压输入的同步降压电源管理芯片&#xff0c;输入电压 4-30V 范围内可实现2.4A 的连续电流输出。通过调节 FB 端口的分压电阻&#xff0c;设定输出 1.8V 到 28V 的稳定电压。AP3464 具有优秀的恒压/恒流(CC/CV)特性。AP3464 采用电流模式的环路控制原理&…

Spring5深入浅出篇:Spring中ioc(控制反转)与DI(依赖注入)

Spring5深入浅出篇:Spring中ioc(控制反转)与DI(依赖注入) 反转(转移)控制(IOC Inverse of Control) 控制&#xff1a;对于成员变量赋值的控制权 反转控制&#xff1a;把对于成员变量赋值的控制权&#xff0c;从代码中反转(转移)到Spring⼯⼚和配置⽂件中完成好处&#xff1a;…

基于YOLOv8的摄像头吸烟行为检测系统(Python源码+Pyqt6界面+数据集)

&#x1f4a1;&#x1f4a1;&#x1f4a1;本文主要内容:详细介绍了摄像头下吸烟行为检测系统&#xff0c;在介绍算法原理的同时&#xff0c;给出Pytorch的源码、训练数据集以及PyQt6的UI界面。在界面中可以选择各种图片、视频进行检测识别&#xff0c;可进行置信度、Iou阈值设定…

Pandas.Series.mode() 众数 详解 含代码 含测试数据集 随Pandas版本持续更新

关于Pandas版本&#xff1a; 本文基于 pandas2.2.0 编写。 关于本文内容更新&#xff1a; 随着pandas的stable版本更迭&#xff0c;本文持续更新&#xff0c;不断完善补充。 传送门&#xff1a; Pandas API参考目录 传送门&#xff1a; Pandas 版本更新及新特性 传送门&…