rest映射与源码分析

1、基本使用

  • 之前使用不同的url表示不同的操作,这些操作都只能使用get 或者 post两种请求方式,区分不同操作的取决于url,而不是请求方式!

  • 例如:/getuser获取用户、/deluser删除用户、/moduser修改用户、/saveuser保存用户;

  • 使用rest风格可以将同一个url用不同的请求方式区分,然后根据不同的请求方式执行不同的操作;也就是说针对同一个url,不同的请求方式做不同的处理。

  • 例如:/userGET-获取用户 DELETE-删除用户 PUT-修改用户 POST-保存用户

1.1 页面参数
  • 页面中需要使用表单提交,且提交非get/post请求时需要提交一个隐藏域,name = “_method” value = “请求”。

  • 首先表单中必须是method = post,然后提交后会解析隐藏域,将post请求转化为对应的请求value值。

<h1>测试rest风格: </h1>
<form action="/user" method="get">
    <input type="submit" value="get-提交">
</form>

<form action="/user" method="post">
    <input type="submit" value="post-提交">
</form>

<form action="/user" method="post">
    <input type="hidden" name="_method" value="PUT">
    <input type="submit" value="put-提交">
</form>

<form action="/user" method="post">
    <input type="hidden" name="_method" value="DELETE">
    <input type="submit" value="delete-提交">
</form>

1.2 控制层
  • 控制层所有的path路径全都是一样的,但是需要给@RequestMapping注解设置属性处理的方式。

  • @ResponseBody表示直接响应到页面中不经过视图处理器。

@Controller
public class RequestController {

    @RequestMapping(value = "/user", method = RequestMethod.GET)
    @ResponseBody
    public String getUser(){
        return "张三 -> get";
    }

    @RequestMapping(value = "/user", method = RequestMethod.POST)
    @ResponseBody
    public String postUser(){
        return "张三 -> post";
    }

    @RequestMapping(value = "/user", method = RequestMethod.PUT)
    @ResponseBody
    public String putUser(){
        return "张三 -> put";
    }

    @RequestMapping(value = "/user", method = RequestMethod.DELETE)
    @ResponseBody
    public String deleteUser(){
        return "张三 -> delete";
    }
}

1.3 application.yaml配置
  • 开启rest风格的允许,否则依旧是不生效的。

  • 这几个步骤缺少其中的任何一个rest风格都不会生效。

spring:
  mvc:
    hiddenmethod:
      filter:
        enabled: true

在这里插入图片描述



2、rest映射原理

  • rest映射主要是通过post请求提交并且携带隐藏域(_method),然后由HiddenHttpMethodFilter类将其转换。

  • SpringBoot启动就自动装配WebMvcAutoConfiguration类,然后由该类进行条件装配OrderedHiddenHttpMethodFilter类。

2.1 OrderedHiddenHttpMethodFilter解析
  • 该类继承自HiddenHttpMethodFilter类,主要是绑定spring.mvc.hiddenmethod.filter配置参数

  • 而这里有个参数name = enabled,并且默认是false的也就是说默认并没有开启rest映射。

public class WebMvcAutoConfiguration {
	@Bean
	@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)			//IOC中是否已经有这个组件
	@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled")	
	//绑定spring.mvc.hiddenmethod.filter配置文件,并且默认情况下是不开启rest
	public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
		return new OrderedHiddenHttpMethodFilter();
	}
}

2.2 HiddenHttpMethodFilter解析
  • OrderedHiddenHttpMethodFilter类继承自HiddenHttpMethodFilter类。

  • HiddenHttpMethodFilter类首先是以过滤器的形式对请求进行过滤拦截,当请求过来被HiddenHttpMethodFilter拦截。

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";	//固定的请求与name名

	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;
		}
	}
}

核心方法doFilterInternal解析如下:

  1. 首先这里必须是post请求,并且请求是合法的!

  2. 然后获取到methodParam隐藏域的值,判断合法性

  3. 不缺分请求方式值的大小写,并且全部转为大写。

  4. 判断提交的请求是否是delete、put、PATCH请求。

  5. 最后由HttpMethodRequestWrapper包装器解析并且返回,返回的值就是真正的请求方式!



3、修改默认的参数

由于无法直接修改绑定的配置参数,进而无法将methodParam = _method改成指定的名称。但是可以根据SpringBoot的条件装配进行装配。

@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled")
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
	return new OrderedHiddenHttpMethodFilter();
}

可以看到这个类的装配只有IOC中没有HiddenHttpMethodFilter类才会装配,那么我们可以手动向容器中注入这个Bean,并且顺手指定methodParam值。

@Configuration
public class WebConfig {
    @Bean
    public HiddenHttpMethodFilter hiddenHttpMethodFilter() {

        HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
        hiddenHttpMethodFilter.setMethodParam("query");
        return hiddenHttpMethodFilter;
    }
}
  • 由于手动向IOC中丢入HiddenHttpMethodFilter类,那么条件装配将不会生效。

  • 且前端传入的隐藏参数名称也要改为指定的query进行转换才能使得rest生效。

<input type="hidden" name="query" value="转换请求类型">


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值