1、Rest风格接口形式
//@RequestMapping(value = "/user",method = RequestMethod.GET) 等同于
@GetMapping("/user")
public String getUser(){
return "GET-张三";
}
//@RequestMapping(value = "/user",method = RequestMethod.POST) 等同于
@PostMapping("/user")
public String saveUser(){
return "POST-张三";
}
//@RequestMapping(value = "/user",method = RequestMethod.PUT) 等同于
@PutMapping("/user")
public String putUser(){
return "PUT-张三";
}
//@RequestMapping(value = "/user",method = RequestMethod.DELETE) 等同于
@DeleteMapping("/user")
public String deleteUser(){
return "DELETE-张三";
}
2、请求映射原理
(1)springMvc请求开始
所有接口请求都是从org.springframework.web.servlet.DispatcherServlet中doDispatch方法进行处理执行
//FrameworkServlet 重写doXXX方法
protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.processRequest(request, response);
}
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
.......
this.doService(request, response);
.......
}
//DispatcherServlet 实现了 doService
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
.........
//核心处理方法
this.doDispatch(request, response);
........
}
(2)doDispatch映射处理分析
获取容器中所有的handlerMappings,然后循环遍历查找能处理请求的handlerMappings,所有的controller中的请求都会在项目启动时封装到RequestMappingHandlerMapping中
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
.........
//获取处理请求的Handler 根据获取到hanlder进行请求处理
mappedHandler = this.getHandler(processedRequest);
.........
}
//循环遍历获取处理请求的handlerMappings
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
Iterator var2 = this.handlerMappings.iterator();
while(var2.hasNext()) {
HandlerMapping mapping = (HandlerMapping)var2.next();
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
(3)匹配原理
根据url匹配所有能处理请求的方法,然后根据RequestMethod值确定唯一方法进行处理
//AbstractHandlerMapping
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = this.getHandlerInternal(request);
.......
}
//RequestMappingInfoHandlerMapping
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
..........
var2 = super.getHandlerInternal(request);
.........
}
//AbstractHandlerMethodMapping
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//获取请求url
String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);
..........
//进行匹配
HandlerMethod handlerMethod = this.lookupHandlerMethod(lookupPath, request);
.........
}
//AbstractHandlerMethodMapping.class
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
......
//获取所有匹配的请求
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
//根据请求行为(method)进行筛选
this.addMatchingMappings(directPathMatches, matches, request);
}
//路径变量处理会在此处进行匹配
if (matches.isEmpty()) {
this.addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
.......
}
(4)自定义HandlerMapping
我们需要一些自定义的映射处理,我们也可以自己给容器中放HandlerMapping,实现自定义处理
3、表单请求Rest接口
(1)表单支持put、delete请求
表单只支持get与post请求,可通过OrderedHiddenHttpMethodFilter实现put与delete请求
spring:
mvc:
hiddenmethod:
filter:
enabled: true # 默认不开启
<!-- 表单post请求提交带上参数_method=PUT -->
<form action="/user" method="post">
<input name="_method" type="hidden" value="PUT"/>
<input value="REST-PUT 提交" type="submit"/>
</form>
(2)实现原理
SpringBoot web环境下,会根据spring.mvc.hiddenmethod.filter值是否注入OrderedHiddenHttpMethodFilter,OrderedHiddenHttpMethodFilter根据_method的值包装request请求
//1、springboot启动会自动加载webmvc自动配置
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnWebApplication(
type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration
//2、按需注入OrderedHiddenHttpMethodFilter
@Bean
@ConditionalOnMissingBean({HiddenHttpMethodFilter.class})
@ConditionalOnProperty(
prefix = "spring.mvc.hiddenmethod.filter",
name = {"enabled"},
matchIfMissing = false
)//默认不开启
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
//3、OrderedHiddenHttpMethodFilter判断绑定method
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
HttpServletRequest requestToUse = request;
//判断是否是post请求,切请求参数中有_method
if ("POST".equals(request.getMethod()) && request.getAttribute("javax.servlet.error.exception") == null) {
String paramValue = request.getParameter(this.methodParam);
if (StringUtils.hasLength(paramValue)) {
String method = paramValue.toUpperCase(Locale.ENGLISH);
if (ALLOWED_METHODS.contains(method)) {
requestToUse = new HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method);
}
}
}
filterChain.doFilter((ServletRequest)requestToUse, response);
}
(3)自定义参数(修改_method)
打破@ConditionalOnMissingBean({HiddenHttpMethodFilter.class}),启动就不会将OrderedHiddenHttpMethodFilter注入到容器中
//容器中注入HiddenHttpMethodFilter,打破自动注入@ConditionalOnMissingBean({HiddenHttpMethodFilter.class})条件
@Bean
public HiddenHttpMethodFilter hiddenHttpMethodFilter(){
HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();
methodFilter.setMethodParam("_m");
return methodFilter;
}