Springboot 2 Foundation - request parameter processing and principle
tags:
- Spring Boot
- 2021 Shang Silicon Valley
- Lei Fengyang
categories:
- Static file configuration
- Principle of static file configuration
- Welcome page and custom Favicon
- Principle of Rest form request
- Request mapping principle
- Use and principle of various parameters
Section I SpringMVC Auto configuration overview
- SpringBoot encapsulates spring MVC. We don't need to customize most scenarios in SpringBoot.
- Spring boot automatically configures what is in spring MVC. Official documents: https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-spring-mvc-auto-configuration
- Content negotiation view parser and BeanName view parser
- Static resources (including webjars)
- Automatically register Converter, GenericConverter and Formatter. For example: automatic conversion of date format
- Support HttpMessageConverters (later we cooperated with content negotiation to understand the principle)
- Automatic registration of MessageCodesResolver (for internationalization) is of little use. If internationalization is really needed, two websites are generally developed.
- Static index HTML page support
- Custom Favicon
- Automatically use the ConfigurableWebBindingInitializer (DataBinder is responsible for binding the request data to the JavaBean)
- No @ EnableWebMvc annotation. Use @ Configuration + WebMvcConfigurer to customize rules
- Declaring WebMvcRegistrations changes the default underlying components
- Use @ EnableWebMvc+@Configuration+DelegatingWebMvcConfiguration to fully take over spring MVC
Section 2 static resource access
- Official documents: https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-spring-mvc-static-content
2.1 static resource directory
-
As long as the static resources are placed in the classpath: called /static (or /public or /resources or /META-INF/resources)
Access: current project root path / + static resource name
- static
- public
- resources
- META-INF/resources
-
Principle: if you want to come in, go to the Controller first to see if you can handle it. All requests that cannot be processed are handed over to the static resource processor. If the static resource cannot be found, the 404 page will be responded
-
Modify the prefix of static resource access
.
- Current project + static path pattern + static resource name = static resource folder: http://127.0.0.1:8080/res/aaaaa.jpg
-
Change the default static resource path
spring: mvc: static-path-pattern: /res/** # Configure access prefix web: resources: static-locations: [classpath:/haha/] # To configure the static resource path, you can write an array or only one
-
webjar this
Use less
. It is equivalent to making jquery into a jar package. Through dependent references.
- Automatic mapping: accessing resources http://localhost:8080/webjars/jquery/3.5.1/jquery.js
- https://www.webjars.org/
<dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.5.1</version> </dependency>
2.2 welcome page and custom Favicon
- Index. Under static resource path html
- Static resource paths can be configured
- However, the access prefix of static resources cannot be configured. Otherwise, index HTML cannot be accessed by default
- controller can handle / index
spring: # mvc: # Static path pattern: / RES / * * this will cause the function of the welcome page to fail
- Custom Favicon
- favicon.ico can be placed in the static resource directory.
spring: # mvc: # Static path pattern: / RES / * * this will lead to the aging of custom Favicon configuration
2.3 static resource allocation process
-
First, SpringBoot starts loading the xxxAutoConfiguration class (autoconfiguration class) by default
-
The automatic configuration class webmvcoautoconfiguration of spring MVC function is determined to be effective
-
See what's in the container.
- org\springframework\boot\spring-boot-autoconfigure\2.4.5\spring-boot-autoconfigure-2.4.5-sources.jar!\org\springframework\boot\autoconfigure\web\servlet\WebMvcAutoConfiguration.java
-
Configuration class in configuration class
As follows. The relevant properties of the configuration file are bound with xxx
- Discover WebMvcProperties and spring MVC configuration file binding
- Found ResourceProperties and spring Resources configuration for binding
@Configuration(proxyBeanMethods = false) @Import(EnableWebMvcConfiguration.class) @EnableConfigurationProperties({ WebMvcProperties.class, org.springframework.boot.autoconfigure.web.ResourceProperties.class, WebProperties.class }) @Order(0) public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
- Extended knowledge: if a configuration class has only one parameterized constructor, the values of all parameters of the parameterized constructor will be determined from the container.
//The values of all parameters of the parameterized constructor are determined from the container //ResourceProperties resourceProperties; Get and spring Resources bind to all the value objects //WebMvcProperties mvcProperties get and spring MVC binds all the value objects //Listablebeanfactory beanFactory beanfactory of spring, container factory //HttpMessageConverters find all HttpMessageConverters //ResourceHandlerRegistrationCustomizer found the customizer for the resource processor=== Emphasis=== //Dispatcherservletpath the path that dispatcherservlet handles //Servlet registrationbean registers servlets and filters for applications public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider, ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider, ObjectProvider<DispatcherServletPath> dispatcherServletPath, ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) { this.resourceProperties = resourceProperties; this.mvcProperties = mvcProperties; this.beanFactory = beanFactory; this.messageConvertersProvider = messageConvertersProvider; this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider.getIfAvailable(); this.dispatcherServletPath = dispatcherServletPath; this.servletRegistrations = servletRegistrations; }
- Look down the code: find the function addResourceHandlers, which handles the default rules for resource processing
2.4 default rules for resource processing
- Function addResourceHandlers, add a breakpoint to the if to see how the default rule takes effect. (mine is the latest framework, and some functions may be inconsistent with the video screen)
- The resource properties (resource configuration file) obtained from the container above has the isAddMappings property. Test the function of this attribute in the configuration file.
- It is found that the default is True. If it is configured as False, the following pile of configurations will not take effect.
@Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { super.addResourceHandlers(registry); if (!this.resourceProperties.isAddMappings()) { logger.debug("Default resource handling disabled"); return; } ServletContext servletContext = getServletContext(); // webjars rules addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/"); // resouser addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> { registration.addResourceLocations(this.resourceProperties.getStaticLocations()); if (servletContext != null) { registration.addResourceLocations(new ServletContextResource(servletContext, SERVLET_LOCATION)); } }); }
web: resources: static-locations: [classpath:/haha/] add-mappings: false # Disable all static resource configurations cache: period: 11000 # Configure the cache time of static resources in seconds
- It calls addResourceHandler, which sets the cache of static resources.
- Find the default location for static resources. resourceProperties.getStaticLocations()
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" };
- Welcome page handlermapping function
// Handler mapping: processor mapping. It saves which requests each handler can handle. @Bean public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) { WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping( new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(), this.mvcProperties.getStaticPathPattern()); welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider)); welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations()); return welcomePageHandlerMapping; } // Click the welcome pagehandlermapping in the above code. The first if also explains that the path defined above cannot be found because "/ * *" equals(staticPathPattern) WelcomePageHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders, ApplicationContext applicationContext, Resource welcomePage, String staticPathPattern) { if (welcomePage != null && "/**".equals(staticPathPattern)) { logger.info("Adding welcome page: " + welcomePage); setRootViewName("forward:index.html"); } else if (welcomeTemplateExists(templateAvailabilityProviders, applicationContext)) { logger.info("Adding welcome page template: index"); setRootViewName("index"); } }
- Favicon has nothing to do with our code. The browser will send / favicon by default ico
Section 3 request parameter processing - Request mapping
3.1 use and principle of rest
-
Form Rest style support (use HTTP request mode verbs to indicate the operation of resources)
- Previous: / getUser get user / deleteUser delete user / editUser modify user / saveUser save user
- Now: / user GET - get user DELETE - DELETE user PUT - modify user POST - save user
-
The method in the front-end form does not support delete and put. It is processed by get by default
, how can it handle us
form
delete and put in.
- Step 1: bring us a default_ METHOD_ Hidden fields of param = '_method' can be.
- Step 2: enable the configuration, manually enable it, and configure hiddenHttpMethodFilter (not enabled by default)
<form action="/user" method="post"> <input name="_method" type="hidden" value="delete"/> <input value="REST-DELETE Submit" type="submit"/> </form> <form action="/user" method="post"> <input name="_method" type="hidden" value="PUT"/> <input value="REST-PUT Submit" type="submit"/> </form> 12345678 # Start configuration manual start mvc: hiddenmethod: filter: enabled: true
- Function flow: find hiddenHttpMethodFilter in webmvcomautoconfiguration, click - > Click to the parent class. Find org springframework. web. filter. Default of hiddenHttpMethodFilter_ METHOD_ Param configuration.
// Test code //@RequestMapping(value = "/user",method = RequestMethod.GET) // Abbreviation @GetMapping("/user") public String getUser(){ return "GET-Zhang San"; } //@RequestMapping(value = "/user",method = RequestMethod.POST) // Abbreviation //@PostMapping("/user") public String saveUser(){ return "POST-Zhang San"; } //@RequestMapping(value = "/user",method = RequestMethod.PUT) // Abbreviation @PutMapping("/user") public String putUser(){ return "PUT-Zhang San"; } //@RequestMapping(value = "/user",method = RequestMethod.DELETE) // Abbreviation @DeleteMapping("/user") public String deleteUser(){ return "DELETE-Zhang San"; }
- Rest principle (when the form submission needs to use rest)
- The form will be submitted with_ method=PUT
- The request was intercepted by HiddenHttpMethodFilter
- Is the request normal and POST
- Get_ The value of method. Compatible with the following requests; PUT.DELETE.PATCH (the value passed is not case sensitive)
- Native request (post). The wrapping pattern requestwrapper overrides the getMethod method method and returns the passed in value.
- The wrapper is used when the filter chain is released. Future method calls getMethod by calling requestwrapper.
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { HttpServletRequest requestToUse = request; // The judgment here must be submitted by POST and there is no error if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) { String paramValue = request.getParameter(this.methodParam); if (StringUtils.hasLength(paramValue)) { // Case insensitive here String method = paramValue.toUpperCase(Locale.ENGLISH); if (ALLOWED_METHODS.contains(method)) { // The wrapper pattern requestwrap overrides the getMethod method method requestToUse = new HttpMethodRequestWrapper(request, method); } } } // The wrapper is used when the filter chain is released. Future method calls getMethod by calling requestwrapper filterChain.doFilter(requestToUse, response); }
-
Rest using client tools
, it just means
Form request
- For example, PostMan directly sends Put, delete and other requests without Filter
- So it chooses to open. We won't actually use it as a page. It's a front-end and back-end separation mode. The pages are written by others. Just drop our interface.
-
If we don't want to use_ method, define a hidden field by yourself, for example:_ m. Write a configuration class to modify and restart the project.
package com.atguigu.boot.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.filter.HiddenHttpMethodFilter; // No dependence and high efficiency @Configuration(proxyBeanMethods = false) public class WebConfig { @Bean public HiddenHttpMethodFilter hiddenHttpMethodFilter(){ HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter(); // Modified into_ Before m_ method can't be used methodFilter.setMethodParam("_m"); return methodFilter; } }
3.2 request mapping principle
- CTRL+N global search class DispatcherServlet, CTRL+H search inheritance tree. Find a way to rewrite the doget and dopost requests of the native http serverlet. You can find it in the FrameworkServlet.
- Calling process: doget - > processrequest - > doservice (Abstract) - > doservice (dispatcher servlet) of subclass - > dodispatch (this is the method we want to study, and every request goes through it)
- Spring MVC function analysis is from org springframework. web. servlet. The doDispatch method of dispatcherservlet. The breakpoint is on this function. function.
- Discovery: getHandler(processedRequest) is the method to determine which Handler to process the request with
- Click to: this Handler mappings processor mappings (all request mappings are in handler mapping). There are five by default. After expanding, you can see some details.
- 0 is RequestMappingHandlerMapping: it saves the mapping rules of all @ RequestMapping and handlers.
- 1 is the welcome pagehandlermapping of the welcome page automatically configured by SpringBoot. Access / be able to access index html;
- Configuration class org springframework. boot. autoconfigure. web. servlet. Webmvcoautoconfiguration. requestMappingHandlerMapping registers methods for handling annotated.
- Request to come in and try all HandlerMapping one by one to see if there is any request information.
- If so, find the handler corresponding to the 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
Section 4 request parameter processing - general parameters and basic annotations
4.1 annotation method - Common annotation
- @PathVariable,@RequestHeader,@ModelAttribute,@RequestParam,@MatrixVariable,@CookieValue,@RequestBody
// car/2/owner/zhangsan @GetMapping("/car/{id}/owner/{username}") public Map<String, Object> getCar( // Path variable id @PathVariable("id") Integer id, // Path variable username @PathVariable("username") String name, // Get all path variables @PathVariable Map<String,String> pv, //Get user agent in request header @RequestHeader("User-Agent") String userAgent, //Get all request headers @RequestHeader Map<String,String> header, // Get request parameter? age=18 @RequestParam("age") Integer age, // Get request parameter inters @RequestParam("inters") List<String> inters, // Get all request parameters @RequestParam Map<String,String> params, // Get the in the cookie_ Value of ga @CookieValue("_ga") String _ga, // Get all the information in the cookie @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; } // Get the value in the request body. Only the Post method has the request body @PostMapping("/save") public Map postMethod(@RequestBody String content){ Map<String,Object> map = new HashMap<>(); map.put("content",content); return map; }
4.2 annotation method - @ RequestAttribute
- @RequestAttribute
@Controller // Ordinary controller, method return is to jump public class RequestController { @GetMapping("/goto") public String goToPage(HttpServletRequest request){ request.setAttribute("msg","succeed..."); request.setAttribute("code",200); return "forward:/success"; //Forward to / success request } @GetMapping("/params") public String testParam(Map<String,Object> map, Model model, HttpServletRequest request, HttpServletResponse response){ map.put("hello","world666"); model.addAttribute("world","hello666"); request.setAttribute("message","HelloWorld"); Cookie cookie = new Cookie("c1","v1"); response.addCookie(cookie); return "forward:/success"; } @ResponseBody @GetMapping("/success") public Map success( // Get the attribute required = false set when forwarding the msg in the request domain. This attribute is not required in the request domain @RequestAttribute(value = "msg",required = false) String msg, // This is not written. You can get all the attributes. Click to have a look @RequestAttribute(value = "code",required = false)Integer code, // Get request through native request HttpServletRequest request){ Object msg1 = request.getAttribute("msg"); Map<String,Object> map = new HashMap<>(); Object hello = request.getAttribute("hello"); Object world = request.getAttribute("world"); Object message = request.getAttribute("message"); map.put("reqMethod_msg",msg1); map.put("annotation_msg",msg); map.put("hello",hello); map.put("world",world); map.put("message",message); return map; } }
4.3 annotation method - use of matrix variable @ MatrixVariable
-
Use of matrix variable @ MatrixVariable
-
Syntax: request path: / cars/sell;low=34;brand=byd,audi,yd
-
Interview question: how to use the content in session when cookie s are disabled in page development;
- Default: session Set (a, b) - > jssessionid - > cookie ----- > carried in every request.
- You can use url Rewriting: / ABC; Jsessionid = XXXX passes the value of the cookie in the form of matrix variables
-
SpringBoot disables the function of matrix variables by default
.
- configurePathMatch in the automatic configuration class.
- Manual opening: principle. Processing of paths. The UrlPathHelper parses and clicks in to find it. removeSemicolonContent = true; (remove semicolon content) support matrix variables.
-
<a href="/cars/sell;low=34;brand=byd,audi,yd">@MatrixVariable(Matrix variable)</a> <a href="/cars/sell;low=34;brand=byd;brand=audi;brand=yd">@MatrixVariable(Matrix variable)</a> <a href="/boss/1;age=20/2;age=10">@MatrixVariable(Matrix variable)/boss/{bossId}/{empId}</a>
- There are two ways to manually turn on the function of matrix variables
- The first way to write it: @ Bean directly puts the WebMvcConfigurer component into the container
- The second way is to implement WebMvcConfigurer. Because there is a default implementation, only the methods that need to be modified can be modified.
// The first way is to put the WebMvcConfigurer component into the container @Configuration(proxyBeanMethods = false) public class WebConfig { @Bean public HiddenHttpMethodFilter hiddenHttpMethodFilter(){ HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter(); methodFilter.setMethodParam("_m"); return methodFilter; } @Bean public WebMvcConfigurer webMvcConfigurer(){ return new WebMvcConfigurer() { @Override public void configurePathMatch(PathMatchConfigurer configurer) { UrlPathHelper urlPathHelper = new UrlPathHelper(); urlPathHelper.setRemoveSemicolonContent(false); configurer.setUrlPathHelper(urlPathHelper); } }; } } // The second way is to implement WebMvcConfigurer @Configuration(proxyBeanMethods = false) public class WebConfig implements WebMvcConfigurer { @Bean public HiddenHttpMethodFilter hiddenHttpMethodFilter(){ HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter(); methodFilter.setMethodParam("_m"); return methodFilter; } @Override public void configurePathMatch(PathMatchConfigurer configurer) { UrlPathHelper urlPathHelper = new UrlPathHelper(); urlPathHelper.setRemoveSemicolonContent(false); configurer.setUrlPathHelper(urlPathHelper); } }
- The matrix variable must have a url path variable to be resolved: it should be written as the representation method of the path variable {path}
@GetMapping("/cars/{path}") public Map carsSell(@MatrixVariable("low") Integer low, @MatrixVariable("brand") List<String> brand, // The real access path is sell @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 two path variables. Each path variable has the same variable name @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; }
4.4 analysis principle of various parameters
-
Initial: as before, CTRL+N, search org springframework. web. servlet. doDispatch under dispatcherservlet. Break point debugging.
- http://127.0.0.1:8080/car/3/owner/lisi?age=18&inters=basketball&inters=game
-
Step 1: mappedHandler = getHandler(processedRequest); Click in and find the Handler (Controller.method()) that can handle the request in HandlerMapping
- mappedHandler = getHandler(processedRequest);
-
Step 2: find an adapter HandlerAdapter for the current Handler; RequestMappingHandlerAdapter
-
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
-
HandlerAdapter is an interface designed at the bottom of spring MVC. Two important functions 1 Support interface, 2 Call processing
-
Click getHandlerAdapter to select all handleradapters
There are four types
.
- Support @ 0 annotation method by default
- 1 - support functional programming
- xxxxxx
-
-
Step 3: execute the target method Or is it doDispatch in the dispatcher servlet
- mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
- First track the getHandle, and then track the handle continuously. Find org springframework. web. servlet. ModelAndView.
- Execution target method: mav = invokeHandlerMethod(request, response, handlerMethod);
- Continue to catch up and see how the target method is implemented. Find fields, find parameter parsers, and return value processors
- argumentResolvers parameter resolver. 27 species
- Determine the value of each parameter of the target method to be executed;
- How many parameter types can spring MVC target methods write. Depends on the parameter parser.
- returnValueHandlers returns the value handler. 15 kinds
-
Step 4: really implement the target method.
- By adding invocablemethod invokeAndHandle(webRequest, mavContainer);. Keep clicking in.
- Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); This will return to our Controller first, and then return to the following function. setResponseStatus(webRequest);
- Continue to click invokeforequest to see how to execute the controller method.
- Get method parameter values: Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
- Continue to click getMethodArgumentValues to see how to obtain parameter values
- Continue to click invokeforequest to see how to execute the controller method.
-
Step 5: how to obtain parameter values.
- Get the details of each parameter: MethodParameter[] parameters = getMethodParameters();
- Declare an args with the same parameter length and finally return it. Object[] args = new Object[parameters.length];
- Traversal parameters: determine whether the parser supports each parameter. if (!this.resolvers.supportsParameter(parameter)) . Specifically, enhance the for loop to judge all parameter parsers one by one.
- Parse parameter value: after confirming the parameter support, pass args [i] = this resolvers. resolveArgument(parameter, mavContainer, request, this.dataBinderFactory); Parse parameter values. Click in.
- resolveArgument in AbstractNamedValueMethodArgumentResolver is a specific parsing function.
-
Step 6: target method execution completed
- Put all data in mavContainer; Contains the page address to go to. It also contains Model data
- Put all data in mavContainer; Contains the page address to go to. It also contains Model data
-
Step 7: process the distribution results
- org.springframework.web.servlet.DispatcherServlet#processDispatchResult
- processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
- Trace to view resolution method: InternalResourceView:
-org.springframework.web.servlet.view.InternalResourceView#renderMergedOutputModel
4.2 Servlet API
- WebRequest,ServletRequest,MultipartRequest, HttpSession,javax.servlet.http.PushBuilder,Principal,InputStream,Reader,HttpMethod,Locale,TimeZone,ZoneId
- The following function parameters are: HttpServletRequest request type.
@GetMapping("/goto") public String goToPage(HttpServletRequest request){ request.setAttribute("msg","succeed..."); request.setAttribute("code",200); return "forward:/success"; //Forward to / success request }
- Access path break point. Look at the process.
- org.springframework.web.method.support.HandlerMethodArgumentResolverComposite#getArgumentResolver resolves to ServletRequestMethodArgumentResolver object
- Click in and find the following:
@Override public boolean supportsParameter(MethodParameter parameter) { Class<?> paramType = parameter.getParameterType(); return (WebRequest.class.isAssignableFrom(paramType) || ServletRequest.class.isAssignableFrom(paramType) || MultipartRequest.class.isAssignableFrom(paramType) || HttpSession.class.isAssignableFrom(paramType) || (pushBuilder != null && pushBuilder.isAssignableFrom(paramType)) || (Principal.class.isAssignableFrom(paramType) && !parameter.hasParameterAnnotations()) || InputStream.class.isAssignableFrom(paramType) || Reader.class.isAssignableFrom(paramType) || HttpMethod.class == paramType || Locale.class == paramType || TimeZone.class == paramType || ZoneId.class == paramType); }
4.3 complex parameters
- Map and model (the data in map and model will be placed in the request field of request, request.setAttribute), Errors/BindingResult, RedirectAttributes, ServletResponse (response), SessionStatus, UriComponentsBuilder and ServletUriComponentsBuilder
// Map < string, Object > map, model model, HttpServletRequest request all can put data into the request field, and finally pass the request Getattribute() get @GetMapping("/params") public String testParam(Map<String,Object> map, Model model, HttpServletRequest request, HttpServletResponse response){ map.put("hello","world666"); model.addAttribute("world","hello666"); request.setAttribute("message","HelloWorld"); Cookie cookie = new Cookie("c1","v1"); response.addCookie(cookie); return "forward:/success"; }
- Like the above analysis, breakpoint tracking:
- For Map and Model type parameters, the underlying layer will return mavcontainer getModel();
- BindingAwareModelMap is a Model and also a Map, mavcontainer getModel(); Gets the of the value
4.4 parameter object of user-defined type
- Automatic type conversion and formatting, cascading encapsulation.
package com.atguigu.boot.bean; import lombok.Data; import java.util.Date; /** * Name: < input name = "username" / > < br / > * Age: < input name = "age" / > < br / > * Birthday: < input name = "birth" / > < br / > * Pet name: < input name = "pet. Name" / > < br / > * Pet age: < input name = "pet. Age" / > */ @Data public class Person { private String userName; private Integer age; private Date birth; private Pet pet; } @Data public class Pet { private String name; private Integer age; }
- First run the index HTML, click the form request at the breakpoint. Let's look at the principle of breakpoints. How does Person bind the data in the page with each attribute of our Person one by one.
@PostMapping("/saveuser") public Person saveuser(Person person){ return person; }
-
The determination is completed by the parameter ServletModelAttributeMethodProcessor.
-
Webdatabinder: Web data binder
, bind the value of the request parameter to the specified JavaBean
- WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
- WebDataBinder uses its Converters to convert the requested data into the specified data type. Encapsulated into JavaBean s again
- GenericConversionService: when setting each value, find all converter s in it, which can convert this data type (string with parameter brought by request) to the specified type (JavaBean – Integer)
byte – > file
-
Add a custom converter so that it can recognize this object
// Add a custom converter so that it can recognize the < input name = "pet" value = "ah cat, 3" / > object @Override public void addFormatters(FormatterRegistry registry) { registry.addConverter(new Converter<String, Pet>() { @Override public Pet convert(String source) { // Ah, cat, 3 if(StringUtils.hasLength(source)){ Pet pet = new Pet(); String[] split = source.split(","); pet.setName(split[0]); pet.setAge(Integer.parseInt(split[1])); return pet; } return null; } }); }