如下图京东购物页面,当我们选择点击访问某一类商品时,就会向后端发起 HTTP 请求,当后端收到请求时,就会找到对应的代码逻辑对请求进行处理,那么,后端是如何来查找处理请求相对应的代码呢?答案就是:通过注解来寻找,同时,注解也有其他很多的功能,也分成了很多的注解,下面就来讲解一些网站开发中,一些常见的,使用频率比较高的注解。
文章目录
- 建立连接
- 使用注解处理请求
- 传递单个参数
- 传递多个参数
- 后端参数重命名(@RequestParam)
- 传递对象
- 传递数组
- 传递集合
- 传递 JSON 数据
- JSON 字符串和 JAVA 对象的互转
- 获取 URL 中的参数(@PathVariable)
- 上传文件(@RequestPart)
- 获取 Cookie
- 获取 Session
- 获取 Header
- 处理响应
- 返回静态页面
- @ResponseBody
- 响应中 body 的类型
- 设置状态码
建立连接
既然 客户端 和 服务器 想要进行交互,就需要先建立起连接,而这个建立连接,就相当于在客户端和服务器之间建立了一个桥梁,能够让客户端发起的请求,通过这个桥梁,找到后端对应的处理请求的代码,所以就需要使用以下两个注解:
- @RequestMapping
- @RestController
- @RequestMapping
@RequestMapping 是 Spring MVC 中最常用的注解之一,用来进行路由映射。
路由映射:当用户访问一个 URL 时,将用户的请求对应到后端代码中的某一个类中的某一个方法。
例如:当服务器收到请求为 127.0.0.1:8080/m1 时,在后端就会映射到 /m1 所修饰的方法,然后进行处理,返回响应,如下图:
????注意:
@RequestMapping 中进行映射的参数不需要一定和方法名相同,但是,一定要和URL中的相同
既然有 @RequestMapping 了,那么为什么还要使用 @RestController 呢?
因为,当客户端发来请求时,Spirng 会根据请求扫描后端的代码,从而找到处理请求所对应的方法,但是,在扫描时,只会对 Spring 管理的对象进行扫描,所以,@RestController 注解其中一个作用就是,将该类交给 Spring 管理。
@RequestMapping 既可以修饰方法,也可以修饰类,如下图:
- @RequestMapping 修饰类时,表示请求路径的初始信息
- @RequestMapping 修饰方法时,表示请求路径的具体信息
- RequestMapping 同时修饰类和方法时,访问时的路径就是 类路径 + 方法路径
最好是同时修饰类和方法,因为,根据请求调用对应的方法时,如果没有使用 @RequestMapping 修饰类的话,会在所有的类中逐个寻找,会拉低效率,没有修饰方法的,反之,@RequestMapping 修饰类,会先根据路径的初始信息确定是哪个类,然后在这一个类中寻找。
????注意:路径中,加不加 ‘/’ 都可以,但习惯上都是会加上
使用注解处理请求
传递单个参数
以下的讲解,均使用 Postman 工具来模拟前端发送的请求。
@RestController
@RequestMapping("/main1")
public class Main1 {
@RequestMapping("/m1")
public String m1(String name){
return "name:" + name;
}
}
????注意:
????注意:当传递的参数为基本数据类型,在后端接受时,尽量使用包装类型,否则可能会出现 500 这样的错误,如下图:
如下图,后端的形参为基本数据类型时,在不进行传参的情况下,就会报错。
将形参改换成包装类,即使前端不进行传参,后端也不会报错,如下图:
传递多个参数
@RequestMapping("/m2")
public String m2(String userName, Integer password) {
return "userName:" + userName + "\npassword:" + password;
}
????注意:当有多个参数时,前后端进行参数匹配时,是根据参数名进行匹配的,和参数的顺序无关
@RequestMapping 处理的是 GET 请求,还是 POST 请求呢?
下面通过实验来验证:
验证方法:通过 Postman 工具发送请求
1 . 发送 GET 请求
- 发送 POST 请求
结论:从上述演示结果得出,@RequestMapping 既支持 GET 请求,又支持 POST 请求。
那么,如果想要指定只能接收 GET / POST 请求时,可以对 @RequestMapping 进行参数设置,将 method 设置成指定的请求方法,如下图:
限制后端只能接收 GET 请求,发送POST请求就会报错
@RequestMapping(value = "/m1",method = RequestMethod.GET)
public String m1(Integer age){
return "age:" + age;
}
后端参数重命名(@RequestParam)
上面讲过,请求中的参数名必须和方法的形参名相同,否则无法获取到请求中的参数,但是,如果想要两者不相同,可以使用 @RequestParam 注解,如下图:
@RestController
@RequestMapping("/main1")
public class Main1 {
@RequestMapping("/m1")
public String m1(@RequestParam("name") String NAME){
return "name:" + NAME;
}
}
????注意:当使用 @RequestParam 进行修饰时,为必传参数,如果前端不传参数,那么就会报错,如下图:
解决办法:将 @RequestParam 中的 required 参数,设置为 false,即使不传参,也不会报错
传递对象
- 先创建一个 User 对象
public class User {
private String name;
private Integer age;
private Integer id;
public String getName(String name) {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", id=" + id +
'}';
}
}
- 设置形参类型为 User
@RequestMapping("/m3")
public String m3(User user) {
return user.toString();
}
传递数组
@RequestMapping("/m4")
public String m4(String[] array) {
return Arrays.toString(array);
}
传递数组时,形参同样也可以使用@RequestParam进行重命名
传递集合
当传递的参数有多个值时,默认情况下是封装到数组中的,如果想要封装到集合中,需要使用 @RequestParam 注解进行绑定,如下图:
@RequestMapping("/m5")
public String m5(@RequestParam List<String> list) {
return list.toString();
}
传递 JSON 数据
JSON就是⼀种数据格式,有⾃⼰的语法,它是使⽤⽂本表⽰⼀个对象或数组的信息,因此JSON本质是字符串.主要负责在不同的语⾔中进行数据传递和交换.
JSON 字符串和 JAVA 对象的互转
**在不使用SpringMVC的情况下,进行互转需要引入jackson依赖,但在Spring MVC框架中,已经把这个依赖给引入进来了,所以我们直接使用即可 **
jackson-databind 依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.5</version>
</dependency>
- 不使用注解的情况
@RequestMapping("/m6")
public String m6() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
User user = new User();
user.setName("李四");
user.setAge(18);
user.setId(1);
//JAVA 对象转 JSON 字符串
String json = objectMapper.writeValueAsString(user);
System.out.println(json);
//JSON 字符串转 JAVA 对象
User user1 = objectMapper.readValue(json, User.class);
System.out.println(user1.toString());
return "转换成功";
}
- JSON 字符串转成 JAVA 对象,使用 readValue()
- JAVA 对象转成 JSON 字符串,使用writeValueAsString()
-
使用 @RequestBody 注解
将客户端传来的 json 对象转换成 Java 对象
@RequestMapping("/m7")
public String m7(@RequestBody User user){
return user.toString();
}
获取 URL 中的参数(@PathVariable)
这个注解的作用是获取请求URL中的参数,如下图:
@RequestMapping("/m8/{name}/{age}")
public String m8(@PathVariable String name, @PathVariable Integer age){
return "name:" + name + ",age" + age;
}
- 方法的形参名和URL中的变量名一致时,不需要给 @PathVariable 中的Value属性赋值,不一致时,则需要进行赋值,类似于重命名操作
@RequestMapping("/m8/{name}/{age}")
public String m8(@PathVariable String name, @PathVariable("age") Integer AGE){
return "name:" + name + ",age" + AGE;
}
上传文件(@RequestPart)
@RequestMapping("/m9")
//如果后端参数的名字和请求中的参数名字不一致,可以在注解中重命名
public String m9(@RequestPart("file")MultipartFile file) throws IOException {
//获取文件名称
String fileName = file.getOriginalFilename();
//文件上传到指定路径
file.transferTo(new File("D:/gitee/" + fileName));
return "接收到的文件名称为:" + fileName;
}
获取 Cookie
1.传统方式获取Cookie
@RequestMapping("/getCookie1")
public String getCookie1(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
StringBuilder stringBuilder = new StringBuilder();
//判断 cookies 是否为空
if(cookies != null) {
for(Cookie cookie : cookies) {
stringBuilder.append(cookie.getName() + ":" + cookie.getValue() );
}
return stringBuilder.toString();
}
retu
Spring MVC 是基于Servlet API 构建的原始web框架,是在Servlet 的基础上实现的,而 HttpServletRequest ,HttpServletResponse 是Servlet 实现的两个类,所以,是 SpringMVC的方法的内置对象,需要使用时,直接在方法中添加声明即可;
HttpServletRequest 对象代表客户端的请求,当客户通过Http协议进行访问时,HTTP请求头中所有的信息都被封装到了这个对象中,通过这个对象提供的方法,即可获得请求头中的信息;
HttpServletResponse 对象代表了服务端的响应,Http 响应的信息都被封装到了这个对象中,通过这个对象提供的方法,即可获取到对应得信息,例如:状态码
2.简洁方式获取Cookie
使用 @CookieValue 注解
@RequestMapping("/getCookie2")
public String getCookie2(@CookieValue("cookie1") String cookie) {
return "cookie:" + cookie;
}
这两种方式的不同点在于,使用传统方式,可以获取到所有的Cookie 内容,使用注解的方式,只能获取到指定的Cookie;
获取 Session
在获取Session之前,需要先设置Session
//设置session
@RequestMapping("/setSession")
public String setSession(HttpServletRequest request) {
HttpSession session = request.getSession();
if(session != null) {
session.setAttribute("userName", "张三");
}
return "session 设置成功";
}
- 传统方式获取Session
//传统方式获取session
@RequestMapping("/getSession1")
public String getSession1(HttpServletRequest request) {
HttpSession session = request.getSession();
if(session != null) {
String userName = (String)session.getAttribute("userName");
return "userName:" + userName;
}
return "Session为空";
}
HttpServletRequest 提供两个获取Session的方法:
- getSession(boolean flag)
- getSession()
getSession(boolean flag),当flag为true时,服务器就算没有Session,该方法也会自动创建一个空的Session,不会发生Session为null的情况;当flag为false时,如果服务器没有Session,该方法不会自动创建Session,会返回一个null。
getSession() 默认情况下为 true
- 简介方式(1)获取Session
//简介方式(1)获取session
@RequestMapping("/getSession2")
public String getSession2(HttpSession session) {
if(session != null) {
String userName = (String)session.getAttribute("userName");
return "userName:"+userName;
}
return "没有指定的session值";
}
直接使用内置对象 HttpSession,默认情况也是 true
- 简介方式(2)获取Session
@RequestMapping("/getSession3")
public String getSession3(@SessionAttribute(value = "userName", required = false) String userName) {
if(userName == null) {
return "Session为空";
}
return "userName:" + userName;
}
这是使用注解的方式,value值代表了要获取的Session,,required 值代表了在没有Session的情况下,是否要自动创建;
获取 Header
1.传统获取 Header
获取 Header 也是从 HttpServletRequest 中获取,代码如下:
//获取header值
@RequestMapping("/getHeader1")
public String getHeader(HttpServletRequest request) {
String header = request.getHeader("user-Agent");
return "user-Agent:" + header;
}
getHeader() 方法中的参数值代表的是请求头中的键值对中的“key”。
下图通过 Fiddler 抓包可以看到,使用浏览器发送请求时,请求头中的“user-Agent”值,正是我们通过代码获取到的。
2.简洁方式@RequestHeader
@RequestMapping("/getHeader2")
public String getHeader(@RequestHeader("user-Agent") String header) {
return "user-Agent:" + header;
}
注解中的参数表示的是请求头中的“key”
处理响应
在上面的代码中,我们演示了针对请求的处理以及请求头的设置,并且响应的都是我们设置的数据,而响应不仅仅可以是数据,也可以是静态页面,也可以针对响应设置响应码,响应头等
返回静态页面
1.先创建出一个静态页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Index⻚⾯</title>
</head>
<body>
Hello,Spring MVC,我是Index⻚⾯.
</body>
</html>
静态页面代码或者是前端代码,需要保存在static中
接下来通过代码获取静态页面:
@RestController
@RequestMapping("/main2")
public class Main2 {
@RequestMapping("/getIndex")
public String getIndex() {
return "/index.html";
}
}
通过响应可以看出来,我们想要的是一个静态页面,但是它给我们返回的却是一个数据,那怎么样才能让MVC给我们返回一个页面呢?
解决方法:将 @RestContrlller 修改成 @Controller
@Controller
@RequestMapping("/main2")
public class Main2 {
@RequestMapping("/getIndex")
public String getIndex() {
return "/index.html";
}
}
@RestController 和 Controller 有什么联系呢?
随着互联网的发展,前后端分离的开发方法方式成为主流,后端人员不需要再关注前端代码,只需要将后端处理过的数据返回即可;
@RestController 表示的就是返回一个数据
@RestController = @Controller + @RequestBody
@Controller 表示定义一个控制器,在项目启动时,将@Controller修饰的对象交给Spring管理
@ResponseBody 定义返回的数据为非视图,而是数据
以下是 @RestController 的源码:;
可以看到,RestController 是被 @Controller 和 @ResponseBody 修饰的,想要返回页面,去掉 @ResponseBody 即可,也就是@Controller
@ResponseBody
@ResponseBody 即是类注解,也是方法注解,当@ResponseBody 修饰类时,表示该类所有的方法返回的都是数据,修饰单个方法时,表示该方法返回的是数据。所以,使用@RestController 修饰时,表示所有的方法都加上了@ResponseBody ,所以返回的都是数据,如果在一个类中,既有返回页面和数据的,就可以使用@Controller 修饰类,在需要返回数据的方法上使用 @ResponseBody 进行修饰即可;
响应中 body 的类型
如果代码中含有 html 片段,在返回时,返回的数据类型也自动设置成 html 类型
@RestController
@RequestMapping("/main2")
public class Main2 {
@RequestMapping("/getHtml")
public String getHtml() {
return "<h1>Hello,HTML~</h1>";
}
}
响应中的Content-type 类型可以根据响应的数据类型,自动进行设置,响应中的 Content-Type 的类型主要分为以下几种:‘
如果请求的是html文件,body数据格式就是 html,上面已经演示过
如果请求的是 js 文件,那么响应中 body 的数据类型就是 application/JavaScript
如果请求的是 css 文件,那么响应中 body 的数据类型就是 application/css
@Controller
@RequestMapping("/main2")
public class Main2 {
@RequestMapping("/getCss")
public String getCss() {
return "/b.css";
}
}
在上面的传递json标题中,已经讲解了如何使用 ObjectMapper 类 将java对象转成json格式数据,这只是转json的一种方法,如果返回的数据是 哈希表,body 也是 json 格式,如下代码:
@ResponseBody
@RequestMapping("/getMap")
public Map<String,Integer> getMap() {
Map<String, Integer> map = new HashMap<>();
map.put("张三", 10);
map.put("李四", 11);
map.put("王五", 12);
return map;
}
设置状态码
使用MVC中内置的 HttpServletResponse对象提供的方法对响应中的状态码进行设置,代码如下:
@RequestMapping("setStatus")
public String setStatus(HttpServletResponse response) {
response.setStatus(404);
return "/index.html";
}
有人可能就会有疑问了,状态码不是已经设置成了 404 吗,为什么还能够访问到页面,这里需要注意,返回的页面和404是没有任何关系的,就比如我们发起请求后,在后端找不到对应的代码,就会返回一个404页面,还有,例如在哔哩哔哩上,我们发起一个错误的请求,它就会给我们返回一个哔哩哔哩的404页面,如下图: