Master the use of @RequestAttribute and @SessionAttribute from the principle level [Learn Spring MVC together]

Keywords: Java Spring Attribute Session

Every sentence

To change us, we must change the essence and remove the dross. Otherwise, wood makes sense.

Preface

If there are very few people who know the @SessionAttributes annotation, then without statistics, I can be sure that even fewer people know the @RequestAttribute annotation. I think there are two main reasons:

  1. @ Request Attribute is a very new annotation, which was not available until Spring 4.3.
  2. We can use the API call (ServletRequest.getAttribute()) to achieve our goal without annotations. And the cost is not too high.

Since Spring has introduced this annotation, it must have its advantages. This article will take you to appreciate its charm.

Spring provides annotations such as @ModelAttribute, @SessionAttributes, @RequestAttribute to simplify development and improve reusability. At the same time, another goal is to completely shield the source Servlet API and increase its scalability.

In this article, I take @RequestAttribute as an example, because @SessionAttribute (also a comment after Spring 4.3) is the same in use and principle. The only difference you can understand is the difference between ServletRequest.getAttribute() and HttpSession.getAttribute().
Again, this means: org. spring framework. web. bind. annotation. SessionAttributes, not org. spring framework. web. bind. annotation. SessionAttributes.

@RequestAttribute

It is much simpler than the @ModelAttribute, @SessionAttributes and other annotations introduced earlier, and it can only be used on method entry. Function: Get the corresponding attribute value from the request.

Many small partners are silly and confused about getParameter() and getAttribute() related methods. It's suggested that you first figure out the difference between param and attribute.~

// @since 4.3
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestAttribute {
    @AliasFor("name")
    String value() default "";
    @AliasFor("value")
    String name() default "";

    // By default, this property is required (no error is reported)
    boolean required() default true;
}

The following sentence is very important: @RequestAttribute is only responsible for extracting attribute values from requests. There are many ways to achieve when you put values in requests:

  1. @ ModelAttribute Annotation Preservation
  2. Prestore in Handler Interceptor Interceptor Interceptor
  3. Request forwarding brought in

Following are three scenarios of using Demo:

@ ModelAttribute Annotation Preservation

Simple, just use the original HttpServletRequest value in the @ModelAttribute annotation method

@RestController
@RequestMapping
public class HelloController {

    // Place attr attribute values
    @ModelAttribute
    public Person personModelAttr(HttpServletRequest request) {
        request.setAttribute("myApplicationName", "fsx-application");
        return new Person("Non-functional approach", 50);
    }

    @GetMapping("/testRequestAttr")
    public void testRequestAttr(@RequestAttribute("myApplicationName") String myApplicationName, HttpServletRequest request, ModelMap modelMap) {
        System.out.println(myApplicationName); //fsx-application

        // Get it from the request
        System.out.println(request.getAttribute("myApplicationName")); //fsx-application

        // Get it from the model
        System.out.println(modelMap.get("myApplicationName")); // null does not get attr attributes
        System.out.println(modelMap.get("person")); // Person(name = nonfunctional method, age=50)
    }
}

Request / testRequestAttr, the results are printed as follows:

fsx-application
fsx-application
null
Person(name=Non-functional approach, age=50)

It's important to note here that @RequestAttribute ("myApplication Name") annotations are not bound to attr attributes if omitted.~

However, this is possible: @RequestAttribute String myApplication Name (Spring MVC will look at the name of the parameter again to confirm the automatic binding if the annotation is not specified)
But if you write @RequestAttribute String aaa like this, the request throws an exception directly 400 errors: org. spring framework. web. bind. ServletRequestBindingException

Prestore in Handler Interceptor Interceptor Interceptor

Simple, direct code:

public class SimpleInterceptor implements HandlerInterceptor {
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        request.setAttribute("myApplicationName", "fsx-application");
        return true;
    }
     ...
}

Test code: slightly.

forward request forwarding

In this way:

request.setAttribute("myApplicationName", "fsx-application");
request.getRequestDispatcher("/index").forward(request, response); 

In fact, it only needs to follow one principle to place attribute values in any place before invoking the processor target method (before parameter encapsulation), and the attribute values can be retrieved.

Principle analysis

According to my habit, even if it's simple, I'll take a look at the principle of it.
From experience, it's easy to think of a Handler Method ArgumentResolver, which is Request Attribute Method ArgumentResolver.

RequestAttributeMethodArgumentResolver

Obviously, it's also @since 4.3, and it matches the naming.

public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {

    // Processing only the entry with the @RequestAttribute annotation
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(RequestAttribute.class);
    }

    // Attributes encapsulating this annotation are processed to NamedValueInfo here for parameter names
    // info.name.isEmpty() means that if you don't specify it, you use the parameter.getParameterName() as the formal parameter.
    @Override
    protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
        RequestAttribute ann = parameter.getParameterAnnotation(RequestAttribute.class);
        Assert.state(ann != null, "No RequestAttribute annotation");
        return new NamedValueInfo(ann.name(), ann.required(), ValueConstants.DEFAULT_NONE);
    }

    // Find attribute values from the request request request domain
    @Override
    @Nullable
    protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request){
        return request.getAttribute(name, RequestAttributes.SCOPE_REQUEST);
    }


    // If the value does not exist, throw an exception ServletRequestBindingException
    @Override
    protected void handleMissingValue(String name, MethodParameter parameter) throws ServletException {
        throw new ServletRequestBindingException("Missing request attribute '" + name +
                "' of type " +  parameter.getNestedParameterType().getSimpleName());
    }

}

The source code is short and concise, very simple.
In fact, its core parsing process for parsing reference is on its parent AbstractNamedValueMethod ArgumentResolver, but it is not the focus of this article. See the section of Handler Method ArgumentResolver for more details.~

@ RequestAttribute property required defaults to true, request.getAttribute will throw an exception ServletRequestBindingException if it can not get parameters; required is set to false, even if it is not obtained from the request, it will ignore skipping and assign null.

summary

This article introduces the use of Demo for @RequestAttribute and its very simple principle analysis. Compared with all previous articles, this one is very easy. I hope it can provide you with a way of thinking to use @RequestAttribute to improve your pushing. Haha (Friendship Tip: Pretend to be cautious.)

Note: Because @SessionAttribute is used almost exactly the same way, there is no need to repeat the length of the article.

summary

This article introduces the core processing principle of @Session Attributes, and also gives a Demo to introduce its basic use. You should have a good harvest on it if you read it unexpectedly, hoping to help you simplify development.~

Relevant Reading

Grasp the use of Handler Method, Invocable Handler Method, Servlet Invocable Handler Method from the principle level [Learn Spring MVC together]
Grasp the Use of @Session Attributes from the Principle Level [Learn Spring MVC Together]
Grasp the Use of @ModelAttribute from the Principle Level (Core Principles Chapter) [Learn Spring MVC Together]
Grasp the Use of @ModelAttribute from the Principle Level [Learn Spring MVC Together]

Knowledge exchange

== The last: If you think this is helpful to you, you might as well give a compliment. Of course, sharing your circle of friends so that more small partners can see it is also authorized by the author himself.~==

** If you are interested in technical content, you can join the wx group: Java Senior Engineer and Architect.
If the group two-dimensional code fails, Please add wx number: fsx641385712 (or scan the wx two-dimensional code below). And note: "java into the group" will be manually invited to join the group**

If the format of the article is confused or the picture is split, please click ` Text Link - Text Link - Text Link

Posted by resting on Thu, 08 Aug 2019 08:19:03 -0700