Spring MVC 如何接收请求

1. 请求

浏览器访问不同的路径就是发送不同的请求,在发送请求时,可能会带有一些参数,所以我们就需要在后端接受参数。

2. 传递单个参数

接收单个参数,在Spring MVC中直接使用方法中的参数即可:

@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request1")
    public String request1(String name) {
        return "接收到参数:" + name;
    }
}

使用PostMan发送带参数的请求:

可以看得到,request1方法接受到了参数 。(Params代表使用查询字符串传参......),注意请求中的 key(name)必须和方法中的参数名(name)相同,不同则接收不到,会默认为null

 接收基本类型:

@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request2")
    public String request2(int age) {
        return "接受到参数:" + age;
    }
}

注意,如果请求中的key和代码中的参数名不同,则相当于没有传递这个参数,没有传递会默认传递一个null,显然把null传递给一个int类型是不行的,所以就会报错: 

 同理,如果我们传递一个非数字的值:

aaa无法强转为int类型,所以也会报错 。

使用包装类型接收:

@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request3")
    public String request3(Integer age) {
        return "接受到参数:" + age;
    }
}

无参数时:

包装类型可以接受一个null,所以不会报错。

参数为aaa:

 

aaa同样无法强转为Integer,所以也会报错 。

所以接受基本类型时,建议使用其对应的包装类。

3. 传递多个参数

和传递单个参数相同,直接使用方法的参数接受即可

@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request4")
    public String request4(String name, Integer age) {
        return "接收到参数,name: " + name + ",age:" + age;
    }
}

当参数过多时,我们要给方法写多个参数,这要很不美观,于是我们可以直接传递一个对象,我们新建一个类:

public class student {
    String name;
    Integer age;
    Character sex;
    Integer id;

    @Override
    public String toString() {
        return "student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                ", id=" + id +
                '}';
    }
}
@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request5")
    public String request5(student s) {
        return "接收到参数,name: " + s;
    }
}

发送请求:

我们发现,并没有成功接收到参数,这是因为,传递对象参数时,服务器会调用默认的构造方法创建一个对象,然后调用set方法来给每个成员赋值,我们没有实现set方法所以没有成功接收到参数。 

我们给student类加上set方法:

public class student {
    String name;
    Integer age;
    Character sex;
    Integer id;

    public void setName(String name) {
        this.name = name;
    }

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

    public void setSex(Character sex) {
        this.sex = sex;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                ", id=" + id +
                '}';
    }
}

可以发现此时就能够成功的接收到参数了。

如果此时我们的id和name使用int类型,我们不传递参数也不会报错,因为在创建对象后,会被默认赋值为0。

注意传递对象时,一定要保证传递的对象有无参数的构造方法,因为,接收参数时会默认调用无参数的构造方法,如果没有就会报错

4. 后端参数重命名

有时候前端传递过来的参数名含义太广,不利于我们阅读代码,例如前端传入一个 name,这个name 是人名,还是动物名,还是商品名,有很多解读,我们可以使用 @RequestParam 注解来重命名前后端的参数值。

@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request6")
    public String request6(@RequestParam("name")String peopleName) {
        return "peopleName:" + peopleName;
    }
}

@RequestParam("name")String peopleName:代表把前端的参数"name"赋值给"peopleName"

 如果我们使用peopleName发送请求:

这时候报错了,所以使用peopleName无法接收到参数,但是 String类型是可以接收 null 类型的 ,为什么会报错?我们在idea查看报错信息:

这里说 方法参数类型为String的参数不存在 ,即报错的原因是没有传递这个参数,所以由此可知:使用@RequestParam 注解的参数必须传递。

要想保留@RequestParam 注解,又想使参数可以不传递,我们可以如下这样写:

@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request7")
    public String request7(@RequestParam(value = "name", required = false)String peopleName) {
        return "peopleName:" + peopleName;
    }
}

value和required称为注解的属性,value就代表接收的参数名,required代表这个参数是否一定需要,我们可以选中这个注解点的 ctrl+B 转到这个注解的定义:

我们发行required的默认值是true, 即默认必须要传递,所以我们把它设置为false,就可以不用传递了。 

5. 传递数组

@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request8")
    public String request8(int[] array) {
        return "接收到参数:" + Arrays.toString(array);
    }
}

数组传参有两种方式:

 

key相同时会组装成一个数组。

6. 传递集合

和传递数组类似:

@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request9")
    public String request9(List<Integer> list) {
        return "接收到参数:" + list;
    }
}

我们发现使用数组的传递方式并没有传递成功,而是报错了,我们查看idea的报错信息 :

第一句就已经告诉了我们错误的原因:没有找到 接口java.util.List 主要的或唯一的构造函数。我们前面就说到了,接收对象时,服务器端会调用其默认的构造方法,然后在把参数赋值进对象,List是一个接口,并没有提供默认的构造方法,所以会报错。

现在我们把List改为 ArrayListL:

@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request9")
    public String request9(ArrayList<Integer> list) {
        return "接收到参数:" + list;
    }
}

我们发现,这次没有报错,但是参数并没有接收成功, 这是因为,默认情况下,请求中参数名相同的多个值,是封装为数组,所以无法将请求中的参数值正确地转换为ArrayList 对象导致的,这时我们可以使用上面使用过的@RequestParam注解:

@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request9")
    public String request9(@RequestParam ArrayList<Integer> list) {
        return "接收到参数:" + list;
    }
}

@RequestParam注解会获取指定名称参数的值(这里没有指定则默认和后端的参数的名称相同),然后根据后端参数类型进行自动类型转换,这里即转换为ArrayList。

此时我们再发送请求就能正常获取到参数了:

既然@RequestParam注解会根据后端参数类型进行自动类型转换,那么代表后端参数并不用调用构造方法,直接接收@RequestParam注解转化的对象,所以我们也可以使用接口作为参数:

@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request9")
    public String request9(@RequestParam List<Integer> list) {
        return "接收到参数:" + list;
    }
}

 7. 传递JSON数据

JSON:JavaScript Object Notation (Java Script 对象表示法)

JSON是一种数据格式,用键值对的形式储存数据,使用文本表示一个对象或数组的信息,本质上是字符串,用于不同语言中数据的传递和交换。

JSON语法:

  1. 数据在键值对中,键和值用 : 隔开
  2. 数据由逗号分隔
  3. 对象用{ }表示
  4. 数组用[ ]表示
  5. 值可以为对象也可以为数组,数组中可以包含多个对象

使用JSON传递一个对象:

@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request10")
    public String request10(student s) {
        return "接收到参数,name: " + s;
    }
}

在PostMan中我们选择Body 然后选择raw就可以看到有方有个蓝色字体的JSON,就可以传递JSON数据了:

我们发现并没有接收成功,这是因为,接收参数时会在接收的数据中找student的各个属性来赋值,而传递的JSON是一个对象是一个整体,所以是找不到student的属性的,这是我们需要使用@RequestBody 注解,表示要把body中的整个数据表示,转化为student对象

@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request10")
    public String request10(@RequestBody student s) {
        return "接收到参数,name: " + s;
    }
}

 JSON字符串转化为Java对象的过程是通过JSON转换工具实现的,Spring MVC框架已经集成了JSON转换工具,jackson-databind,如果要脱离Spring MVC使用则要添加对应的依赖。

使用示例:

public class JSONTest {
    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        String s = "{\n" +
                "    \"name\":\"小明\",\n" +
                "    \"age\":20,\n" +
                "    \"sex\":\"男\",\n" +
                "    \"id\":1001\n" +
                "}";
        student stu = objectMapper.readValue(s, student.class);
        System.out.println(stu);
    }
}

 这个方法的原理是通过反射获取到student的造方法创建对象,然后解析 字符串s中的内容映射到student对象中,注意要提供无参数的构造方法,否则可能会出错

8. 获取URL中的参数 

参数可以直接放在URL中,例如: http://127.0.0.1:8080/request/request11/123456

这个123456可能不是代表路径,而是一个数据。

获取URL中的数据需要使用 @ PathVariable注解:

@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request11/{id}")
    public String request11(@PathVariable("id") Integer id) {
        return "接收到参数:" + id;
    }
}

作为参数的部分路径要使用{ } 括起来,两个注解中获取的路径名称要相同(即都是id),@PathVariable 中可不写参数(即不写id),这是则要求,后面参数的名称要和URL中相同(即Integer id),如果@PathVariable 中可写了参数,则对后面(Integer)的参数名没有要求。

9. 上传文件 

文件要使用 MultipartFile 接口来接收,并且需要加上@RequestPart注解

@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request12")
    public String request11(@RequestPart("file") MultipartFile file) {
        return "接收到文件:" + file.getOriginalFilename();
    }
}

@RequestPart注解的参数要和接收的数据的Key相同

在PostMan中点击Body 再点击 form-data 或者 x-www-form-urlencoded 就可以传输文件

成功返回了文件的名称。

10. 获取Cookie/Session

  • Cookie:之前我们介绍过Cookie,简单来说,Cookie就是一段数据,存储了关于用户的一些信息。当我们在某个网站登录时,网站会发送给我们一个令牌(token),这个令牌就储存在Cookie中,有了这个令牌,我们下次访问网站时把Cookie传入到服务器,服务器就可以知道我们的身份,就不用每次登录都要登录账号。
  • Session:Session是用于服务器储存用户的信息的,上面我们说,我们访问网站时,登录后网站会给我们一个令牌,Session就可以理解为,记录每个令牌对应的用户数据,让服务器拿到令牌时能区分出用户,Session的本质是一个哈希表,储存了一些键值对结构,Key称为SessionId,Value就是用户信息,令牌就可以看作SessionId。
  • SessionId是服务器生成的一个“唯一性字符串”,从Session机制的⻆度来看,这个唯⼀性字符串称为SessionId但是站在整个登录流程中看待,也可以把这个唯⼀性字符串称为token,(注意SessionId只是实现token的一种方式,两者不能完全对等)

 Cookie和Session的区别:

  • Cookie是客户端保存用户信息的一种机制,Session是服务器保存用户信息的一种机制
  • Session默认保存在内存中,如果重新服务器Session数据会丢失,Cookie储存在硬盘中
  • Cookie和Session经常会配合在一起使用,但不是必须配和,SessionId不一定非要保存在Cookie中,SessionId也不一定非要通过Cookie传输。

 传统方式获取Cookie:

@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request13")
    public String getCookie(HttpServletRequest request, HttpServletResponse response) {
        Cookie[] cookies = request.getCookies();
        if(cookies != null) {
            Arrays.stream(cookies).forEach(x -> System.out.println(x.getName() + ":" + x.getValue()));
        }
        return "接收到Cookie";
    }
}

HttpServletRequest类用于接收一个请求,即包含了请求中的所有内容

调用getCookies()方法即可的到对应的Cookie数组,由于我们并没有Cookie所以获取到的Cookie是空的,我们可以通过浏览器的调试工具添加Cookie

也可以使用PostMan修改Cookie

 通过@CookieValue注解获取Cookie:

@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request14")
    public String getCookie2(@CookieValue("ck") String ck) {
        return "接收到Cookie,ck:" + ck;
    }
}

注解中填要获取的Cookie的Key,一次只能获取一个:

传统方式设置Session:

@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request15")
    public String setSession(HttpServletRequest request) {
        //从Cookie中获取SessionId再通过SessionId找到Session
        HttpSession session = request.getSession();
        session.setAttribute("name", "小明");
        return "设置Session成功";
    }
}

访问该方法即可设置Session

直接在参数中写HttpSession类:

@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request16")
    public String setSession2(HttpSession session) {
        session.setAttribute("name", "小明");
        return "设置Session成功";
    }
}

传统方式获取Session:

@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request17")
    public String getSession1(HttpServletRequest request) {
        //从Cookie中获取SessionId再通过SessionId找到Session
        HttpSession session = request.getSession();
        String name = (String)session.getAttribute("name");
        return "获取到Session:" + name;
    }
}

 通过@SessionAttribute注解获取Session:

@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request18")
    public String getSession2(@SessionAttribute("name") String name) {
        return "获取到Session:" + name;
    }
}

11. 获取Header

Header包含在请求中,我们同样可以使用HttpServletRequest 类获取到:

@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request19")
    public String getHeader1(HttpServletRequest request) {
        String userAgent = request.getHeader("User-Agent");
        return "获取到,User-Agent:" + userAgent;
    }
}

使用@RequestHeader注解获取:

@RequestMapping("/request")
@RestController
public class RequestController {
    @RequestMapping("/request20")
    public String getHeader1(@RequestHeader("User-Agent")String userAgent) {
        return "获取到,User-Agent:" + userAgent;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ting-yu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值