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语法:
- 数据在键值对中,键和值用 : 隔开
- 数据由逗号分隔
- 对象用{ }表示
- 数组用[ ]表示
- 值可以为对象也可以为数组,数组中可以包含多个对象
使用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;
}
}