I want to create a base controller class that my other controllers will inherit from. I have a simple public api that takes the authentication token via the query string, so I want to do this:
public class MyBaseController {
private String token = "";
public MyBaseController() {
}
}
And then my real controller would be like:
#Controller
#RequestMapping("/api/users")
public class UserController extends MyBaseControler {
// controller methods here
}
My question is, how can i get access to the HttpServletRequest in my base controller, and get the querystring parameter "?token=abc123" value and set the token var with the value.
Is this thread safe? It is my understanding that there will be a new controller instance per request correct?
Your controllers are better off if they're stateless.
You can inject them with Spring services as needed, but I don't see any reason why they have to hang onto the value of the token as a member variable.
It's far more likely that you'll want to store the token in session scope. I think your idea is wrong-headed.
I'll point out that Spring itself has moved away from inheritance for controllers. They're all annotation-based now, with no common base class or interface. Why do you think devolving back to the design they abandoned is a good thing?
You don't need a base controller, either.
Related
I am using a Spring Boot to design REST API. I want to know what difference it will make while using nested classes in request body?
REST Endpoint:
#PostMapping("/create")
public void (#RequestBody RequestData.UserDetails details) {}
My RequestData class:
public class RequestData {
public static final class UserDetails {
private String name;
}
}
So my question is which of the following class definations is safe?
Creating a seperate class for UserDetails to get requested data
Creating a nested class as stated above
Do nested classes affect during multiple concurrent requests or in some other way?
Do nested classes affect during multiple concurrent requests or in some other way?
No, the request body will be mapped to an instance of the RequestData.UserDetails or simply UserDetails if it is a separate class. If you don't store this is instance as a class attribute in your Controllers, Services, etc, there is no concurrent requests concern because each request to your Controller will have its own instance of such a class and multi-threading is not a problem because you are not storing state.
This means that having a nested class or a separate class is irrelevant to the fact that you have a threadsafe Controller, Service, etc or not. The important thing is to not store state on them.
In this case, having a nested class or a separate class is more a question of taste and organization than anything else.
I am quiet new in MVC and Spring and I want to learn best practices and solution so I decided to ask what is the best practice or how you would solve my problem.
I got controller with scope session (To store data in global variable not overrided when another user send request). I got global variable as I mentioned and two endpoints. First endpoint POST - here I send form and call another REST service to fetch data - call depends on data from form. Second endpoint GET - here i send which page to return. This endpoint is used for pagination.
Where is the problem? I have to store data in global variable because when I fetch data in POST endpoint I do not have access to it in GET endpoint. I do not like this solution. Do you have any ideas how to solve it better?
#Controller
#SessionScope
public class someController {
Global variable
#PostMapping(value = "/endpoint")
public String endpoint1(Form form){
//here I fetch data from another REST service depends on form data and save it to global variable
}
#GetMapping(value = "/anotherenpoint")
public String endpoint1(int page){
//here I get data from global variable and return to view as Page object
}
Your #Controller shouldn't be session scoped, instead make your variable session scoped. (you can also annotate it with #Autowired, so your controller automatically has the right variable for the current user)
I'm using Spring MVC Framework and I'd like all the .jsp pages of the View to have access to the User's attributes(name, sex, age...). So far, I use the addAttribute method of the Model(UI) in every Controller to pass the current User's attributes to the View. Is there a way to do this only once and avoid having the same code in every Controller?
You can use Spring's #ControllerAdvice annotation on a new Controller class like this:
#ControllerAdvice
public class GlobalControllerAdvice {
#ModelAttribute("user")
public List<Exercice> populateUser() {
User user = /* Get your user from service or security context or elsewhere */;
return user;
}
}
The populateUser method will be executed on every request and since it has a #ModelAttribute annotation, the result of the method (the User object) will be put into the model for every request through the user name, it declared on the #ModelAttribute annotation.
Theefore the user will be available in your jsp using ${user} since that was the name given to the #ModelAttribute (example: #ModelAttribute("fooBar") -> ${fooBar} )
You can pass some arguments to the #ControllerAdvice annotation to specify which controllers are advised by this Global controller. For example:
#ControllerAdvice(assignableTypes={FooController.class,BarController.class})
or
#ControllerAdvice(basePackages={"foo.bar.web.admin","foo.bar.web.management"}))
If it is about User's attributes, you can bind the model bean to session as an attribute which can be accessed on every view. This needs to be done only once.
Another option could be is to implement a HandlerInterceptor, and expose the model to every request.
I have on user registration form, a startup controler (with request method get) that loads the user class to that form and a post method to save the user. Everything uses spring. But now I want to move the registration form to a popup in the header file and every page will import that.
The problem is, I don't want to insert the user class in all Get methods. What I really want is to "inject" in all models the user class without having to do something in all other methods.
Is this possible to do? And how?
In Spring 3.2, there is a #ControllerAdvice class level annotation introduced. If you place your model attribute in a separate class with #ControllerAdvice, it will be available to all controllers. For example add getUserForm() in the #ControllerAdvice annotated class, instead of your original controller(s):
#ControllerAdvice
public class ModelAttributeAdvice {
#ModelAttribute
public SearchForm getUserForm(){
return new UserForm();
}
}
I have a question about spring mvc and thread safety.
We are developing web application that will be stored on tomcat. If I understand right, Tomcat creates thread per request and it has some thread pool. Now, dispatcher servlet is shared between requests and probably is thread safe.
But when I create controller like this:
#Controller
#RequestMapping("/manage")
public class QuestionManagementController {
he has Singleton scope so the same controller is used by every request that comes from every user.
I am wondering how this problem is usually solved:
1: are controllers created with Session scope? (but I think that there also could be problems if one user quickly do some things that may lead to race conditions in the controller).
2: controllers are scoped as request
3: creating stateless controllers that don't share any variables at class level, or have them in read only mode
or maybe there is some better "best practice" that solves this kind of problem.
I am asking this question, because now we have them as Singleton scoped, and there is a problem, that in most methods we are querying for user in the database , and we can't store this information in class level variable because of the scope. We could try to use some thread safe collection but later there could be other resources needing synchronized access.
A lot of parameters can be added to the controller methods like request, session, principal etc to avoid your problem.
Usually there's a 3-layers architecture:
#Controller (they delegates to services)
#Service (they do the work using DAOs or Repositories)
#Repository (or DAOs, they do DB access)
So depending on what you are querying for in the DB, I would advise having a service, injected by Spring with a cache if hitting the DB is costly and everytime you need the stuff from the DB call the service (i.e. nothing stored in the controller class level)
A short example, let's say we are behind spring-security and everything need a fully logged-in user. We have an userData table where the key is the user login, we have an url /data to get a page showing my user data:
#Controller
#RequestMapping("/data")
public class UserDataController
{
#Autowired
private UserService userService;
#RequestMapping(value = "", method = RequestMethod.GET)
public ModelAndView data(final Principal principal) {
Assert.notNull(principal); // throw if assertion fails
Assert.hasText(principal.getName());
final UserData userData = this.userService.findByUserName(principal.getName());
Assert.notNull(userData, "userData not found");
return new ModelAndView("userData", "userData", userData);
}
}
#Service("userService")
public class userService
{
private static final String USERDATA_CACHE = "com.acme.foo.UserData";
#Autowired
private UserDataRepository userDataRepository;
#Cacheable(USERDATA_CACHE)
public UserData findByUserName(final String userName) {
return this.userDataRepository.findByUserName(userName);
}
}
#Repository
public class UserDataRepository
{
// or use spring-data-jpa
public UserData findByUserName(final String userName) {
// query table userData and create an UserData from results.
}
}
Here I use principal and spring ensure that this is current user one.
Refs:
#Cachable
see also Initialize Singletons in Spring Framework 3 MVC
Note sure if this answer fully to your concerns