天天看点

Spring MVC参数传递各种方式汇总@RequestParam @RequestBody时间参数等一、基本数据类型二、普通对象三、数组四、集合List五、对象+List同时接收六、时间参数传递

一、基本数据类型

@RequestParam

注解定义

@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 "\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n";
}
           

关于@AliasFor注解说明:标识2个属性作用一致

在Spring的众多注解中,经常会发现很多注解的不同属性起着相同的作用,比如@RequestParam

的value属性和name属性,这就需要做一些基本的限制,比如value和path的值不能冲突,比如任意设置value或者设置path属性的值,都能够通过另一个属性来获取值等等。为了统一处理这些情况,Spring创建了@AliasFor标签。

@RequestMapping注解中也有应用。

注解使用示例

后台代码:

@RequestMapping("demo")
public String demo(Model model
    // 走默认装配规则,参数名称和名字一致,选传
    ,String name
     // 参数名称和名字默认一直,必传参数,不传报错
    ,@RequestParam String name0
    // 通过value属性定义名称,必传参数,不传报错
    ,@RequestParam(value = "name1") String name1
     // 通过name属性定义,非必传参数
    ,@RequestParam(name = "name2",required = false) String name2
     // 通过value属性定义,必传参数,有默认值,可以不传自动赋值
    ,@RequestParam(value = "name3",defaultValue = "t3") String name3
    // 自定义参数名字,不必加name或者value属性,必传
    ,@RequestParam("name444") String name4
){
    System.out.println("name:"+name);
    System.out.println("name0:"+name0);
    System.out.println("name1:"+name1);
    System.out.println("name2:"+name2);
    System.out.println("name3:"+name3);
    System.out.println("name4:"+name4);
    return "hello";
}
           

请求连接:

/demo?name=t&name0=t0&name1=t1&name2=t2&name444=t44
           

控制台输出:

name:t
name0:t0
name1:t1
name2:t2
name3:t3
name4:t44
           

必传参数name1,不传会报400错误,如下:

Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Tue Apr 13 11:16:17 CST 2021
There was an unexpected error (type=Bad Request, status=400).
Required String parameter 'name1' is not present
org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'name1' is not present
	at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:202)
	at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:113)
	at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:126)
	at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:166)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895
           

@PathVariable

注:和@RequestParam注解使用相同的地方简述

注解定义,注释同上

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PathVariable {
    @AliasFor("name")
    String value() default "";

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

    boolean required() default true;
}
           

注解使用示例

后台代码:

@RequestMapping(value={
        "demo1/{name1}/{name2}/{name3}"
        // 配合name3选传,此种场景应用较少,一般使用此注解均为必传参数
        ,"demo1/{name1}/{name2}"
})
public String demo1(Model model
        //注意,没加注解,使用问号后追加参数请求
        ,String name
        // 必传
        ,@PathVariable String name1
        // 必传
        ,@PathVariable("name2") String name2
        // 选传
        ,@PathVariable(value = "name3",required = false) String name3
){
    System.out.println("name:"+name);
    System.out.println("name1:"+name1);
    System.out.println("name2:"+name2);
    System.out.println("name3:"+name3);
    return "hello";
}
           

请求连接:

/demo1/t1/t2?name=t0
/demo1/t1/t2/t3
/demo1/t1  ===> 404地址找不到
           

控制台输出:

name:t0
name1:t1
name2:t2
name3:null
===============================
name:null
name1:t1
name2:t2
name3:t3
           

如果是使用注解@PathVariable必传的参数类型,不加参数会报404。

总结:参数传递时,可以使用@RequestParam和@PathVariable传递参数,也可以走Spring

Mvc默认的装配规则,根据实际使用场景来选择即可。

二、普通对象

非JSON请求

前台

localhost:8080/demo2?name=1&number=2
           

后台

@ResponseBody
@RequestMapping("demo2")
public Demo demo2(Demo demo){
    System.out.println("demo:"+demo);
    return demo;
}
           

JSON请求

前台

localhost:8080/demo22
===========headers==============
Content-Type:application/json
============body==============
{
    "name":"11",
    "number":"22"
}
           

后台

@ResponseBody
@PostMapping("demo22")
public Demo demo22(@RequestBody Demo demo){
    System.out.println("demo:"+demo);
    return demo;
}
           

三、数组

非JSON请求

前台

localhost:8080/demo3?ids=1&ids=2&ids=3
           

http://localhost:8080/demo3?ids=1,2,3
           

后台

@ResponseBody
@RequestMapping("demo3")
public Long[] demo3(Long[] ids){
    System.out.println("ids:"+ids.length);
    return ids;
}
           

JSON请求

前台

localhost:8080/demo33
===========headers==============
Content-Type:application/json
============body==============
[1,2,3]
           

后台

@ResponseBody
@RequestMapping("demo33")
public Long[] demo33(@RequestBody Long[] ids){
    System.out.println("ids:"+ids.length);
    return ids;
}
           

四、集合List

非JSON请求

前台

localhost:8080/demo4?idList=1&idList=2
           

http://localhost:8080/demo4?idList=1,2,3
           

后台(@RequestParam注解不可缺少)

@ResponseBody
@RequestMapping("demo4")
public List<Long> demo4(@RequestParam List<Long> idList){
    System.out.println("ids:"+idList);
    return idList;
}
           

JSON请求

前台

localhost:8080/demo5
===========headers==============
Content-Type:application/json
============body==============
[1,2,3]
           

后台

@ResponseBody
@RequestMapping("demo5")
public List<Long> demo5(@RequestBody List<Long> idList){
    System.out.println("ids:"+idList);
    return idList;
}
           

五、对象+List同时接收

非JSON请求

前台-html

<form action="/demo2" method="POST">

    name:<input type="text" name="name"/><br/>
    number:<input type="text" name="number"/><br/>

    <!-- 以下部分可以动态添加 -->
    nickname:<input type="text" name="demoCList[0].nickname"/>
    number:<input type="text" name="demoCList[0].number"/><br/>

    nickname:<input type="text" name="demoCList[1].nickname"/>
    number:<input type="text" name="demoCList[1].number"/><br/>


    nickname:<input type="text" name="demoCList[2].nickname"/>
    number:<input type="text" name="demoCList[2].number"/><br/>

    nickname:<input type="text" name="demoCList[3].nickname"/>
    number:<input type="text" name="demoCList[3].number"/><br/>
    <button type="submit">提交</button>
</form>
           

请求

http://localhost:8080/demo2
=============Form Data====================
name: 
111
number: 
111
demoCList[0].nickname: 
1
demoCList[0].number: 
11
demoCList[1].nickname: 
222
demoCList[1].number: 
22
demoCList[2].nickname: 
333
demoCList[2].number: 
333
demoCList[3].nickname: 
444
demoCList[3].number: 
44
           

后台

@ResponseBody
@RequestMapping("demo6")
public Demo demo6(Demo demo){
    System.out.println("demo:"+demo);
    return demo;
}
           

==============================================

public class Demo {

    private String name;
    private String number;
    private List<DemoC> demoCList;
    ....省略get set方法....
}
           

JSON请求

前台

l

localhost:8080/demo5
===========headers==============
Content-Type:application/json
============body==============
{
    "name":"0616",
    "number":"2",
    "demoCList":[
        {
            "id":"2",
            "nickname":"1111",
            "number":"11111"
        },
        {
            "nickname":"1111",
            "number":"11111"
        },
        {
            "nickname":"1111",
            "number":"11111"
        }
    ]
}
           

后台

@ResponseBody
@RequestMapping("demo7")
public Demo demo7(@RequestBody Demo demo){
    System.out.println("demo:"+demo);
    return demo;
}
           

六、时间参数传递

相关注解

注:时间格式参数,不加格式化注解或者全局入参出参配置,前台传递参数时会报400,后台返回时格式不是正常的时间格式

@DateTimeFormat 单个字段入参格式化(不带@RequestBody注解的参数有效)

注:添加有注解@RequestBody参数时该注解无效。

@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime logintime;


//后台时间格式化
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date logintime;
           

@JsonFormat 单个字段出参格式化

注:添加有注解@RequestBody参数时,该注解对于入参和出参同时有效。

//后台时间格式化
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private LocalDateTime logintime;

//后台时间格式化
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date logintime;
           

@DateTimeFormat 和@JsonFormat 可以使用在同一个字段上入参和出参均格式化

//后台时间格式化
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime logintime;


//后台时间格式化
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date logintime;
           

项目全局的入参格式化

@ControllerAdvice 是spring

3.2提供的新注解,它是一个controller增强器,可以对controller中使用到@RequestMapping注解的方法做逻辑处理

@InitBinder用于在控制器(Controller)中标注于方法上,表示为当前控制器注册一个属性编辑器,只对当前的Controller有效。@InitBinder标注的方法必须有一个参数WebDataBinder。webDataBinder是用于表单到方法的数据绑定的。所谓的属性编辑器可以理解就是帮助我们完成参数绑定。

Date类型

@ControllerAdvice
public class InitBinderAdviseController {
    /**
     * 将前台传递过来的日期格式的字符串,自动转化为时间类型
     */
    @InitBinder
    public void initBinder(WebDataBinder binder)
    {
        // Date 类型转换
        DateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        binder.registerCustomEditor(Date.class,new CustomDateEditor(dateFormat, true));
}
           

LocalDate/LocalDateTime

@ControllerAdvice
public class InitBinderAdviseController {
    /**
     * 将前台传递过来的日期格式的字符串,自动转化为时间类型
     */
    @InitBinder
    public void initBinder(WebDataBinder binder)
    {
        // LocalDateTime 类型转换
        binder.registerCustomEditor(LocalDateTime.class, new PropertyEditorSupport()
        {
            @Override
            public void setAsText(String text)
            {
                if(!StringUtils.isEmpty(text)){
                    setValue(LocalDateTime.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                }
            }
        });
    }
}
           

项目全局的出参格式化

Date类型

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

LocalDate/LocalDateTime类型

private static final String dateTimeFormat = "yyyy-MM-dd HH:mm:ss";
/**
 * @Bean  <bean id="xxx"></bean>
 * @return
 */
@Bean
public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
    return builder -> {
        builder.simpleDateFormat(dateTimeFormat);
        builder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(dateTimeFormat)));
    };
}