下文使用postman模拟客户端传递信息。
1.postman传参介绍
1.1传递单个参数
1.2传递多个参数
注意事项
使⽤基本类型(int...)来接收参数时, 参数必须传(除boolean类型), 否则会报500错误
类型不匹配时, 会报400错误
对于包装类型, 如果不传对应参数,Spring 接收到的数据则为null
所以对于参数可能为空的数据,建议使⽤包装类型
1.3传递数组参数
@RequestMapping("/r1")String r1(String[] arr){return "r1:" + Arrays.toString(arr);}
也可以这样传入:
1.4传递对象
@RequestMapping("/r3")String r3(Person person){return "person:" + person;}
public class Person {private String name;private String password;private Integer age;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", password='" + password + '\'' +", age=" + age +'}';}
}
也可以不按顺序传入:
1.5后端参数重命名(后端参数映射)
有时候前端为了保证前端代码的保密性,会把参数的名字起得后端人员难以理解,这时我们就可以借助注解@RequestParam 来重命名前后端的参数值.
@RequestMapping("/r4")String r4(@RequestParam("q") String keyword){return keyword;}
将前端传入的参数名“q”重命名为keyword
并且使⽤ @RequestParam 进⾏参数重命名时, 参数就变成了必传参数
如果不传参数,会报错
我们可以借助@RequestParam注解实现非必传参数的设置
@RequestMapping("/r5")String r5(@RequestParam(value = "q" ,required = false) String keyword){return "keyword: " + keyword;}
1.6 传递集合
集合参数:和数组类似, 同⼀个请求参数名有为多个, 且需要使⽤ @RequestParam 绑定参数关系
默认情况下,请求中参数名相同的多个值,是封装到数组. 如果要封装到集合,要使⽤
@RequestParam 绑定参数关系
@RequestMapping("/r6")String r6(@RequestParam(value = "q") List<String> list){return Arrays.toString(list.toArray());}
同样也可以一起传
1.8传递JSON数据
JSON概念
JSON:JavaScript Object Notation 【JavaScript 对象表⽰法】
JSON是⼀种轻量级的数据交互格式. 它基于 ECMAScript (欧洲计算机协会制定的js规范)的⼀个⼦集,采⽤完全独⽴于编程语⾔的⽂本格式来存储和表⽰数据。--百度百科
我们可以理解为一种数据结构/对象,用于在不同的语⾔中数据传递和交换.
JSON语法
JSON 是⼀个字符串,其格式⾮常类似于 JavaScript 对象字⾯量的格式
数据在键值对(Key/Value) 中
数据由逗号 , 分隔
对象⽤ {} 表⽰
数组⽤ [] 表⽰
值可以为对象, 也可以为数组, 数组中可以包含多个对象
{"squadName": "Super hero squad","homeTown": "Metro City","formed": 2016,"secretBase": "Super tower","active": true,"members": [{"name": "Molecule Man","age": 29,"secretIdentity": "Dan Jukes","powers": ["Radiation resistance", "Turning tiny", "Radiationblast"]}, {"name": "Madame Uppercut","age": 39,"secretIdentity": "Jane Wilson","powers": ["Million tonne punch", "Damage resistance", "Superhuman reflexes"]}, {"name": "Eternal Flame","age": 1000000,"secretIdentity": "Unknown","powers": ["Immortality", "Heat Immunity", "Inferno",
"Teleportation", "Interdimensional travel"]}]
}
可以使⽤在线JSON格式化⼯具来进⾏校验和书写: 在线JSON校验格式化⼯具
1.9JSON字符串和Java对象互转
public class JSONUtils {private static ObjectMapper objectMapper = new ObjectMapper();public static void main(String[] args) throws JsonProcessingException {Person person = new Person();person.setId(5);person.setName("zhangsan");person.setPassword("123456");//对象转为JSON字符串String jsonStr = objectMapper.writeValueAsString(person);System.out.println("JSON字符串为:"+jsonStr);//JSON字符串转为对象Person p = objectMapper.readValue(jsonStr,Person.class);System.out.println("转换的对象
id:"+p.getId()+",name:"+p.getName()+",password:"+p.getPassword());}
}
使用ObjectMapper 对象提供的两个⽅法, 可以完成对象和JSON字符串的互转:
writeValueAsString: 把对象转为JSON字符串
readValue: 把字符串转为对象
1.10传递JSON对象
接收JSON对象, 需要使⽤ @RequestBody 注解
@RequestMapping("/r7")String r7(@RequestBody Person person){return person.toString();}
2.获取参数
2.1获取URL中参数@PathVariable
@RequestMapping("/article/{id}")String r8(@PathVariable() String id) {return "id: " + id;}
也可以变换参数名称:
@RequestMapping("/article/{articleId}")String r8(@PathVariable("articleId") String id) {return "id: " + id;}
2.2上传文件并接收到本地
使用@REquestPart
@RequestMapping("/r9")String r9(@RequestPart("userAgent") MultipartFile file) throws IOException {String fileName = file.getOriginalFilename();file.transferTo(new File("D:\\Test2" + fileName));return "接收文件名称为:" + fileName;}
接收文件并复制到本地文件夹
2.3获取Cookie/Session
cookie
当我们登录QQ时,并不是每一次需要输入账号密码进行验证,程序会根据用户之前登陆的信息直接进行登录,这就涉及了cookie及session的知识了。
上述图中的 "令牌" 通常就存储在 Cookie 字段中
此时在服务器这边就需要记录"令牌"信息, 以及令牌对应的⽤⼾信息, 这个就是 Session 机制所做的⼯作
我们使用抓包软件随便查看一个进程的cookie
其内部都存储一定信息,这就是cookie的作用
session
我们先来了解⼀下什么是会话.
会话: 对话的意思
在计算机领域, 会话是⼀个客⼾与服务器之间的不中断的请求响应. 对客⼾的每个请求,服务器能够识别出请求来⾃于同⼀个客⼾. 当⼀个未知的客⼾向Web应⽤程序发送第⼀个请求时就开始了⼀个会话.当客⼾明确结束会话或服务器在⼀个时限内没有接受到客⼾的任何请求时,会话就结束了
⽐如我们打客服电话
每次打客服电话, 是⼀个会话. 挂断电话, 会话就结束了
下次再打客服电话, ⼜是⼀个新的会话.
如果我们⻓时间不说话, 没有新的请求, 会话也会结束
Session是服务器为了保存⽤⼾信息⽽创建的⼀个特殊的对象
Session的本质就是⼀个 "哈希表", 存储了⼀些键值对结构. Key 就是SessionID, Value 就是⽤⼾信息(⽤⼾信息可以根据需求灵活设计)
获取cookie
@RequestMapping("/getCookie")String getCookie(HttpServletRequest request, HttpServletResponse response){Cookie[] cookies = request.getCookies();StringBuilder sb = new StringBuilder();for (Cookie cookie : cookies) {sb.append(cookie.getName() + ":" + cookie.getValue());}return "获取cookie:" + sb;}//简洁版@RequestMapping("/getCookie2")String getCookie2(@CookieValue("man") String bite) {return "man:" + bite;}
HttpServletRequest在有连接时直接使用(像String一样使用)
调用getCookies()方法获取cookie
从这个例⼦中, 也可以看出Cookie是可以伪造的, 也就是不安全的, 所以使⽤Cookie时, 后端需要进⾏ Cookie校验
设置Session
Session 存储和获取
Session是服务器端的机制, 我们需要先存储, 才能再获取
Session 也是基于HttpServletRequest 来存储和获取的
@RequestMapping("/setSession")String getSession(HttpServletRequest request) {HttpSession session = request.getSession();session.setAttribute("user",1);session.setAttribute("user",2);return "设置session";}
当调用request.getSession()时,如果没有session对象,那么系统将自动分配一个sessionId,然后再放回cookie中,再使用cookie访问session对象,获取session的信息
当然,也可以采用简化写法,既然如果没有session对象,那么系统将自动分配一个sessionId
.....那么我们直接声明一个 HttpSession session
@RequestMapping("/setSession2")String setSession2(String name, HttpSession session) {session.setAttribute("name","zhangsan");session.setAttribute("age",19);return "设置session";}
同样可以自动分配
此时我们再调用session
调用session
@RequestMapping("/getSession")String getSession(HttpServletRequest request) {HttpSession session = request.getSession(false);String name = (String)session.getAttribute("name");Integer age = (Integer)session.getAttribute("age");return "从session中获取信息 name:" + name + ",age:" + age;}
调用 session.getAttribute("name")...(因为有cookie,直接就可以调用上一步存储的信息)
这样我们就可以完成信息的保留 也就是会话
当然,也可以像刚才那样简化一下
@RequestMapping("/getSession2")String getSession2(HttpSession session) {String name = (String)session.getAttribute("name");Integer age = (Integer)session.getAttribute("age");return "从session中获取信息 name:" + name + ",age:" + age;}
还有封装的注解也可以调用session
@SessionAttribute("name")
@RequestMapping("/getSession3")String getSession3(@SessionAttribute("name") String name) {return "从session中获取信息 name:" + name;}
2.4获取header
首先,大家还记得header是什么吗?在网络编程的学习中,想必大家已经了解过,那么我来帮大家回忆一下。
header是以键值对的方式存储运输的,我们可以从HttpServletrequest中获取
@RequestMapping("/getHeader")String getHeader(HttpServletRequest request) {String userAgent = request.getHeader("user-agent");return "user-agent:" + userAgent;}
显然,获取成功了
同样也有简洁的获取方式:使用注解@RequestHeader
@RequestMapping("/getHeader2")String getHeader2(@RequestHeader("user-agent") String userAgent) {return "user-agent:" + userAgent;}
3.响应
3.1返回静态界面
返回一个html界面
html代码如下:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<h1>我是响应页面</h1>
</body>
</html>
后端代码:
@RequestMapping("/response")
@RestController
public class ResponseController {@RequestMapping("/r1")public String r1(){return "Response.html";}
}
我们看是否可以获得到界面
并没有得到想要的结果,只打印了这几个字
这是为什么呢?
我们先将@RequestController替换为@Controller看一下结果
@RequestMapping("/response")
@Controller
public class ResponseController {@RequestMapping("/r1")public String r1(){return "/Response.html";}
}
@RestController 和 @Controller 有着什么样的关联和区别呢?
再回到MVC的概念:
随着互联⽹的发展, ⽬前项⽬开发流⾏"前后端分离"模式, Java主要是⽤来做后端项⽬的开发, 所以也就不再处理前端相关的内容了
MVC的概念也逐渐发⽣了变化, View不再返回视图, ⽽是返回显⽰视图时需要的数据.
所以前⾯使⽤的 @RestController 其实是返回的数据
@RestController = @Controller + @ResponseBody
通过查看@RestController的源码
可以得到:
如果想返回视图的话, 只需要把 @ResponseBody 去掉就可以了, 也就是 @Controller
3.2返回数据@ResponseBody
我们上⾯讲到, @ResponseBody 表⽰返回数据
@RequestMapping("/response")
@Controller
@ResponseBody
public class ResponseController {@RequestMapping("/r1")public String r1(){return "/Response.html";}
}
加上 @ResponseBody 注解, 该⽅法就会把 "/index.html" 当做⼀个数据返回给前端
@ResponseBody 既是类注解, ⼜是⽅法注解
如果作⽤在类上, 表⽰该类的所有⽅法, 返回的都是数据, 如果作⽤在⽅法上, 表⽰该⽅法返回的是数据.
也就是说: 在类上添加 @ResponseBody 就相当于在所有的⽅法上添加了 @ResponseBody 注解.
同样, 如果类上有 @RestController 注解时:表⽰所有的⽅法上添加了 @ResponseBody 注
解, 也就是当前类下所有的⽅法返回值做为响应数据
如果⼀个类的⽅法⾥, 既有返回数据的, ⼜有返回⻚⾯的, 就把 @ResponseBody 注解添加到对应的⽅法上即可
注意:多个注解时, 没有先后顺序, 先写哪个都可以
如果返回值不加 / ,注解会寻找不到该路径的文件报404错误(也就是写了路径名不存在的对象)
@RequestMapping("/response")
@Controller
public class ResponseController {@RequestMapping("/r1")public String r1(){return "Response.html";}
}
3.3返回HTML正文
后端返回数据时, 如果数据中有HTML代码, 也会被浏览器解析
@RequestMapping("/r2")public String r2() {return "<h1>Response</h1>";}
3.4返回JOSN
@RequestMapping("/returnJosn")@ResponseBodypublic HashMap<String, String> returnJson(){HashMap<String, String> map = new HashMap<>();map.put("name", "bit");map.put("age", "18");return map;}
3.5设置状态码
Spring MVC会根据我们⽅法的返回结果⾃动设置响应状态码, 程序员也可以⼿动指定状态码
通过Spring MVC的内置对象HttpServletResponse 提供的⽅法来进⾏设置
@RequestMapping("setStatus")@ResponseBodypublic String setStatus(HttpServletResponse response) {response.setStatus(401);return "设置状态码";}