天天看点

6,SpringMvc获取请求参数

SpringMvc获取请求参数

V哥官网:http://www.vgxit.com

本文对应视频教程:http://www.vgxit.com/course/24

1,概述

我们使用SpringMvc的控制器的时候,接受参数其实就是我们做业务开发的第一步。本节课开始,V哥就会细细的给大家讲SpringMvc接受参数。就是我们使用HttpServletReqeust本来也是可以接收参数的,但是SpringMvc为我们提供了更好的,更方便的接收参数的方式。

2,通过参数名完全匹配的方式获取请求参数

就是说,我们定义Controller对应的方法的时候,我们写入对应的方法参数,参数的名字和请求中参数的名字完全匹配。这个时候,SpringMvc会自动的把请求的参数的值赋值到方法参数上。

@Controller
@RequestMapping("/param")
public class ParamController {
    @GetMapping("/name-equals")
    public ModelAndView nameEqueals(String name, Integer age) {
        System.out.println("name=" + name + ", age=" + age);
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("sayhello");
        return modelAndView;
    }
}
           

3,指定请求参数名获取请求参数

有的时候我们用户提交上来的参数性可能我们定义的Controller的方法的方法参数的名字不匹配,这个时候怎么办?我们只需要增加@RequestParam注解就行了。

@GetMapping("/name-not-equals")
public ModelAndView nameNotEqueals(@RequestParam("n") String name, @RequestParam("a") Integer age) {
    System.out.println("name=" + name + ", age=" + age);
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("sayhello");
    return modelAndView;
}
           

4,GET请求和POST请求获取参数方式一样

意思就是我们通过GET请求或者POST请求,我们获取参数的方式都是一样的。我们直接用Postman演示一下就行。

5,自定义对象接受参数

上线我们是通过定义方法参数的名字和请求参数的名字一模一样,或者加上@RequestParam注解的方式来接受客户端提交上来的参数。但是有时候有一个很大的问题。就说如果提交上来的参数非常多怎么办?比如我们要添加用户,我们需要添加用户名,密码,昵称,年龄,性别,籍贯…等等一共假如说有20个参数,这个时候,你直接在方法上写20哥方法参数是不是非常的麻烦啊?还有,我们学习编码规范的时候,我们都知道,一个方法的参数的数量不能太多,一般情况下,参数的个数不能超过7个。这个时候,我们可以自定义一个封装对象来接受参数。

1,定义自定义对象:

package com.vgxit.learn.springmvc.quickstart.ro;

import lombok.Data;

@Data
public class UserAddRO {
    private String username;

    private String nickname;

    private Integer age;
}
           

2,编写接受参数的方法:

@PostMapping("/add-user")
public ModelAndView addUser(UserAddRO userAddRO) {
    System.out.println(userAddRO);
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("sayhello");
    return modelAndView;
}
           

6,使用URL来传递参数

这个往往在基于RestFul风格的Api系统中非常常见,比如我们要获取一个用户的数据,可能对外提供的Api接口的地址如下:“GET http://www.vgxit.com/api/v1/user/1”,其实在这个URL中的1表示请求上来的一个参数,这个1代表的就是用户的id。那如果遇到这种情况,我们怎么样来做呢?

@GetMapping("/get-user/{id}")
public ModelAndView getUser(@PathVariable("id") int id) {
    System.out.println("id=" + id);
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("sayhello");
    return modelAndView;
}
           

7,Rest接口,返回json数据

就是我们使用Rest接口的时候,一般我们是在前后端分离的项目中使用,这个时候,我们返回的数据通常就是Json格式的,而我们上面的方式,只是简单的通过ModelAndView来指定了一个视图层页面。这个显然是不满足需求的。那么如果我们要使用Json格式返回数据,怎么办?

1,首先,我们要引入一个包,一个jackson-databind包:

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.4</version>
</dependency>
           

2,定义Rest接口的Controller:

@GetMapping("/get-user/{id}")
public ModelAndView getUser(@PathVariable("id") int id) {
    User user = User.builder()
            .id(id)
            .username("liyitong")
            .nickname("李一桐")
            .age(30)
            .build();
    ModelAndView modelAndView = new ModelAndView();
    //设置返回的视图为Json格式,MappingJackson2JsonView就是Jackson给我们提供的返回json格式数据的视图
    modelAndView.setView(new MappingJackson2JsonView());
    //再把我们要返回的数据设置到这个modelAndView中
    modelAndView.addObject(user);
    return modelAndView;
}
           

8,Rest接口返回Json简写方式

但是我们上面写的通过modelAndView的方式来返回Json是比较麻烦的,那么SpringMvc为我们提供了一个简单的方式来返回Json数据:

@GetMapping("/get-json-user/{id}")
//@ResponseBody表示我们返回的数据格式是对应的Java对象的Json
public @ResponseBody User getJsonUser(@PathVariable("id") int id) {
    User user = User.builder()
            .id(id)
            .username("liyitong")
            .nickname("李一桐")
            .age(30)
            .build();
    return user;
}
           

9,整个项目全Rest接口,Json返回方式

就是我们现阶段的开发中,基本上都是前后端分离的项目,比如前端可能就是用Vue或者React来通过Ajax来访问后端接口的。相当于,我们后端程序员,不用再来些页面了,我们后端的代码中,没有Html、Css、Js都没有。我们提供的全是接口。这个时候,我们所有的接口全部都是返回Json数据。按照上面的方式,每个接口我们都需要加上@ResponseBody注解,真的是非常的麻烦。这个时候,我们只需要通过另外一个注解来修饰COntroller就行了。

package com.vgxit.learn.springmvc.quickstart;

import com.vgxit.learn.springmvc.quickstart.po.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/user")
public class UserController {
    @GetMapping("/get-user/{id}")
    public User getUser(@PathVariable("id") int id) {
        User user = User.builder()
                .id(id)
                .username("liyitong")
                .nickname("李一桐")
                .age(30)
                .build();
        return user;
    }

    @GetMapping("/all")
    public List<User> all() {
        List<User> users = new ArrayList<User>();
        for (int i = 0; i < 10; i++) {
            User user = User.builder()
                    .id(i + 1)
                    .username("username" + i)
                    .nickname("nickname" + i)
                    .age(20 + i)
                    .build();
            users.add(user);
        }
        return users;
    }
}
           

10,使用json的方式来传递参数

在Rest接口的开发中,前端给我们Post,PUT提交参数的时候,往往是直接用Json格式来提交的。

对应的Controller代码如下:

@PostMapping("/add")
//@RequestBody的意思,就是表示我们的UserAddRO中的数据由客户端提交上来的Json数据填充
public String add(@RequestBody UserAddRO userAddRO) {
    System.out.println(userAddRO);
    return "ok";
}
           

对应的Jsp页面我们用Json来实现提交:

<%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2021/8/14
  Time: 18:18
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script type="text/javascript" src="https://vgxitdata-1256295173.cos.ap-chengdu.myqcloud.com/jquery-files/jquery-1.12.4.min.js"></script>
    <script type="text/javascript">
        function addUser() {
            var postData = {
                "username":"liyitong",
                "nickname":"桐桐",
                "age":30
            };
            $.post({
                url:"http://localhost/01quickstart/user/add",
                "contentType":"application/json",
                data: JSON.stringify(postData),
                success: function (res) {
                    alert(res);
                }
            })
        }
    </script>
</head>
<body>
<button onclick="addUser();">点击提交</button>
</body>
</html>
           

11,json方式接受列表数据

有些同学可能会问V哥,如果我们一次性添加多个用户,怎么办?一次性添加多个用户,无非就是一次性上传一个Json的数组上来,而我们Java的Controller用一个List来接收,是不是就好了?

@PostMapping("/batch-add")
public String batchAdd(@RequestBody List<UserAddRO> userAddROS) {
    System.out.println(userAddROS);
    return "ok";
}
           

12,转换器

之前,我们定义参数的时候,我们都是用的String,Int,就是我们使用的是基本数据类型+String来接受参数的。但是如果我们接收的参数不是基本数据类型和String的时候怎么办。比如我们接受的数据类型是Date类型。

@GetMapping("/test-date")
public String testDate(Date date) {
    System.out.println(date);
    return "ok";
}
           

以上代码,程序直接报错了,因为我们传上来的date是一个String类型的数据。如果我们要转化成Date类型的数据,那么我们要使用SimpleDateFormat来转换,而现在,我们的SpringMvc根本就不知道你用的是什么格式来转化,所以直接就报错。

那么我们要解决上线的问题,我们需要编写一个转换器,这个转换器就是我们写了一段代码,这段代码告诉我们如何把String转化为Date。然后我们把这个转换器提供了SpringMvc就可以了。

1,首先要编写一个转换器,这个转换器必须实现一个接口Converter:

package com.vgxit.learn.springmvc.quickstart.converter;

import org.springframework.core.convert.converter.Converter;
import org.springframework.util.ObjectUtils;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class VgeStringToDateConverter implements Converter<String, Date> {
    //这个方法就是具体的吧String转换成Date的方法
    public Date convert(String s) {
        if (ObjectUtils.isEmpty(s)) {
            throw new NullPointerException("要转换的日期不能为空");
        }
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        try {
            Date date = dateFormat.parse(s);
            return date;
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }
}
           

2,配置转换器工厂:

<!--配置一个转换器工厂-->
<bean id="converterService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <!--注入一个新的类型的转换器-->
    <property name="converters">
        <set>
            <bean class="com.vgxit.learn.springmvc.quickstart.converter.VgeStringToDateConverter"/>
        </set>
    </property>
</bean>
<!--通过conversion-service="converterService"引用配置器工厂-->
<mvc:annotation-driven conversion-service="converterService"/>
           

转换器,不光是可以转换Date类型,其他类型依然是可以转换的。比如我们自定义的类型也是可以转换的:

@GetMapping("/test-user")
public String testUser(UserAddRO userAddRO) {
    System.out.println(userAddRO);
    return "ok";
}

package com.vgxit.learn.springmvc.quickstart.converter;

import com.vgxit.learn.springmvc.quickstart.ro.UserAddRO;
import org.springframework.core.convert.converter.Converter;

public class VgeStringToUserAddRoConverter implements Converter<String, UserAddRO> {
    public UserAddRO convert(String s) {
        String[] split = s.split(":");
        UserAddRO userAddRO = new UserAddRO();
        userAddRO.setUsername(split[0]);
        userAddRO.setNickname(split[1]);
        userAddRO.setAge(Integer.parseInt(split[2]));
        return userAddRO;
    }
}
           

就是,我们如果是Json格式提交的时候,那么是什么情况。就是我们干掉了我们配置的转换器工厂之后,我们用Json格式提交参数,数据转换是没有问题的,比如我们把UserAddRO里面的age改成Date类型的birthday,也是转换没问题的。这个是应为我们做Json转换的时候,用的Jackson包给我们提供的工具,MappingJackson2HttpMessageConverter,这个工具他在转换的时候,就已经定义好了一些日期转换的格式,所以,我们不需要再自定义转换器的。

package com.vgxit.learn.springmvc.quickstart.ro;

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;

import java.util.Date;

@Data
public class UserAddRO {
    private String username;

    private String nickname;

    @JsonFormat(timezone = "GMT+8", pattern = "yyyy年MM月dd号")//指定日期格式
    private Date birthday;
}