Turn on SpringBoot Restful style mapping implementation process and request mapping principle

Request mapping

@xxxMapping;

@GetMapping
@PostMapping
@PutMapping
@DeleteMapping

Rest style support (using HTTP request verbs to express operations on resources)

before:

/getUser 获取用户
/deleteUser 删除用户
/editUser 修改用户
/saveUser保存用户

Now: /user

GET-获取用户
DELETE-删除用户
PUT-修改用户
POST-保存用户

核心Filter;HiddenHttpMethodFilter

usage

Turn on the Rest function of the
page form. The attribute of the page form is method=post, hidden domain _method=put, delete, etc. (If you get or post directly, you don’t need to hide the domain).
Write request mapping

spring:
  mvc:
    hiddenmethod:
      filter:
        enabled: true   #开启页面表单的Rest功能

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

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

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

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

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

@PostMapping("/user")
//@RequestMapping(value = "/user",method = RequestMethod.POST)
public String saveUser(){
    
    
    return "POST-张三";
}

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

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

Rest principle

(When the form submission is to use REST) ​​The
form submission will bring the _method=PUT
request and be intercepted by HiddenHttpMethodFilter. Whether the
request is normal and it is POST

  1. Get the value of _method.
  2. Compatible with the following requests; PUT.DELETE.PATCH
  3. Native request (post), the wrapper mode requestsWrapper rewrites the getMethod method, and returns the value passed in.
  4. Use a wrapper when the filter chain is released. The subsequent method call getMethod is to call requesWrapper.
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()));

	/** Default method parameter: {@code _method}. */
	public static final String DEFAULT_METHOD_PARAM = "_method";

	private String methodParam = DEFAULT_METHOD_PARAM;


	/**
	 * Set the parameter name to look for HTTP methods.
	 * @see #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);
	}


	/**
	 * Simple {@link HttpServletRequest} wrapper that returns the supplied method for
	 * {@link HttpServletRequest#getMethod()}.
	 */
	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;
		}
	}

}

How to change the default _method

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({
    
     Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({
    
     DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
		ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
    
    

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

@ConditionalOnMissingBean(HiddenHttpMethodFilter.class) means that hiddenHttpMethodFilter() is executed when there is no HiddenHttpMethodFilter. Therefore, we can customize the filter and change the default _method. E.g:

@Configuration(proxyBeanMethods = false)
public class WebConfig{
    
    
    //自定义filter
    @Bean
    public HiddenHttpMethodFilter hiddenHttpMethodFilter(){
    
    
        HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();
        methodFilter.setMethodParam("_m");
        return methodFilter;
    }    
}

Change _method to _m.

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

Request mapping principle

  • SpringBoot automatically configures the WelcomePageHandlerMapping of the welcome page. Access/can access index.html;

  • SpringBoot automatically configures the default RequestMappingHandlerMapping

  • When the request comes in, try all HandlerMapping one by one to see if there is any request information.

  • If so, find the handler corresponding to this request

  • If not, it is the next HandlerMapping

  • We need some custom mapping processing, we can also put HandlerMapping in the container ourselves. Custom HandlerMapping

IDEA shortcut keys:

  1. Ctrl + Alt + U: UML class diagrams show which inherited classes, derived classes and which interfaces are implemented by the class.
  2. Crtl + Alt + Shift + U: Same as above, the difference is that the result of the previous shortcut key is displayed on the new page, while the result of this shortcut key is displayed on the pop-up window.
  3. Ctrl + H: Display the class hierarchy diagram in a tree-like manner.

Guess you like

Origin blog.csdn.net/david2000999/article/details/115261090