建立个人免费网站,18年公众号价格,1.申请网站空间,上海专业网站建注解相关
AliasFor#xff1a;.在同个注解中为同一个功能定义两个名称不一样的属性#xff0c;那么这两个属性彼此互为别名 RequestMapping注解里面的代码 AliasFor(path)String[] value() default {};AliasFor(value)String[] path() default {};G…注解相关
AliasFor.在同个注解中为同一个功能定义两个名称不一样的属性那么这两个属性彼此互为别名 RequestMapping注解里面的代码 AliasFor(path)String[] value() default {};AliasFor(value)String[] path() default {};
GetMapping PostMapping DeleteMapping等都是RequestMapping修饰
RequestMapping(method RequestMethod.GET)
public interface GetMapping {}
MVC处理流程
一springmvc请求方式的选择
如果是用的表单提交 不能支持delete那些方式 需要开启一下过滤器。但是现在前后端分离 直接就可以发delete那些方式。 在WebMvcAutoConfiguration中 配置了一个命令隐藏方法过滤器 一直进去可以看见这里默认的参数是_method 回到WebMvcAutoConfiguration中 我们看见 如果默认过滤器是false 未开启 我们去配置文件中开启
配置
spring:mvc:hiddenmethod:filter:enabled: true
前端form action/test methodpostinput typehidden name_method valueDELETEinput typesubmit value提交
/form
后端ResponseBodyRequestMapping(value /test, method RequestMethod.DELETE)public String getTest(){return DELETE;}
结果就是成功请求到 如果没有开启 就会失败现在我们来看一下请求过程
请求进来 判断是不是post请求 并且是否正常如果是就进入if里面
进来后获取到this.methodParam里面的值 点进去发现就是_method
所以 这里就是获取我们过程名字为_method的input标签里面的值
拿到以后会判断这个值是不是正常 正常的话就变成大写所有我们前端大写小写都可以
然后去判断ALLOWED_METHODS里面是不是包含这个值 如果包含就new一个HttpMethodRequestWrapper返回
HttpMethodRequestWrapper就是重写了ServletRequest进行了包装这里可以看见mvc支持这些请求 特别注意 因为表单只能发post和get 所有才会进入if里面 如果是客户端工具 直接发送delete就不用进去 直接就用的requestToUse
自定义_method 这里给了我们方法 我们只需要修改一下 给他注入到容器里面就可以了。
Configuration(proxyBeanMethods false)//Configuration(proxyBeanMethods false)提高Spring启动速度
public class WebConfig {Beanpublic HiddenHttpMethodFilter hiddenHttpMethodFilter(){HiddenHttpMethodFilter hiddenHttpMethodFilter1 new HiddenHttpMethodFilter();hiddenHttpMethodFilter1.setMethodParam(_myMethod);return hiddenHttpMethodFilter1;}
}二请求映射原理
所有请求都会来到中央处理器DispatcherServlet 我们去里面找到doGet和doPost在FrameworkServlet中 我们找到了
再doGet里面processRequest再调用他本类里面的doService方法处理rqquest和response这里的doService是一个抽象方法 并没有实现 所有一定在子类里面实现。 在中央处理器DispatcherServlet里面 doService被实现了 经过一系列的初始化过程 doService里面 调用了doDispatch(request, response);每个请求进来都会调用doDispatch方法 这才是我们要研究的方法。
综上所述经过系列的辗转反侧 我们终于找到了最终处理request, response的方法 就是doDispatch 我们继续研究doDispatch方法
请求过来以后 会把请求包装一下然后判断是不是文件上传multipartRequestParsed请求 默认是false.
WebAsyncManager asyncManager WebAsyncUtils.getAsyncManager(request);
判断是不是异步 是的话就使用一个异步管理器。再往下走 走到核心这里 这就是找到映射地址的关键 这里调用本类的一个getHandler方法 在这个方法里面找到映射地址 进入这个方法 我们看见这里是一个for循环的方式来找寻找。 这里的handermappers一共有5个 我们需要的就是第一个 在这里面我们找到了所有的映射地址 包括系统给我们写的 当然 也有这次要找的。 在这里面就可以找到这个映射地址的方法叫getTest 在helloController这个类里面 在for循环的Mapping.getHander()方法里面 调用了一个方法在这个方法里面找到最终的结果 我们一直往下运行 找到RequestMappingInfoHandlerMapping类 这里面有一个方法处理了request请求 进入这个方法 我们看见这里面找到了路径
但是路径可能相同 但是请求方式不同这里把路径和requst再进行处理 我们发现这里相同的路径找到了两个请求 然后又把这两个结果放到一个方法里面去找最佳匹配 经过这里的循环 就找到了最终的结果
三参数解析原理
走到了这一步
接着上面的 拿到具体的方法以后 我们就要去到一个适配器 进去后发现 这里有4个处理器适配器
支持RequestMapping我们的controller都是这个支持函数式编程 这里返回的就是RequestMappingHandlerAdapter 返回以后中央处理器我们继续往下走 我们会走到一个核心方法Actually invoke the handler.实际调用处理程序。 进入这个方法 我们会走到RequestMappingHandlerAdapter 这里做一些真正的处理 在这里执行目标方法 在这个方法里面有一个参数解析器 参数解析器里面有这些这里确定我们将要执行的目标方法的每一个参数的值是什么。我们平时写的RequestParam就在这里第一个处理的。 这里还有返回值处理器
继续往下处理请求的一个方法就在这里 进去这个方法里面 就会来到我们的controller 真真真执行目标方法ServletInvocableHandlerMethod类里面。 这里面再进去 会到InvocableHandlerMethod 这里面获取参数的值代码如下
protected Object[] getMethodArgumentValues(NativeWebRequest request, Nullable ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {MethodParameter[] parameters getMethodParameters();if (ObjectUtils.isEmpty(parameters)) {return EMPTY_ARGS;}Object[] args new Object[parameters.length];for (int i 0; i parameters.length; i) {MethodParameter parameter parameters[i];parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);args[i] findProvidedArgument(parameter, providedArgs);if (args[i] ! null) {continue;}if (!this.resolvers.supportsParameter(parameter)) {throw new IllegalStateException(formatArgumentError(parameter, No suitable resolver));}try {args[i] this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);}catch (Exception ex) {// Leave stack trace for later, exception may actually be resolved and handled...if (logger.isDebugEnabled()) {String exMsg ex.getMessage();if (exMsg ! null !exMsg.contains(parameter.getExecutable().toGenericString())) {logger.debug(formatArgumentError(parameter, exMsg));}}throw ex;}}return args;}总结 请求进来以后会先去走过滤器拿到它是哪一种请求方式
拿到以后走service方法去走一个请求转发通过if else找到请求方式 去调用doGet, doPost等方法。 然后就是上面的去寻找具体方法。