访问不同的路径, 就是发送不同的请求。在发送请求时, 可能会带⼀些参数, 所以学习Spring的请求, 主要是学习如何传递参数到后端以及后端如何接收。
传递参数,我们通过postman测试。
@RequestMapping("/param")
@RestController
public class ParamController {
@RequestMapping("/m1")
public String m1(String name){
return "name: " + name;
}
}
正常传递:
可以看到, 后端程序正确拿到了name参数的值。
Spring MVC 会根据⽅法的参数名, 找到对应的参数, 赋值给⽅法。
所以这里要注意,传递的参数要和后端代码中的参数一致。
那不一致会出现什么现象呢?我们直接测试,如图:
可以发现是获不得参数的,name依旧为空。
这里还需要注意,参数的类型如果不是包装类(boolean),参数必须传,不然会报500错误,类型也要一致,不然会报400错误。
对于参数可能为空的数据,建议使⽤包装类型。
把参数类型修改为int:
@RequestMapping("/param")
@RestController
public class ParamController {
@RequestMapping("/m1")
public String m1(int n){
return "n = " + n;
}
}
@RequestMapping("/param")
@RestController
public class ParamController {
@RequestMapping("/m2")
public String m2(String name, Integer age){
return "name: " + name + ", age: " + age;
}
}
正常传递:
参数要一致,但是它们顺序可以调换。 要求和单个参数一样的。
但是可以发现这种还是有弊端,就是当增加新的参数,修改代码会非常麻烦,这个时候就可以把这些参数封装成对象,当增加新的参数,只需要多封装个属性。
创建Person类:
package com.example.demo;
public class Person {
private String name;
private int age;
private String password;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", password='" + password + '\'' +
'}';
}
}
这个时候,传递对象代码:
public class ParamController {
@RequestMapping("/m4")
public String m4(Person person){
return person.toString();
}
}
正常传参:
当传参后,后端代码拿到对应的参数,Spring 会根据参数名称⾃动绑定到对象的各个属性上, 如果某个属性未传递, 则赋值为null(基本类型则
赋值为默认初识值, ⽐如int类型的属性, 会被赋值为0)。
如果增加新的参数,只需要修改Person中代码,变得更加简单。
有时,前端参数的名字,我们想做出修改,让它更加的方便区分,这个时候就用到@RequestParam ,这个注解可以后端参数映射为其他名。
修改m2方法。
@RequestMapping("/param")
@RestController
public class ParamController {
@RequestMapping("/m2")
public String m2(@RequestParam("name") String myName, @RequestParam("age") Integer myAge){
return "name: " + myName + ", age: " + myAge;
}
}
但也可以改变,查看@RequestParam源码:
发现required默认值为true,含义就是它修饰的参数为必传,那么只要修改它的返回值即可。
如下面代码,这时就不是比传参数。
public String m2(@RequestParam(value = "name",required = false) String myName, @RequestParam(value = "age", required = false) Integer myAge){
return "name: " + myName + ", age: " + myAge;
}
@RequestMapping("/param")
@RestController
public class ParamController {
@RequestMapping("/m5")
public String m5(String[] array){
return Arrays.toString(array);
}
}
@RequestMapping("/param")
@RestController
public class ParamController {
@RequestMapping("/m6")
public String m6(@RequestParam List<String> list){
return list + "";
}
}
当用postman传参:
可以正常请求,但是当使用浏览器时,有时要进行转义编码。
例如:, 转义为%2c。
且需要使⽤ @RequestParam 绑定参数关系。
默认情况下,请求中参数名相同的多个值,是封装到数组. 如果要封装到集合,要使⽤@RequestParam绑定参数关系。
@RequestMapping("/m7")
public String m7(@RequestBody Person person){
return person.toString();
}
接收JSON对象, 需要使⽤ @RequestBody 注解。
RequestBody: 请求正⽂,意思是这个注解作⽤在请求正⽂的数据绑定,请求参数必须在写在请求正⽂中。
不使用注解将无法赋值。
传递参数:
这时,请求类型就是JOSN。
@RequestMapping("/m8/{age}/{name}")
public String m8(@PathVariable Integer age, @PathVariable("name") String useName){
return "解析参数: " + age + ", name: " + useName;
}
传参:
@PathVariable:这个注解主要作⽤在请求URL路径上的数据绑定。
如果⽅法参数名称和需要绑定的URL中的变量名称⼀致时, 可以简写, 不⽤给@PathVariable的属性赋值, 如上述例⼦中的id变量。
如果⽅法参数名称和需要绑定的URL中的变量名称不⼀致时, 需要@PathVariable的属性value赋值,如上述例⼦中的userName变量。
@RequestMapping("/m9")
public String m9(@RequestPart("file") MultipartFile file) throws IOException {
//获得文件名称
String s = file.getOriginalFilename();
//上传到指定路径
file.transferTo(new File("D:/temp/" + file.getOriginalFilename()));
return s;
}
@RequestMapping("/m10")
public String m10(HttpServletRequest request){
//获得所有Cooike
Cookie[] cookies = request.getCookies();
//打印
StringBuilder stringBuilder = new StringBuilder();
if(cookies != null){
for (Cookie cookie: cookies) {
stringBuilder.append(cookie.getName() + " : " + cookie.getValue());
}
}
return "Cookie: " + stringBuilder;
}
上面是Servlet获得Cookie的方式,因为Spring MVC是基于Servlet API实现的Web框架,所以HttpServletRequest , HttpServletResponse 是Servlet提供的两个类, 是Spring MVC⽅法的内置对象. 需要时直接在⽅法中添加声明即可。
响应结果并没有Cookie,这是因为网站中并没有Cookie,直接在postman中添加Cookie即可。
通过这个也可以看出,Cookie是可以伪造的,后端收到Cookie要进行校验。
上面方式也可以通过注解@CookieValue 简化,简化后的代码如下。
@RequestMapping("/getCookie")
public String getCookie(@CookieValue String xiaochen){
return "name: " + xiaochen;
}
}
@RequestMapping("/setSession")
public String setSession(HttpServletRequest request){
HttpSession session = request.getSession();
if(session != null){
session.setAttribute("name","java");
}
return "存储成功";
}
Session在服务端,所以无法直接添加,可以通过上述方式。
HttpSession getSession(boolean create) : 参数如果为 true, 则当不存在会话时新建会话; 参数如果为 false, 则当不存在会话时返回 null 。默认为true。
void setAttribute(String name, Object value): 使⽤指定的名称绑定⼀个对象到该 session 会话。
通过Fiddler观察Http请求和响应情况:
获得Session方法和获得Cookie一样有很多种,通常使用下面简单的两种。HttpSession session = request.getSession();
Session 不存在的话, 会⾃动进⾏创建。
@RequestMapping("/getSession1")
public String getSession(@SessionAttribute(required = false) String name){
return "name: " + name;
}
@RequestMapping("/getSession2")
public String getSession2(HttpSession session){
String name = (String) session.getAttribute("name");
return "name: " + name;
}
@RequestMapping("/getHeader")
public String getHeader(@RequestHeader("User-Agent") String useragent){
return useragent;
}
在我们前⾯的代码例⼦中,都已经设置了响应数据, Http响应结果可以是数据, 也可以是静态⻚⾯,也可以针对响应设置状态码, Header信息等。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Index页面title>
head>
<body>
Hello,Spring MVC.
body>
html>
后端返回代码如何写呢?先按照响应的模式写,代码如下。
@RequestMapping("/return")
@RestController
public class ReturnController {
@RequestMapping("/index")
public String returnIndex(){
return "/index.html";
}
}
直接返回,运行查看:
这很不明显不对,这是返回了一个字符串。
这时,就需要另一个注解了,我们需要把最前面的@RestController 改为 @Controller。
再次请求,便可以得到我们想要的结果:
@RequestMapping("/return")
//@RestController
@Controller
@ResponseBody
public class ReturnController {
@RequestMapping("returnData")
public String returnData(){
return "返回数据";
}
}
返回数据,前面其实一直在用,如果返回静态界面,需要写@Controller 注解,如果要直接返回数据,还需要加上个@ResponseBody注解。注意:@ResponseBody 即可作用在类上,表示类中所以方法返回都是数据,也可以作用在方法上,只表示该方法返回数据,这两个注解也可以和二为一,就是前面经常写的@RestController,但它也只能修饰类了。
@RequestMapping("/returnHtml")
@ResponseBody
public String html(){
return "hello,html
";
}
当返回数据有HTML代码,浏览器会自动解析:
如果用Fiffler抓包,可以看到Content-Type为text/html。
响应中的 Content-Type 常⻅取值有以下⼏种:
- text/html : body 数据格式是 HTML。
- text/css : body 数据格式是 CSS。
- application/javascript : body 数据格式是 JavaScript。
- application/json : body 数据格式是 JSON。
如果请求的是js⽂件, 那么Spring MVC会⾃动设置Content-Type为 application/javascript。
如果请求的是css⽂件, 那么SpringMVC会⾃动设置Content-Type为 text/css。
@RequestMapping("/returnJosn")
@ResponseBody
public HashMap<String,String> josn(){
HashMap<String,String> map = new HashMap<>();
map.put("Java","Java V");
map.put("Mysql","Mysql V");
return map;
}
@RequestMapping("/setStatus")
@ResponseBody
public String setStatus(HttpServletResponse response){
response.setStatus(401);
return "设置状态码成功";
}