Usage of different ViewResolver in Spring Mvc - spring

I am a beginner in spring-mvc. While going through the view resolvers, I am able to understand that how to use following view resolvers:
BeanNameViewResolver,InternalResourceViewResolver and
UrlBasedViewResolver
I have already gone through the google to understand but still i am not clear about their pros and cons over each other.
How one should decide when to use which view Resolver.
If someone can help me in understanding that,it would be a great help.
Thanks,

InternalResourceViewResolver is a subclass of UrlBasedViewResolver.
UrlBasedViewResolver and InternalResourceViewResolver are often used in MVC application where the controller return the name of the view that should been rendered. The controller return an logical name of the view, and the resolver made it a file name (of the jsp), by adding some pre - and postfix. For example: logical view name return by the controller: main/example, prefix: /WEB-INF/pages/, postfix: .jsp -> /WEB-INF/pages/main/example.jsp gets rendered with the model-data provided by the controller
The UrlBasedViewResolver needs a View class (like the most other ViewResolvers too). (very brif: The view class is responsible for rendering, while the resolver is responsible to pick the right template/...) The view used in UrlBasedViewResolver has to be an subclass of AbstractUrlBasedView.
The InternalResourceViewResolver is convenient subclass of UrlBasedViewResolver that has be default already a configured view: InternalResourceView (or JstlView when Jstl is present). So it is the right resolver when JSPs are used as template engine.
There are other AbstractUrlBasedView implementations, for example for JasperReports, Freemaker, Velocity, Tiles, .... Most of them has a convenient subclass of UrlBasedViewResolver too.
BeanNameViewResolver very very old resolvers, from the old Spring 2.0 time. At this time each controller was for handling one URL. At this time there was no #RequestMapping annotation, and one has to tell Spring which controller was for which url. One could list them all, or have this Resolver, that was able to map url->controller by the controller name. Since Spring 3.0 (more exact since 2.5) and Springs annotation support, this resolver is used very rarely.

When your Spring application loads there is default ViewResolver that gets loaded - InternalResourceViewResolver. You can refer to the default beans that gets initialized in DisplacherServlet.properties in spring-webmvc jar In case of View Resolvers it is -
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
which essentially returns a JSTL view.
There are lot of URLBasedViewResolvers like -
InternalResourceViewResolver
VelocityViewReolver
FreeMarkerViewReolver
ThymeleafViewResolver
XsltViewReolver
Yup you read it right. InternalResourceViewResolver is a convenient subclass of UrlBasedViewResolver.
If you want to know more about these View Resolvers see - http://www.studytrails.com/frameworks/spring/spring-mvc-view-resolver.jsp
NOTE : Important point to note in case of chaining of view resolvers. In the chain Spring moves on to next View resolver only if current View resolver returns null. Some URLBasedViewResolvers (Tiles, Velocity,Freemarker) check if resource exist and return null. So they can be anywhere in the view resolver chain. Others must be last (JSTL/JSP, XSLT, JSON)

Related

Putting Spring WebFlux Publisher inside Model, good or bad practice?

I'm working on a code audit on a SpringBoot Application with Spring WebFlux and the team is putting Publisher directly inside the Model and then resolve the view.
I'm wondering if it is a good or bad practice because it seems to be working but in that case, which component is in charge of executing the Publisher ?
I think that it's the ViewResolver and it should not be its job. What do you think ?
Moreover, if the Publisher is not executed by the Controller, the classes annotated by #ControllerAdvice such like ExceptionHandler won't work if these Publisher return an error, right ?
Extract of the Spring WebFlux documentation :
Spring WebFlux, unlike Spring MVC, explicitly supports reactive types in the model (for example, Mono or io.reactivex.Single). Such asynchronous model attributes can be transparently resolved (and the model updated) to their actual values at the time of #RequestMapping invocation, provided a #ModelAttribute argument is declared without a wrapper, as the following example shows:
#ModelAttribute
public void addAccount(#RequestParam String number) {
Mono<Account> accountMono = accountRepository.findAccount(number);
model.addAttribute("account", accountMono);
}
#PostMapping("/accounts")
public String handle(#ModelAttribute Account account, BindingResult errors) {
// ...
}
In addition, any model attributes that have a reactive type wrapper are resolved to their actual values (and the model updated) just prior to view rendering.
https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-ann-modelattrib-methods
Doesn't come as a shock to me.
Actually seems to be a good trade off between complexity and efficiency when the Publisher is handling complex stuff.
It has the advantage of executing the Publisher only if and when needed.
Although it might be a problem if the ModelMap handler does not have the capacity to use it properly.
As for the exceptional cases, maybe you do not want it to be executed and just printed, thus failing faster.
As for the question about what is executing the Publisher, a specific ViewResolver can be used as it is the component responsible for the "rendering". IMHO that's it's job. I do not know if a standard ViewResolver can be used for detecting values vs publishers and handle those automagically, yet this seems completely doable and efficient.

Multiple View Rendering issue in Spring Boot

I am using Spring Boot application. In that i have used Spring MVC at front end. I have a requirement to download various reports like pdf, xls. As i understand, Spring Boot, internally uses ContentNegotiatingViewResolver, BeanNameViewResolver, ViewResolverComposite and InternalResourceViewResolver. I am not overriding any beans in code and using default configurations as provided
Currently to test, i am using below url
http://localhost:8080/SearchCustomers.xls
Properties in application.properties file are
spring.mvc.media-types.pdf=application/pdf
spring.mvc.media-types.xls=application/vnd.ms-excel
In my code, i have created a view class which extends from AbstractPdfView.It is a spring bean and it's id is "SearchCustomers".Controller code returns "SearchCustomers" as a view name.
Whenever i execute above code, ContentNegotiatingViewResolver doesn't returns any view.ContentNegotiatingViewResolver internally uses BeanNameViewResolver, ViewResolverComposite and InteralResourceViewRsolver to resolve view names.In our case, the bean name matches with view but its media type doesn't as it matches the path extension internally along with the bean content type.This is a correct Behavior?
However DispatcherServlet reiterates through all view resolvers and which is causing an issue.
In the second iteration, BeanNameViewResolver matches the bean id with returned view name from controller and it invokes the pdf view,which i believe is incorrect.
Is there any workaround for this?
I found out the solution
If you want just one controller method to handle all type of requests..then in that case your view should be given id in below format
id - viewname + path extension
Ex
My controller method returns view name as "SearchCustomers" for all type of request..
I have created different views for different requests like
#Component("SearchCustomers.pdf")
class MyPdfView extends from AbstractPdfView
#Component("SearchCustomer.xls")
class MyExcelView extends from AbstractExcelView
Interanally, CNVR searches for these beans. and then it matches the mediatype/contenttype which returns the correct view

Spring: new() operator and autowired together

If I use Spring, which of these two methods is more correct.
Can I use the new() operator even if I use dipendency injection?.Can I mix both?
I would like to have some clarification on these concepts.
Thanks
First method:
#RequestMapping(method=RequestMethod.GET)
public String create(Model model){
model.addAttribute(new User());
return "index";
}
Second Method:
#Autowired
User user;
#RequestMapping(method=RequestMethod.GET)
public String create(Model model){
model.addAttribute(user);
return "index";
}
By using dependency injection does not mean that the use of new operator is automatically prohibited throughout your code. It's just different approaches applied to different requirements.
A web application in spring is composed of a number of collaborating beans that are instantiated by the framework and (unless overriding the default scope) are singletons. This means that they must not preserve any state since they are shared across all requests (threads). In other words if you autowire the User object (or any other model attribute), it is created on application context initialization and the same instance is given to any user request. This also means that if a request modifies the object, other requests will see the modification as well. Needless to say this is erroneous behavior in multithreaded applications because your User object (or other model attribute) belongs to the request, so it must have the very narrow scope of a method invocation, or session at most.
You can also have spring create beans with different scopes for you, but for a simple scenario of a model attribute initialization, the new operator is sufficient. See the following documentation if interested in bean scopes : Bean scopes
So in your use case, the second method is totally wrong.
But you can also delegate the creation of your model attributes to spring if they are used as command objects (i.e. if you want to bind request parameters to them). Just add it in the method signature (with or without the modelattribute annotation).
So you may also write the above code as
#RequestMapping(method=RequestMethod.GET)
public String create(#ModelAttribute User user){
return "index";
}
see also : Supported method argument types
If you want your beans to be "managed" by Spring (for e.g. to use with Dependency Injection or PropertySources or any other Spring-related functionality), then you do NOT create new objects on your own. You declare them (via XML or JavaConfig) and let Spring create and manage them.
If the beans don't need to be "managed" by Spring, you can create a new instance using new operator.
In your case, is this particular object - User - used anywhere else in code? Is it being injected into any other Spring bean? Or is any other Spring bean being injected in User? How about any other Spring-based functionality?
If the answer to all these questions is "No", then you can use the first method (create a new object and return it). As soon as the create() method execution is complete, the User object created there would go out of scope and will be marked for GC. The User object created in this method will eventually be GC-ed.
Things can be injected in two ways in a Spring MVC applications. And yes, you can you can mix injection and creation if doing right.
Components like the controller in your example are singletons managed by the application context. If you inject anything to them it is global, not per request or session! So a user is not the right thing to inject, a user directory can be. Be aware of this as you are writing a multithreaded application!
Request related things can be injected to the method like the used locale, the request, the user principal may be injected as parameters, see a full list at Spring MVC Documentation.
But if you create a model attribute you may use new() to create it from scratch. I will not be filled by spring but to be used by your view to display data created by the controller. When created in the request mapped method that is ok.

Accessing Spring Controller Name from View

With Spring, how can i retrieve the following Controller attributes in the view?
Controller name
Controller's #RequestMapping URI
Action method name
Action method's #RequestMapping URI
One approach which i have tried is by creating a subclass of HandlerInterceptorAdapter and overriding postHandle. I register my subclass as an mvc:interceptor for a list of given paths - which is clunky to maintain but was the only way to avoid my interceptor being called for ResourceHandler requests (which i don't want). In my postHandle i can easily add the 2 name attributes, but not the URIs...
Parsing from the HttpRequest object requires constraints on all Controller RequestMappings. I.e. i must always map /Controller/Action or equiv scheme. Quite limiting.
Creating an ApplicationContext and querying that with the requestURI is too long-winded.
I am thinking about dropping the HandlerInterceptorAdapter and instead defining a BaseController for all my controllers to extend.
I wanted to ask before i do this, is there a better approach?
You haven't stated why you need to do this (it sometimes helps to include your motivation, as others can suggest alternative approaches).
But I'm guessing that the Spring 3.1 features loosely termed "end point documentation" may do what you are asking... See RequestMappingHandlerMapping in the Spring documentation which doesn't provide a lot of detail, so this example project is the best place to see it in action:
Spring MVC 3.1 Demo App
example controller
example JSP page

Ninject MVC 3 - Injecting dependencies into models and controllers

I don't fully understand what's happening behind the scenes when we inject dependencies into controllers and models.
I have the following controller:
public class TypeController : CommonController
{
private ILookUpService lookUpService;
public TypeController(ILookUpService lookUpService)
{
this.lookUpService = lookUpService;
}
}
As the application starts, the lookup service is already available. So I guess that somewhere behind scenes we have code on the lines of
TypeController controller = new TypeController(service);
or something to do with factory (which I need to read up about).
When it comes to injecting a service into a view model, it doesn't work as I need to invoke an empty constructor without passing interface to my service.
So what is happening behind the scenes? How do I inject a service into a view model? I guess I'm missing some real fundamental stuff which is stopping me from doing what I need.
I have included FactoryPattern in the tags as my gut feeling tell me it has something to do with my problem..
Thank you
You shouldn't inject anything into the view model. The view model should be a simple data container which is filled from the controller and therefore shouldn't have any dependencies.

Resources