Organising View in Spring MVC in real enterprise based application? - spring

I am learning Spring MVC framework, and created a simple "Hello world" kind of web-application using Spring MVC framework.
My controller code is like this:
#Controller
public class SimpleController {
#RequestMapping("/welcome")
ModelAndView handleIncomingWelcomeReq() {
ModelAndView mw = new ModelAndView("WelcomePage","welcomeKey","WelcomeKey's value!");
return mw;
}
}
The spring configuration is:
<beans>
<context:component-scan base-package="com.example.controller, com.example.util"/>
<bean id="viewResolver1" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix"> <value>/WEB-INF/</value> </property>
<property name="suffix"> <value>.jsp</value> </property>
</bean>
</beans>
The code is straightforward, for /welcome , handleIncomingWelcomeReq() gets invoked and welcomePage.jsp is returned to the client.
For this simple application, we need to specifically mention the view page which it returns. Now my question is:
In real enterprise web-applications, how do we organise the view / page which gets returned for matching url. Wouldn't the spring configuration get too big, because we have to specifically mention the page which gets returned for each incoming url.
Is this the way Spring MVC builds the real life enterprise web application. Each page specifically mentioned in the spring configuration page?
Any inputs on this which help clarify this really appreciated.

The responsibility of defining the page flow specifically lies on individual controllers and views; for instance, you usually map a web request to a controller, and the controller is the one that decides which logical view needs to be returned as a response. This is sufficient for straightforward page flows, but when your application gets more and more complex (real enterprise web-applications) in terms of user interface flows, maintainance becomes a nightmare. If you are going to develop such a complex flow-based application, then Spring Web Flow can be a good companion. Spring Web Flow allows you to define and execute user interface flows within your web application.

Related

Specify complete path of view file in spring controller instead of using view resolver

Is it possible to specify complete path of a view file in controller without making use of view resolver?
Suppose I have just one file, say a XML file in my views and for a particular request I want to serve that XML file. By using view resolver, I am not able to find a way to pick up such a file and server it directly like me serve a jsp. So, for such a case can I do something in which I specify complete path in controller like we used to do in servlet's getRequestDispatcher?
My view resolver is currently configured for JSP only, I am not able to find a view using view resolvers to handle this situation, my view resolver is like as given below:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/jsp/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
Currently I am using getRequestDispatcher in controller for this? Is there any spring based alternative?
Spring MVC allows you to create a request handling method with different return types, see the reference guide. Instead of a String return a View from your method which points directly to your resource. When you return a View instance Spring MVC will not consult a ViewResolver but simply use the view as is. For you case you probably want to use an InternalResourceView.
#RequestMapping
public View yourRequestHandlingMethod() {
return new InternalResourceView("path/to/resource");
}

Spring customised PropertyPlaceholderConfigurer

I have config xml based spring application for which I have moved proprties required at start up time in database. It was very difficult to manage hundreds in property file and that is why database is introduced. To read properties a spring restful service is developed to return a map of all properties required at start up time.
I want to know how to replace properties reading from a map to spring context file e.g. ${config.service.url} should be polulated from a map read via web service.
One option I considered is to upgrade to Annotation based and start using MapPropertySource and Environment interface as environment.getRequiredProperty("config.service.url"). However upgrading to Annotation based is a big impact on project and is no at this time.
Second option that I am looking forward is to have a customised PropertyPlaceholderConfigurer.
Any pointer/help on this will be great.
Cheers,
Amber
You could define a PropertyPlaceholderConfigurer, but instead of specifying a file location, you can pass the properties directly as returned by your restful service.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties" .../>
</bean>

Managing custom Acccept header in Spring MVC

I have a RESTful web service developed using Spring MVC and without any configuration I can return objects from my #ResponseBody annotated controller methods that get serialized to JSON. This works as soon as the Accept header in the request is not set or is application/json.
As I'm getting inspired by the GitHub API specification, I wanted to implement custom mime type for my API as GitHub does, for example: application/vnd.myservice+json. But then I need to tell Spring MVC that my controllers can provide this mime type and that it should be serialized by Json (i.e org.springframework.web.servlet.view.json.MappingJacksonJsonView class).
Any idea how to do it?
You can probably do exactly what is being done with org.springframework.http.converter.json.MappingJacksonHttpMessageConverter. Since it is not a final class, you can derive your converter from this one this way:
class MyCustomVndConverter extends MappingJacksonHttpMessageConverter{
public MyCustomVndConverter (){
super(MediaType.valueOf("application/vnd.myservice+json"));
}
}
then register your converter this way:
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="MyCustomVndConverter "/>
</mvc:message-converters>
</mvc:annotation-driven>
It should just work with these changes

Abstract a web application using Spring

We have a web application that is domain specific. By domain specific I mean that some values and behaviour are hard coded and not generic enough to handle new domain. So we are in a phase of abstracting the application and make it more open to new domain.
We are using maven, spring and JSP. The idea is to have a project that is generic and one project by domain that would contain the resources. The final application would be a combination of the generic app and one of the domain resources.
I identified different elements that we need to abstract, and wanted to know the best practices to achieve the abstraction using Spring.
Static HTML page like contact us information.
The current implementation is a controller method coupled with a contact.jsp page.
#RequestMapping("/contact.htm")
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) {
return new ModelAndView("contact");
}
Spring is looking for a page contact.jsp in /WEB-INF/jsp/contact.jsp.
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean
I added a new dependency that contains the contact.jsp. In my-resources.jar, I have the jsp file under /WEB-INF/jsp/contact.jsp. Is there a way to configure the viewResolver to fetch the file as a resource from the jar instead of fetching the file as a File on the file system?
UI
We have a radio button that allows the user to choose between several versions. Not all versions apply to all domain, so for one domain only 2 versions would be displayed, and for another domain, 4 versions would be displayed.
The idea is to create a property file in the my-resources.jar to configure the UI.
versions.supported = 2, 3
What is the best way to access the property file since it would be needed in almost all the controllers?
Because you are using maven, why not make your generic project package as war? This will solve your problem. Also you domain specific project can over ride generic project files if needed.I worked on a project with similar requirements. You will always find a case where you need to override generic project files.

Spring: Global Path Variable or Request Parameter without Controller

I have a Spring Boot & Spring Security application running, which should now get multi tenancy support.
I'd like to keep things as simple as possible. Though I'd like to determine the the database by path variable or request parameter. (the Apache Web Server in front of the Spring Boot app will handle that, i.e. it maps from subdomain to either path variable or request parameter).
Now I need a way to grab the first path variable (or a specific request param) before Spring calls the controller, and of course the value must be stored somewhere, so I can access it when I need to choose the right database.
So either (depending on what's possible / easier)
http://localhost:8080/customer1 (which I'd prefer) or
http://localhost:8080?_customer=customer1
should simply call the #Controller with #RequestMapping("") and the value customer1 should be stored somewhere for that request.
I know that 2. might be simpler, because it will already hit the right #Controller, but I'd prefer 1. somehow.
Thank you!
EDIT:
I just recognized, that HandlerInterceptor doesn't work as expected, because Spring Security always handles the requests first. Though I need an Interceptor that handles it before Spring Security kicks in.
You can make use of org.springframework.web.servlet.HandlerInterceptor. Implement the logic to store the values in request via preHandle method.
Configure it in spring config file as below
<mvc:interceptors>
<bean class="com.blah.interceptor.SomeInterceptor"/>
</mvc:interceptors>
In case requests are to be intercepted based on path, use below config instead
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/customer1" />
<bean class="com.blah.interceptor.SomeInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>

Resources