How can i share an object between all controllers? - spring

I'm using Spring-Boot and Thymeleaf as a template engine.
I have a web application which has a search input that is accessible in every view to anyone (the search triggers a form submission), the form has a th:object="${searchObject}" attribute and I'm using#RequestBody in my post controller to get the object.
Now, what i did so far was adding a model.addAttribute("searchObject", new SearchObject()) to every controller and it worked just fine but it made me think, what if there is a way to share an object between the whole app that i could declare once and use everywhere .. ?
So i did a little search and found out various solutions that refers to the available contexts in a spring application.
Iv'e tried to implement few of them but couldn't figure out how.
So, is there any simple way of sharing an object between the whole app so it can be accessed inside thymeleaf without writing the same code in every controller?
I'm thinking it should look something like this
th:object="${#sharedObjects.getObjectByName(object)}"
Thanks.

You can use a #ControllerAdvice to add a model attribute in all of your controllers:
#ControllerAdvice
public class SearchObjectModelAttributeAdvice {
#ModelAttribute("searchObject")
public SearchObject searchObject() {
return new SearchObject();
}
}

Related

Request body field processing in spring

I am working on a spring base web application where, we have a few RestControllers and some Request DTO classes. Request DTO contains a token field which needs some validation. So I used spring validators to validate that. After validation, we want to send that field to an external system using another REST API (Just for some kind of analytics logging). The same field is repeated in multiple DTO objects and their controllers. So, I am easily able to define annotations for validators and reuse them across the DTOs. But I am not sure how to process that field after validation succeeds (i.e. call analytics API to consume that field post validation), without mixing it with the core logic of controllers.
Approaches I could think of:
Implement a filter/interceptor and process the field there. But then
there is a limitation that request body can be read only once so I
need to use some alternate ways by creating request wrappers.
Repeat the logic in every controller and it is very error prone as for
every new controller we need to remember to write that code.
But non of these approaches look cleaner. Can someone recommend a better way to achieve that?
Thanks in advance.
You can create a BaseController and implement the method there. Extend this BaseController wherever you need this logging service. Like below.
BaseController.java
class BaseController {
protected void remoteLogging(String name,String token) {
//Calling the remote log services}
}
AppController.java
#Controller
#RequestMapping("register")
public class LeaseController extends BaseController {
#PostMapping("new")
public String new(#Valid #ModelAttribute("registration") Registration registration,BindingResult result){
if(rest.hasErrors(){
remoteLogging("name","token");
}
}

ASP.NET WebAPI: Generic controller for OData endpoint

I'm currently experimenting with OData endpoints in ASP.NET MVC 4 Web API. I like the concept and try to come up with efficient ways to use it in our project.
One question I have is the following: we have a service that is able to return an IQueryable and takes the name of an entity as Input:
public IQueryable GetAll(string entityName);
In standard Web API (as opposed to OData Controllers) I can create a generic controller, that can be called in the form /api/entities/{entityName} and returns the IQueryable.
In case of an OData Controller, I carry out the following entity-specific steps:
Register the entities in the model.
Create a separate Controller for each entity that derives from EntitySetController<>.
I want to use the generic service and avoid as much entity-specific implementations as possible. The first step can easily be automated if the service can return a list of the entities and the corresponding types.
That leaves step 2, because up to now I need to create a specific controller for each entity. I also want to avoid that and create a generic controller that uses the generic service.
Can anyone recommend a solution, maybe by influencing OData routing?
You can create a custom routing convention that selects the same controller no matter what the entity set is. Example,
public class CustomControllerRoutingConvention : IODataRoutingConvention
{
public string SelectAction(ODataPath odataPath, HttpControllerContext controllerContext, ILookup<string, HttpActionDescriptor> actionMap)
{
return null;
}
public string SelectController(ODataPath odataPath, HttpRequestMessage request)
{
return "SomeFixedContrllerNameWithoutTheControllerSuffix";
}
}
You can register that routing convention using the following code,
IList<IODataRoutingConvention> routingConventions = ODataRoutingConventions.CreateDefault();
routingConventions.Insert(0, new CustomControllerRoutingConvention());
config.Routes.MapODataRoute("OData", "odata", builder.GetEdmModel(), new DefaultODataPathHandler(), routingConventions);
I came up against the same problem, and ended up writing a custom IHttpControllerSelector instead of an IODataRoutingConvention. IODataRoutingConvention looks like a good option if your generic controller doesn't require generics :) . But since IODataRoutingConvention.SelectController() only returns a string, I don't see how it will work for instantiating a controller with generic type parameters.
I decided this problem needs a good, general-purpose, open-source solution - so I created one: https://github.com/EntityRepository/ODataServer . It's prerelease now, but I'm currently doing a lot of work on it. I think there's more to it than just choosing the right controller, there are general patterns to define for shared controllers, and by default Web API OData expects strongly typed and strongly named navigation properties which makes it challenging to create a re-usable implementation.

How to map a path to multiple controllers?

I'm currently working on a spring based web application and have a special requirement that seems not (at least not out of the box) be provided by spring MVC. The application serves data for multiple users each organized in their own "company". Once a user has logged in, I'm able to identify to which company he belongs to.
The application itself is built with multiple "modules", each with it's own domain objects, DAO, Service and Controller classes. The idea behind this concept is that I can for example extend a certain controller class (let's say to use a different service class) based upon the user and here is my problem.
Since i do not want to change my request paths for certain users, I'm currently looking for a way how to serve a request issued on a certain request path with different instances of a controller based upon the user issuing the request.
I came up with the idea to attach a HTTP Header Field for the company
Example:
X-Company:12345
and have my controllers configured like this:
#Controller
#RequestMapping(value="/foo/")
public class FooController {
// ...
}
#Controller
#RequestMapping(value="/foo" headers="X-Company=12345")
public class SpecialFooController extends FooController {
// ...
}
However this is not possible, since spring MVC treats each header (except Content-Type and Accept) as a kind of restriction, so in my case it would handle all requests with the FooController instead of the SpecialFooController unless i add a "headers" restriction on the FooController as well, which is not practicable.
Is there some way how to customize this behaviour or some direction one could point me to look for? Or maybe someone has another idea how to achieve this. It'll be highly appreciated.
Thanks!
I'am not sure but I think you can do this with HandlerMapping. Have a look at the documentation
To take your own suggestion, you can use the #RequestHeader annotation in your controller methods:
#Controller
public class MyController {
#RequestMapping("/someAction")
public void myControllerMethod(#RequestHeader('X-Company-Id') String companyId) {
}
}
Or you could use #PathVariable:
#Controller
public class MyController {
#RequestMapping("/{companyId}/someAction")
public void myControllerMethod(#PathVariable("companyId") String companyId) {
}
}
Using this approach would mean that it is in fact different URLs for each company, but if you can set the company id header, I guess you also can suffix the URLs with the company id.
But there are also other possibilities. You could write an interceptor that puts the company id in a session or request variable. Then you wouldn't have to add the annotation to every controller method. You could also use a subdomain for each company, but that wouldn't look too pretty if the company id is a random alphanumeric string. E.g: companyone.mydomain.com, companytwo.mydomain.com
Edit
#RequestMapping can be added to the controller level as you know, so you should be able to do
#Controller
#RequestMapping("/controller/{companyId}")
as the base url, if that's a better option.
I was able to meet the requirement by making usage of a customized RequestCondition. By defining your own annotation that can be placed at the type and method level of a controller. Extending the RequestMappingHandlerMapping by your own implementation and overriding the getCustomTypeCondition() and getCustomMethodCondition() methods translates a controller annotation into your own RequestCondition.
When a request comes in, the custom RequestCondition will be evaluated and the annotated controller(method) will then be called to serve the request. However this has the downside, that one needs to remove a servlet-context.xml file and switch to the WebMvcConfigurationSupport class instead in order to be able to use your customized RequestMappingHandlerMapping class.
This question was also discussed here.
Edit:
A pretty good example using this can be found here.

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.

how to organize & implement jsp file structure using Spring

I'm a php programmer now doing a Java web project using Spring framework. I'm trying to organize my JSP files the way i would have organized my .tpl files in php.
So if it would have been php i would have done it like this:
index.tpl
includes one of layout.tpls (ajax.tpl, mobile.tpl, general.tpl, simplified.tpl . . .)
includes the header of the page
includes menus
includes the actual content of the page
includes the page footer
then from the php controller i would be able to do something like this:
setLayout('general');
showTopMenu(false);
setContent('mySexyPage');
beside that i would have organized my stuff so that my views (tpl files) will be organized in folderŅ‹ each corresponding to a single controller. like this:
userManager
addUSer.tpl
editUser.tpl
editUserPermissions.tpl
articleManager
addArticle.tpl
editArticle.tpl
and in each controller somehow define from which folder to load my content template.
Now in Spring i have a controller with methods handling requests and each of the methods returning what the view should be. I can extend all my controllers from a single abstract class where i will create an instance of ModelAndView with all default values set, then request handling methods will add what they need to the instance their daddy already created and return it.
The problem with the above approach is that i'm not forcing the coder who's writing controllers to use the ModelAndView object i created, he way still return anything he wants from the handling method he wrote.
Is there some interface containing a method like ModelAndView getModelAndView() my daddy controller will implement so Spring will ignore whatever handler methods are returning?
Or is there some better way to do this ?
Content Template Issue
The Java world has a (more than one actually, but I'm sticking with the one I know) solution for this problem, it is called Tiles. check out section 16 of the Spring 3.0.5 Reference.
ModelAndView Issue
This is more interesting. First, you can use Model with out view and have your controllers just return the view name (i.e. return a String). I believe you want to create the initial Model somewhere. Then have each controller hander method accept an argument of type Model.
Here is what I tend to do (no claim that it is a best practice):
Have a Controller.get(Model model) method that sets the initial values.
#RequestMapping(method = RequestMethod.GET)
public String get(Model model)
{ ... set default stuff ... }
Every Handler method is a variation of this:
#RequestMapping(value = "/search", method = RequestMethod.POST)
public String search(Model model, ... other stuff as needed ...)
{ ... set stuff in model ... }

Resources