由前端接口入门学习后端的controller层
由前端接口入门学习后端的controller层
- 一、简单介绍一下controller层:
- 二、前端调用后端接口时,一般会传递参数给后端,后端的控制层是如何接收的呢?
- 三、更深入地介绍一下关于请求体参数
- DTO作为入参
- Map作为入参
本文是以一个前端工程师,后端小白的视角,详细介绍了关于controller的一些基本信息。大部分知识点还加上了简单的demo,真正做到了在实践中学习。
一、简单介绍一下controller层:
主要责任是接收来自用户界面(通常是Web浏览器)的请求,并根据请求的内容执行适当的操作。【即前端调用接口时就是在这里接收】
控制器通常是应用程序的入口点。它负责路由请求到正确的处理程序,并将处理后的结果返回给用户界面。控制器还可以负责验证用户输入、管理会话状态和处理异常情况等。
相当于是用户界面【前端web】和应用程序逻辑【后端代码逻辑】之间的中介。
二、前端调用后端接口时,一般会传递参数给后端,后端的控制层是如何接收的呢?
在后端的控制器层,接收前端传递的参数通常有以下几种方式,根据不同的方式,给出基于Spring Boot框架,使用了Spring Web模块提供的注解和API。你可以根据自己的实际需求和业务逻辑进行适当调整。记得在应用程序的启动类上添加@SpringBootApplication注解以启用Spring Boot的自动配置和组件扫描功能。
-
查询参数(Query Parameters):【GET】
-
前端可以将参数作为URL的一部分通过查询字符串的形式传递,例如
/api/users?name=John&age=25。const param1 = 'name'; const param2 = 'age';const url = `/api/users?param1=${encodeURIComponent(param1)}¶m2=${encodeURIComponent(param2)}`;fetch(url).then(response => response.json()).then(data => {// 处理响应数据}).catch(error => {// 处理错误}); -
在控制器中,可以通过读取请求对象的查询参数来获取这些值。
@RestController @RequestMapping("/api/users") public class UserController {@GetMappingpublic ResponseEntity<List<User>> getUsers(@RequestParam("name") String name, @RequestParam("age") int age) {// 执行相应的逻辑,例如根据参数查询用户列表List<User> users = userService.getUsersByNameAndAge(name, age);return ResponseEntity.ok(users);}// 其他控制器方法... }
-
-
路径参数(Path Parameters):【GET】
-
前端可以将参数作为URL的一部分通过路径参数的形式传递,例如
/api/users/123,其中123为用户ID。下面是一个示例,展示了如何在前端使用路径参数传递多个参数给后端:
const param1 = 'id';const url = `/api/users/${param1}`;fetch(url).then(response => response.json()).then(data => {// 处理响应数据}).catch(error => {// 处理错误});在上述示例中,我们使用 ${param1} 将两个参数拼接到 URL 的末尾,并将其作为请求的路径参数。最终的 URL 类似于 /api/users/id。
-
在控制器中,可以通过路由配置或路由参数的方式来提取路径参数的值。
@RestController @RequestMapping("/api/users") public class UserController {@GetMapping("/{id}")public ResponseEntity<User> getUser(@PathVariable("id") Long id) {// 执行相应的逻辑,例如根据参数获取特定用户User user = userService.getUserById(id);return ResponseEntity.ok(user);}// 其他控制器方法... }
-
-
请求体参数(Request Body Parameters):【POST、PUT 或 PATCH】
-
对于一些HTTP方法(如POST、PUT等),前端可以将参数作为请求体的一部分发送。这通常用于传递较大或复杂的数据。下面是一个使用
fetch发送带有 JSON 参数的 POST 请求的示例:const data = {name: 'John',email: 'john@example.com' };fetch('/api/users', {method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify(data) }).then(response => response.json()).then(data => {// 处理响应数据}).catch(error => {// 处理错误}); -
在控制器中,可以通过读取请求对象的请求体来获取这些参数的值。
@RestController @RequestMapping("/api/users") public class UserController {@PostMappingpublic ResponseEntity<User> createUser(@RequestBody CreateUserRequest request) {// 执行相应的逻辑,例如根据参数创建新用户User user = userService.createUser(request);return ResponseEntity.ok(user);}// 其他控制器方法... }
-
-
请求头参数(Request Header Parameters):
-
前端可以将参数作为请求头的一部分发送,例如在请求头中添加
Authorization字段来传递身份验证令牌。下面是一个使用
fetch发送带有请求头的 GET 请求的示例:fetch('/api/users', {method: 'GET',headers: {'Content-Type': 'application/json','Authorization': 'Bearer your_token','Custom-Header': 'custom_value'} }).then(response => response.json()).then(data => {// 处理响应数据}).catch(error => {// 处理错误});在上述示例中,通过设置
headers选项来添加请求头。你可以根据实际需求添加自定义的请求头字段,如'Authorization'和'Custom-Header',并为其指定相应的值。 -
在控制器中,可以通过读取请求对象的请求头来获取这些参数的值。
@RestController @RequestMapping("/api/users") public class UserController {@GetMappingpublic ResponseEntity<List<User>> getUsers(@RequestHeader("Authorization") String authToken) {// 执行相应的逻辑,例如根据身份验证令牌获取用户列表List<User> users = userService.getUsersByAuthToken(authToken);return ResponseEntity.ok(users);}// 其他控制器方法... }
-
三、更深入地介绍一下关于请求体参数
请求体参数可以是DTO 也可以是Map,通常来说,推荐使用 DTO 对象,因为它提供了更好的类型安全性和代码可读性,尤其是当参数具有明确的属性结构的时候。
DTO作为入参
DTO 是一个用于封装数据的对象,通常用于传输数据或承载多个属性的复杂对象。如果你的请求参数具有多个属性,那么使用 DTO 是一个不错的选择。使用 DTO 可以使代码更具可读性,并且在开发过程中可以方便地对数据进行验证和处理。例如:
// DTO类
public class UserDTO {private String username;private String password;// 其他属性和方法// Getters and setters
}// 控制器方法
@PostMapping("/users")
public ResponseEntity<UserDTO> createUser(@RequestBody UserDTO userDTO) {// 使用 userDTO 对象进行处理// ...return ResponseEntity.ok(userDTO);
}
在上述示例中,UserDTO 是一个包含 username 和 password 属性的 DTO 类。前端使用 JSON数据作为请求参数,控制器方法 createUser 使用 @RequestBody 注解将请求的 JSON 数据映射到 UserDTO 对象中,然后可以直接使用 userDTO 对象进行处理。
DTO 需要定义和维护DTO类:使用 DTO 需要创建相应的类,并定义属性和方法。
优点:
- 明确定义类型和属性,减少类型错误;
- 代码可读性强和可维护性;
- DTO 对象可以包含验证逻辑和转换方法,用于对请求参数进行验证和处理,提供更严谨和一致的数据处理;
- 可扩展性:DTO 对象可以根据业务需求灵活扩展,添加新的属性和方法,而不会影响控制器方法的签名。
缺点:
-
很麻烦。如果请求参数很简单,还要特地建一个类,才一两个属性,因此如果请求参数很简单,尽量使用Map。
-
上述的例子使用的是
@RequestBody注解将请求的 JSON 数据映射到UserDTO对象。实际上,还有一些情况是没有办法使用这个注解 直接将 JSON 数据→UserDTO对象。而是需要我们使用一些对象映射工具(如 ModelMapper、Dozer、MapStruct)或手动进行属性赋值。
-
例如,使用 ModelMapper:
@PostMapping("/users") public ResponseEntity<UserDTO> createUser(@RequestBody UserCreateRequest request) {ModelMapper modelMapper = new ModelMapper();UserDTO userDTO = modelMapper.map(request, UserDTO.class);// 处理 userDTO 对象// ...return ResponseEntity.ok(userDTO); }
常见的情况比如:
-
表单提交:如果请求是通过 HTML 表单提交的,而不是以 JSON 数据的形式发送,则无法直接使用
@RequestBody注解将请求参数映射到 DTO 对象。在这种情况下,通常会使用@ModelAttribute注解或直接将表单字段作为方法参数来获取请求参数。例如:
当使用 HTML 表单提交数据时,可以使用
@ModelAttribute注解将请求参数映射到 DTO 对象。下面是一个使用@ModelAttribute注解的简单示例:@Controller public class UserController {@PostMapping("/users")public String createUser(@ModelAttribute UserDTO userDTO) {// 处理 userDTO 对象// ...return "redirect:/users";}}在上面的示例中,
@PostMapping注解指定了处理 POST 请求的路径为/users。而@ModelAttribute注解应用于UserDTO类型的参数,它告诉 Spring MVC 框架将请求参数映射到该对象。假设有一个 HTML 表单,包含以下字段:
<form action="/users" method="post"><input type="text" name="name" /><input type="email" name="email" /><input type="submit" value="Submit" /> </form>当用户填写表单并提交时,表单中的字段名将与
UserDTO对象的属性名相匹配。Spring MVC 框架将自动将请求参数映射到UserDTO对象的对应属性。例如,name字段值将映射到UserDTO的name属性,email字段值将映射到UserDTO的email属性。在
createUser方法中,你可以对接收到的UserDTO对象进行处理,例如将其保存到数据库中。然后,可以使用重定向 (redirect) 将用户重定向到另一个页面,例如用户列表页面 (/users)。需要注意的是,
@ModelAttribute注解可以不写,因为它是 Spring MVC 默认的参数绑定方式。但为了增加代码的可读性和明确性,显式地添加@ModelAttribute注解是一个好习惯。这是一个简单的示例,展示了如何使用
@ModelAttribute注解将表单数据映射到 DTO 对象。根据实际需求,你可以在 DTO 对象中定义更多的属性,以便处理更多的请求参数。 -
文件上传:当请求涉及文件上传时,
@RequestBody注解通常无法直接处理文件数据。文件上传通常需要使用MultipartFile或类似的类型来处理文件数据,并可能需要其他额外的注解和配置来支持文件上传功能。 -
自定义请求处理:在某些情况下,你可能需要对请求进行自定义处理,使用特定的解析逻辑或处理器来解析请求的内容。这种情况下,你可能不会使用
@RequestBody注解,而是手动处理请求的输入流或使用其他自定义的方式来映射请求数据到 DTO 对象。 这种方法适用于简单的场景,当 DTO 对象的属性较少时,手动赋值可能更加直观和简单。// 在控制器方法中,根据请求参数的名称,逐个从请求对象中获取值,并将其赋值给 DTO 对象的对应属性。@PostMapping("/users")public ResponseEntity<UserDTO> createUser(@RequestBody UserCreateRequest request) {UserDTO userDTO = new UserDTO();userDTO.setName(request.getName());userDTO.setEmail(request.getEmail());// 手动赋值其他属性// ...// 处理 userDTO 对象// ...return ResponseEntity.ok(userDTO);}
-
Map作为入参
如果你的请求参数是一组松散的键值对,并且你更关注请求中的数据而不是明确的对象结构,那么使用 Map 作为入参可能更合适。Map 可以接收各种参数,并以键值对的形式提供访问参数的灵活性。但是,使用 Map 作为入参可能会降低代码的可读性,因为你需要通过键来获取参数。例如:
@PostMapping("/users")
public ResponseEntity<UserDTO> createUser(@RequestBody Map<String, Object> requestMap) {String username = (String) requestMap.get("username");String password = (String) requestMap.get("password");// 处理用户名和密码// ...return ResponseEntity.ok(userDTO);
}
在上述示例中,控制器方法 createUser 使用 @RequestBody 注解将请求的 JSON 数据映射到 Map<String, Object> 对象中。然后,通过键值对的方式从 requestMap 中获取 username 和 password 属性的值,并使用它们进行处理。注意需要手动进行类型转换,并且无法获得编译时的类型安全性。因此,确保请求的参数和键的名称保持一致,并进行适当的类型检查。
Map不用像DTO特地去维护一个类:
优点:
- 灵活和简单:Map 可以接收各种键值对形式的请求参数,适用于不确定或变化的请求结构,不需要在DTO类中去维护。
- 可以直接操作键值对:通过键值对的方式,可以直接获取和操作请求参数,适用于对请求数据的灵活处理。
缺点:
- 需要手动进行类型转换和验证,容易引入类型错误。
- 较低的可维护性:由于 Map 不提供明确的结构和属性,对于复杂的请求参数处理,可能需要在控制器方法中编写更多的逻辑来处理参数。
- 可读性较差:相对于 DTO,使用 Map 作为入参可能会降低代码的可读性,因为需要通过键来获取具体的参数值。
相关文章:
由前端接口入门学习后端的controller层
由前端接口入门学习后端的controller层 一、简单介绍一下controller层:二、前端调用后端接口时,一般会传递参数给后端,后端的控制层是如何接收的呢?三、更深入地介绍一下关于请求体参数DTO作为入参Map作为入参 本文是以一个前端工…...
HJ71 字符串通配符
Powered by:NEFU AB-IN Link 文章目录 HJ71 字符串通配符题意思路代码 HJ71 字符串通配符 题意 问题描述:在计算机中,通配符一种特殊语法,广泛应用于文件搜索、数据库、正则表达式等领域。现要求各位实现字符串通配符的算法。 要求ÿ…...
ffmpeg 开发笔记
参考: FFmpeg音视频处理 - 知乎 通过python实时生成音视频数据并通过ffmpeg推送和混流 - 知乎 直播常用 FFmpeg & ffplay 命令 - 知乎 音视频 FFMPEG 滤镜使用 - 知乎 官网: ffmpeg Documentation...
一种基于注意机制的快速、鲁棒的混合气体识别和浓度检测算法,配备了具有双损失函数的递归神经网络
A fast and robust mixture gases identification and concentration detection algorithm based on attention mechanism equipped recurrent neural network with double loss function 摘要 提出一个由注意力机制组成的电子鼻系统。首先采用端到端的编码器译码器ÿ…...
[运维|系统] go程序设置开机启动踩坑笔记
参考文献 记systemctl启动go程序 在Ubuntu上作为systemctl服务运行时Go找不到文件 go语言程序设置开机启动,配置不生效 需要在服务配置文件中加入工作目录配置,示例 WorkingDirectory/path/to/go/program/directory...
CRC原理介绍及STM32 CRC外设的使用
1. CRC简介 循环冗余校验(英语:Cyclic redundancy check,简称CRC),由 W. Wesley Peterson 于 1961 年首次提出的一种纠错码理论。 CRC是一种数据纠错方法,主要应用于数据通信或者数据存储的场合ÿ…...
Python 操作 Word
上次给大家介绍了 Python 如何操作 Excel ,是不是感觉还挺有趣的,今天为大家再介绍下,用 Python 如何操作 Word ,这个可能跟数据处理关系不大,用的也不多,不过可以先了解下都能实现什么功能,以备…...
Linux--进程创建(fork)-退出--孤儿进程
进程创建: ①使用fork函数创建一个进程,创建的新进程被称为子进程。 #include <unistd.h>//头文件 pid_t fork(void); fork函数调用成功,返回两次: 返回值为0, 代表当前进程为子进程; 返回值为非负数…...
LeetCode 热题 HOT 100:链表专题
LeetCode 热题 HOT 100:https://leetcode.cn/problem-list/2cktkvj/ 文章目录 2. 两数相加19. 删除链表的倒数第 N 个结点21. 合并两个有序链表23. 合并 K 个升序链表141. 环形链表142. 环形链表 II148. 排序链表160. 相交链表206. 反转链表234. 回文链表 2. 两数相…...
Redis发布订阅
在现代的软件开发中,数据存储和管理是至关重要的一环。Redis,作为一个开源的、内存中的数据结构存储系统,以其出色的性能和灵活的数据结构,赢得了开发者们的广泛喜爱。它不仅可以用作数据库,还可以用作缓存和消息代理。…...
在Windows操作系统上安装PostgreSQL数据库
在Windows操作系统上安装PostgreSQL数据库 一、在Windows操作系统上安装PostgreSQL数据库 一、在Windows操作系统上安装PostgreSQL数据库 点击 PostgreSQL可跳转至PostGreSQL的官方下载地址。 (1) (2)选择安装的目录ÿ…...
【云原生】Kubeadmin部署Kubernetes集群
目录 编辑 一、环境准备 1.2调整内核参数 二、所有节点部署docker 三、所有节点安装kubeadm,kubelet和kubectl 3.1定义kubernetes源 3.2开机自启kubelet 四、部署K8S集群 4.1查看初始化需要的镜像 4.2在 master 节点上传 v1.20.11.zip 压缩包至 /opt 目录…...
Java中wait和notify详解
线程的调度是无序的,随机的,但是也是有一定的需求场景,希望能够有序执行,join算是一种控制顺序的方式(功能有限)——》一个线程执行完,才能执行另一个线程! 本文主要讲解的…...
算法竞赛个人注意事项
浅浅记录一下自己在算法竞赛中的注意事项。 数据类 注意看数大小,数学库中的函数尽量加上 * 1.0,转成double,防止整型溢出。,int型相乘如果可能溢出,乘 * 1LL。 数据范围大于1e6,注意用快读。 浮点数输…...
ClickHouse和Doris超大数据集存储
文章目录 一. ClickHouse1. 性能2. 可靠性3. 可扩展性4. 支持SQL和复杂查询5. 适用场景 二. Doris1. 性能2. 可靠性3. 易用性4. 适用场景 三. ClickHouse和Doris的比较1. 架构2. 性能3. 可靠性4. 易用性5. 适用场景 四. 总结 ClickHouse和Doris是两种流行的超大数据集存储方案。…...
02-Flask-对象初始化参数
对象初始化参数 前言对象初始化参数import_namestatic_url_pathstatic_foldertemplate_floder 前言 本篇来学习Flask中对象初始化参数 对象初始化参数 import_name Flask程序所在的包(模块),传__name__就可以 _name_ 是一个标识 Python 模块的名字的变量&#x…...
第5篇 vue的通信框架axios和ui框架-element-ui以及node.js
一 axios的使用 1.1 介绍以及作用 axios是独立于vue的一个项目,基于promise用于浏览器和node.js的http客户端。 在浏览器中可以帮助我们完成 ajax请求的发送在node.js中可以向远程接口发送请求 1.2 案例使用axios实现前后端数据交互 1.后端代码 2.前端代码 &…...
RabbitMQ 知识点解读
1、AMQP 协议 1.1、AMQP 生产者的流转过程 当客户端与Broker 建立连接的时候,会调用factory .newConnection 方法,这个方法会进一步封装成Protocol Header 0-9-1 的报文头发送给Broker ,以此通知Broker 本次交互采用的是AMQPO-9-1 协议&…...
SimVODIS++: Neural Semantic Visual Odometry in Dynamic Environments 论文阅读
论文信息 题目:SimVODIS: Neural Semantic Visual Odometry in Dynamic Environments 作者:Ue-Hwan Kim , Se-Ho Kim , and Jong-Hwan Kim , Fellow, IEEE 时间:2022 来源: IEEE ROBOTICS AND AUTOMATION LETTERS(RAL…...
7.Xaml Image控件
1.运行图片 2.运行源码 a.xaml源码 <!--Source="/th.gif" 图像源--><!--Stretch="Fill" 填充模式--><Image x:Name...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
