一.SpringMVC常用注解
1.1.@RequestMapping
@RequestMapping注解是一个用来处理请求地址映射的注解,可用于映射一个请求或一个方法,可以用在类或方法上。
标注在方法上运行代码
用于方法上,表示在类的父路径下追加方法上注解中的地址将会访问到该方法
@Controller public class HelloController { @RequestMapping("/requestTest") public String requestTest(){ return "success"; } }
此时请求映射所映射的请求的请求路径为:
http://localhost:8080/springmvc01/requestTest
springmvc01表示项目名
- 标注在类和方法上
用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
注意:当你在类上添加RequestMapping注解后,如果要请求映射,就意味着请求要先映射到标注类的位置,然后再映射到该类的方法上
@Controller @RequestMapping("/hello") public class HelloController { @RequestMapping("/requestTest") public String requestTest(){ return "success"; } }
此时请求映射所映射的请求的请求路径为:
http://localhost:8080/springmvc01/hello/requestTest
springmvc01表示项目名
- 参数列表
示例一:@RequestMapping的params属性
@RequestMapping(value = "/test",params = "username") public String test(){ return "success"; }
注意:我们设置了params属性,就意味着该请求映射的请求必须包含username才能够请求成功。
示例二:@RequestMapping的headers属性
@RequestMapping(value = "/test",headers = "Host = localhost:8081") public String test(){ return "success"; }
注意:如果当前请求不满足headers属性,此时页面就会显示404错误,即资源未找到。
扩展:
@GetMapping:处理get方式请求的映射 @PostMapping:处理post方式请求的映射 @PutMapping:处理put方式请求的映射 @DeleteMapping:处理delete方式请求的映射 @GetMapping就相当于@RequestMapping(method=RequestMethod.GET),它会将get映射到特定的方法上。
1.2.@RequestParam
@RequestParam主要用于将请求参数区域的数据映射到控制层方法的参数上
示例:
@RequestMapping("/queryBooks") public List<Book> queryBooks( @RequestParam(required = false,defaultValue = "0",value="page") int page, @RequestParam(required = false,defaultValue = "10",value = "rows") int rows){ return bookService.queryBooks(page,rows); }
1.3.@ModelAttribute
@ModelAttribute一个具有如下三个作用:
绑定请求参数到命令对象:放在功能处理方法的入参上时,用于将多个请求参数绑定到一个命令对象,从而简化绑定流程,而且自动暴露为模型数据用于视图页面展示时使用;
暴露表单引用对象为模型数据:放在处理器的一般方法(非功能处理方法)上时,是为表单准备要展示的表单引用对象,如注册时需要选择的所在城市等,而且在执行功能处理方法(@RequestMapping注解的方法)之前,自动添加到模型对象中,用于视图页面展示时使用;
暴露@RequestMapping方法返回值为模型数据:放在功能处理方法的返回值上时,是暴露功能处理方法的返回值为模型数据,用于视图页面展示时使用。
示例一:绑定请求参数到命令对象
如用户登录,我们需要捕获用户登录的请求参数(用户名、密码)并封装为用户对象,此时我们可以使用@ModelAttribute绑定多个请求参数到我们的命令对象。
public String test1(@ModelAttribute("user") UserModel user)
它的作用是将该绑定的命令对象以“user”为名称添加到模型对象中供视图页面展示使用。我们此时可以在视图页面使用${user.username}来获取绑定的命令对象的属性。
示例二:暴露表单引用对象为模型数据
@ModelAttribute public void init(Model model){ model.addAttribute("book",new Book()); }
如上代码会在执行功能处理方法之前执行,并将其自动添加到模型对象中。
@RequestMapping("/toBookList") public String toBookList(){ System.out.println("toBookList"); return "book/bookList"; }
示例三:暴露@RequestMapping方法返回值为模型数据
@ModelAttribute注解的返回值会覆盖@RequestMapping注解方法中的@ModelAttribute注解的同名命令对象。
public @ModelAttribute("user2") UserModel test3(@ModelAttribute("user2") UserModel user)
1.4.@SessionAttributes
在默认情况下,当ModelMap中的属性作用域是request级别时,也就是说,当本次请求结束后,ModelMap中的属性将销毁。如果希望在多个请求中共享ModelMap中的属性,必须将其属性转存到session中,这样ModelMap的属性才会被跨请求访问;
spring允许我们有选择地指定ModelMap中的哪些属性需要转存到session中,以便下一个请求属对应的ModelMap的属性列表中还能访问到这些属性。
SpringMVC为我们提供这样一个注解来实现上面的场景:@SessionAttributes:将ModelMap的属性值共享到session中。
注意:@SessionAttributes注解只能使用在类上,用于在多个请求之间传递参数,类似于Session的Attribute,但不完全一样,一般来说@SessionAttributes设置的参数只用于暂时的传递(存入sessionAttributeStore),而不是长期的保存,长期保存的数据还是要放到Session中。
有两种方式将ModelMap中的属性值共享到session中:
1.使用注解的value属性:可以通过属性名指定需要放到会话中的属性;
@Controller @SessionAttributes("user") //将ModelMap中key为user的属性共享到session中 public class DemoController { @RequestMapping("/hello") public String hello(ModelMap model) { //向ModelMap中添加key为user和user1的属性 model.addAttribute("user", new User(520, "U love me")); model.addAttribute("user1", new User("I love U")); return "result"; } }
2.使用注解的types属性:还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中。
@SessionAttributes(types = {User.class}) @Controller public class DemoController{ @RequestMapping("/hello") public String hello(Map<String, Object> map){ map.put("user1", new User(520, "U love me")); return "hello"; } }
1.5.@RequestBody
@RequestBody主要用来接收前端传递给后端的json字符串中的数据的(即请求体中的数据的);
GET方式无请求体,所以使用@RequestBody接收数据时,前端不能使用GET方式提交数据,而是用POST方式进行提交。在后端的同一个接收方法里,@RequestBody与@RequestParam()可以同时使用,@RequestBody最多只能有一个,而@RequestParam()可以有多个。
简言之:
一个请求:只有一个@RequestBody;
一个请求:可以有多个@RequestParam。
Content-type: (1)application/x-www-form-urlencoded:@RequestBody不是必须加的 (2)mutipart/form-data:@RequestBody不能处理这种格式 (3)其他格式,比如application/json,application/xml等,必须使用@RequestBody来处理
@RequestMapping("/hello") public String toHello1(@RequestBody Book book){ log.info(">>>> 使用@RequestBody传递JSON格式的参数:{}", JSON.toJSONString(book)); return "index"; }
@RequestBody注解对应的类在将HTTP的输入流(含请求体)装配到目标类(即:@RequestBody后面的类)时,会根据json字符串中的key来匹配对应实体类的属性,如果匹配一致且json中的该key对应的值符合(或可转换为)实体类的对应属性的类型要求时,会调用实体类的setter方法将值赋给该属性。
1.6.@RequestHeader
使用 @RequestHeader 注解可以获取指定的请求头信息。如果想要获取所有的请求头信息,可以使用 Map<String,String>、MultiValueMap<String,String>、HttpHeaders 这三个 Map 中的任何一个封装所有请求头的 name 和 value。
参数列表
示例:
@GetMapping("/headParams") public Map userInfo( @RequestHeader(value = "zking",defaultValue = "hello zking") String username, // 将请求头中 name=Accept-Encoding 赋值给形参 encoding @RequestHeader("Accept-Encoding") String encoding, // 将请求头中 name=Host 赋值给形参 host @RequestHeader("Host") String host, // 将所有请求头的 name 和 value 封装到 Map 集合 headsMap 中 @RequestHeader Map<String,String> headsMap) { Map map = new HashMap<String, Object>(); map.put("username",username); map.put("Accept-Encoding",encoding); map.put("Host",host); map.put("headsMap",headsMap); return map; }
由于请求头中不存在 name=zking 这个信息,所以如果只用 value=zking 会抛出异常。
解决方案: 1、required 的默认值为 true ,也就是请求头中没有 name=zking 会报错,将其值改为 false,即没有该头信息也不报错
@RequestHeader(value = "zking",required = "false") String username
2、不修改 required=true 这个默认值,当头信息中不包含 name=zking ,给它一个默认值 hello zking
@RequestHeader(value = "zking",defaultValue = "hello zking") String username
1.7.@PathVariable
该注解请求URI中的模板变量部分到处理器功能处理方法的方法参数上的绑定。
即当使用@RequestMapping URI template 样式映射时, 即 someUrl/{paramId}, 这时的paramId可通过 @Pathvariable注解绑定它传过来的值到方法的参数上。
//@PathVariable可以用来映射URL中的占位符到目标方法的参数中 @RequestMapping("/testPathVariable/{id}") public String testPathVariable(@PathVariable("id") Integer id) { System.out.println("testPathVariable:"+id); return SUCCESS; }
Rest
即 Representational State Transfer。(资源)表现层状态转化。是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。
资源(Resources):网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的 URI 。要获取这个资源,访问它的URI就可以,因此 URI 即为每一个资源的独一无二的识别符。
表现层(Representation):把资源具体呈现出来的形式,叫做它的表现层(Representation)。比如,文本可以用 txt 格式表现,也可以用 HTML 格式、XML 格式、JSON 格式表现,甚至可以采用二进制格式。
状态转化(State Transfer):每发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“状态转化”(State Transfer)。而这种转化是建立在表现层之上的,所以就是 “表现层状态转化”。具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。
示例:
- /order/1 HTTP GET :得到 id = 1 的 order - /order/1 HTTP DELETE :删除 id = 1 的 order - /order/1 HTTP PUT :更新 id = 1 的 order - /order HTTP POST :新增 order
1.8.@CookieValue
@CookieValue注解主要是将请求的Cookie数据,映射到功能处理方法的参数上。
参数列表
示例:
@RequestMapping("/testCookieValue") public Map<String, Object> testCookieValue( @CookieValue("JSESSIONID") String cookie) { response.put("cookie", cookie); return response; }
二.SpingMVC的参数传递
1.简单类型参数
package com.YU.web; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; /** * @author YU * @create 2023-09-05 15:14 */ @Slf4j @Controller @RequestMapping("/param") public class ParamController { @RequestMapping("/hello1") public String index(String bname,Integer bid) { log.info("简单类型参数:bname:{},bid:{}",bname,bid); return "index"; } }
这里我们通过在地址栏输入携带的参数进行访问,通过日志信息查看是否将参数传递到前端页面
日志信息:
由日志信息可得知,我们的简单类型参数通过前端地址栏可以进行传输到后台
2. 复杂类型参数
@RequestMapping("/hello2") public String index2(Book book, HttpServletRequest request) { //原生Servlet获取参数 log.info("复杂类型参数:bname:{},bid:{}", request.getParameter("bname"), request.getParameter("bid")); //复杂传参 log.info("复杂类型参数:book:{}",book.toString()); return "index"; }
这里我们通过复杂传参对比原生Servlet传参
访问地址栏带参数:
日志信息:
由此我们可以得出,传参时可以将对象直接进行传递,通过对象获取对应属性
3. requestParam传参
@RequestMapping("/hello3") public String index3( @RequestParam String bname, @RequestParam(required =false) Integer bid) { //@requestParam参数 log.info("@requestParam参数:bname:{},bid:{}",bname,bid); return "index"; }
我们将字段bname加上@RequestParam注解,这样当我们在访问时必须携带bname参数
@RequestParam传参可以对参数进行限制,必须携带或者可以不携带
4.PathVariable路径传参
@RequestMapping("/hello4/{bid}") public String index4(@PathVariable("bid") Integer bid) { //@PathVariable log.info("@PathVariable: bid:{}",bid); return "index"; }
我们可以通过在地址栏的路径中进行传参,而不是用变量去携带某一个参数
日志信息:
5.RequestBody传参
@RequestMapping("/hello5") public String index5(Map map) { //@PathVariable log.info("@RequestBody: map:{}",map); return "index"; } @RequestMapping("/hello6") public String index6(@RequestBody Map map) { //@PathVariable log.info("@RequestBody: map:{}",map); return "index"; }
这里我们列出两种情况进行对比,第一个是没有@RequestBody注解的,第二个有@RequestBody注解
1.这里我们使用Eolink进行发送请求,首先是对hello6进行发送请求(有@RequestBody注解)
日志信息结果:
2.然后对hello5(无@RequestBody注解)
日志信息结果:
结论:
当我们需要去传递json格式数据时,需要用到RequestBody注解进行传递,否则请求时响应不到结果
6.RequestHeader传参
@RequestHeader是对请求头进行传参获取响应数据
@RequestMapping(value = "/hello7") public String index7(@RequestHeader("jwt") String jwt) { //@PathVariable log.info("@RequestHeader: jwt:{}",jwt); return "index"; }
我们在对该路径进行传参响应的时候设置请求头信息
日志信息:
7.总结集成所有常用类型传参
@RequestMapping(value = "/hello8") public String index8( Book book, @RequestBody Map map, @RequestHeader("jwt") String jwt) { //@PathVariable log.info("@RequestHeader: jwt:{}",jwt); return "index"; }
请求体中的json数据(Map)
Query参数(对象Book)
请求头参数
最终日志信息结果:
结论
常用的传参方式可以一起使用包括请求头传参,复杂传参,RequestHeader传参