In my current Spring project (using Thymeleaf), I have this two controllers HomeController and a generic controller extended to all controllers associated to the entities from the model layer.
In the HomeController, i have this modelAttribute mthod:
#ModelAttribute("usuario")
public Usuario usuario() {
return usuario.findBy("username", SecurityContextHolder.getContext().getAuthentication().getName());
}
Which obviously is acessible by the views mapped in this controller. Is there any way of share this modelAttribute with the views mapped in the other controller?
I read in many places about this RedirectAttributes resource, but I am guessing that only works with redirected views (like modelAndView.setViewName("redirect:welcome");)?
Move the method to a separate class and add the #ControllerAdvice annotation to that class. This way all the model attributes in that class will apply to all controllers in the application.
If you want to limit the set of controllers where the model attribute will be available you can specify in the #ControllerAdvice annotation that only controllers in specific packages or with specific annotations or implementing specific interfaces should be enhanced.
Related
There is a Controller class in protected/components that starts with the following comment:
/**
* Controller is the customized base controller class.
* All controller classes for this application should extend from this base class.
*/
class Controller extends CController {
...
Can I define an alternative base controller, lets say Controller2:
class Controller2 extends CController {
...
And derive some user controllers from it? Will it violate Yii architecture or introduce some flaws somehow?
Yes, you can have multiple base controllers. Default template represents pretty basic application so some concepts are simplified. In bigger applications having multiple base controllers is pretty common (for example separate modules can have its own base controller), although usually you have some hierarchy and there is one base controller at the top of inheritance tree.
You can have multiple base controllers which extends CController directly, but it may be harder to introduce app-specific behavior - in your case you would need to copy the same code to both Controller and Controller2 classes. So usually it is good practice to create app-level base controller which will be base for all controllers - even if it is empty at the beginning in may save you the trouble of changing each controller at a later stage of the project.
For example you may have separated base controllers for backend and frontend, which extends one app-level base controller:
class FrontendController extends Controller {
// frontend-specific adjustments
}
class BackendController extends Controller {
// backend-specific adjustments
}
class Controller extends CController {
// app-specific adjustments (for backend and frontend)
}
I usually add objects in my jsp requestScopes using Controllers.
For example, if I need to list categories in "localhost/products/viewall", I simply change my ProductsController adding something like
#RequestMapping("/products/viewall")
public void viewCategories(Model model) {
List<Category> categories = service.findAllCategories();
model.addAttribute("categories", categories);
}
so, this method adds a list of categories to my requestScope.
I need to do the same, but for all the pages of the website (since the variable I need will be used in the layout of the site).
How can I add something to all the pages requestScopes with Spring?
I think you have at least two possible options for this:
Using an MVC Interceptor. With an interceptor you can perform common operations for all requests. You can extend HandlerInterceptorAdapter and add common model data in postHandle
Using the #ModelAttribute annotation within an Controller. You can use this to add common data for all request mappings within a controller. You can also use an #ControllerAdvice (with #ModelAttribute annotated methods inside) if you want provide model data to all controllers. The section Using #ModelAttribute on a method should provide some additional information for this.
I have multiple SimpleFormController controllers. One controller contains a command object used to filter results in the other controllers. I seem to be missing something simple, but I can't seem to find a way to use the same instance of the command object in the other controllers.
My setup is such that this main controller, let's call it RootController extends SimpleFormController, and the rest of the controllers extend RootController. The idea was that the command object is stored in one place - RootController and the controllers that extend it reuse the same object. However, it doesn't seem to be working that way, other controllers seem to have their own copy of the command object.
Form backing objects are just normal Pojos, so you can inherit it form each other.
public class BaseCommand {
...
}
public class MoreCommand extends BaseComman {
...
}
May you just forget the "update" the commandClass in your Controller Subclasses.
Anyway: notice that SimpleFormController is deprecated in Spring 3.0. Instead the Annotation Style is preferred.
Update: One INSTANCE of an command object, can be handled by only one INSTANCE of an Controller. So you can subclass the Controller (don't miss to call super), but you can not have two instances of the controller and hope that both are invoked.
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 ... }
I'd like to be able to create a base controller in my Spring app that, among other things, determines if a user is a registered user or not. This base controller, following the template design pattern, would contain an abstract protected method that controller subclasses would implement.
The abstract method would have passed to it an instance of User, registered or otherwise. However, I have no idea how I would do this since it seems that by using controllers purely using the #Controller annotation each controller is free to define their request handling method however they like.
Would creating some sort of user service class that is injected into each controller and used to validate a user be one way to get around this? This begs the question (at least for me) how does such a controller get a hold of a HttpServletRequest or the Session object?
Thanks.
Define an abstract BaseController, with no annotations
Define concrete and abstract methods
Call these methods from subclasses (which are annotated with #Controller) whenever needed.
I think the Base Controller is not a good idea if the only code it is to have is for UserAuthentication...instead use Spring security. This is the best option.
Alternatively, you can have methods like this...take a look at the Spring reference..
#Controller("loginController")
public class LoginController {
#RequestMapping(value="/login.do", method=RequestMethod.POST)
public String login(Model model, HttpServletRequest request) {
String userIdFromRequest = (String)request.getParameter("userId");
String password = (String)request.getParameter("password");
boolean verified = ...send userIdFromRequest and password to the user service for
verification...
if (verified){
request.getSession().setAttribute("userId", userIdFromRequest);
}
}
//More Methods
}
Did it help?
-SB
The basic problem is that annotational bootstrapping is not polymorphic. I found this paper useful: http://sanguinecomputing.com/design-pattern-for-hierarchical-controller-organization-with-annotational-configuration-spring-mvc-3/