一、基础知识铺垫 Axios使用 使用axios发送请求,一般有三个最常用的属性。
属性
含义
url
请求的端点 URL
。
method
HTTP
请求方法(如 get
, post
, put
, delete
, patch
等)。
params
/ data
如果 method
是 get
或 delete
,使用 params
来传递 URL
查询参数。如果是 post
, put
, patch
,则使用 data
传递请求体数据。通常是一个对象 {}。
HTTP请求方式 Restful
风格定义了多种请求方式。
方式
简介
常用场景
GET
请求指定的资源。通常用来获取或查询资源。
读取或查询资源,如获取用户列表或特定用户的详细信息。
POST
向指定资源提交数据,请求服务器进行处理(如创建或修改)。数据包含在请求体中。
创建新资源(如新用户、新帖子),或提交用户数据表单。
PUT
用请求体中的数据替换目标资源的所有当前表示。
更新现有资源的全部内容,如编辑用户的完整个人信息。
PATCH
对资源应用部分修改。
更新资源的一部分,如修改用户的邮箱地址或密码。
DELETE
删除指定的资源。
删除资源,如删除用户账户或帖子。
数据传输方式
方式
介绍
URL路径参数(Path Variables
)
通过 URL
的路径部分传递数据。在 Spring Boot
中使用 @PathVariable
注解获取。适用于 RESTful
风格的 API
,例如获取特定资源的详情。
查询参数(Query Parameters
)
通过 URL
的查询字符串(?key=value 形式)传递数据。在 Spring Boot
中使用 @RequestParam
注解获取。适用于 GET
和 DELETE
请求。
请求体(Request Body
)
通过 HTTP
请求的 body
部分传递数据。在 Spring Boot
中使用 @RequestBody
注解获取。适用于 POST
, PUT
和 PATCH
请求,发送复杂的数据结构。
SpringBoot获取数据的方式 需要提及的是,单单从”获取数据”的角度,我们可以把Delete
和Get
归为一类,把Put
、Patch
、Post
归为一类。
前者在axios
中使用params
传递参数,属于Query Parameters
。
后者在axios
中使用data
传递参数,属于Request Body
。
无论是哪一种,都可以有Path Variables
。
在 Spring Boot(及一般的 HTTP 服务开发)中,将请求分为”GET 体系”和”POST 体系”可能会导致一些混淆,因为每种 HTTP 方法(GET、POST、PUT、PATCH、DELETE 等)都设计有其独特的用途和语义。不过,如果我们从”如何获取请求中的数据”这个角度来看,可以有一种比较宽泛的分类方式,尤其是关注于数据是通过 URL 还是请求体传递。
体系
获取数据的常用注解
Path Variables
@PathVariable
Get、Delete类
@RequestParam
、@ModelAttribute
Post、Put、Patch类
@RequestBody
二、基础传递代码示例 除了特殊的数据类型,普通的数据传递,默认以axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8';
为策略。
(一)Path Variables Path Variables
数据在url
上,无关乎get
还是post
。
language-javascript 1 2 3 4 5 6 7 8 9 10 return request({ url: '/test/users/123', method: 'get' }); return request({ url: '/test/users/345/info', method: 'post' });
language-java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @RestController @RequestMapping("/test") public class CourseTestController { @GetMapping("/users/{userId}") public String getUser(@PathVariable String userId) { return "Received GET request for User ID: " + userId; } @PostMapping("/users/{userId}/info") public String updateUser(@PathVariable String userId) { return "Received POST request for User ID: " + userId; } }
(二)Get、Delete @RequestParam @RequestParam
主要用于将单个请求参数
绑定到方法的参数上,通过指定 value
或 name
属性,你可以明确告诉 Spring Boot
请求参数的实际名称。
language-javascript 1 2 3 4 5 6 7 8 9 10 return request({ url: '/users', method: 'get', params:{ type:"1", status:"2", } });
language-java 1 2 3 4 5 @GetMapping("/users") public String getUser(@RequestParam String type, @RequestParam(name = "status") String userStatus) { return "Received GET request for" + type + " " + userStatus; }
@ModelAttribute 利用 @ModelAttribute
注解。这个注解会告诉 Spring Boot
,应该将请求中的查询参数自动绑定到方法参数对象的属性上。
language-javascript 1 2 3 4 5 6 7 8 9 10 return request({ url: '/users', method: 'get', params:{ type:"1", status:"2", } });
language-java 1 2 3 4 5 6 7 8 9 10 11 @GetMapping("/users") public String getUser(@ModelAttribute Query query) { return "Received GET request for" + query.toString(); } @Data class Query{ String type; String status; }
通常情况下,我们会将所有的查询参数封装到一个对象中,而不是分开为两个对象,除非这两个对象在逻辑上代表着完全不同的东西
,且您希望显式地区分它们。如果您确实有特定的理由需要这样做,也是可行的。比如第二个Query2
表示分页查询时的分页参数
。
language-javascript 1 2 3 4 5 6 7 8 9 10 return request({ url: '/users', method: 'delete', params:{ type:"1", status:"2", } });
language-java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @DeleteMapping("/users") public String deleteUser(@ModelAttribute Query1 query1, @ModelAttribute Query2 query2) { return "Received GET request for" + query1.toString() + query2.toString(); } @Data class Query1{ String type; } @Data class Query2{ String userStatus; // 如果您希望整个对象通过 @ModelAttribute 来绑定,同时又有个别属性名不匹配 // 您可以在后端对象中添加 setter 方法,并在其中处理名称不匹配的问题 // 注意:Lombok @Data 注解会生成默认的 setter 方法, // 所以如果使用 Lombok,您需要手动添加一个额外的 setter 方法来处理不匹配的情况 public void setStatus(String status) { this.userStatus = status; } }
(三)Post、Put、Patch @RequestBody language-javascript 1 2 3 4 5 6 7 8 9 10 11 12 return request({ url: '/users', method: 'post', data:{ userId: 123, userName: "John Doe", userAge: 30, userSex: "Male" } });
language-java 1 2 3 4 5 6 7 8 9 10 11 12 13 @PostMapping("/users") public String getUser(@RequestBody UserVo userVo) { return userVo.toString(); } @Data class UserVo{ Long userId; String userName; Long userAge; String userSex; }
当 Spring Boot
后端的 UserVo
类中的属性名和前端传递的 JSON
对象的键名不一致时,可以使用@JsonProperty
。
language-javascript 1 2 3 4 5 6 7 8 9 10 11 12 return request({ url: '/users', method: 'put', data:{ userId: 123, userName: "John Doe", userAge: 32, userSex: "Male" } });
language-java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @PutMapping("/users") public String getUser(@RequestBody UserVo userVo) { return userVo.toString(); } @Data class UserVo{ Long userId; @JsonProperty("userName") String name; Long userAge; String userSex; }
language-javascript 1 2 3 4 5 6 7 8 9 10 return request({ url: '/users', method: 'patch', data:{ userId: 123, userAge: 34, } });
language-java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @PatchMapping("/users") public String getUser(@RequestBody UserVo userVo) { return userVo.toString(); } @Data class UserVo{ Long userId; @JsonProperty("userName") String name; Long userAge; String userSex; }
如果你不想额外写一个类作为@RequestBody
的参数,你可以选择使用Map
或者JsonNode
。
language-java 1 2 3 4 5 6 7 @PutMapping("/users") public R<Boolean> getUser(@RequestBody Map<String, Object> body) { Long id = Long.valueOf(body.get("userId").toString()); String mind = (String) body.get("name"); // 业务逻辑 }
language-java 1 2 3 4 5 6 7 @PutMapping("/users") public R<Boolean> getUser(@RequestBody JsonNode body) { Long id = body.get("userId").asLong(); String mind = body.get("name").asText(); // 业务逻辑 }
三、稍微复杂一点的传递 (一)数组 如果用的是Post
,那么一般一切安好。
language-javascript 1 2 3 4 5 6 7 8 9 10 return request({ url: '/users', method: 'post', data:{ userId: 123, userOrder: ['1223', '3445', '556'], } });
language-java 1 2 3 4 5 6 7 8 9 10 11 @PostMapping("/users") public String getUser(@RequestBody UserVo userVo) { return userVo.toString(); } @Data class UserVo{ Long userId; List<String> userOrder; }
如果用的是Get
,就需要注意默认情况下,Spring Boot 期望列表或数组类型的查询参数以特定的格式传递,例如:userOrder=1223&userOrder=3445&userOrder=556
。但在你的例子中,由于是通过 axios 发送请求,并且当你在请求的 params 中包含一个数组时,axios 会将数组转换为 userOrder[0]=1223&userOrder[1]=3445&userOrder[2]=556
的格式,这与 Spring Boot 的默认期望不匹配
。
language-javascript 1 2 3 4 5 6 7 8 9 10 return request({ url: '/users', method: 'get', params:{ userId: 123, userOrder: ['1223', '3445', '556'].join(','), } });
language-java 1 2 3 4 5 @GetMapping("/users") public String getUser(@RequestParam String userId, @RequestParam List<String> userOrder) { return userId + "\n" + userOrder.toString(); }
对于数组元素是简单类型,直接用字符’,’拼接即可,变成userOrder=1223,3445,556
,Springboot也能匹配。或者可以去参考qs.stringify
也就是qs
库的用法。
如果数组元素比较复杂呢?如果你仍然坚持使用get
,建议去阅读qs
使用。一般的做法是用post
,可以省去很多麻烦。
language-javascript 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 return request({ url: '/users', method: 'post', data:{ userId: 123, userOrder: [ { id: '1223', name: 'Order1' }, { id: '3445', name: 'Order2' }, { id: '556', name: 'Order3' } ] } });
language-java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @PostMapping("/users") public String getUser(@RequestBody UserVo userVo) { return userVo.toString(); } @Data class UserVo{ Long userId; List<Item> userOrder; } @Data class Item{ String id; String name; }
(二)GET/POST复合型 对于复合型请求,即在URL
中通过查询参数(例如分页信息)传递部分数据,同时在请求体中通过JSON
传递更复杂的数据(例如筛选条件),Spring Boot
可以通过同时使用@RequestParam
和@RequestBody
注解来接收这两种类型的数据。
language-javascript 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const pageParams = { page: 1, size: 10 }; return request({ url: `/users?page=${ pageParams.page}&size=${ pageParams.size}`, method: 'post', data:{ userId: 123, userName: "Jack" } });
language-java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @PostMapping("/users") public String getUser( @RequestBody UserVo userVo, @RequestParam("page") int page, @RequestParam("size") int size ) { return userVo.toString(); } @Data class UserVo{ Long userId; String userName; }
四、特殊数据 (一)文件 上传文件时,使用的 Content-Type
通常是 multipart/form-data
。这种类型允许将请求体中的数据作为一系列部分(parts)发送,每个部分可以包含文件内容或其他数据。这种方式非常适合文件上传,因为它支持在单个请求中发送文件数据及其他表单字段
。
language-javascript 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const formData = new FormData(); formData.append('file', file); formData.append('filename', file.name); formData.append('chunkIndex', i.toString()); formData.append('totalChunks', totalChunks.toString()); formData.append('md5', md5); const rsp = await addChunk(formData); export const addChunk = (data: any) => { return request({ url: '/video/chunk', method: 'post', data: data }); };
language-java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @PostMapping(value = "/video/chunk") public R<String> handleChunkUpload( @RequestParam("file") MultipartFile file, @RequestParam("md5") String md5, @RequestParam("filename") String filename, @RequestParam("chunkIndex") int chunkIndex, @RequestParam("totalChunks") int totalChunks) { if (ObjectUtil.isNull(file)) { return R.fail("上传文件不能为空"); } Boolean b = mediaFilesService.handleChunkUpload(file, md5); if (b){ return R.ok(); }else { return R.fail(); } }
在 Vue 3
的框架 Element Plus
中,el-upload
组件用于文件上传,它底层使用的也是 multipart/form-data
这种 Content-Type 来上传文件。这是因为 multipart/form-data
允许在一个请求中发送多部分数据,包括文本字段和文件,非常适合文件上传的场景
language-html 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 <template> <el-upload action="http://example.com/upload" :data="extraData" :on-success="handleSuccess" :on-error="handleError" > <el-button size="small" type="primary">点击上传</el-button> </el-upload> </template> <script setup> import { ElMessage } from 'element-plus'; import { ref } from 'vue'; // 额外数据 const extraData = ref({ userId: "123", description: "这是一个文件描述" }); const handleSuccess = (response, file, fileList) => { // 文件上传成功的回调 ElMessage.success('文件上传成功'); }; const handleError = (err, file, fileList) => { // 文件上传失败的回调 ElMessage.error('文件上传失败'); }; </script>
language-java 1 2 3 4 5 6 7 8 9 10 11 12 @RestController public class FileUploadController { @PostMapping("/upload") public String handleFileUpload( @RequestParam("file") MultipartFile file, @RequestParam("userId") String userId, @RequestParam("description") String description) { return "文件上传成功,用户ID: " + userId + ",描述: " + description; } }
(二)Cookies s aultValue`指定的默认值 “”会被使用。