if we put the annotation #ModelAttribute before a method, it will be called before every request (before #RequestMapping)
Is there any similar way to call method after every request?
The way to do this would be to define a Spring Interceptor or more generally using AOP.
#ModelAttribute annoted methods serve a different purpose, their primary purpose is to set common model attributes, a side effect of which is that such methods need to be invoked before the actual #RequestMapped methods.
Related
I have some entities and a separate controller for each of them. In these controllers, there is one method that is always the same and it is the edit form route. I have a service that builds a form for any given entity so basically this method has three lines: build the form, assign to the model, return the view name. The view is also the same as the only difference on that page is the form. So what is different is the path and the path variable's type (Entity type).
I would like to move this one method to a common superclass. I could solve the type of the path variable with some generic types. The problem is the path. I know that the value of #RequestMapping has to be a constant so is there any other way around it?
I guess I could technically create a method that does what I need then in every inherited class I can create another method that calls this one or even overrides the original method. I was just curious if there was a better way.
I believe what you're describing: 'creating a method that does what you need in the super class' then assigning the #RequestMapping in the concrete implementation to create the routing, is likely the common best practice for handling this in Spring.
If you want to be fancy with the Spring route mapping you can manipulate them at start up using the RequestMappingHandler to manually assign route mappings to a controller method, but note that #RequestMapping on a class will create a route for the method even if it's an abstract class (not sure about on abstract methods, but I assume not). However you can use #RequestMapping on interfaces abstractly. You can find an example of how to do that here
Using the above handler you could create your own type of inheritance chain using reflections and a custom annotation on the base class that you manually assign to the route base in the request mapping handler.
public ModelAndView loginPage(HttpServletRequest request, Locale locale) {}
As you know, Spring injects HttpServletRequest and Locale into the method. I want to know
how is it done behind the curtains ? My guess is, there is a data converter system working behind
that takes http request headers and body data and fill them into the suitable classes that are given
in arguments by the coder. Am I right ?
When working with Spring MVC there are multiple parts moving to solve the problem of mapping HandlerMapping and execution HandlerAdapter.
Each #Controller is scanned for #RequestMapping annotated methods, the methods are mapped to URLs based on the metadata available in the #RequestMapping annotation, this is done by the RequestMappingHandlerMapping class.
When a request comes in the specific method is matched on the incoming request. This selected method is passed the RequestMappingHandlerAdapter which consults all method arguments. The actual handling of the method argument is left to different HandlerMethodArgumentResolver implementations (you could also implement your own).
The same happens for the return value of your method although that is delegated to a HandlerMethodReturnValueHandler.
Yes, you're right. In short, there is a single entry point into the application (there may be more than one entry point) that routes incoming traffic, passing incoming data to methods as parameters. This is known as the front controller pattern.
Spring's DispatcherServlet is an implementation of the front controller pattern. The Spring reference details the pattern as followed in Spring, and the pattern is listed among the core Java EE patterns.
In Spring MVC, Inside a Controller class, the method annotated with #RequestMapping annotation are allowed to have Flexible Method Signature.
If I want to do something like this with my own custom annotation, Can somebody give me some pointers for the same.
Thanks in Advance.
Spring MVC has a lot of features in that regard so it might be easier to look elsewhere as a starting point. The new messaging abstraction that was introduced in Spring 4 has similar features.
Look at #MessageMapping which allows you to build a flexible signature against a Message instance. You could for instance inject a header of the message
public void foo(#Header("myHeader") int myHeader)
Or you could validate that the payload against a Validator
public void bar(#Payload #Validated Order order)
The core of the infrastructure is located in InvocableHandlerMethod which is going to invoke a java.lang.reflect.Method you have provided on a given bean instance based on an incoming Message and additional parameters you may provide (see public final Object invoke(Message<?> message, Object... providedArgs)
To create that instance, you need to provide a set of HandlerMethodArgumentResolver. Each HandlerMethodArgumentResolver is responsible to handle a method parameter. In short, that's basically going to provide you a MethodParameter instance (i.e. a reference to a parameter of the method you want to handle, such as the annotated order in the last example) and you're going to tell if you support it or not and when you do, handle that parameter so that the right value is injected. For the header example, the implementation looks for a header with the name on the annotation. Simple!
A set of default resolvers are created for example in SimpAnnotationMethodMessageHandler (look at initArgumentResolvers). That's going to show you the kind of parameters you can inject there by default. By extending that list (or providing custom instances) you can augment what the user can use in the method signature.
In Spring 4.1, we rely on this infrastructure to provide JMS listener annotated endpoints and those endpoints may have a flexible signature as well. It's actually already implemented so you may want to have a look to that for yet another example.
When using Spring AOP to create a proxy for a class using NameMatchMethodPointcutAdvisor and BeanNameAutoProxyCreator does this essentially proxy every call to the object, but only apply the advice to the matched methods, or somehow create a Proxied object that only has those methods and uses the normal object for the calls that are supposed to be intercepted?
The way, I think I understand it is that it does proxy every call to the object but then only calls the Advisor on the methods that match - but I can't find a good example/post to confirm this.
Depends on the technique used. (It is configurable by an attribute proxy-target-class in your aop config)
JDK dynamic proxies are proxies by interface - each methods of the interface goes through the proxy, as you said, and if it matches happens to be an "advised" method, the advisor is applied. Otherwise it is delegated to the original object
CGLIB proxies are effectively subclasses defined at runtime of your concrete classes. I can't be sure in this, but I assume only the "advised" methods are overridden, the rest retain the definition of the superclass.
However, no matter which mechanism is used:
it isn't your concern how exactly are the proxies implemented
this doesn't impact performance in a significant way - Debunking myths: proxies impact performance by the Spring team about proxy performance myths
or somehow create a Proxied object that only has those methods and uses the normal object for the calls that are supposed to be intercepted?
How would this actually work? When a class has a reference to the class that is being proxied, it only has one reference to it. It either has to invoke a proxy class or a non-proxied class. Spring can't know which methods you are calling and therefore can't give you one type if you need to call the advised method and another type if you're not.
With Spring MVC, it's easy to express a concept like "A user is submitting the form if they use POST or if they include the 'isSubmit' parameter." You'd just extend SimpleFormController and override the isFormSubmission method.
However, Spring MVC now uses these neat annotations like #RequestMapping to handle requests. #RequestMapping has an obvious filter for whether somebody used a GET or a POST, but I don't see any inherent support for all of the useful logic SimpleFormController provided. Is it still available to me with annotations?
So, after a bit of investigation, there are in fact a couple of ways to handle this situation.
The first way is to go ahead and use a SimpleFormController with with #RequestMapping annotation at the class level. A lesser-known but pretty cool property of #RequestMapping is that it knows perfectly well how to deal with the classes that implement Spring's Controller interface. The only downside here is that I'm still using the old MVC interfaces and classes, and they're going to be deprecated in Spring 3.0.
The second way was pointed out by kgiannakakis above. Simply create a #RequestMapping method for every way that the submit can be called, and have them all just call a single submit method, either in a constructor-chaining style or with some private method. Simple and easy to understand. Thanks, kgiannakakis!
Copying from here:
Path mappings can be narrowed through parameter conditions: a sequence of
"myParam=myValue" style expressions, with a request only mapped if each such
parameter is found to have the given value. "myParam" style expressions are
also supported, with such parameters having to be present in the request
(allowed to have any value). Finally, "!myParam" style expressions indicate
that the specified parameter is not supposed to be present in the request.
You can only use the RequestMapping options to define the desired functionality. The Annotations Controller doesn't implement any interface to work with.
Here is one example of using Path mappings:
#RequestMapping(params = "formAction=APPROVE", method = RequestMethod.POST)
public String myMethod ()....
This method will only be called then for POSTs where there is a field named "formAction" with a value of "APPROVE".
The other answers listed work fine for a method annotated with #RequestMapping.
However, if you want to achieve the same thing on a method annotated with #InitBinder, you can simply do this:
#InitBinder
public void initBinder(HttpServletRequest request) {
if ("POST".equals(request.getMethod()){
//Do something
}
}