当前位置: 首页 > news >正文

由前端接口入门学习后端的controller层

由前端接口入门学习后端的controller层

  • 一、简单介绍一下controller层:
  • 二、前端调用后端接口时,一般会传递参数给后端,后端的控制层是如何接收的呢?
  • 三、更深入地介绍一下关于请求体参数
    • DTO作为入参
    • Map作为入参

本文是以一个前端工程师,后端小白的视角,详细介绍了关于controller的一些基本信息。大部分知识点还加上了简单的demo,真正做到了在实践中学习。

一、简单介绍一下controller层:

主要责任是接收来自用户界面(通常是Web浏览器)的请求,并根据请求的内容执行适当的操作。【即前端调用接口时就是在这里接收】

控制器通常是应用程序的入口点。它负责路由请求到正确的处理程序,并将处理后的结果返回给用户界面。控制器还可以负责验证用户输入、管理会话状态和处理异常情况等。

相当于是用户界面【前端web】和应用程序逻辑【后端代码逻辑】之间的中介。

二、前端调用后端接口时,一般会传递参数给后端,后端的控制层是如何接收的呢?

在后端的控制器层,接收前端传递的参数通常有以下几种方式,根据不同的方式,给出基于Spring Boot框架,使用了Spring Web模块提供的注解和API。你可以根据自己的实际需求和业务逻辑进行适当调整。记得在应用程序的启动类上添加@SpringBootApplication注解以启用Spring Boot的自动配置和组件扫描功能。

  1. 查询参数(Query Parameters):【GET】

    • 前端可以将参数作为URL的一部分通过查询字符串的形式传递,例如/api/users?name=John&age=25

      const param1 = 'name';
      const param2 = 'age';const url = `/api/users?param1=${encodeURIComponent(param1)}&param2=${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);}// 其他控制器方法...
      }
      
  2. 路径参数(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);}// 其他控制器方法...
      }
      
  3. 请求体参数(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);}// 其他控制器方法...
      }
      
  4. 请求头参数(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 是一个包含 usernamepassword 属性的 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);
      }
      

    常见的情况比如:

    1. 表单提交:如果请求是通过 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 字段值将映射到 UserDTOname 属性,email 字段值将映射到 UserDTOemail 属性。

      createUser 方法中,你可以对接收到的 UserDTO 对象进行处理,例如将其保存到数据库中。然后,可以使用重定向 (redirect) 将用户重定向到另一个页面,例如用户列表页面 (/users)。

      需要注意的是,@ModelAttribute 注解可以不写,因为它是 Spring MVC 默认的参数绑定方式。但为了增加代码的可读性和明确性,显式地添加 @ModelAttribute 注解是一个好习惯。

      这是一个简单的示例,展示了如何使用 @ModelAttribute 注解将表单数据映射到 DTO 对象。根据实际需求,你可以在 DTO 对象中定义更多的属性,以便处理更多的请求参数。

    2. 文件上传:当请求涉及文件上传时,@RequestBody 注解通常无法直接处理文件数据。文件上传通常需要使用 MultipartFile 或类似的类型来处理文件数据,并可能需要其他额外的注解和配置来支持文件上传功能。

    3. 自定义请求处理:在某些情况下,你可能需要对请求进行自定义处理,使用特定的解析逻辑或处理器来解析请求的内容。这种情况下,你可能不会使用 @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 中获取 usernamepassword 属性的值,并使用它们进行处理。注意需要手动进行类型转换,并且无法获得编译时的类型安全性。因此,确保请求的参数和键的名称保持一致,并进行适当的类型检查。

Map不用像DTO特地去维护一个类:

优点:

  • 灵活和简单:Map 可以接收各种键值对形式的请求参数,适用于不确定或变化的请求结构,不需要在DTO类中去维护。
  • 可以直接操作键值对:通过键值对的方式,可以直接获取和操作请求参数,适用于对请求数据的灵活处理。

缺点:

  1. 需要手动进行类型转换和验证,容易引入类型错误。
  2. 较低的可维护性:由于 Map 不提供明确的结构和属性,对于复杂的请求参数处理,可能需要在控制器方法中编写更多的逻辑来处理参数。
  3. 可读性较差:相对于 DTO,使用 Map 作为入参可能会降低代码的可读性,因为需要通过键来获取具体的参数值。

相关文章:

由前端接口入门学习后端的controller层

由前端接口入门学习后端的controller层 一、简单介绍一下controller层&#xff1a;二、前端调用后端接口时&#xff0c;一般会传递参数给后端&#xff0c;后端的控制层是如何接收的呢&#xff1f;三、更深入地介绍一下关于请求体参数DTO作为入参Map作为入参 本文是以一个前端工…...

HJ71 字符串通配符

Powered by:NEFU AB-IN Link 文章目录 HJ71 字符串通配符题意思路代码 HJ71 字符串通配符 题意 问题描述&#xff1a;在计算机中&#xff0c;通配符一种特殊语法&#xff0c;广泛应用于文件搜索、数据库、正则表达式等领域。现要求各位实现字符串通配符的算法。 要求&#xff…...

ffmpeg 开发笔记

参考&#xff1a; FFmpeg音视频处理 - 知乎 通过python实时生成音视频数据并通过ffmpeg推送和混流 - 知乎 直播常用 FFmpeg & ffplay 命令 - 知乎 音视频 FFMPEG 滤镜使用 - 知乎 官网&#xff1a; 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 摘要 提出一个由注意力机制组成的电子鼻系统。首先采用端到端的编码器译码器&#xff…...

[运维|系统] go程序设置开机启动踩坑笔记

参考文献 记systemctl启动go程序 在Ubuntu上作为systemctl服务运行时Go找不到文件 go语言程序设置开机启动&#xff0c;配置不生效 需要在服务配置文件中加入工作目录配置&#xff0c;示例 WorkingDirectory/path/to/go/program/directory...

CRC原理介绍及STM32 CRC外设的使用

1. CRC简介 循环冗余校验&#xff08;英语&#xff1a;Cyclic redundancy check&#xff0c;简称CRC&#xff09;&#xff0c;由 W. Wesley Peterson 于 1961 年首次提出的一种纠错码理论。 CRC是一种数据纠错方法&#xff0c;主要应用于数据通信或者数据存储的场合&#xff…...

Python 操作 Word

上次给大家介绍了 Python 如何操作 Excel &#xff0c;是不是感觉还挺有趣的&#xff0c;今天为大家再介绍下&#xff0c;用 Python 如何操作 Word &#xff0c;这个可能跟数据处理关系不大&#xff0c;用的也不多&#xff0c;不过可以先了解下都能实现什么功能&#xff0c;以备…...

Linux--进程创建(fork)-退出--孤儿进程

进程创建&#xff1a; ①使用fork函数创建一个进程&#xff0c;创建的新进程被称为子进程。 #include <unistd.h>//头文件 pid_t fork(void); fork函数调用成功&#xff0c;返回两次&#xff1a; 返回值为0&#xff0c; 代表当前进程为子进程&#xff1b; 返回值为非负数…...

LeetCode 热题 HOT 100:链表专题

LeetCode 热题 HOT 100&#xff1a;https://leetcode.cn/problem-list/2cktkvj/ 文章目录 2. 两数相加19. 删除链表的倒数第 N 个结点21. 合并两个有序链表23. 合并 K 个升序链表141. 环形链表142. 环形链表 II148. 排序链表160. 相交链表206. 反转链表234. 回文链表 2. 两数相…...

Redis发布订阅

在现代的软件开发中&#xff0c;数据存储和管理是至关重要的一环。Redis&#xff0c;作为一个开源的、内存中的数据结构存储系统&#xff0c;以其出色的性能和灵活的数据结构&#xff0c;赢得了开发者们的广泛喜爱。它不仅可以用作数据库&#xff0c;还可以用作缓存和消息代理。…...

在Windows操作系统上安装PostgreSQL数据库

在Windows操作系统上安装PostgreSQL数据库 一、在Windows操作系统上安装PostgreSQL数据库 一、在Windows操作系统上安装PostgreSQL数据库 点击 PostgreSQL可跳转至PostGreSQL的官方下载地址。 &#xff08;1&#xff09; &#xff08;2&#xff09;选择安装的目录&#xff…...

【云原生】Kubeadmin部署Kubernetes集群

目录 ​编辑 一、环境准备 1.2调整内核参数 二、所有节点部署docker 三、所有节点安装kubeadm&#xff0c;kubelet和kubectl 3.1定义kubernetes源 3.2开机自启kubelet 四、部署K8S集群 4.1查看初始化需要的镜像 4.2在 master 节点上传 v1.20.11.zip 压缩包至 /opt 目录…...

Java中wait和notify详解

线程的调度是无序的&#xff0c;随机的&#xff0c;但是也是有一定的需求场景&#xff0c;希望能够有序执行&#xff0c;join算是一种控制顺序的方式&#xff08;功能有限&#xff09;——》一个线程执行完&#xff0c;才能执行另一个线程&#xff01; 本文主要讲解的&#xf…...

算法竞赛个人注意事项

浅浅记录一下自己在算法竞赛中的注意事项。 数据类 注意看数大小&#xff0c;数学库中的函数尽量加上 * 1.0&#xff0c;转成double&#xff0c;防止整型溢出。&#xff0c;int型相乘如果可能溢出&#xff0c;乘 * 1LL。 数据范围大于1e6&#xff0c;注意用快读。 浮点数输…...

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程序所在的包(模块)&#xff0c;传__name__就可以 _name_ 是一个标识 Python 模块的名字的变量&#x…...

第5篇 vue的通信框架axios和ui框架-element-ui以及node.js

一 axios的使用 1.1 介绍以及作用 axios是独立于vue的一个项目&#xff0c;基于promise用于浏览器和node.js的http客户端。 在浏览器中可以帮助我们完成 ajax请求的发送在node.js中可以向远程接口发送请求 1.2 案例使用axios实现前后端数据交互 1.后端代码 2.前端代码 &…...

RabbitMQ 知识点解读

1、AMQP 协议 1.1、AMQP 生产者的流转过程 当客户端与Broker 建立连接的时候&#xff0c;会调用factory .newConnection 方法&#xff0c;这个方法会进一步封装成Protocol Header 0-9-1 的报文头发送给Broker &#xff0c;以此通知Broker 本次交互采用的是AMQPO-9-1 协议&…...

SimVODIS++: Neural Semantic Visual Odometry in Dynamic Environments 论文阅读

论文信息 题目&#xff1a;SimVODIS: Neural Semantic Visual Odometry in Dynamic Environments 作者&#xff1a;Ue-Hwan Kim , Se-Ho Kim , and Jong-Hwan Kim , Fellow, IEEE 时间&#xff1a;2022 来源&#xff1a; IEEE ROBOTICS AND AUTOMATION LETTERS&#xff08;RAL…...

7.Xaml Image控件

1.运行图片 2.运行源码 a.xaml源码 <!--Source="/th.gif" 图像源--><!--Stretch="Fill" 填充模式--><Image x:Name...

Solidity 小白教程:11. 构造函数和修饰器

Solidity 小白教程&#xff1a;11. 构造函数和修饰器 这一讲&#xff0c;我们将用合约权限控制&#xff08;Ownable&#xff09;的例子介绍solidity语言中构造函数&#xff08;constructor&#xff09;和独有的修饰器&#xff08;modifier&#xff09;。 构造函数 构造函数&…...

静态工厂模式,抽象工厂模式,建造者模式

静态工厂模式 ublic class FruitFactory {public static Fruit getFruit(String name) {Fruit fnull;switch (name){case "APPLE":{fnew Apple();}case "BANANA":{fnew Banana();}default :{System.out.println("Unknown Fruit");}}return f;} …...

【动手学深度学习笔记】--门控循环单元GRU

文章目录 门控循环单元GRU1.门控隐状态1.1重置门和更新门1.2候选隐状态1.3隐状态 2.从零开始实现2.1读取数据2.2初始化模型参数2.3定义模型2.4训练与预测 3.简洁实现 门控循环单元GRU 学习视频&#xff1a;门控循环单元&#xff08;GRU&#xff09;【动手学深度学习v2】 官方…...

浅析linux异步io框架 io_uring

前言 Linux内核5.1支持了新的异步IO框架iouring&#xff0c;由Block IO大神也即Fio作者Jens Axboe开发&#xff0c;意在提供一套公用的网络和磁盘异步IO&#xff0c;不过io_uring目前在磁盘方面要比网络方面更加成熟。 目录 背景简介 io_uring 系统API liburing 高级特性…...

访问者模式的一个使用案例——文档格式转换

访问者模式的一个使用案例——文档格式转换 假设我们在开发一个文档编辑器&#xff0c;它支持多种不同的文档元素&#xff08;如段落、图片、表格等&#xff09;&#xff0c;现在我们需要添加一个功能——将文档导出为 HTML 或 Markdown 格式。 这就是一个典型的访问者模式的…...

【MySql】数据库的聚合查询

写在最前面的话 哈喽&#xff0c;宝子们&#xff0c;今天给大家带来的是MySql数据库的聚合查询。在前面CRUD章节我们学习了表达式查询&#xff0c;表达式查询是针对列和列之间进行运算的&#xff0c;那么如果想在行和行之间进行运算&#xff0c;那么就需要用到聚合查询。聚合查…...

Linux初探 - 概念上的理解和常见指令的使用

目录 Linux背景 Linux发展史 GNU 应用场景 发行版本 从概念上认识Linux 操作系统的概念 用户的概念 路径与目录 Linux下的文件 时间戳的概念 常规权限 特殊权限 Shell的概念 常用指令 ls tree stat clear pwd echo cd touch mkdir rmdir rm cp mv …...

苹果上架Guideline 4.3 - Design

最近上架苹果商店&#xff0c;审核提示 Guideline 4.3 - DesignWe noticed your app shares a similar binary, metadata, and/or concept as apps previously submitted by a terminated Apple Developer Program account.Submitting similar or repackaged apps is a form o…...

【数据分析入门】【淘宝电商API接入与电商数据分析】初识Web API(一)

今天开始我们将学习如何使用Web应用变成借口(API)自动请求网站到特定信息而不是整个网站&#xff0c;再对这些信息进行可视化。由于这样编写到程序始终使用最新到数据来生成可视化&#xff0c;因此即便数据瞬息万变&#xff0c;它呈现到信息也都是最新的。比如&#xff0c;我们…...

蓝桥杯官网练习题(李白打酒)

题目描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 话说大诗人李白&#xff0c;一生好饮。幸好他从不开车。 一天&#xff0c;他提着酒壶&#xff0c;从家里出来&#xff0c;酒壶中有酒2斗。他边走边唱&#xff1a; …...