《SpringBoot项目实战》第一篇—接口参数的一些弯弯绕绕

news2024/12/22 14:53:46

系列文章导航
第一篇—接口参数的一些弯弯绕绕
第二篇—接口用户上下文的设计与实现
第三篇—留下用户调用接口的痕迹
第四篇—接口的权限控制
第五篇—接口发生异常如何统一处理

本文参考项目源码地址:summo-springboot-interface-demo

前言

大家好!我是sum墨,一个一线的底层码农,平时喜欢研究和思考一些技术相关的问题并整理成文,限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教。

作为一名从业已达六年的老码农,我的工作主要是开发后端Java业务系统,包括各种管理后台和小程序等。在这些项目中,我设计过单/多租户体系系统,对接过许多开放平台,也搞过消息中心这类较为复杂的应用,但幸运的是,我至今还没有遇到过线上系统由于代码崩溃导致资损的情况。这其中的原因有三点:一是业务系统本身并不复杂;二是我一直遵循某大厂代码规约,在开发过程中尽可能按规约编写代码;三是经过多年的开发经验积累,我成为了一名熟练工,掌握了一些实用的技巧。

接口参数是导致很多BUG产生的始作俑者,原因在于接口参数有3多:接口参数的取值地方多,如查询参数(Query Parameters)、路径参数(Path Parameters)、请求体(Request Body)等;数据类型多,如数字、字符、日期、文件等;判断情况多,如空值判断、格式判断、大小判断等;

一、接口参数的取值

1. 放在查询参数和请求体里

a、方法参数

示例代码如下:

@GetMapping("/testParams1")
public ResponseEntity<String> testParams1(String param1, Integer param2) {
  return ResponseEntity.ok(MessageFormat.format("param1:[{0}];param2:[{1}]", param1, param2));
}

调用请求:http://localhost:8080/testParams1?param1=111&param2=222
返回如下:

没啥坑。

b、请求对象

GET请求

示例代码如下

@GetMapping("/testParams2")
public ResponseEntity<String> testParams2(ParamsReq paramsReq) {
  return ResponseEntity.ok(MessageFormat.format("param1:[{0}];param2:[{1}]", paramsReq.getParam1(), paramsReq.getParam2()));
}

ParamsReq.java

public class ParamsReq {

    private String param1;

    private String param2;

    public ParamsReq() {
    }

    public ParamsReq(String param1, String param2) {
        this.param1 = param1;
        this.param2 = param2;
    }

    public String getParam1() {
        return param1;
    }

    public void setParam1(String param1) {
        this.param1 = param1;
    }

    public String getParam2() {
        return param2;
    }

    public void setParam2(String param2) {
        this.param2 = param2;
    }

    @Override
    public String toString() {
        return "ParamsReq{" +
            "param1='" + param1 + '\'' +
            ", param2='" + param2 + '\'' +
            '}';
    }
}

调用请求:http://localhost:8080/testParams2?param1=111&param2=222
返回如下:

这种有一个坑,Spring默认使用无参构造函数来实例化对象,所以ParamsReq不能是接口、抽象类等特殊类。

POST请求

示例代码如下:

@PostMapping("/testParams3")
public ResponseEntity<String> testParams3(ParamsReq paramsReq) {
  return ResponseEntity.ok(MessageFormat.format("param1:[{0}];param2:[{1}]", paramsReq.getParam1(), paramsReq.getParam2()));
}

ParamsReq类代码同上

  • 调用方式1:参数放在链接上

和GET请求类似,没啥坑。

  • 调用方式2:放在Form表单中,content-type为application/x-www-form-urlencoded

没啥坑。

  • 调用方式3:放在body参数中,content-type为application/json

这里有坑了,当content-type为application/json时,接口参数取值为空。这时就需要在参数前加上一个注解:@RequestBody,原因是通过@RequestBody注解,Spring Boot可以自动地将请求体中的JSON数据转换为Java对象,从而方便地进行数据的处理和转换。如果不加@RequestBody注解,Spring Boot默认会将请求体中的JSON数据作为普通的表单数据来处理,而不会自动转换为Java对象。:

改成这样就行:public ResponseEntity<String> testParams3(@RequestBody ParamsReq paramsReq)

2. 放在路径参数上

示例代码如下:

@GetMapping("/testParams4/{pathParam}")
public ResponseEntity<String> testParams4(@PathVariable("pathParam") String pathParam) {
  return ResponseEntity.ok(MessageFormat.format("pathParam:[{0}];", pathParam));
}

参数使用{}框起来,然后使用@PathVariable即可获取到值,坑不多。

3. 放在请求头和Cookie

这两种情况里面的参数主要是标识类的参数如userToken,一般都是不变的,业务中很少使用到。

二、接口参数的类型

1. 数字、字符串

没啥坑。

2. 日期

示例代码如下:

@GetMapping("/testParams5")
public ResponseEntity<String> testParams5(Date date) {
  return ResponseEntity.ok(MessageFormat.format("pathParam:[{0}];", date));
}

这里有个问题,这样的接口前端怎么传这个date值,字符串?时间戳?我已经替大家试过了,都不行,接口直接报400。

正确的做法是在日期参数前加上@DateTimeFormat注解,改成这样就行了:public ResponseEntity<String> testParams5(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date date)
传参的话传字符串:2023-09-14 00:00:00 即可

3. 列表

示例代码如下:

@GetMapping("/testParams6")
public ResponseEntity<String> testParams6(List<Integer> paramList) {
  return ResponseEntity.ok(MessageFormat.format("paramList:[{0}];", paramList));
}

这串代码不用测试,它本身就是错误的,前面说过Spring默认使用无参构造函数来实例化对象,但是List是一个接口,没有无参构造函数。
为了解决这个问题,可以使用Spring的@RequestParam注解来指定参数名,并将多个参数值绑定到一个List对象中。

修改代码如下:public String testParams6(@RequestParam("paramList") List<Integer> paramList) 即可
然后,通过使用逗号分隔的参数值来访问接口,如:http://localhost:8080/testParams6?paramList=1,2,3
这样就可以成功传递参数列表并访问接口了。

4. 文件

先写一个简单上传界面
upload.html

<!DOCTYPE html>
<html>
<head>
    <title>File Upload Demo</title>
</head>
<body>
    <h1>File Upload Demo</h1>
    <form action="http://localhost:8080/upload" method="post" enctype="multipart/form-data">
        <input type="file" name="file" />
        <br/><br/>
        <input type="submit" value="Upload" />
    </form>
</body>
</html>

后端上传代码
FileUploadController.java

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

@Controller
public class FileUploadController {

    @PostMapping("/upload")
    public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {
        // Check if file is empty
        if (file.isEmpty()) {
            return new ResponseEntity<>("File is empty", HttpStatus.BAD_REQUEST);
        }

        // Save the file
        try {
            byte[] bytes = file.getBytes();
            // Logic to save the file to a desired location

            return new ResponseEntity<>("File uploaded successfully", HttpStatus.OK);
        } catch (Exception e) {
            return new ResponseEntity<>("Failed to upload file", HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
}

上传接口后端其实还好,主要是前端需要处理的内容多一些,由于MultipartFile类也是一个接口,所以这里也需要加上@RequestParam注解。

三、接口参数的判断

前面提到的@RequestBody@RequestParam注解都是SpringBoot自带的,它们主要的功能是将请求参数转换为我们接口定义的变量或者Java对象,而校验参数值是否合法通常有下面几种做法:

  • 自己写校验逻辑,一般是配合使用Assert进行参数校验
  • 使用javax.validation包的校验注解,如@NotNull@NotBlank

这里主要讲一下javax.validation如何使用!

1. pom.xml引入

<!-- 接口参数校验 -->
<dependency>
  <groupId>javax.validation</groupId>
  <artifactId>validation-api</artifactId>
  <version>2.0.1.Final</version>
</dependency>

2. 注解分类

a. 空值检查

注解说明使用频率
@NotNull不能为null,常用于数字、日期常用
@NotBlank不能为null也不能为空,常用于字符串常用
@NotEmpty集合不能为空,常用于List、Map、Set常用

b. 数值检查

注解说明使用频率
@Max被注释的元素必须小于等于指定的值常用
@Min被注释的元素必须大于等于指定的值常用
@Positive被注释的元素必须是正数不常用
@Negative被注释的元素必须是负数不常用

c. Boolean 检查

注解说明使用频率
@AssertFalse被注释的元素必须是false常用
@AssertTrue被注释的元素必须是true常用

d. 日期检查

注解说明使用频率
@Future被注释的元素必须是将来的日期不常用
@Past被注释的元素必须是过去的日期不常用

e. 日期检查

注解说明使用频率
@Email被注释的元素必须是电子邮箱地址常用
@Pattern被注释的元素必须是符合正则表达式,我经常使用这个判断手机号是否合法常用

3. 使用方法

下面是一个经典的案例

@Data
public class StudentReq {
    @NotBlank(message = "主键不能为空")
    private String id;
    @NotBlank(message = "名字不能为空")
    @Size(min = 2, max = 4, message = "名字字符长度必须为 2~4个")
    private String name;
    @Pattern(regexp = "^1[3456789]\\d{9}$", message = "手机号格式错误")
    private String phone;
    @Email(message = "邮箱格式错误")
    private String email;
    @Past(message = "生日必须早于当前时间")
    private Date birth;
    @Min(value = 0, message = "年龄必须为 0~100")
    @Max(value = 100, message = "年龄必须为 0~100")
    private Integer age;
    @PositiveOrZero
    private Double score;
}

这些东西看看就行了,用的时候翻一下文档就行,记也记不住。

四、一些可以直接获取到的参数

  • HttpServletRequest:用于获取HTTP请求的相关信息,包括请求头、请求参数、请求方法等。
  • HttpServletResponse:用于控制HTTP响应,包括设置响应状态码、设置响应头、发送响应内容等。
  • HttpSession:用于获取当前会话的信息,可以用来存储和获取会话级别的数据。
  • Principal:用于获取当前用户的身份信息,通常用于认证和授权。
  • Model/ModelMap:用于在请求处理方法中传递数据给前端视图。
  • BindingResult:用于获取请求参数绑定和验证的结果,包含了校验的错误信息。
  • Locale:用于获取当前请求的语言环境,可以用来进行国际化处理。
  • MultipartFile(或者List):用于处理上传的文件,包括文件的名称、大小、内容等。
  • RedirectAttributes:用于在重定向时传递数据给目标页面。
  • ServletRequest/ServletResponse:HttpServletRequest/HttpServletResponse的父类,可以使用其提供的通用方法。
  • @ModelAttribute注解:用于获取请求参数,并将其绑定到一个对象上。

这些对象可以直接在接口参数上使用,通过框架自动注入的方式获取其实例。在使用时,需要保证框架已经正确配置和启用了对应的注解和拦截器。用的最多的就是HttpServletRequest和HttpServletResponse了。

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

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

相关文章

MessageQueue 深入理解Android卷2 学习笔记

MessageQueue类封装了与消息队列有关的操作&#xff0c;一个以消息驱动的系统中&#xff0c;最重要部分就是消息队列和消息处理循环。 MessageQueue的核心代码在native层&#xff0c;可以处理java和native的事件 1.1MessageQueue创建 构造方法&#xff0c;调用nativeInit fra…

外网访问|SD-WAN跨境网络专线助力企业摆脱网络困境

在如今国际市场的大趋势下&#xff0c;跨境访问和沟通对于外贸企业来说至关重要&#xff0c;国际市场的竞争越来越激烈&#xff0c;外贸企业需要与全球各地的合作伙伴、客户和供应商保持紧密的跨境访问和沟通。而在解决跨境网络困境方面&#xff0c;MPLS、VPN和SD-WAN是常见的选…

CVE漏洞复现-CVE-2023-38831 WinRAR代码执行漏洞

CVE-2023-38831 WinRAR代码执行漏洞 WinRAR介绍 WinRAR 是一款功能强大的压缩包管理器&#xff0c;它是档案工具RAR在 Windows环境下的图形界面。 该软件可用于备份数据&#xff0c;缩减电子邮件附件的大小&#xff0c;解压缩从 Internet 上下载的RAR、ZIP及其它类型文件&…

装了固态硬盘Win10开机很慢的解决方法

在Win10电脑中&#xff0c;用户反映自己装了固态硬盘后&#xff0c;电脑开机变得很慢&#xff0c;想知道解决此问题的方法。接下来小编给大家详细介绍关于解决装了固态硬盘Win10电脑开机很慢的问题&#xff0c;解决后Win10电脑开机速度就能变得更快。 装了固态硬盘Win10开机很慢…

【速看】如何通过合理的封装,让你的自动化脚本更上一层楼!

1. 前言 上一篇推文利用一个在图片范围内实现随机坐标点击的例子&#xff0c;去教会大家如何将自己想要的效果实现出来&#xff0c;受到大家的热情反响&#xff0c;在我们官方讨论群中&#xff0c;还有大佬对我们的示例代码进行优化改进&#xff0c;做了很多合理的函数封装&…

B链圆桌派 — 创新的去中心化存储网络 BNB GREENFIELD 主网上线

B链圆桌派 主題: BNB GREENFIELD主网上线 - 创新的去中心化资料储存网路 日期: 10/19, 8 pm utc8 頻道&#xff1a; BNB Chain 华语电报群 ○ AMA环节 ○ BNB GREENFIELD主网上线 一、回复主持人问题 嘉宾回答主持人提出的问题。本环节请大家保持安静&#xff0c;专注嘉宾…

Flink CDC 2.0 主要是借鉴 DBLog 算法

DBLog 算法原理 DBLog 这个算法的原理分成两个部分&#xff0c;第一部分是分 chunk&#xff0c;第二部分是读 chunk。分 chunk 就是把一张表分为多个 chunk&#xff08;桶/片&#xff09;。我可以把这些 chunk 分发给不同的并发的 task 去做。例如&#xff1a;有 reader1 和 re…

Windows详细安装和彻底删除RabbitMQ图文流程

RabbiitMQ简介 RabbitMQ是实现了高级消息队列协议&#xff08;AMQP&#xff1a;Advanced Message Queue Protocol&#xff09;的开源消息代理软件&#xff08;亦称面向消息的中间件&#xff09;。RabbitMQ服务器是用Erlang语言编写的&#xff0c;而聚类和故障转移是构建在开放…

Redis -- 基础知识3 数据类型及指令

FLUSHALL:清空所有键值对操作(最好别搞,删库要被绳之以法的) 1.string类型 1.介绍 1.redis的字符串,直接按照二进制进行存储,所以可以存储任何数据,取出时不需要转码 2.redis的string类型,限制大小最大为512M,因为为单线程模型为了操作短平快 2.操作 1.set与get set key value …

财务数字化转型是什么?_光点科技

财务数字化转型是当今企业发展中的一项关键策略&#xff0c;旨在借助先进的数字技术&#xff0c;重新塑造和优化财务管理体系&#xff0c;以适应迅速变化的商业环境。这一转型不仅仅是技术的升级&#xff0c;更是对企业财务理念和流程的全面升级和改革。 财务数字化转型的核心在…

【Java】Java开发环境搭建

Java开发环境搭建 文章目录 Java开发环境搭建1. Java开发环境搭建1.1 什么是JDK、JRE1.2 JDK的下载1.3 JDK的安装1.4 配置path环境变量1.4.1 理解path环境变量1.4.2 JDK8配置&#xff1a;配置JAVA_HOMEpath1.4.3 JDK17配置方案&#xff1a;自动配置 1. Java开发环境搭建 1.1 什…

掌握CSS Flexbox,打造完美响应式布局,适配各种设备!

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! ​ 目录 ⭐ 专栏简介 &#x1f4d8; 文章引言 基…

磁盘监控:告警时发送邮件

1.配置邮箱 1.编辑邮箱配置文件 vim /etc/mail.rc2.在末尾输入自己的邮箱配置&#xff0c;以163邮箱为例 #开启ssl set ssl-verifyignore #证书目录&#xff0c;下方为centos系统证书默认位置&#xff0c;也自行生成证书并指定 set nss-config-dir/etc/pki/nssdb # 配置的第…

Windows 11 如何同步文件到OneDrive ?

Windows 11 中的 OneDrive OneDrive 默认内置于 Windows 11系统中。Windows 11从设置中删除了原来的两种备份方法并添加了OneDrive。更重要的是&#xff0c;微软在设置中添加了OneDrive Sync&#xff0c;以取代设置中的备份功能。 您可以使用 OneDrive 在计算机和云之间同步文…

【Leetcode】200. 岛屿数量

给你一个由 1&#xff08;陆地&#xff09;和 0&#xff08;水&#xff09;组成的的二维网格&#xff0c;请你计算网格中岛屿的数量。 岛屿总是被水包围&#xff0c;并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。 此外&#xff0c;你可以假设该网格的四条边…

【信创】 银河麒麟 软件目录及 常见问题汇总(持续更新)

1. 官方问题列举常见问题 常见问题国产操作系统、银河麒麟、中标麒麟、开放麒麟、星光麒麟——麒麟软件官方网站 2. 官方资源池目录 Index of /kylin/KYLIN-ALL/pool/ 如 gcc 的安装依赖 deb包目录&#xff1a; 3. 麒麟系统各版本 软件源使用方法

70 搜索插入位置

搜索插入位置 题解1 二分查找防越界写法 题解2 STL大法两行 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c; 并返回其索引。如果目标值不存在于数组中&#xff0c; 返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O ( l o g n ) O(log n…

学习paddle-detection(paddlex的使用)

首先下载paddlex&#xff08;网页&#xff09;的本地软件&#xff0c;下载链接如下&#xff1a; paddlex 下载完成后进行安装 打开后选择开发者模式&#xff0c;开发者模式主要是和VScode进行集成 本章节主要介绍在开发者模式下可以查看和编辑的文件及其作用&#xff0c;关于…

Vuex插件的安装与使用原理

Vuex插件的安装与使用原理 Vuex安装和环境搭建 安装Vuex 第一步&#xff1a;打开CMD窗口&#xff0c;通过命令转到Vue的安装路径第二步&#xff1a;输入安装Vuex的命令 vue2 安装 Vuex3 版本&#xff1a;npm i vuex3vue3 安装 Vuex4 版本&#xff1a;npm i vuex4 当在CMD窗口…

pycharm运行R语言脚本(环境安装)

文章目录 简介1. pycharm安装插件2. 安装R语言解释器2.1下载安装包2.2具体安装过程 3.编辑环境变量4.pycharm中配置安装好的R语言解释器 简介 pycharm 安装 R language for Intellij R language for Intellij 是一个插件&#xff0c;它为Intellij IDEA集成开发环境添加了对R语…