RequestMapping
- 首先添加依赖
- Maven的配置
测试
在controller创建HelloController,如果只加@RequestMapping,默认跳转到新页面
如果要是加上@ResponseBody就把数据封装在包(JSON),标签@RestController是前后分离的注解(因为默认用@ResponseBody)
通配符
精度:'?' > '*' > '**'
例子:
/hell?
可以匹配 /hello 、 /hella 、/hellob,不可以匹配/helloo,因为oo是多个字符
/hell*
可以匹配/hello 、 /hella、/helloo等单层结构,/hello/a不可以
/hello/**
可以匹配所有/hello子层的结构
方法限定method
现在我们限定一个POST方式的Controller
测试需要用到Postman,因为浏览器不能自主Post,然后用Postman发送一个POST
可以看到POST结果返回成功,GET就返回405
方法类型
在 RequestMethod方法上有八种方法
参数限定params
http://localhost:8080/test02?age=18&username=zhangsan&gender=0
正常返回
测试
http://localhost:8080/test02?age=17&username=zhangsan&gender=0
异常,原因是age不为18。
http://localhost:8080/test02?age=18&gender=0
异常,原因是不包含username。
http://localhost:8080/test02?age=18&gender=0&username=wangwu
正常,顺序不影响结果
http://localhost:8080/test02?age=18&gender=1&username=wangwu
异常,原因是gender为1
请求头限定headers
内容类型限定consumes、produces
MediaType的类型
用json格式返回成功
用text格式返回415异常
produces限定类型,与consumes的区别是一个是消费者、一个是生产者,consumes是客户端到服务端的类型,produces是服务端到客户端的响应类型,即响应报文
请求实战演练
1.使用普通变量收集参数
/*
没有携带自动封装为null,有就自动封装
*/
@RequestMapping("/handle01")
public String test(String username ,
String password ,
String cellphone ,
boolean agreement){
System.out.println(username + " " + password + " " + cellphone + " " + agreement);
return "ok";
}
发送三次请求分别为
第一次:http://localhost:8080/handle01?username=zhangsan&password=123456&cellphone=23142234
第二次:http://localhost:8080/handle01?username=zhangsan&password=123456&cellphone=23142234&agreement=on
第三次:http://localhost:8080/handle01?username=zhangsan&cellphone=23142234
2.使用RequestParam明确收集参数
使用RequestParam明确收集参数默认必须携带,否则报错
ps:不管参数是放到url?后面还是请求体,都能被RequestParam接收
/*
使用RequestParam明确收集参数默认必须携带
如果不携带就炸了
*/
@RequestMapping("/handle02")
public String handle02(@RequestParam("username") String name ,
@RequestParam("password") String pwd ,
@RequestParam("cellphone") String phone ,
@RequestParam("agreement") boolean ok){
System.out.println(name + " " + pwd + " " + phone + " " + ok);
return "ok";
}
发送http://localhost:8080/handle02?username=zhangsan&password=32451&cellphone=2341234&agreement=on
正常
发送http://localhost:8080/handle02?username=zhangsan&password=32451&agreement=on
则报错,因为没有携带cellphone信息
@RequestMapping("/handle02")
public String handle02(@RequestParam("username") String name ,
@RequestParam(value = "password" , defaultValue = "123456") String pwd ,
@RequestParam(value = "cellphone" ) String phone ,
@RequestParam(value = "agreement" , required = false) boolean ok){
System.out.println(name + " " + pwd + " " + phone + " " + ok);
return "ok";
}
如果属性required=false表示可以不用携带参数、default表示添加默认值,也可以不用携带参数
发送http://localhost:8080/handle02?username=zhangsan&cellphone=2341234&agreement=on
返回zhangsan 123456 2341234 true
3.使用Pojo封装所有参数
Person.java
package com.atguigu.springmvc.bean;
import lombok.Data;
import lombok.ToString;
@Data
@ToString
public class Person {
private String username ;
private String password ;
private String cellphone ;
private boolean agreement ;
}
@RequestMapping("/handle03")
public String handle03(Person person){
System.out.println(person.toString());
return "ok";
}
4.@RequestHeader
@RequestMapping("/handle04")
public String handle04(@RequestHeader("host") String host){
System.out.println(host);
return "ok~"+host;
}
5.获取Cookie的键值对
用@CookieValue(value = “value”)获取
@RequestMapping("/handle05")
public String handle05(@CookieValue("haha") String haha){
return "ok" + haha;
}
发送一个含有value = haha的cookie的报文
结果正常返回,然后我就好奇如果用@RequestHeader(“Cookie”)会发生什么呢,让我们开始实验
@RequestMapping("/handle05")
public String handle05(@CookieValue("haha") String haha,@RequestHeader("Cookie") String ck){
System.out.println(haha + " " + ck);
return "ok" + haha + " " + ck;
}
结果如下
6.pojo级联封装复杂对象
package com.atguigu.springmvc.bean;
import lombok.Data;
import java.util.Arrays;
@Data
public class Person {
private String username ;
private String password ;
private String cellphone ;
private boolean agreement ;
private Address address ;
private String sex ;
private String[] hobby;
private String grade;
}
@Data
class Address {
private String province;
private String city ;
private String area;
}
如果遇到以下这种笔记复杂的对象,可以考虑级联(嵌套)封装
ps:由于一直返回地址,不知道什么地方出了问题,然后我就手动Data,即alt + insert
快捷键生成,代码如下。
package com.atguigu.springmvc.bean;
import lombok.Data;
import java.util.Arrays;
public class Person {
private String username ;
private String password ;
private String cellphone ;
private Boolean agreement ;
private Address address ;
private String sex ;
private String[] hobby;
private String grade;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getCellphone() {
return cellphone;
}
public void setCellphone(String cellphone) {
this.cellphone = cellphone;
}
public Boolean getAgreement() {
return agreement;
}
public void setAgreement(Boolean agreement) {
this.agreement = agreement;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String[] getHobby() {
return hobby;
}
public void setHobby(String[] hobby) {
this.hobby = hobby;
}
public String getGrade() {
return grade;
}
public void setGrade(String grade) {
this.grade = grade;
}
@Override
public String toString() {
return "Person{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", cellphone='" + cellphone + '\'' +
", agreement=" + agreement +
", address=" + address +
", sex='" + sex + '\'' +
", hobby=" + Arrays.toString(hobby) +
", grade='" + grade + '\'' +
'}';
}
}
class Address {
private String province;
private String city ;
private String area;
public String getArea() {
return area;
}
public void setArea(String area) {
this.area = area;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
@Override
public String toString() {
return "Address{" +
"area='" + area + '\'' +
", province='" + province + '\'' +
", city='" + city + '\'' +
'}';
}
}
结果正常显示
7.@RequestBody接收json字符并转换
首先编写如下代码
@RequestMapping("/handle07")
public String handle07(Person person){
System.out.println(person);
return "ok";
}
用postman发送请求
返回的结果如下
这是因为不使用 @RequestBody 注解,将无法直接接收 JSON 格式的数据,当不使用@RequestsBody的时候,Spring会处理表单数据(form-data/x-www-form-urlencoded)或者url?name=value,即键值对。
现在给它加上一个@RequestBody
@RequestMapping("/handle07")
public String handle07(@RequestBody Person person){
System.out.println(person);
return "ok";
}
8.文件上传
- 文件上传的要求
method = post , enctype = “multipart/form-data” - 代码的编写
@RequestMapping("/handle08")
public String handle08(Person person,@RequestParam("headerImg") MultipartFile headerImgFile,
@RequestParam("lifeImg") MultipartFile[] lifeImgFile) throws IOException {
//获取原始路径
String originalFilename = headerImgFile.getOriginalFilename();
long size = headerImgFile.getSize();
InputStream inputStream = headerImgFile.getInputStream();
System.out.println(originalFilename + "=>" + size);
headerImgFile.transferTo(new File("D:\\javastudy\\img\\" + originalFilename));
System.out.println("头像保存结束");
if(lifeImgFile.length > 0){
for(MultipartFile imgFile : lifeImgFile){
imgFile.transferTo(new File("D:\\javastudy\\img\\" + imgFile.getOriginalFilename()));
}
System.out.println("生活照保存结束");
}
System.out.println(person);
return "ok!!!";
}
用MultipartFile的接收文件,MultipartFile的源代码如下
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.web.multipart;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import org.springframework.core.io.InputStreamSource;
import org.springframework.core.io.Resource;
import org.springframework.lang.Nullable;
import org.springframework.util.FileCopyUtils;
public interface MultipartFile extends InputStreamSource {
String getName();
@Nullable
String getOriginalFilename();
@Nullable
String getContentType();
boolean isEmpty();
long getSize();
byte[] getBytes() throws IOException;
InputStream getInputStream() throws IOException;
default Resource getResource() {
return new MultipartFileResource(this);
}
void transferTo(File dest) throws IOException, IllegalStateException;
default void transferTo(Path dest) throws IOException, IllegalStateException {
FileCopyUtils.copy(this.getInputStream(), Files.newOutputStream(dest));
}
}
Test:
在properties中添加以下两句话可以修改传送文件大小
9.HttpEntity获取整个请求
@RequestMapping("/handle09")
public String handle09(HttpEntity<String> entity){
System.out.println("请求头"+entity.getHeaders());
System.out.println("请求体"+entity.getBody());
return "OK~~~";
}
就是Entity是请求头、请求体的总和,用HttpEntity可以获得请求头和请求体。
10.原生api HttpServletRequestRequest、HttpServletResponse
@RequestMapping("/handle10")
public String handle10(HttpServletRequest request, HttpServletResponse response){
//原生api,HttpServletRequestRequest和HttpServletResponse 可以参考javaweb
String username = request.getParameter("username");
System.out.println(username);
return "OK~~~";
}
获取HttpMethod方法
@RequestMapping("/handle10")
public String handle10(HttpServletRequest request, HttpServletResponse response, HttpMethod method){
System.out.println(method);
//原生api,HttpServletRequestRequest和HttpServletResponse 可以参考javaweb
String username = request.getParameter("username");
System.out.println(username);
return "OK~~~";
}
小结
响应实战演练
1.返回json
不加任何注释,默认返回json
package com.atguigu.springmvc.controller;
import com.atguigu.springmvc.bean.Person;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ResponseTestController {
@RequestMapping("/resp01")
public Person resp01() {
Person person = new Person();
person.setUsername("zhangsan");
person.setPassword("111");
person.setCellphone("1234");
person.setAgreement(true);
person.setSex("男");
person.setHobby(new String[]{"足球","篮球"});
person.setGrade("三年级");
return person;
}
}
核心原因:@RestController包含@ReponseBody(返回json对象)
2.文件下载
@RequestMapping("/download")
public ResponseEntity<byte[]> download() throws IOException {
FileInputStream inputStream = new FileInputStream("D://javastudy//img//d2d0adc1a979dc30d622b1cb1596875f.png");
byte[] bytes = inputStream.readAllBytes();
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.contentLength(bytes.length)
//文件处理方式
.header("Content-Disposition" , "attachment;filename=haha.png")
.body(bytes);
}
首先返回值为一个响应体为字节流的响应体,理由是可以调用响应头的文件类型,然后开始把自己想传输的文件整成一个文件流,然后在ResponseEnitity中配置整个响应的信息。
ps:ResponseEntity.ok()/contentType返回的都是ResponseEntity类,所以顺序先后不影响 , APPLICATION_OCTET_STREAM是八进制流文件。