2023.12.5 关于 Spring Boot 统一数据格式返回

目录

引言

 统一数据格式

实例理解

特殊 String 类型处理 

实例理解

分析返回的流程

补充知识

分析报错原因

解决方案一

解决方案二

最终测试


引言

  • 统一数据格式能 方便前端程序员更好的接收和解析后端返回的数据
  • 统一数据格式能 降低约定前后端交互接口的成本,因为所有接口都是这样返回的
  • 统一数据格式 有利于项目统一数据的维护和修改

 统一数据格式

  • 两步实现统一数据格式返回

实例理解

  • 创建一个 ResponseAdvice 类,并添加 @ControllerAdvice 注解
package com.example.demo.component;

import org.springframework.web.bind.annotation.ControllerAdvice;

@ControllerAdvice
public class ResponseAdvice {
    
}
  • 实现 ResponseBodyAdvice 接口,重写 supports 和 beforeBodyWrite 方法
package com.example.demo.component;

import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.HashMap;

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {

    /*
    *  supports 方法默认返回 false,即默认不执行 beforeBodyWrite 方法
    *  将 false 改为 true 意味着将会执行 beforeBodyWrite 方法
    * */
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
//        此处判断传来的 body 为 HashMap 类型时,将直接返回
        if(body instanceof HashMap) {
            return body;
        }
//        到这里表示 body 不为 HashMap 类型,需要统一数据返回格式
        HashMap<String,Object> result = new HashMap<>();
        result.put("code",200);
        result.put("msg","");
        result.put("data",body);
        return result;
    }
}
  • 其中的 beforeBodyWrite 方法用来实现统一数据返回
  • 我们再创建一个 UserController 类,并编写两个 test1 和 test2 方法用来测试
package com.example.demo.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;

@RestController
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/test1")
    public int test1() {
        return 1;
    }

    @RequestMapping("/test2")
    public HashMap<String,Object> test2() {
        HashMap<String,Object> result = new HashMap<>();
        result.put("code",200);
        result.put("msg","");
        result.put("data",2);
        return result;
    }
}
  • 在浏览器中输入对应的 URL,来访问调用 UserController 类中的 test1 和 test2 方法

  • 此时成功实现相同数据格式返回

注意:

  • 该写法其实相当于设定了一个保底的返回格式,属于保底策略
  • 当返回的数据格式不是约定好的数据格式时,上述方法就会帮我们将其修改为按照约定好的数据格式在进行返回给前端

特殊 String 类型处理 

实例理解

  • 我们创建一个 UserController 类,并编写 test3 方法用来测试上述的统一数据格式返回
  • 此处我们将返回一个字符串 "hello!",并希望其帮我们修改为标准的数据返回格式
package com.example.demo.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;

@RestController
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/test3")
    public String test3() {
        return "hello!";
    }
}
  • 在浏览器中输入对应的 URL,来访问调用 UserController 类中的 test3 方法

  • 此处报错信息为 试图将 HashMap 类型强制转化成 String 类型

分析返回的流程

  1. test3 方法准备返回 String 类型,返回前需要进行类型的判断,如果为 HashMap 类型则 直接返回
  2. 经判定此处不为 HashMap 类型,则统一返回数据格式 ——> 将 String 类型转换为 HashMap 类型
  3. 最后再将 HashMap 转换为 application/json 字符串给前端

补充知识

  • 在执行第三步时,Spring 框架会根据返回的类型进行判断,选择不同的转换器进行类型转换


分析报错原因

  • 正是因为 test3 方法的返回类型为 String 类型
  • 所以此时 HashMap 类型的数据 将会使用 StringHttpMessageConverter 转换器 来将其转化为 json 格式的字符串
  • 然而 StringHttpMessageConverter 转换器是专门用于处理 String 类型数据的
  • 这样就导致了 异常的发生,即在使用 StringHttpMessageConverter 转换器的前提下试图将 HashMap 对象强制转化成 String 类型(json格式的字符串为 String 类型)


解决方案一

  • 直接将 StringHttpMessageConverter 移除
package com.example.demo.config;

import com.example.demo.component.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
public class MyConfig implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.removeIf(converter -> converter instanceof StringHttpMessageConverter);
    }
}

解决方案二

  • 在统一数据返回格式时,单独处理 String 类型,让其返回一个 String 字符串,而非 HashMap 
package com.example.demo.component;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.HashMap;

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {

    @Autowired
    private ObjectMapper objectMapper;

    /*
    *  supports 方法默认返回 false,即默认不执行 beforeBodyWrite 方法
    *  将 false 改为 true 意味着将会执行 beforeBodyWrite 方法
    * */
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
//        此处判断传来的 body 为 HashMap 类型时,将直接返回
        if(body instanceof HashMap) {
            return body;
        }
//        到这里表示 body 不为 HashMap 类型,需要统一数据返回格式
        HashMap<String,Object> result = new HashMap<>();
        result.put("code",200);
        result.put("msg","");
        result.put("data",body);
//        判断 body 的类型是否为 String 类型
        if(body instanceof String) {
            try {
//               该方法可以将 HashMap 或 Java 对象转换为 json 格式的字符串
                return objectMapper.writeValueAsString(result);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
        return result;
    }
}

最终测试

  • 此处我们任选一种解决方案 进行代码的修改和添加
  • 并在浏览器中输入对应的 URL 对 test3 方法进行访问调用

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

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

相关文章

Vue2中v-html引发的安全问题

前言&#xff1a;v-html指令 1.作用&#xff1a;向指定节点中渲染包含html结构的内容。 2.与插值语法的区别&#xff1a; (1).v-html会替换掉节点中所有的内容&#xff0c;{{xx}}则不会。 (2).v-html可以识别html结构。 3.严重注意&#xff1a;v-html有安全性问题&#xff0…

搭梯子之后电脑连接WIFI打不开浏览器网页:远程计算机或者设备不接受连接

问题描述&#xff1a; 打不开网页&#xff0c;但是能正常使用微信等app windows网络诊断&#xff1a; 远程计算机或者设备不接受连接 解决办法&#xff1a; 电脑搜索【internet选项】 进入连接&#xff0c;点击局域网设置&#xff0c;将里面的代理服务器选项关掉就可以正常打开…

总结|哪些平台有大模型知识库的Web API服务

截止2023/12/6 笔者个人的调研&#xff0c;有三家有大模型知识库的web api服务&#xff1a; 平台类型文档数量文档上传并解析的结构api情况返回页码文心一言插件版多文档有问答api&#xff0c;文档上传是通过网页进行上传有&#xff0c;而且是具体的chunk id&#xff0c;需要设…

【Java】实现顺序表基本的操作(数据结构)

文章目录 前言顺序表1、打印顺序表2、增加元素3、在任意位置增加元素4、判断是否包含某个元素5、查找某个元素对于的位置6、获取任意位置的元素7、将任意位置的元素设为value8、删除第一次出现的关键字9、获取顺序表长度10、清空顺序表总结 前言 在了解顺序表之前我们要先了解…

强化学习第1天:强化学习概述

☁️主页 Nowl &#x1f525;专栏《机器学习实战》 《机器学习》 &#x1f4d1;君子坐而论道&#xff0c;少年起而行之 ​​ 文章目录 介绍 强化学习要素 强化学习任务示例 环境搭建&#xff1a;gym 基本用法 环境信息查看 创建智能体 过程可视化 完整代码 结语…

LLM大语言模型(一):ChatGLM3-6B本地部署

目录 前言 本机环境 ChatGLM3代码库下载 模型文件下载 修改为从本地模型文件启动 启动模型网页版对话demo 超参数设置 GPU资源使用情况 &#xff08;网页对话非常流畅&#xff09; 前言 LLM大语言模型工程化&#xff0c;在本地搭建一套开源的LLM&#xff0c;方便后续的…

一致性哈希详解

目录 一. 前言 二. 一致性哈希算法 三. Redis Cluster 的一致性哈希算法 四. Java 实现的一致性哈希 五. 分库分表中一致性哈希实践 5.1. 基于 hash 环一致性哈希算法的分库分表 5.2. 美团一致性哈希算法 5.3. 平均分布方案 一. 前言 普通的 hash 算法&#xff08;hash…

Ubuntu 20.04 安装 mysql8 LTS

Ubuntu 20.04 安装 mysql8 LTS sudo apt-get update sudo apt-get install mysql-server mysql --version mysql Ver 8.0.35-0ubuntu0.20.04.1 for Linux on x86_64 ((Ubuntu)) Ubuntu20.04 是自带了 MySQL8. 几版本的&#xff0c;低于 20.04 则默认安装是 MySQL5.7.33 s…

Day03 linux高级系统编程--进程

概念 进程与程序的区别 进程&#xff1a;一个正在运行的代码就叫做进程&#xff0c;是动态的&#xff0c;会占用内存 程序&#xff1a;一段封装好的待运行的代码或可执行文件&#xff0c;是静态的&#xff0c;会占用磁盘空间 单道与多道程序 单道&#xff1a;程序一个一个…

[NAND Flash 2.1] NAND Flash 闪存改变了现代生活

依公知及经验整理&#xff0c;原创保护&#xff0c;禁止转载。 专栏 《深入理解NAND Flash》 <<<< 返回总目录 <<<< ​ 1989年NAND闪存面世了&#xff0c;它曾经且正在改变了我们的日常生活。 NAND 闪存发明之所以伟大&#xff0c;是因为&#xff0c…

Hello World

世界上最著名的程序 from fastapi import FastAPIapp FastAPI()app.get("/") async def root():return {"message": "Hello World"}app.get("/hello/{name}") async def say_hello(name: str):return {"message": f"…

Vue2与Vue3的语法对比

Vue2与Vue3的语法对比 Vue.js是一款流行的JavaScript框架&#xff0c;通过它可以更加轻松地构建Web用户界面。随着Vue.js的不断发展&#xff0c;Vue2的语法已经在很多应用中得到了广泛应用。而Vue3于2020年正式发布&#xff0c;带来了许多新的特性和改进&#xff0c;同时也带来…

D. In Love

贪心&#xff0c;维护最靠左的右端点以及最靠右的左端点 // Problem: D. In Love // Contest: Codeforces - Codeforces Round 905 (Div. 3) // URL: https://codeforces.com/contest/1883/problem/D // Memory Limit: 256 MB // Time Limit: 2000 ms // // Powered by CP Edi…

一:C语言常见概念

一&#xff1a;C语言常见概念 1.认识C语言&#xff1a; ​ C语言是人和计算机交流的语言 ​ C语言是一门面向过程的语言&#xff0c;而C&#xff0c;Java&#xff0c;Python等是一门面向对象的语言 ​ 软件开发&#xff08;项目&#xff09;&#xff1a;面向过程面向对象 …

芯片半导体科普

我们在日常工作和生活中&#xff0c;经常会使用到各种各样的电子或电器产品&#xff0c;例如电脑、手机、电视、冰箱、洗衣机等。 这些产品&#xff0c;如果我们把它拆开&#xff0c;都会看到类似下面这样的一块绿色板子。 有时候是蓝色或黑色的 大家都知道&#xff0c;这个绿…

Android开发之横屏模式布局

创建一个同名的layout文件 Android Studio会创建res/layout-land目录&#xff0c;并放入一个名为activity_main.xml的新布局文件中。要查看新建文件和文件夹&#xff0c;可把项目工具窗口切换至Project视角模式&#xff1b;要查看文件汇总&#xff0c;请切回Android视角模式。…

基于jsp+servlet+mybatis的简易在线选课系统

目录 一.数据库 1.数据库和表的创建 2.数据插入 二.代码实现 1.pojo类 &#xff08;1&#xff09;Course &#xff08;2&#xff09;User &#xff08;3&#xff09;Elective 2.mapper接口 &#xff08;1&#xff09;UserMapper &#xff08;2&#xff09;ElectiveMap…

Park Unpark

文章目录 当先调用park时&#xff1a;如果_counter0&#xff0c;这时候该线程阻塞&#xff0c;进入_cond阻塞&#xff0c;之后Unpark设置_counter为1后停止阻塞 当先调用Unpark时&#xff1a;此时先将_counter设置为1&#xff0c;当后面出现park时一判断_counter为1&#xff0c…

IntelliJ IDEA 之初体验

文章目录 第一步&#xff1a;下载与安装 IntelliJ IDEA1&#xff09;官网下载2&#xff09;选择那种安装包3&#xff09;开始下载4&#xff09;解压 第二步&#xff1a;启动 IntelliJ IDEA第三步&#xff1a;创建第一个 Java 项目第四步&#xff1a;运行第一个 Java 程序1&…

Java注册并监听全局快捷键

背景 之前在博客中分享了SWT托盘功能, 随之带来一个问题, 当程序最小化后无法快速唤醒, 按照平时使用软件的思路, 自然想到了注册全局快捷键, 本文介绍使用java方式实现全局快捷键的注册. 方案 通过google,搜到一个现成的库: jintellitype, 使用maven可以直接引用, 非常方便…