SpringBoot:如何优雅地进行参数传递、响应数据封装、异常处理?

【BUG】org.springframework.web.HttpMediaTypeNotSupportedException:Content type ‘multipart/form-data; 一个BUG 今天开发一个功能,使用APpiPost测试的时候,报了一个错误,如下: 08:35:20.818 [http-nio-9203-exec-9] ERROR c.r.c.s.h.GlobalExceptionHandler - [handleException,81] - 请求地址'/coord',发生系统异常. org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'multipart/form- 阅读详情

作者:云深i不知处

blog.youkuaiyun.com/mu_wind/article/details/99960645

在项目开发中,接口与接口之间、前后端之间的数据传输都使用 JSON 格式。

1 fastjson使用

阿里巴巴的 fastjson是目前应用最广泛的JSON解析框架。本文也将使用fastjson。

1.1 引入依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.35</version>
</dependency>

2 统一封装返回数据

在web项目中,接口返回数据一般要包含状态码、信息、数据等,例如下面的接口示例:

import com.alibaba.fastjson.JSONObject;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author guozhengMu
 * @version 1.0
 * @date 2019/8/21 14:55
 * @description
 * @modify
 */
@RestController
@RequestMapping(value = "/test", method = RequestMethod.GET)
public class TestController {
    @RequestMapping("/json")
    public JSONObject test() {
        JSONObject result = new JSONObject();
        try {
            // 业务逻辑代码
            result.put("code", 0);
            result.put("msg", "操作成功!");
            result.put("data", "测试数据");
        } catch (Exception e) {
            result.put("code", 500);
            result.put("msg", "系统异常,请联系管理员!");
        }
        return result;
    }
}

这样的话,每个接口都这样处理,非常麻烦,需要一种更优雅的实现方式。

2.1 定义统一的JSON结构

统一的 JSON 结构中属性包括数据、状态码、提示信息,其他项可以自己根据需要添加。一般来说,应该有默认的返回结构,也应该有用户指定的返回结构。由于返回数据类型无法确定,需要使用泛型,代码如下:

public class ResponseInfo<T> {
    /**
     * 状态码
     */
    protected String code;
    /**
     * 响应信息
     */
    protected String msg;
    /**
     * 返回数据
     */
    private T data;

    /**
     * 若没有数据返回,默认状态码为 0,提示信息为“操作成功!”
     */
    public ResponseInfo() {
        this.code = 0;
        this.msg = "操作成功!";
    }

    /**
     * 若没有数据返回,可以人为指定状态码和提示信息
     * @param code
     * @param msg
     */
    public ResponseInfo(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    /**
     * 有数据返回时,状态码为 0,默认提示信息为“操作成功!”
     * @param data
     */
    public ResponseInfo(T data) {
        this.data = data;
        this.code = 0;
        this.msg = "操作成功!";
    }

    /**
     * 有数据返回,状态码为 0,人为指定提示信息
     * @param data
     * @param msg
     */
    public ResponseInfo(T data, String msg) {
        this.data = data;
        this.code = 0;
        this.msg = msg;
    }
    // 省略 get 和 set 方法
}

2.2 使用统一的JSON结构

我们封装了统一的返回数据结构后,在接口中就可以直接使用了。如下:

import com.example.demo.model.ResponseInfo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author guozhengMu
 * @version 1.0
 * @date 2019/8/21 14:55
 * @description
 * @modify
 */
@RestController
@RequestMapping(value = "/test", method = RequestMethod.GET)
public class TestController {
    @RequestMapping("/json")
    public ResponseInfo test() {
        try {
            // 模拟异常业务代码
            int num = 1 / 0;
            return new ResponseInfo("测试数据");
        } catch (Exception e) {
            return new ResponseInfo(500, "系统异常,请联系管理员!");
        }
    }
}

如上,接口的返回数据处理便优雅了许多。针对上面接口做个测试,启动项目,通过浏览器访问:localhost:8096/test/json,得到响应结果:

{"code":500,"msg":"系统异常,请联系管理员!","data":null}

3 全局异常处理

3.1 系统定义异常处理

新建一个 ExceptionHandlerAdvice 全局异常处理类,然后加上 @RestControllerAdvice 注解即可拦截项目中抛出的异常,如下代码中包含了几个异常处理,如参数格式异常、参数缺失、系统异常等,见下例:

@RestControllerAdvice
@Slf4j
public class ExceptionHandlerAdvice {

    // 参数格式异常处理
    @ExceptionHandler({IllegalArgumentException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseInfo badRequestException(IllegalArgumentException exception) {
     log.error("参数格式不合法:" + e.getMessage());
        return new ResponseInfo(HttpStatus.BAD_REQUEST.value() + "", "参数格式不符!");
    }

 // 权限不足异常处理
    @ExceptionHandler({AccessDeniedException.class})
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public ResponseInfo badRequestException(AccessDeniedException exception) {
        return new ResponseInfo(HttpStatus.FORBIDDEN.value() + "", exception.getMessage());
    }

 // 参数缺失异常处理
    @ExceptionHandler({MissingServletRequestParameterException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseInfo badRequestException(Exception exception) {
        return new ResponseInfo(HttpStatus.BAD_REQUEST.value() + "", "缺少必填参数!");
    }

    // 空指针异常
    @ExceptionHandler(NullPointerException.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseInfo handleTypeMismatchException(NullPointerException ex) {
        log.error("空指针异常,{}", ex.getMessage());
        return new JsonResult("500", "空指针异常");
    }

    @ExceptionHandler(Exception.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    public JsonResult handleUnexpectedServer(Exception ex) {
        log.error("系统异常:", ex);
        return new JsonResult("500", "系统发生异常,请联系管理员");
    }
    
    // 系统异常处理
    @ExceptionHandler(Throwable.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseInfo exception(Throwable throwable) {
        log.error("系统异常", throwable);
        return new ResponseInfo(HttpStatus.INTERNAL_SERVER_ERROR.value() + "系统异常,请联系管理员!");
    }
}
  1. @RestControllerAdvice 注解包含了 @Component 注解,说明在 Spring Boot 启动时,也会把该类作为组件交给 Spring 来管理。

  2. @RestControllerAdvice 注解包含了 @ResponseBody 注解,为了异常处理完之后给调用方输出一个 JSON 格式的封装数据。

  3. @RestControllerAdvice 注解还有个 basePackages 属性,该属性用来拦截哪个包中的异常信息,一般我们不指定这个属性,我们拦截项目工程中的所有异常。

  4. 在方法上通过 @ExceptionHandler 注解来指定具体的异常,然后在方法中处理该异常信息,最后将结果通过统一的 JSON 结构体返回给调用者。

  5. 但在项目中,我们一般都会比较详细地去拦截一些常见异常,拦截 Exception 虽然可以一劳永逸,但是不利于我们去排查或者定位问题。实际项目中,可以把拦截 Exception 异常写在 GlobalExceptionHandler 最下面,如果都没有找到,最后再拦截一下 Exception 异常,保证输出信息友好。

下面我们通过一个接口来进行测试:

@RestController
@RequestMapping(value = "/test", method = RequestMethod.POST)
public class TestController {
    @RequestMapping("/json")
    public ResponseInfo test(@RequestParam String userName, @RequestParam String password) {
        try {
            String data = "登录用户:" + userName + ",密码:" + password;
            return new ResponseInfo("0", "操作成功!", data);
        } catch (Exception e) {
            return new ResponseInfo("500", "系统异常,请联系管理员!");
        }
    }
}

接口调用,password这项故意空缺:

899bbd94eb18b7a6fbdb7da530fd9427.png

Spring Boot:如何优雅地进行参数传递、响应数据封装、异常处理? 统一的 JSON 结构中属性包括数据、状态码、提示信息,其他项可以自己根据需要添加。一般来说,应该有默认的返回结构,也应该有用户指定的返回结构。/*** 状态码*//*** 响应信息*//*** 返回数据*//*** 若没有数据返回,默认状态码为 0,提示信息为“操作成功!*/this.msg = "操作成功!/*** 若没有数据返回,可以人为指定状态码和提示信息*//*** 有数据返回时,状态码为 0,默认提示信息为“操作成功!*/ 阅读详情

相关推荐

一文梳理金融风控建模全流程(Python)

。借助A卡模型,银行或金融机构能够根据申请人的个人信息和历史数据,对其进行风险评估。这种评估能够帮助金融机构判断借款人是否具备偿还贷款的能力和意愿。

weixin_43420291的博客 4778

springboot(九)--统一异常处理(500)、错误页处理(404)

如题,本篇我们介绍下springboot中统一异常500处理,以及错误页404处理。 一、统一异常处理(500) 主要针对于服务器出现500异常的情况,返回自定义的500页面到用户浏览器,或者输出错误json数据到用户浏览器。 如果ex是业务层抛出的自定义异常则或取自定义异常的自定义状态码和自定义消息+错误堆栈信息;如果ex不是自定义异常,则获取ex的错误堆栈信息。 MvcExceptio...

jasnet_u的博客 2万+

在 STM32CubeIDE 中针对 STM32F407 移植 ThreadX

在 STM32CubeIDE 中针对 STM32F407 移植 ThreadX,不依赖盗版破解的Keil MDK、IAR等软件。

wangyuewu08的博客 3377

SpringBoot中使用RestTemplate封装请求头

RestTemplate的基本使用 关于RestTemplate的使用可以参考这篇文章 转载:https://blog.youkuaiyun.com/jinjiniao1/article/details/100849237 在RestTemplate中设置请求头和请求体 废话不多说,先上代码 String url = "**********************"; HttpHeaders headers ...

g13954103148的博客 1768

多传感器标定全栈系统学习教程

无论是激光雷达(Lidar)、毫米波雷达(Radar)、相机(Camera)还是惯导(IMU),传感器之间的精确标定直接决定了系统的可靠性与性能。本文将以系统化的视角,梳理多传感器标定的核心知识体系,并分享一套覆盖全栈技术的学习路径。Calibration)是实现点云与图像融合的前提,而雷达与车辆的标定(Radar2Car)则是精准速度估计的关键。:Lidar2Car、Camera2Car的快速标定流程,标定板布置规范。:从单传感器标定入手(如相机内参),逐步过渡到多传感器联合标定。

weixin_41792788的博客 905

【题解-洛谷】B3644 【模板】拓扑排序 / 家谱树

有个人的家族很大,辈分关系很混乱,请你帮整理一下这种关系。给出每个人的后代的信息。输出一个序列,使得每个人的后辈都比那个人后列出。输出一个序列,使得每个人的后辈都比那个人后列出。如果有多种不同的序列,输出任意一种即可。),表示家族的人数。

写代码的犄角旮瘩 1065

spring boot——参数传递——HttpServletRequest获取请求header、请求cookie、请求入参——HttpServletRespon设置返回header、返回cookie、...

控制器: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 packagecom.awaimai.web; importor...

小白龙白龙马的博客 1万+

常见卫星图源下载教程

上面列出的8个常见的亚米级别数据源都可以通过xyz协议或者wmts/wms协议进行下载。这些协议是什么?地理信息数据为了方便网络传输,制定了一系列的地理数据传输标准(wms/wmts/xyz等)。协议特点优点缺点栅格数据支持矢量数据支持WMS通过HTTP请求获取GIS数据,服务器会将数据渲染成图像高度定制的地图;交互性强服务器渲染图像,响应时间较长支持有限支持WMTS提供预渲染的地图瓦片速度快,因为地图瓦片可以预先生成并在请求时快速提供瓦片的内容是预先确定的,无法进行定制支持。

锐多宝的地理空间 1万+

SpringBoot:如何优雅地进行参数传递、响应数据封装、异常处理

点击“终码一生”,关注,置顶公众号 每日技术干货,第一时间送达! 在项目开发中,接口与接口之间、前后端之间的数据传输都使用 JSON 格式。 1、fastjson使用 阿里巴巴的 fastjson是目前应用最广泛的JSON解析框架。本文也将使用fastjson。 1.1 引入依赖 <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjs...

终码一生 391

【Matlab】飞行器气动弹性仿真与分析

气动弹性是飞行器设计领域的核心交叉学科,融合了空气动力学、结构动力学和控制理论,主要研究飞行器结构在气动力作用下的弹性变形、振动响应及相互耦合规律,直接影响飞行器的飞行稳定性、操纵性和结构安全性。随着飞行器向高速度、高机动性、轻量化方向发展,气动弹性问题愈发突出,如颤振、发散、嗡鸣等现象,严重时会导致飞行器结构破坏甚至飞行事故,因此气动弹性仿真与分析已成为飞行器设计、验证和优化的关键环节。当前,飞行器气动弹性仿真面临诸多技术挑战:气动力与结构变形的强耦合特性难以精准描述,易出现仿真误差;

unber的博客 238

Python爬虫实战:中国土地市场网招拍挂数据抓取与分析

本文详细介绍了如何使用Python爬虫技术从中国土地市场网抓取土地招拍挂数据,并进行初步的数据分析与可视化。文章涵盖了爬虫的基本原理、反爬虫策略应对、数据清洗与存储、数据分析与可视化等多个方面,为土地市场研究者提供了一套完整的数据获取与分析解决方案。

2201_76125261的博客 688

SpringBoot:如何优雅地进行参数传递、响应数据封装

import com.alibaba.fastjson.JSONObject;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RestController;/**@author guozhengMu@version 1.

2301_76238237的博客 1180

【RT-DETR有效改进】手把手带你调参RT-DETR,1:1复现官方版本实验环境

本文是带大家进行调参,利用ultralytics仓库1:1复现RT-DETR官方实验环境,从而在后期发表论文 的时候省去一些不必要的麻烦,例如被审稿人提出质疑,本文的调参内容均有依据,根据RT-DETR官方Github上发布的版本进行设置本文的调参以ResNet18为例,其余的何其的调参基本一致。RT-DETR剑指论文专栏,持续复现各种顶会内容——论文收割机RT-DETR。

Snu77的博客 9942

SpringBoot-4:如何优雅地进行参数传递、响应数据封装与全局异常处理

web项目之统一数据封装与全局异常处理1 fastjson使用1.1 引入依赖2 统一封装返回数据2.1 定义统一的JSON结构2.2 使用统一的JSON结构3 全局异常处理3.1 系统定义异常处理3.2 自定义异常拦截3.2.1 定义异常信息3.2.2 拦截自定义异常 在项目开发中,接口与接口之间、前后端之间的数据传输都使用 JSON 格式。 1 fastjson使用 阿里巴巴的 fastjso...

云深不知处 1万+

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

SpringBoot:如何优雅地进行参数传递、响应数据封装(1)

Java面试核心知识点一共有30个专题,足够读者朋友们应付面试啦,也节省朋友们去到处搜刮资料自己整理的时间!Java面试核心知识点《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!” />[外链图片转存中…(img-HoSU36Ha-1712685511761)]Java面试核心知识点一共有30个专题,足够读者朋友们应付面试啦,也节省朋友们去到处搜刮资料自己整理的时间![外链图片转存中…(img-maO0H7x6-1712685511761)]

2301_79963818的博客 807

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

上一篇: 学会 IDEA 的这个功能,阅读源码简直太简单了!!!
下一篇: 爆赞,微信官宣,1000W+新年红包封面开发!
Java思维导图
博客等级 码龄10年 306粉丝 71原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值