☰
SpringBoot接口参数接收全解析:从GET/POST到注解原理与实战排错
2026/10/13 11:24:03 网站建设 项目流程

同事跑过来问:"我Postman里测得好好的,参数也都传了,怎么一到前端页面就收不到?" 这种场景我遇到不止一次。做SpringBoot接口开发的人,多半都在Get请求和POST请求的接收参数上踩过类似的坑。其实大部分参数接收问题,根源不在代码写错,而是没搞清楚SpringBoot在背后是怎么把这些参数从HTTP报文里"抠"出来的。

这篇就把Get请求和POST请求接收参数的完整链路和工作原理讲明白,从最基础的注解用法到进阶的对象绑定、文件上传、日期转换,再附上我实际排查过的高频问题。无论你是刚接触SpringBoot的新手,还是准备面试想系统梳理一遍的开发者,这篇文章都能直接帮上忙。

1. 请求参数接收的底层链路:从HTTP报文到Controller参数的映射过程

说句实话,我见过不少开发者用@RequestParam、@RequestBody用得飞起,但一旦遇到参数回收不到、报415、出现乱码这类问题,就开始对着代码瞎猜。这样排查效率极低。想把这部分彻底吃透,得从报文结构看起——你只有知道参数"来的时候"长什么样,才能理解SpringBoot"接的时候"在做什么。

1.1 参数到底藏在哪里:HTTP报文结构复习

一个HTTP请求分三部分:请求行、请求头、请求体。

  • 请求行里有请求方法和URL,例如GET /api/user/query?userId=1001&nickName=老张 HTTP/1.1。
  • 请求头里包含Content-Type、Accept、Authorization等元信息。
  • 请求体是POST/PUT这类方法携带的正文数据,GET一般没有请求体。

在此之前,先说结论:Get请求的参数默认放在URL的查询字符串(query string)里,例如?page=1&size=10;POST请求的参数通常放在请求体(body)里,但也不是必须,POST的URL上同样可以带查询参数。这就引出了SpringBoot接收参数时的第一层逻辑:你写的Controller方法声明了什么注解,Spring就在对应位置去找参数。

实际的格式取决于请求头的Content-Type。同一个参数"userId=1001",在表单格式下是application/x-www-form-urlencoded,POST请求体里是一串userId=1001&nickName=老张;在JSON格式下是application/json,请求体是{"userId":1001,"nickName":"老张"}。这两种携带方式,对应的接收注解完全不同。

1.2 DispatcherServlet如何把参数"塞"进方法签名

SpringBoot的Web层底层是SpringMVC,核心入口是DispatcherServlet。当一个请求到达时,它的处理链路大致是:

DispatcherServlet -> HandlerMapping(找到对应的Controller方法) -> HandlerAdapter(执行方法前先解析参数) -> HandlerMethodArgumentResolver(参数解析器) -> 业务方法执行 -> 返回结果渲染

关键在于HandlerMethodArgumentResolver。SpringBoot内置了几十个参数解析器,每个解析器负责处理特定的注解场景:

  • RequestParamMethodArgumentResolver:处理@RequestParam注解,以及简单类型的普通参数。
  • PathVariableMethodArgumentResolver:处理@PathVariable注解,从URL路径模板中取值。
  • RequestResponseBodyMethodProcessor:处理@RequestBody注解,通过HttpMessageConverter把请求体反序列化成对象。
  • ServletModelAttributeMethodProcessor:处理对象绑定,把请求参数按字段名映射到POJO属性上。

SpringBoot启动的时候,这些解析器会被注册到HandlerAdapter里。请求来了之后,它遍历解析器,看哪个支持当前方法参数上的注解,就用哪个去解析。这也是为什么你在IntelliJ IDEA里打断点,会看到执行链路过InvocableHandlerMethod.getMethodArgumentValues——这就是参数解析的必经之路。

1.3 排查参数问题前先养成的习惯:看请求头

参数接收出问题,九成是Content-Type和接收方式不匹配。我个人的排查三步走是:

  1. 打开浏览器开发者工具或Postman,看请求头的Content-Type。
  2. 看请求体或URL里携带参数的实际格式。
  3. 再回头检查Controller注解用的是哪个。

如果请求头发的是application/json,Controller却用@RequestParam接收,结果必然是参数为null;反过来,如果发的是form格式,Controller用@RequestBody接收,轻则拿到一个空对象,重则直接415。

这里顺带说一个最常用的对照表,刚入门的同学可以直接保存:

前端携带方式Content-Type后端推荐接收方式
URL查询参数无 / 任意@RequestParam、对象绑定
URL路径参数无@PathVariable
表单提交application/x-www-form-urlencoded@RequestParam、对象绑定
JSON报文application/json@RequestBody+ DTO
文件上传multipart/form-data@RequestParam("file") MultipartFile

记住这张表,参数接收的基本盘就在手里了。

2. GET请求的三板斧:@RequestParam、@PathVariable与对象绑定

GET请求本身语义是"获取数据"。它的参数都挂在URL上,而URL又是明文且会进日志的,所以敏感数据不要用GET传,这是后话。在SpringBoot里,GET请求的接收方式基本有三种,我按使用频次和适用场景逐一拆解。

2.1 @RequestParam处理URL查询参数:基础与required/defaultValue

@RequestParam是GET请求最常见的接收方式,专门对应URL上的?key=value查询参数。最基础的写法:

@RestController @RequestMapping("/api/user") public class UserController { @GetMapping("/query") public String query(@RequestParam("userId") Long userId, @RequestParam(value = "nickName", required = false) String nickName) { return "userId=" + userId + ", nickName=" + nickName; } }

请求GET /api/user/query?userId=1001&nickName=laozhang,Spring就会把userId自动转成Long,nickName转成String。

这里的几个细节需要特别留意。

第一,required属性默认是true。如果请求里没带userId,Spring会直接抛出MissingServletRequestParameterException,接口返回400。这也是前后端联调时常见的"我没传这个字段,后端就报400"的原因。如果你希望某些参数可带可不带,要么设置required = false,要么用defaultValue给个兜底值:

@GetMapping("/query") public String query(@RequestParam(value = "page", defaultValue = "1") Integer page) { return "page=" + page; }

注意,设置了defaultValue之后,required就自动失去意义了——有默认值意味着参数本身就是可选的。

第二,参数名可以显式指定。@RequestParam("userId")里的userId是HTTP请求里的参数名,跟方法参数名无关。如果不写这个value,SpringBoot默认会按方法参数名去匹配。这里有个隐含前提:编译时必须保留参数名信息。SpringBoot项目使用spring-boot-starter-parent作为父工程时,Maven默认开了-parameters编译参数,所以你省略value时通常没问题。如果你自己搭了个没有继承Starter Parent的Maven工程,编译时参数名可能被编译器丢掉,注解里的value最好是显式写出来,省得踩坑。

第三,类型转换失败会返回400。比如接口声明Integer page,前端传了page=abc,Spring的ConversionService转不动,就会抛MethodArgumentTypeMismatchException。这种问题在日志里很好认,看到"Cannot convert value of type 'java.lang.String' to required type 'java.lang.Integer'"就明白了。

2.2 @PathVariable实现RESTful路径传参:什么时候用它

RESTful风格的接口经常把资源ID放在URL路径里,例如/api/user/1001,而不是/api/user?id=1001。这种场景就该用@PathVariable:

@GetMapping("/detail/{id}") public String detail(@PathVariable Long id) { return "id=" + id; }

请求GET /api/user/detail/1001时,id就会自动被填充为1001L。

@PathVariable和@RequestParam都是为了从URL取参数,但语义完全不同。@PathVariable取的是路径模板中的变量值,@RequestParam取的是问号后面的查询参数。在设计接口时要有意识地使用:路径变量对应"资源定位"(我要查某个用户),查询参数对应"筛选条件"(我要查某一页用户)。比如"查询ID为1001的用户资料"用/api/user/1001更合理,"分页查用户列表"用/api/user?page=1&size=10更合理。

路径变量还支持正则约束,限定参数格式,比如:

@GetMapping("/detail/{id:[0-9]+}") public String detail(@PathVariable Long id) { return "id=" + id; }

这样/api/user/detail/abc会直接匹配不到接口,返回404而不是类型转换异常。对于强调接口严谨性的项目,这个技巧很实用。

2.3 多个查询参数的对象绑定:参数多了之后的最优解

当GET请求的查询参数超过三四个,还在Controller方法里一个个写@RequestParam,代码就会非常啰嗦。更好的方式是定义一个查询对象,让Spring自动按字段名绑定:

public class UserQuery { private String nickName; private Integer page; private Integer size; // getter/setter 省略 } @GetMapping("/list") public String list(UserQuery query) { return query.getNickName() + " - " + query.getPage() + " - " + query.getSize(); }

请求GET /api/user/list?nickName=laozhang&page=1&size=10,Spring会调用UserQuery属性的setter方法,把参数逐一对齐。这里有一个非常有用的特性:Spring的属性绑定是递归的,支持嵌套对象。比如:

public class PageQuery { private UserCondition condition; private Integer page; } public class UserCondition { private String nickName; }

前端配合传参condition.nickName=laozhang&page=1,后端PageQuery里的condition.nickName就能正确赋值。这种写法在做多条件组合查询时特别顺手,Query对象可以直接复用,配合MyBatis的查询条件类使用非常丝滑。

2.4 GET请求中的数组与集合参数

GET请求还有一种高频场景:多选参数。前端想传多个tag值,有两种常见写法:

/api/user/tags?tag=java&tag=spring /api/user/tags?tag=java,spring

第一种写法,后端可以直接用数组或List接收:

@GetMapping("/tags") public String tags(@RequestParam("tag") List<String> tag) { return tag.toString(); }

第二种逗号分隔的写法,稍微麻烦一点。Spring默认不会自动按逗号拆成List,如果坚持用List<String>接收,收到的会是一个包含完整字符串"java,spring"的单元素List。这种情况下要么前端拆好再传,要么后端自己处理String参数再split,我在项目里通常建议前端规范为多值写法tag=java&tag=spring,这也是URL参数的标准多值语义。

3. POST请求的三类Content-Type与@RequestBody的边界

POST请求的场景比GET丰富得多,因为它的参数可以放在body里,而body又分好几种格式。很多人搞不清楚@RequestParam和@RequestBody的边界,根源就是没弄明白POST请求体的Content-Type。这一节把三类常见格式一次讲透。

3.1 application/x-www-form-urlencoded与@RequestParam

application/x-www-form-urlencoded是HTML表单的原生提交格式,请求体长这样:

username=laozhang&password=123456

和URL查询参数的编码格式完全一致,只是位置从URL挪到了body里。SpringBoot接收这类POST请求,用的依然是@RequestParam:

@PostMapping("/form") public String form(@RequestParam String username, @RequestParam String password) { return "username=" + username + ", password=" + password; }

你可能好奇:为什么@RequestParam既能接GET的URL参数,又能接POST的表单参数?因为Servlet容器的HttpServletRequest.getParameter()方法本身就把这两类统一了——它既会解析URL query string,也会解析application/x-www-form-urlencoded格式的body。SpringMVC的@RequestParam底层调用的就是这个getParameter(),所以你用一个注解吃遍这两种场景。

3.2 application/json与@RequestBody反序列化

前后端分离的项目里,POST请求的默认格式早就变成JSON了。请求体长这样:

{ "username": "laozhang", "password": "123456" }

此时getParameter()从请求体里什么都读不到,必须用@RequestBody让Spring把整个body反序列化成Java对象:

public class LoginDTO { private String username; private String password; // getter/setter 省略 } @PostMapping("/json") public String json(@RequestBody LoginDTO dto) { return "json: " + dto.getUsername() + " - " + dto.getPassword(); }

@RequestBody背后的机制是HttpMessageConverter,SpringBoot集成了Jackson,核心逻辑就是ObjectMapper.readValue(body, LoginDTO.class)。因此JSON的字段名和Java类的属性名必须对应上。如果前端传的是user_name这种下划线风格,后端属性是userName,可以给字段加@JsonProperty("user_name")显式指定映射。

使用@RequestBody时有几个点容易踩雷,我逐一说明。

第一,必须保证请求头Content-Type是application/json(或application/*+json)。否则Spring找不到合适的HttpMessageConverter,直接返回415 Unsupported Media Type。这是新手上路最常见的报错,没有之一。

第二,请求体为空或格式错误时,会抛HttpMessageNotReadableException。比如前端传了个空body或者JSON少了个括号,后端一接收就崩。建议在全局异常处理器里统一捕获这个异常,返回给前端一个友好的提示。

第三,JSON里的未知字段默认不会报错。SpringBoot的Jackson自动配置默认关闭了FAIL_ON_UNKNOWN_PROPERTIES,前端多传了字段,后端不会炸。如果你希望严格校验,可以在配置文件里改回来:

spring.jackson.deserialization.fail-on-unknown-properties=true

但说实话,在迭代快的业务项目里,我一般不建议开,否则前端加个字段后端就得跟着兼容,反而拖慢联调速度。

3.3 multipart/form-data与MultipartFile文件参数

文件上传场景用的是multipart/form-data格式,和普通表单最大的区别是:body会被按boundary切分成多个Part,每个Part既可以是普通字段,也可以是文件。后端接收文件的标准姿势:

@PostMapping("/upload") public String upload(@RequestParam("file") MultipartFile file, @RequestParam String description) { return "fileName=" + file.getOriginalFilename() + ", size=" + file.getSize() + ", description=" + description; }

支持多个文件的话,用数组接:

@PostMapping("/uploadBatch") public String uploadBatch(@RequestParam("files") MultipartFile[] files) { return "files=" + files.length; }

MultipartFile对象封装了文件流、文件名、大小等信息,拿到之后可以调用transferTo(File dest)落盘,或者getInputStream()流传给其他组件处理。

文件上传的坑通常不在接收方式,而在大小限制。SpringBoot默认max-file-size是1MB,max-request-size是10MB。超过限制会抛MaxUploadSizeExceededException,前端收到的就是500。实际项目基本都要调大,配置如下:

spring.servlet.multipart.max-file-size=50MB spring.servlet.multipart.max-request-size=100MB

注意SpringBoot 2.x是用spring.servlet.multipart前缀,SpringBoot 3.x也是一样的结构,别和老的spring.http.multipart搞混。

3.4 GET与POST的本质区别:为什么Postman能调通而浏览器不行

有个问题面试经常考:GET和POST都能在URL上带参数,为什么POST还专门把参数放body里?其实规范层面并没有强制规定"GET不能带body、POST必须有body",HTTP协议只定义了语义。但实际工程里大家默认遵守:GET侧重读取,参数在URL;POST侧重提交,参数在body。

浏览器环境里尤其明显。fetch或XMLHttpRequest规范明确禁止GET请求携带body——就算你写了,浏览器也会忽略或者直接报错。这导致一个经典联调事故:后端用@RequestBody接收,Postman里GET也能测通(Postman允许GET带body),一上浏览器前端页面就废。所以我遇到后端接口用GET+@RequestBody的设计,都会提醒一句:趁早改成POST,否则必然有浏览器环境调不通的一天。

4. 数组、List、嵌套对象与日期参数:进阶接收姿势

基础篇讲完之后,进阶篇要处理的是那些"看起来简单、上手就出错"的参数类型:数组、集合、嵌套对象、日期时间、枚举。这些场景的复杂性不在注解本身,而在于类型转换的细节。

4.1 数组与列表在多值场景下的完整接收方式

前面提到GET请求可以用?tag=java&tag=spring配合List<String>接收。这个能力对POST同样适用:

  • POST + form格式:tag=java&tag=spring,用@RequestParam("tag") List<String>接收。
  • POST + JSON格式:{"tags":["java","spring"]},用@RequestBody+DTO里声明List<String> tags接收。

还有一类特殊场景:前端在form格式下用索引方式传List:

users[0].name=laozhang&users[0].age=18&users[1].name=wangwu&users[1].age=20

这种格式Spring的ServletModelAttributeMethodProcessor也能绑定,但需要后端对象这样定义:

public class BatchUserForm { private List<UserItem> users; } public class UserItem { private String name; private Integer age; }

这个方法在兼容老前端系统时偶尔能救命,但新项目我强烈建议直接走JSON,可读性和可维护性都高得多。

4.2 嵌套对象的query参数与JSON映射

嵌套对象在GET和POST里的表现方式不同,但原理相通,都是Spring的DataBinder在做JavaBean属性绑定。

GET场景,前端传参:

condition.nickName=laozhang&page=1

后端用之前定义过的PageQuery接收,属性路径上的点号就是嵌套层级的映射。

POST JSON场景更常见。比如创建订单,DTO里嵌套了用户信息和地址信息:

public class OrderCreateDTO { private String orderNo; private UserInfo user; private AddressInfo address; }

前端直接传嵌套JSON:

{ "orderNo": "NO20250101", "user": { "userId": 1001, "phone": "13800000000" }, "address": { "province": "Zhejiang", "city": "Hangzhou" } }

后端@RequestBody OrderCreateDTO就能完整反序列化。这里唯一要小心的还是命名策略:如果全局配置了spring.jackson.property-naming-strategy=SNAKE_CASE,那么JSON里的order_no会映射到Java的orderNo字段,但嵌套对象同样受此约束,必须统一风格。

4.3 日期时间参数的类型转换:@DateTimeFormat与@JsonFormat

日期参数是类型转换里的重灾区。前端字符串传日期,后端到底怎么接,取决于请求格式。

表单或URL场景:用@DateTimeFormat指定解析格式。

@GetMapping("/search") public String search(@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime) { return startTime.toString(); }

请求/api/order/search?startTime=2025-01-01 12:00:00,Spring的ConversionService会按指定pattern解析。如果不加这个注解,Spring默认按ISO格式解析,即2025-01-01T12:00:00这种带T的格式,前端按yyyy-MM-dd HH:mm:ss传就直接400。

JSON场景:要用Jackson的@JsonFormat,因为它管的是反序列化,和Spring的DataBinder无关:

public class TimeDTO { @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime createTime; }

顺便说一句,Java 8的LocalDateTime能够被Jackson直接序列化,依赖的是jackson-datatype-jsr310,SpringBoot的自动配置已经把模块注册进去了,所以不用额外处理。真正要关注的是全局时间格式统一:与其在每个DTO字段上都堆@JsonFormat,不如在配置文件里设置全局策略:

spring.jackson.date-format=yyyy-MM-dd HH:mm:ss spring.jackson.time-zone=GMT+8

但要注意,spring.jackson.date-format只对java.util.Date生效,对LocalDateTime并不生效。LocalDateTime要全局格式化,得自定义Jackson2ObjectMapperBuilderCustomizer,或者退回逐字段@JsonFormat。这是个非常容易踩的暗坑,我建议读者自行评估项目里是否大量使用LocalDateTime,如果用了,就统一封装一个全局配置,别靠人肉在每个字段上加注解。

4.4 枚举、布尔与自定义类型转换器

枚举参数在接收时有个常见的误解:以为@RequestParam和@RequestBody在枚举上的处理逻辑一样。其实不一样。

  • @RequestParam接收枚举:Spring通过ConversionService调用Enum.valueOf(),按枚举的name()匹配。所以前端传的字符串必须是枚举名,比如Status.ENABLE对应"ENABLE"。注意大小写敏感。
  • @RequestBody接收枚举:Jackson的枚举反序列化器默认也是按name()匹配,同样大小写敏感。

如果前端非要传enable(小写),后端枚举类是ENABLE,怎么办?方案有两个:一是给枚举加@JsonCreator自定义反序列化工厂;二是在枚举上使用@JsonValue指定对外口径。这块也是Jackson的使用细节,面试考到枚举反序列化情景时,能答出@JsonCreator的用法会是很加分的点。

布尔类型的接收相对简单:Spring的StringToBooleanConverter支持true/false/on/off/yes/no/1/0,前端传"1"也能正确转成true。不过建议前后端还是统一用true/false,可读性最强。

5. 参数接收排查实录:实测中遇到的五类典型问题

理论讲完,来看实际遇到过的五类问题。每类我都保留真实的排查思路,目的是让你下次遇到同类情况时能沿着链路快速定位,而不是瞎试。

5.1 Content-Type不匹配导致415或参数全空

现象:前端说"我明明传了参数,后端收到的全是null",或者后端日志报415。

前端代码:

axios.post('/api/user/json', { username: 'laozhang', password: '123456' })

后端代码:

@PostMapping("/json") public String json(@RequestParam String username, @RequestParam String password) { ... }

Axios发送对象时默认Content-Type是application/json,参数在body里是JSON字符串;后端用@RequestParam,它从getParameter()里取值,JSON body对它是不可见的,自然全null。

正确做法:要么后端改成@RequestBody LoginDTO,要么前端用URLSearchParams或qs库把参数序列化成form格式。排查这类问题的核心就是在浏览器开发者工具里看一眼Content-Type和请求体结构,只要这两项和后端注解对上,99%的问题当场解决。

5.2 GET中文乱码:历史遗留与解决

现象:GET请求URL里带中文参数,后端接收后出现乱码。

本质是URL编码问题。Tomcat对URI的默认编码在8.5+版本是UTF-8,SpringBoot内嵌的Tomcat一般没这个问题。但如果你部署到了外部Tomcat,或者项目里有过旧配置,就可能出现:

server.tomcat.uri-encoding=ISO-8859-1

这种配置下,前端URL里的中文会被按ISO-8859-1解码,后端看到的就是乱码。解决方式就是删掉这种配置,或显式设置:

server.tomcat.uri-encoding=UTF-8

另一个容易忽视的点是路径变量的中文。/api/user/detail/张三这种,浏览器会自动编码,但某些客户端不编码,后端@PathVariable String name拿到的是原始URL编码串。处理方式是在前端统一使用encodeURIComponent编码路径参数,后端按规范解析即可。

5.3 过滤器读取请求体后Controller拿不到参数的经典翻车

这是一个我实际排查了大半天才定位的问题。项目里为了做XSS防护,加了一个全局过滤器,要读取POST请求体里的JSON做校验。结果过滤器一加上,所有@RequestBody接口全部拿到空对象,没有任何报错。

原因很简单:ServletInputStream只能被读取一次。过滤器先调用了getInputStream()把body读完了,等请求走到Controller,Spring再想读body时已经读不到了。

解决方案是包装请求对象。自己写一个RequestWrapper,在过滤器里先把body字节全部读出来缓存到内存,然后包装后的getInputStream()每次返回一个新的ByteArrayInputStream,这样Controller被调用的那一次依然能读到完整body。Spring也内置了ContentCachingRequestWrapper,但它有个细节:它只缓存被实际读取过的内容,必须手动先读一遍流才能把内容装进去。我在项目里嫌它不够直观,就一直用自封装的方式。这类问题的高发场景除了XSS过滤,还有接口日志记录过滤器、痕迹审计过滤器,凡是"先读body再做额外处理"的组件,都要留意流的可重读性。

5.4 Controller单例陷阱:并发压力下参数串值

有次压测,用JMeter模拟十个并发POST请求,每个请求带了不同的参数,结果接口打印出来的参数值出现了串值现象。起初以为是Mock数据的问题,最后定位到Controller里写了这样一段代码:

@RestController public class UserController { private String tempName; @PostMapping("/save") public String save(@RequestParam String name) { this.tempName = name; // 业务处理用了 tempName } }

问题一目了然:SpringMVC的Controller默认是单例的,多个请求共用同一个Controller实例,tempName这种实例字段就是共享变量,并发下必然出现互相覆盖。

参数接收这类无状态操作,原则是:用方法参数传递数据,绝不把请求值挂到Controller的成员变量上。JMeter并发测试发现"参数串了",第一反应先看是不是有人写了共享状态,而不是怀疑并发工具的问题。

5.5 前后端联调参数对不上的定位方法

最后分享一套前后端联调时快速对齐参数的步骤,这套流程让我少吵了很多架:

  1. 让前端在浏览器控制台或抓包工具里复制出完整的curl命令给我。
  2. 我在本地或测试环境直接执行这条curl,如果接口正常,说明后端逻辑没问题,问题定位在前端请求构造环节。
  3. 如果curl复现了问题,把curl里的Content-Type、参数位置和Controller注解逐项对比。

很多联调争议其实就差这一步:与其互相猜"你到底传没传",不如用一条curl把请求原原本本摆到桌面上。这个方法特别适合排查"Postman能调通、前端不行"的疑难杂症,因为curl就是最透明的HTTP请求载体,谁能调通、谁不能调通,一跑便知。


参数接收在SpringBoot里看似是个入门话题,但它串联了HTTP协议、Servlet规范、SpringMVC参数解析器和Jackson反序列化一整条链路。我个人的心得是:遇到接收不到参数的时候,先看请求头,再看请求体格式,最后才看代码;写接口的时候,先想清楚参数会以什么格式过来,再决定用@RequestParam还是@RequestBody。这套思路理顺之后,你在SpringBoot里的接口开发效率会提升一大截,排查问题的速度也会比闷头改代码快得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询