Springboot笔记<6>Rest的使用和请求参数注解@PathVariable、@RequestHeader、@ModelAttribute、@RequestParam、@MatrixVariable、@CookieValue、@RequestBody
Rest的使用和原理
Rest风格支持(使用HTTP请求方式动词来表示对资源的操作)
• 以前:/getUser 获取用户 /deleteUser 删除用户 /editUser 修改用户 /saveUser 保存用户
• 现在: /user GET-获取用户 DELETE-删除用户 PUT-修改用户 POST-保存用户。
看下面的一个例子,这是一个表单:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hah</title>
</head>
<body>
<form action="/user" method="get">
<input value="get" type="submit">
</form>
<form action="/user" method="post">
<input value="post" type="submit">
</form>
<form action="/user" method="post">
<input value="put" type="submit">
</form>
<form action="/user" method="post">
<input value="delete" type="submit">
</form>
</body>
</html>
处理上述表单提交的controller。但是我们以put方式和delete方式提交表单时,发现返回的都是GET-张三,不支持put和delete请求。
@RestController
public class UserController {
@RequestMapping(value = "/user",method = RequestMethod.GET)
public String getUser(){
return "GET-张三";
}
@RequestMapping(value = "/user",method = RequestMethod.POST)
public String saveUser(){
return "POST-张三";
}
@RequestMapping(value = "/user",method = RequestMethod.PUT)
public String putUser(){
return "PUT-张三";
}
@RequestMapping(value = "/user",method = RequestMethod.DELETE)
public String deleteUser(){
return "DELETE-张三";
}
}
在WebMvcAutoConfiguration中hiddenHttpMethodFilter方法,返回一个filter->OrderedHiddenHttpMethodFilter。OrderedHiddenHttpMethodFilter继承自HiddenHttpMethodFilter。@ConditionalOnMissingBean({HiddenHttpMethodFilter.class})需要之前HiddenHttpMethodFilter没有被注入,并且 @ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = {"enabled"})要求spring.mvc.hiddenmethod.filter.enabled=true.
@Bean
@ConditionalOnMissingBean({HiddenHttpMethodFilter.class})
@ConditionalOnProperty(
prefix = "spring.mvc.hiddenmethod.filter",
name = {"enabled"}
)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
public class OrderedHiddenHttpMethodFilter extends HiddenHttpMethodFilter implements OrderedFilter {
/**
* The default order is high to ensure the filter is applied before Spring Security.
*/
public static final int DEFAULT_ORDER = REQUEST_WRAPPER_FILTER_MAX_ORDER - 10000;
private int order = DEFAULT_ORDER;
@Override
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
}
HiddenHttpMethodFilter中有个DEFAULT_METHOD_PARAM字段"_method"。所以我们在提交表单时也要提交一个"_method"参数。并且spring.mvc.hiddenmethod.filter.enabled=true.
public class HiddenHttpMethodFilter extends OncePerRequestFilter {
private static final List<String> ALLOWED_METHODS =
Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(),
HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));
public static final String DEFAULT_METHOD_PARAM = "_method";
private String methodParam = DEFAULT_METHOD_PARAM;
public void setMethodParam(String methodParam) {
Assert.hasText(methodParam, "'methodParam' must not be empty");
this.methodParam = methodParam;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
HttpServletRequest requestToUse = request;
if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
String paramValue = request.getParameter(this.methodParam);
if (StringUtils.hasLength(paramValue)) {
String method = paramValue.toUpperCase(Locale.ENGLISH);
if (ALLOWED_METHODS.contains(method)) {
requestToUse = new HttpMethodRequestWrapper(request, method);
}
}
}
filterChain.doFilter(requestToUse, response);
}
private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
private final String method;
public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
super(request);
this.method = method;
}
@Override
public String getMethod() {
return this.method;
}
}
}
因此修改表单如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hah</title>
</head>
<body>
<form action="/user" method="get">
<input value="get" type="submit">
</form>
<form action="/user" method="post">
<input value="post" type="submit">
</form>
<form action="/user" method="post">
<input name="_method" type="hidden" value="put">
<input value="put" type="submit">
</form>
<form action="/user" method="post">
<input name="_method" type="hidden" value="delete">
<input value="delete" type="submit">
</form>
</body>
</html>
配置yaml:
spring:
mvc:
hiddenmethod:
filter:
enabled: true #开启页面表单的Rest功能
修改表单,配置yaml之后,再点击delete 和put就可以发送delete 和put请求了。
Rest原理
表单提交要使用REST的时候:
表单提交会带上_method=PUT
请求过来被HiddenHttpMethodFilter拦截
1.如果请求正常,并且是POST(if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) )则获取_method的值
- 2.获取到_method的值,如果是ALLOWED_METHODS里的方法(PUT.DELETE.PATCH)则将方法传给包装模式类requesWrapper,requesWrapper只改变了请求方式。
原生request(post),包装模式requesWrapper重写了getMethod方法,返回的是传入的值。
过滤器链放行的时候用wrapper。以后的方法调用getMethod是调用requesWrapper的。
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
HttpServletRequest requestToUse = request;
if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
// paramValue拿到的是_method
String paramValue = request.getParameter(this.methodParam);
if (StringUtils.hasLength(paramValue)) {
String method = paramValue.toUpperCase(Locale.ENGLISH);
if (ALLOWED_METHODS.contains(method)) {
requestToUse = new HttpMethodRequestWrapper(request, method);
}
}
}
filterChain.doFilter(requestToUse, response);
}
private static final List<String> ALLOWED_METHODS =
Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(),
HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));
requesWrapper:
private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
private final String method;
public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
super(request);
this.method = method;
}
@Override
public String getMethod() {
return this.method;
}
}
将_method改成其他名字
将_method改成了_m,此时因为程序中无法获取_m,所以我们表单中点击delete依然是post,因此我们需要再更改表单即可。
//自定义filter
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.HiddenHttpMethodFilter;
@Configuration(proxyBeanMethods = false)
public class RestConfig {
@Bean
public HiddenHttpMethodFilter hiddenHttpMethodFilter(){
HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();
methodFilter.setMethodParam("_m");
return methodFilter;
}
}
修改form表单,添加_m:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hah</title>
</head>
<body>
<form action="/user" method="get">
<input value="get" type="submit">
</form>
<form action="/user" method="post">
<input value="post" type="submit">
</form>
<form action="/user" method="post">
<input name="_method" type="hidden" value="put">
<input name="_m" type="hidden" value="put">
<input value="put" type="submit">
</form>
<form action="/user" method="post">
<input name="_method" type="hidden" value="delete">
<input name="_m" type="hidden" value="delete">
<input value="delete" type="submit">
</form>
</body>
</html>
Rest使用客户端工具
- 如PostMan直接发送Put、delete等方式请求,无需Filter。表单只能用get,post请求。
请求处理----参数注解
@PathVariable、@RequestHeader、@ModelAttribute、@RequestParam、@MatrixVariable、@CookieValue、@RequestBody
参数注解作用
@PathVariable
作用:@PathVariable是spring3.0的一个新功能:接收请求路径中占位符的值,将URL中占位符参数{xxx}绑定到处理器类的方法形参中@PathVariable(“xxx“),上如果有多个占位符,形参列表需要定义多个参数,不是很方便,可以直接定义一个map集合 @PathVariable Map<String,String> kv,会自动映射多个参数;
@RequestParam
@RequestParam主要用于将请求参数区域的数据映射到控制层方法的参数上
@RequestParam(value=”参数名”,required=”true/false”,defaultValue=””)
value:请求中传入参数的名称,即前端传过来时定义的参数名。如果不设置value值,则前端定义的参数名必须和后端接口参数名相同required:该参数是否为必传项。默认是true,表示请求中一定要传入对应的参数,否则会报404错误;如果设置为false,当请求中没有此参数,将会默认为null。而对于基本数据类型的变量,则必须有值,这时会抛出空指针异常。如果允许空值,则接口中变量需要使用包装类来声明。defaultValue:参数的默认值,如果请求中没有同名的参数时,该变量默认为此值。
@RequestBody
作用:@RequestBody主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的)
- GET方式无请求体,所以使用@RequestBody接收数据时,前端不能使用GET方式提交数据,而是用POST方式进行提交
- 在后端的同一个接收方法里,@RequestBody与@RequestParam()可以同时使用,@RequestBody最多只能有一个,而@RequestParam()可以有多个
- 如果参数时放在请求体application/json传入后台的话,那么后台要用@RequestBody才能接收到
- 如果不是放在请求体中的话,那么后台接收前台传过来的参数时,要用@RequestParam来接收,或者形参前 什么也不写也能接收
@CookieValue
同请求头类似,可以获取cookie属性,也可以将获取到的属性封装为cookie对象
@RequestAttribute
获取请求域中的信息
@Controller
public class GoController {
@GetMapping("/goto")
public String goPage(HttpServletRequest request){
request.setAttribute("msg","成功");
request.setAttribute("code","200");
return "forward:/success";
}
@ResponseBody
@GetMapping("/success")
public Map<String,Object> getmap(@RequestAttribute("msg") String msg,
@RequestAttribute("code") String code){
HashMap<String, Object> map = new HashMap<>();
map.put("msg",msg);
map.put("code",code);
return map;
}
}
@MatrixVariable
读取矩阵变量,矩阵变量语法如下,每一个变量之间用分号隔开
语法: 请求路径:/cars/sell;low=34;brand=byd,audi,yd
//cars/sell;low=34;brand=byd,audi,yd
@GetMapping("/car/{path}")
public Map test2(@MatrixVariable("low") String low,
@MatrixVariable("brand") List<String> brand,
@PathVariable("path") String path){
HashMap<String, Object> map = new HashMap<>();
map.put("low",low);
map.put("brand",brand);
map.put("path",path);
return map;
}
//{"path":"sell","low":34,"brand":["byd","audi","yd"]}
示例:
请求地址如果为:http://localhost:9999/car/2/owner/zhangsan?age=18&inters=basketball&inters=football
@PathVariable("id") Integer id: 获取路径中{id}
@PathVariable("username") String name: 获取路径中{username}
@PathVariable Map<String, String> pv: 获取路径中所有的路径变量
@RequestHeader("User-Agent") String userAgent: 获取请求头中userAgent
@RequestHeader Map<String, String> header: 获取请求头中所有参数
@RequestParam("age") Integer age: 获取请求参数中"age"
@RequestParam("inters") List<String> inters: 获取请求参数中"inters"
@RequestParam Map<String, String> params: 获取所有的请求参数
@CookieValue("_ga") String _ga: 获取cookie中_ga的值
@CookieValue("_ga") Cookie cookie) : 获取cookie
import javax.servlet.http.Cookie;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
public class ParameterTestController {
// http://localhost:9999/car/2/owner/zhangsan?age=18&inters=basketball&inters=football
@GetMapping("/car/{id}/owner/{username}")
public Map<String, Object> getCar(@PathVariable("id") Integer id,
@PathVariable("username") String name,
@PathVariable Map<String, String> pv,
@RequestHeader("User-Agent") String userAgent,
@RequestHeader Map<String, String> header,
@RequestParam("age") Integer age,
@RequestParam("inters") List<String> inters,
@RequestParam Map<String, String> params,
@CookieValue("_ga") String _ga,
@CookieValue("_ga") Cookie cookie) {
Map<String, Object> map = new HashMap<>();
map.put("id", id);
map.put("name", name);
map.put("pv", pv);
map.put("userAgent", userAgent);
map.put("headers", header);
map.put("age", age);
map.put("inters", inters);
map.put("params", params);
map.put("_ga", _ga);
System.out.println(cookie.getName() + "===>" + cookie.getValue());
return map;
}
@PostMapping("/save")
public Map postMethod(@RequestBody String content) {
Map<String, Object> map = new HashMap<>();
map.put("content", content);
return map;
}
//1、语法: 请求路径:/cars/sell;low=34;brand=byd,audi,yd
//2、SpringBoot默认是禁用了矩阵变量的功能
// 手动开启:原理。对于路径的处理。UrlPathHelper进行解析。
// removeSemicolonContent(移除分号内容)支持矩阵变量的
//3、矩阵变量必须有url路径变量才能被解析
@GetMapping("/cars/{path}")
public Map carsSell(@MatrixVariable("low") Integer low,
@MatrixVariable("brand") List<String> brand,
@PathVariable("path") String path) {
Map<String, Object> map = new HashMap<>();
map.put("low", low);
map.put("brand", brand);
map.put("path", path);
return map;
}
// /boss/1;age=20/2;age=10
@GetMapping("/boss/{bossId}/{empId}")
public Map boss(@MatrixVariable(value = "age", pathVar = "bossId") Integer bossAge,
@MatrixVariable(value = "age", pathVar = "empId") Integer empAge) {
Map<String, Object> map = new HashMap<>();
map.put("bossAge", bossAge);
map.put("empAge", empAge);
return map;
}
}
Springboot笔记<6>Rest的使用和请求参数注解@PathVariable、@RequestHeader、@ModelAttribute、@RequestParam、@MatrixVariable、@CookieValue、@RequestBody的更多相关文章
- SpringBoot系列教程web篇之Post请求参数解析姿势汇总
作为一个常年提供各种Http接口的后端而言,如何获取请求参数可以说是一项基本技能了,本篇为<190824-SpringBoot系列教程web篇之Get请求参数解析姿势汇总>之后的第二篇,对 ...
- SpringBoot系列教程web篇之Get请求参数解析姿势汇总
一般在开发web应用的时候,如果提供http接口,最常见的http请求方式为GET/POST,我们知道这两种请求方式的一个显著区别是GET请求的参数在url中,而post请求可以不在url中:那么一个 ...
- 接口测试工具-Jmeter使用笔记(二:GET/POST请求参数填写)
举例来说 我的被测系统API的http请求涉及到GET/POST/PUT/DELETE四种.请求传参可分为两种: GET请求 http://请求路径/Ecs-duHc0U4E #该请求参数“Ecs-d ...
- SpringMVC中post请求参数注解@requestBody使用问题
一.httpClient发送Post 原文https://www.cnblogs.com/Vdiao/p/5339487.html public static String httpPostWithJ ...
- SpringMVC请求参数注解两个小问题
今天遇到使用SpringMVC请求注解遇到的两个小问题: 如果用@requestBody注解,则请求体内容类型一般要为application/json,如果其类型为multipart/form-dat ...
- Android】Retrofit网络请求参数注解,@Path、@Query、@QueryMap...(转)
对Retrofit已经使用了一点时间了,是时候归纳一下各种网络请求的service了. 下面分为GET.POST.DELETE还有PUT的请求,说明@Path.@Query.@QueryMap.@Bo ...
- 【Android】Retrofit网络请求参数注解,@Path、@Query、@QueryMap.
对Retrofit已经使用了一点时间了,是时候归纳一下各种网络请求的service了. 下面分为GET.POST.DELETE还有PUT的请求,说明@Path.@Query.@QueryMap.@Bo ...
- SpringMVC之请求参数的获取方式
转载出处:https://www.toutiao.com/i6510822190219264516/ SpringMVC之请求参数的获取方式 常见的一个web服务,如何获取请求参数? 一般最常见的请求 ...
- 学习SpringMVC——如何获取请求参数
@RequestParam,你一定见过:@PathVariable,你肯定也知道:@QueryParam,你怎么会不晓得?!还有你熟悉的他(@CookieValue)!她(@ModelAndView) ...
- springMvc源码学习之:spirngMVC获取请求参数的方法2
@RequestParam,你一定见过:@PathVariable,你肯定也知道:@QueryParam,你怎么会不晓得?!还有你熟悉的他 (@CookieValue)!她(@ModelAndView ...
随机推荐
- nginx配置2个不同端口的应用
如何配置nginx,在同一台服务器上,部署2个不同端口的web应用? 1,利用Django框架搭建的web应用,默认端口是8000: 2,利用Flask框架搭建的web应用,默认端口是5000: 第一 ...
- 官方的 MCP C# SDK:csharp-sdk
csharp-sdk 这是 Model Context Protocol(MCP)官方提供的 C# SDK,为 MCP 服务器和客户端提供简单易用的接口, 主要由微软维护.MCP 是由 Claude( ...
- Ubuntu更换cuda版本,gcc,g++版本
Ubuntu更换cuda版本,gcc,g++版本 更换cuda版本 这个比较简单 可以看到 /usr/local下面有一个软链接,更换到我们需要的版本即可,cuda对应版本安装可参考官网. 创建软连接 ...
- BUUCTF---天干地址+甲子
题目 直接参考天干地支表作结,转ASCII flag{Goodjob}
- CSS实现单行显示文本并适应浏览器大小
实现 .text { white-space:nowrap; /*文本不换行*/ overflow: hidden; /*超出文本隐藏*/ text-overflow:ell ...
- shell处理字符串
概念 字符串是shell编程中最常用最有用的数据类型(除了数字和字符串,也没啥其它类型好用了),字符串可以用单引号,也可以用双引号,也可以不用引号. 单引号声明字符串 单引号里的任何字符都会原样输出, ...
- PHP传递参数(跨文件)的8种常见方法
以下是 PHP 中跨文件传递参数的 8 种常见方法,按场景和安全性分类整理,附详细说明和示例代码: 一.超全局变量(适合请求间数据共享) 1. $_GET / $_POST 用途:通过 URL 或表单 ...
- 测试工作中用到的MongoDB命令
1.远程连接MongoDB mongo host:port/dbname (host和port根据自己需要修改) 连接成功页面如下: 2.显示所有数据库 show dbs 3.切换到oversea-a ...
- c++指针传递与引用传递
c 不支持引用传递的! 在 C++中,指针传递和引用传递是两种常用的参数传递方式,它们各自有不同的特点和适用场景.下面是两者之间的主要区别: 1. 语法和使用 指针传递 定义和调用:函数参数是一个指针 ...
- 康谋方案 | 从概念到生产的自动驾驶软件在环(SiL)测试解决方案
一.自动驾驶软件在环(SiL)测试解决方案 自动驾驶软件在环(SiL)测试解决方案能够研究和验证高历程实验和恶劣驾驶环境下的AD系统的性能,支持云端和PC端操作,提供高保真度的仿真环境和传感器模型,实 ...