草庐IT

SpringBoot接收参数的几种常用方式

怪 咖@ 2023-09-09 原文

目录

如果对@RequestMapping不是特别了解的,建议读一下这篇文章: https://blog.csdn.net/weixin_43888891/article/details/126861310

参数映射准确来说是springmvc来帮我们干的活,但是由于springboot太过火爆,简化了springmvc相关配置文件,以至于很多人会误认为是springboot的功能。其实springboot是帮我们整合了spring相关框架。记住只是简化,底层还是不变的!

一、四种传参方式

在学习接收参数前,肯定要先了解一共有几种传参方式,下面一共提供了四种,供参考学习:

1)params传参,params传参的格式是http://xxx?参数名=值&参数名=值。在postman当中params当中添加参数会发现,他就是在地址栏上加的参数。

2)body表单传参,就是请求体传参

form-data的请求是在body中,为key=value格式,同时可以传文件,Content-Type为multipart/form-data,后端可以用@RequestParam接收。

3)json传参

json传参也是在body当中,只不过json是一种数据格式,后端可以用@RequestBody接收。

4)地址栏传参,直接通过/在地址上拼接参数值,这种方式不需要在地址栏上写参数名,后端只需要知道他在地址的哪个位置传的参数就可以拿到值!

这两个实体类用来当做测试类,用来接参数,后续我们会不断的使用到他:

public class Params {
    private String userName;
    private Integer age;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Param{" +
                "userName='" + userName + '\'' +
                ", age=" + age +
                '}';
    }
}
public class User {
    private String userName;

    @Override
    public String toString() {
        return "User{" +
                "userName='" + userName + '\'' +
                '}';
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }
}

二、无注解

import com.gzl.cn.demo.entity.Params;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/noAnno")
public class NoAnnoController {

    @GetMapping("/url")
    public String getMapping(String msg) {
        return msg;
    }
	
	// 可以有多个实体类参数
    @GetMapping("/body")
    public String getMapping(Params param,User user) {
    	System.out.println(param);
        System.out.println(user);
        return param.toString();
    }

    @PostMapping("/post")
    public String postMapping(String msg) {
        return msg;
    }

    @PostMapping("/post-body")
    public String postMapping(Params msg) {
        return msg.toString();
    }

}

以下是测试的详细步骤:

(1)测试无注解params传参

测试:get请求:

http://localhost:8080/noAnno/url?msg=111
http://localhost:8080/noAnno/body?userName=张三&age=11

测试:post请求:post请求我们无法通过浏览器来访问,得需要借助postman调用

http://localhost:8080/noAnno/post?msg=111
http://localhost:8080/noAnno/post-body?userName=张三&age=22

当然也可以借用cmd框当中的curl命令来请求post
curl http://localhost:8080/noAnno/post-body -X POST -d "userName=66&age=22"

(2)测试无注解body表单传参

(3)测试无注解params传参+body表单传参 两种同时传参

总结:

  1. 没有注解的时候可以选择params传参也可以选择body表单传参,甚至可以两种同时传,两种同时传会将body传的参数使用逗号拼接上params传的参数
  2. 不管是body还是params 在不传参的情况下都不会报错,在后端会拿到null值,这块需要注意一下!假如是null值的情况下去get属性,或者是tostring就会空指针!如果传参的话,参数名要和controller当中定义的变量名一样才能接受到参数!任意请求方式 都是一样的!
  3. 可以有多个参数的,如果是实体类接参数的话,也是可以有多个实体类的!就算两个实体类当中有参数重复了,也不影响,两个实体类都会接到参数的!

三、@RequestParam

http://localhost:8089/conformity/parm/requestParm8?uid=1&uname=222&pwd=2222

就是在地址?然后加上&拼接。

不携带@RequestParm的时候,可以连key值都不传。

@GetMapping("/requestParm")
public void requestParm(Integer id){
	System.out.println("get不带@RequestParam:"+id);
}

携带@RequestParm的时候,必须传值。因为@RequestParam注解的required默认是true。假如不传会报错。

@GetMapping("/requestParm1")
public void requestParm1(@RequestParam Integer id){
	System.out.println("get带@RequestParam:"+id);
}
  • @RequestParam接收参数,不可使用使用实体来封装,如下所示,直接会报400错误。
  • 不带@RequstParm然后使用实体来接参数,其实是没问题的,并且不传key值也是可以的。post、get都一样。
// 错误的
@PostMapping("/requestParm7")
public void requestParm7(@RequestParam User user){
	System.out.println("get带@RequestParam:"+user);
}

@RequestParam参数映射:注意@RequestParam默认是以变量名作为前端传参名称,但是假如我们注解设置了名称,如下,那么参数名称以注解当中的属性为准!假如前端传msg而不是msg1就会报异常。

@GetMapping("/url")
public String getMapping(@RequestParam("msg1") String msg) {
    System.out.println(msg);
    System.out.println(aaa);
    return msg;
}

总结:

1、传单个参数的时候可以使用@RequestParam,不带也可以,带上就意味着前端必须传这个值。

2、实体接受参数的话,不可以带,带上就会报错。不带的话是可以接受多个参数的。并且没有key限制。

@RequestParam的属性

  • valuename属性使用了@AliasFor,在spring当中起着一个注解属性别名传递值的作用。也就是我给value属性赋值,name属性同样也能取到值,name属性赋值,value属性也同样可以取到值。
    @RequestParam(value = "msg")等同于@RequestParam("msg"),因为注解当中不带属性名称默认指的就是value属性,而@RequestParam("msg")等同于@RequestParam(name = "msg")
  • required属性代表的是否是必填,默认是true,这个true代表的是前端必须传key值,value值可以随意,但是key值是必须的。假如不传就是400异常!
  • defaultValue属性:设置默认值,可以避免required属性设置为true然后前端不传key值报错的问题。相当于设置defaultValue属性之后,前端传不传值都可以,传值就以前端的为准,不传值就以设置的defaultValue值为准!示例如下:
    @RequestParam(name = "pageNo",required = false,defaultValue = "1") Integer pageNo
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {

	@AliasFor("name")
	String value() default "";

	@AliasFor("value")
	String name() default "";

	boolean required() default true;

	String defaultValue() default ValueConstants.DEFAULT_NONE;
}

四、@PathVariable

@PathVariable 用于绑定 url 中的占位符。例如:请求 url 中 /delete/{id},这个{id}就是 url 占位符。url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。

@RequestMapping("/pathVariable2/{id}")
public void pathVariable2(@PathVariable Integer id){
	System.out.println("get带@RequestParam:"+id);
}

上面代码示例使用了地址栏传参,就算不带@PathVariable也可以访问,只不过接不到值。

@PathVariable 的属性

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PathVariable {

	@AliasFor("name")
	String value() default "";

	@AliasFor("value")
	String name() default "";

	boolean required() default true;

}

总结:

  • 如果@PathVariable不设置属性值,默认的话,只要参数名称和占位符当中的名称一致就可以,如果名称不一致就会报错
  • 一旦设置属性值了,就一定要和占位符当中的一致,否则就会报错!

五、@RequestBody

@RequestBody一般被用来接收http请求中body中json数据。

get、post都可以使用。一般用于post。

@RequestMapping("/requestBody2")
public void requestBody2(@RequestBody Params params){
    System.out.println("get带@RequestParam:"+params);
}

{"userName":"111","age":"11"},传输json数据,也可以不传key。这里有一点需要注意,mvc给我们做了参数类型转换,Params 对象当中的age是Integer类型,但是json传字符串,照样可以映射进去。Boolean、BigDecimal、Integer、String、Date这些其实都可以映射进去的。当然Date相对来说比较特殊一点。传yyyy-MM-dd格式是不会报错的。但是其他格式可能就会报错了,一般使用Date类型接参数涉及到需要咱们自己格式化,关于日期相关问题感兴趣的可以看这一篇文章:https://blog.csdn.net/weixin_43888891/article/details/126846791

@RequestBody 的属性

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestBody {

	boolean required() default true;

}
  • required默认为true,代表的就是json不能什么都不传,否则报错400,但是允许个别属性不传。
  • 设置为false的话就是可以什么都不传。

六、@RequestHeader

@RequestHeader主要用来获取请求当中的请求头

@RestController
@RequestMapping("/requestHeader")
public class RequestHeaderController {
    
    @PostMapping("/header")
    public String getMapping(@RequestHeader("param")String param){
        return param;
    }
}

我们通过header进行参数传递,同样它可以设置是否必传,默认值等,请大家自行翻阅源码,就不一一罗列了。

七、HttpServletRequest

这是直接拿到request对象,通过request可以从对象中灵活的获取参数:

@RestController
@RequestMapping("/request")
public class HttpServletRequestController {

    @GetMapping("/getUrlValue")
    public String getUrlValue(HttpServletRequest request) {
        // 没有的时候不会报错,直接为null
        String msg = request.getParameter("msg");
        System.out.println(msg);
        return msg;
    }

    @GetMapping("/getUrlValues")
    public String getHttpServletRequestValue(HttpServletRequest request) {
        Map<String, String[]> parameterMap = request.getParameterMap();
        return JSONObject.toJSONString(request.getParameterMap());;
    }
}

针对于request.getParameter("msg");,其实就是跟@RequestParam差不多,可以获取到body当中的for-data的数据以及使用url ?拼接的参数的数据

http://localhost:8080/request/getUrlValue

有关SpringBoot接收参数的几种常用方式的更多相关文章

  1. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  2. ruby - 如何以所有可能的方式将字符串拆分为长度最多为 3 的连续子字符串? - 2

    我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123

  3. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  4. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  5. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

  6. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

    我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

  7. ruby - 检查方法参数的类型 - 2

    我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

  8. ruby-on-rails - 在默认方法参数中使用 .reverse_merge 或 .merge - 2

    两者都可以defsetup(options={})options.reverse_merge:size=>25,:velocity=>10end和defsetup(options={}){:size=>25,:velocity=>10}.merge(options)end在方法的参数中分配默认值。问题是:哪个更好?您更愿意使用哪一个?在性能、代码可读性或其他方面有什么不同吗?编辑:我无意中添加了bang(!)...并不是要询问nobang方法与bang方法之间的区别 最佳答案 我倾向于使用reverse_merge方法:option

  9. ruby - 定义方法参数的条件 - 2

    我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano

  10. ruby-on-rails - RSpec:避免使用允许接收的任何实例 - 2

    我正在处理旧代码的一部分。beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)endRubocop错误如下:Avoidstubbingusing'allow_any_instance_of'我读到了RuboCop::RSpec:AnyInstance我试着像下面那样改变它。由此beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)end对此:let(:sport_

随机推荐