requestbody requestparam pathvariable前端端实战,让你彻底了解如何传值

requestbody requestparam pathvariable前端端实战,让你彻底了解如何传值

前言

这个文章分为原理篇和实战篇,如果你只想知道如何使用,可以直接跳转到实战篇,这里会用springboot3加vue3来演示如何进行一个传值。

原理篇

首先用一个最简单的图来说明他们的区别:

注解 用途 常见应用场景
@RequestBody 从请求体中提取数据,通常用于获取JSON或XML格式的数据 创建或更新资源时传递复杂数据
@RequestParam 从请求参数中提取单个值,通常用于获取URL查询参数或表单参数 简单的查询操作,例如根据ID查询
@PathVariable 从URL路径中提取变量值,通常用于获取URL中的路径变量 获取特定资源的详细信息

之后我们来详细分析他们的源码:

1. @RequestBody

@RequestBody注解用于将HTTP请求体中的原始数据绑定到控制器方法的参数上。通常用于处理POST或PUT请求,这些请求的body中包含了要提交的数据。

当一个请求到达时,Spring会查找所有实现了HttpMessageConverter接口的组件,并检查它们是否能够处理请求的Content-Type。如果可以,Spring会使用这些转换器将请求体中的原始数据转换为Java对象。这个过程是通过RequestMappingHandlerAdapter中的invokeHandlerMethod方法来完成的,该方法会调用RequestResponseBodyMethodProcessorresolveArgument方法,最终通过HttpMessageConverter读取并转换请求体数据

在Spring的源码中,@RequestBody注解是由RequestBodyAdvice接口的实现类处理的。当一个请求到达时,Spring会查找所有实现了RequestBodyAdvice接口的bean,并调用它们的beforeBodyRead方法。在这个方法中,可以根据请求的内容类型(Content-Type)来决定是否需要将请求体读取为一个对象。

scala 复制代码
public interface RequestBodyAdvice {
​
    boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType);
​
    HttpInputMessage convertHttpInputMessage(HttpServletRequest request, Object hint) throws IOException;
​
    Object afterBodyRead(Object body, Class<?> type, Class<? extends HttpMessageConverter<?>> converterType, HttpServletRequest request, Object hint) throws IOException;
​
}

2. @RequestParam

@RequestParam注解用于从URL的查询字符串中获取值,并将其绑定到控制器方法的参数上。这个注解可以处理简单的数据类型,如字符串、布尔值和数字,也可以处理集合类型的数据。@RequestParam的工作原理是通过RequestMappingHandlerAdapter中的invokeHandlerMethod方法来解析URL中的查询参数,并将其作为方法参数传递给控制器方法

在Spring的源码中,@RequestParam的处理是由RequestMappingHandlerAdapter类负责的。当请求到达时,RequestMappingHandlerAdapter会查找所有匹配的@RequestMapping注解,并根据注解中的参数来调用相应的方法。如果方法参数上使用了@RequestParam,它会从请求的查询参数中获取值,并将其转换为方法参数的类型。

scala 复制代码
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter {
​
    // ...
​
    private RequestBodyMethodArgumentResolver requestBodyArgumentResolver;
​
    // ...
​
    @Override
    public boolean supportsInternal(HttpServletRequest request, HandlerMethod handlerMethod) {
        // ...
    }
​
    // ...
​
}

3. @PathVariable

@PathVariable注解用于将URL模板变量绑定到控制器方法的参数上。这允许你从URL的路径部分获取值。

@PathVariable注解用于从URL模板变量中提取值,并将其绑定到控制器方法的参数上。这在构建RESTful服务时非常有用,因为它允许你将URL的一部分作为参数动态处理。@PathVariable的工作原理是在URL模式与请求的URL匹配后,Spring会将URL中的占位符替换为对应的变量值,并通过RequestMappingHandlerMappingHandlerMethodArgumentResolver接口的实现来处理这些变量

在Spring的源码中,@PathVariable的处理是由RequestMappingHandlerMapping类负责的。当配置了@RequestMapping的URL模式时,Spring会解析URL模板,并为其中的变量创建一个PathVariableMethodArgumentResolver。 当请求到达时,RequestMappingHandlerMapping会根据请求的URL找到匹配的模式,并使用PathVariableMethodArgumentResolver来解析URL中的变量,然后将这些变量作为参数传递给控制器方法。

scala 复制代码
复制public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<RequestMapping> {
​
    // ...
​
    private List<HandlerMethodArgumentResolver> argumentResolvers;
​
    // ...
​
    @Override
    protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        // ...
    }
​
    // ...
​
}

实战篇

后端篇

我们会演示创建用户、获取用户信息和更新用户信息

首先我们创建一个User的实体类

kotlin 复制代码
​
@Data
public class User {
    private Long id;
    private String username;
    private String email;
}

这里的service和mapper我就不写了,我用的是mybatis-x来生成的

之后我们来看controller层

less 复制代码
@RestController
@RequestMapping("/api/users")
public class UserController {
​
    @Resource
    private UsersService userService;
​
    /**
     * 创建用户
     *
     * @param user 要创建的用户对象
     * @return ResponseEntity 包含创建的用户对象
     */
    @PostMapping
    public ResponseEntity<Users> createUser(@RequestBody Users user) {
        userService.save(user);
        return ResponseEntity.ok(user);
    }
​
    /**
     * 获取用户信息
     *
     * @param id 用户ID
     * @return ResponseEntity 包含用户信息的字符串
     */
    @GetMapping("/{id}")
    public ResponseEntity<Users> getUser(@PathVariable("id") Long id) {
        Users user = userService.getById(id);
        return ResponseEntity.ok(user);
    }
​
    /**
     * 更新用户信息
     *
     * @param id   要更新的用户ID
     * @param user 更新后的用户对象
     * @return ResponseEntity 包含更新后的用户对象
     */
    @PutMapping("/{id}")
    public ResponseEntity<Users> updateUser(@PathVariable("id") Long id, @RequestBody Users user) {
        // 实际情况中,此处应该更新用户信息到数据库中
        user.setId(id);
        userService.updateById(user);
        // 返回更新后的用户对象
        return ResponseEntity.ok(user);
    }
​
    /**
     * 根据用户名搜索用户
     *
     * @param username 要搜索的用户名
     * @return ResponseEntity 包含搜索结果的字符串
     */
    @GetMapping("/search")
    public ResponseEntity<Users> searchUserByUsername(@RequestParam("username") String username) {
        QueryWrapper<Users> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("username", username);
        Users user = userService.getOne(queryWrapper);
        return ResponseEntity.ok(user);
    }

相信大家应该很好理解。

我们用apifox来一个一个先看他们要如何传值的。

这个时候不得不提一下apifox的自动生成非常的不错,调试起来很方便。

这个是用RequestBody来接受的User对象,所以我们需要一个json对象

之后我们来看第二个函数

@PathVariable("id") Long id

这个path的意思,也就是我们{id}里面要填的东西。

比如说

我们直接访问http://localhost:8081/api/users/58

也是同样的效果

之后来看第三个

@PathVariable("id") Long id, @RequestBody Users user

第三个有点困难。

例如我们刚才58是朱芳,我们这里需要传入id和user。

当然这里也可以简单的设计,直接传user,然后从user里面获取id。我这样只是为了更好的区别这三个注解。实际开发还是直接传入一个user比较好。

猜猜我们传入这俩个,会变成什么样子。直接揭秘。

之后来看最后一个@RequestParam("username") String username

这个和http://localhost:8081/api/users/search?username=罗超

这个是等价的

前端篇

我们首先来看前端的效果:

这个是前端的代码:

xml 复制代码
<template>
  <div>
    <h1>用户管理</h1>
    <form @submit.prevent="createUser">
      <input type="text" v-model="newUser.username" placeholder="用户名" required>
      <input type="email" v-model="newUser.email" placeholder="邮箱" required>
      <button type="submit">创建用户</button>
    </form>
​
    <h2>搜索用户</h2>
    <input type="text" v-model="searchUsername" placeholder="输入用户名">
    <button @click="searchUser">搜索</button>
​
    <h2>用户信息</h2>
    <div v-if="user">
      <p><strong>ID:</strong> {{ user.id }}</p>
      <p><strong>用户名:</strong> {{ user.username }}</p>
      <p><strong>邮箱:</strong> {{ user.email }}</p>
    </div>
​
    <h2>更新用户信息</h2>
    <form v-if="user" @submit.prevent="updateUser">
      <input type="text" v-model="updateUserModel.username" placeholder="用户名" required>
      <input type="email" v-model="updateUserModel.email" placeholder="邮箱" required>
      <button type="submit">更新用户信息</button>
    </form>
  </div>
</template>
​
<script setup>
import { ref } from 'vue';
import axios from 'axios';
​
const newUser = ref({ username: '', email: '' });
const user = ref(null);
const searchUsername = ref('');
const updateUserModel = ref({ username: '', email: '' });
​
const createUser = async () => {
  try {
    const response = await axios.post('/api/users', newUser.value);
    user.value = response.data;
    newUser.value = { username: '', email: '' }; // 清空表单
  } catch (error) {
    console.error('创建用户失败:', error);
  }
};
​
const searchUser = async () => {
  try {
    const response = await axios.get('/api/users/search', {
      params: { username: searchUsername.value }
    });
    user.value = response.data;
    // 在搜索用户后,调用getUser函数以便获取完整用户信息
    getUser(response.data.id);
  } catch (error) {
    console.error('搜索用户失败:', error);
  }
};
​
const getUser = async (id) => {
  try {
    const response = await axios.get(`/api/users/${id}`);
    user.value = response.data;
    updateUserModel.value = { username: response.data.username, email: response.data.email }; // 更新更新用户信息表单
  } catch (error) {
    console.error('获取用户信息失败:', error);
  }
};
​
const updateUser = async () => {
  try {
    const response = await axios.put(`/api/users/${user.value.id}`, updateUserModel.value);
    user.value = response.data;
    updateUserModel.value = { username: '', email: '' }; // 清空表单
  } catch (error) {
    console.error('更新用户信息失败:', error);
  }
};
</script>

大概总结一下可以是下面的样子:

后端注解 传值方式 代码示例
@RequestBody 将数据作为请求的主体发送给后端 axios.post('/api/endpoint', dataObject)
@RequestParam 将数据作为 URL 查询参数发送给后端 axios.get('/api/endpoint', { params: data })
@PathVariable 将数据作为 URL 的一部分发送给后端 axios.get(/api/endpoint/${value})

因为我最近学前端是比较多的,所以再给各位前端总结一个东西:

总结篇

Axios方法 后端参数 描述
axios.get(url) 发送GET请求,从指定的URL获取数据。
axios.get(url, { params: { key: value } }) @RequestParam("key") 发送GET请求,从指定的URL获取数据,并在URL中添加查询参数,后端通过@RequestParam("key")获取这些参数的值。
axios.post(url, data) 请求体中的数据 发送POST请求,将数据作为请求体发送到指定的URL。
axios.put(url, data) @PathVariable("id") 发送PUT请求,将数据作为请求体发送到指定的URL,路径中的id变量对应后端的@PathVariable("id")
axios.delete(url) @PathVariable("id") 发送DELETE请求,从指定的URL删除资源,路径中的id变量对应后端的@PathVariable("id")
axios.patch(url, data) @PathVariable("id") 发送PATCH请求,用指定的数据部分更新资源,路径中的id变量对应后端的@PathVariable("id")
axios.head(url) 发送HEAD请求,检索指定URL的头信息。
axios.options(url) 发送OPTIONS请求,检索指定URL的可用方法。
axios.request(config) 根据请求配置对象中的所有参数 发送自定义配置的请求。可以指定URL、请求方法、请求头、请求体等。

简而言之:

  • @RequestBody 用于接收请求体中的数据。
  • @RequestParam 用于接收请求 URL 中的查询参数。
  • @PathVariable 用于接收请求 URL 中的路径参数。

记住这个就可以了。

希望大家可以看到这个文章之后,彻底的了解这三个注释的区别。

文章中所有用到的源码均在

xiaou61/xiaou-easy-code: 前后端通用解决方案 springboot vue react 原生js (github.com)

文章也会同步到:Xiaou-EasyCode-Docs (xiaou61.top)

相关推荐
前端小咸鱼一条几秒前
13. React中为什么使用setState
前端·javascript·react.js
9号达人2 分钟前
认证方案的设计与思考
java·后端·面试
BingoGo2 分钟前
PHP 组件未来:Livewire 4 正式发布,性能更快,功能更完整
后端·php
William_cl5 分钟前
拆解ASP.NET MVC 视图模型:为 View 量身定制的 “数据小票“
后端·asp.net·mvc
辜月十5 分钟前
设置 Root 账号 并能够 SSH进行链接
后端
QZQ541885 分钟前
当数据多到放不下内存时,算子的外部执行机制
后端
没有bug.的程序员12 分钟前
Spring Boot 常见性能与配置优化
java·spring boot·后端·spring·动态代理
没有bug.的程序员15 分钟前
Spring Boot Actuator 监控机制解析
java·前端·spring boot·spring·源码
骇客野人1 小时前
Spring Boot项目快速稳健架构指南
spring boot·后端·架构
OpenTiny社区1 小时前
如何使用 TinyEditor 快速部署一个协同编辑器
前端·开源·编辑器·opentiny