The SpringBoot series parses complex parameters

Posted by Prank on Sun, 30 Jan 2022 04:28:37 +0100

SpringBoot series (III) parsing complex parameters

preface

When we write the interface, we will pass in complex parameters, such as Map and Model. Such similar parameters will be parsed by the corresponding parameter parser, and finally the parsed value will be put into the request field. Let's explore the principle together.

Tip: the following is the main content of this article. The following cases can be used for reference

1, Code example

Now, let's start our exploration journey with a demo. Please see below:
controller:

@GetMapping(value = "/params")
    public String hello(Model model,
                        Map<String,Object> map){
        model.addAttribute("hello","zhangsan");
        map.put("world","lisi");
        return "forward:/test/render";
    }

    @GetMapping(value = "/render")
    @ResponseBody
    public String success(HttpServletRequest request){
        Object hello = request.getAttribute("hello");
        Object world = request.getAttribute("world");
        System.out.println(hello);
        System.out.println(world);
        return "aaa";
    }

Output result:

zhangsan
lisi

2, Principle analysis

Let's first look at the method call stack:

Next, let's analyze the getMethodArgumentValues method:

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;
			}
			//one ⃣  find a parser that can be used to parse the parameter
			if (!this.resolvers.supportsParameter(parameter)) {
				throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
			}
			try {
			//two ⃣ Resolve the parameter and put it into mavContainer
				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;
			}
		}
		//three ⃣ Return the parsed parameters
		return args;
	}

1. For key points 1 ⃣ 7078 28326 16529 1046 9070 14429 13408 18111 6785 15408 7788

As we can see from the figure, the red line can support the two parameters passed in our code example.

2. For key points 2 ⃣ Next, let's take a look at its schematic diagram:

Next step:

Then proceed to the next step:

From here, we can see that the parsed value is put into the BindingAwareModelMap. Let's take a look at the value of the args array finally parsed:

As can be seen from the figure, the parameters of Map and Model are finally parsed and put into BindingAwareModelMap. Then obtain the return value through the reflection execution target method, as shown in the following figure:

Next, call the getModelAndView method, take out the value in mavContainer, encapsulate it into a ModelAndView, and return it as follows:

Then execute the processDispatchResult method as follows:




Here comes the most critical step, as shown in the following figure:

As we can see from the figure, we put the value in the model in ModelAndView into the request field.

summary

The above introduces the analysis principle of SpringBoot on complex parameters. debug step by step according to the above steps, and you can clearly understand the analysis of each complex parameter.

Topics: Java Spring Spring Boot