Declaring HttpSession Object in Controller - spring

We have defined a controller and need to declare the HttpSession object. I can autowire it or pass as an object to the method. What is the difference between the two options and which is preferable?
Option 1
#Controller
public class UserController {
#Autowired
HttpSession session;
..
..
}
Option 2
#Controller
public class UserController {
#RequestMapping(value="/user", method=RequestMethod.GET)
public #ResponseBody User getUser(HttpSession session) {
..
..
}
}

In a Controller, you should use Option2.
A session is start from a http request begin, end until the request stop, but the controller is available until the application stoped. So you should not autowired the HttpSession in Controller.
One of the situation you can autowired the http session like that:
#Component
#Scope(value=WebApplicationContext.SCOPE_SESSION)
public class CurrentUserHolder{
#Autowired
private HttpSession session;
public User currentUser() {
return this.get();
}
#Override
public User get() {
return (User)session.getAttribute("currentUser");
}
}
So you can get current user in a service which can not get the session:
#Service
public class UserService{
private #Autowired CurrentUserHolder currentUserHolder;
......
}

If you have more than one methods in your controller which requires HttpSession, the Option 1 is preferrable. Otherwise, you can go with 'Option 2' instead of parameterizing it in every method.

Related

Calling other request mapping from rest controller

I am trying to call other rest controller from reqest mapping .
#RestController
class MyController{
#Autowired
OtherController other
#RequestMapping(/{token}/add)
public MyDto add(String token){
String[] tokens = token.split("\\.");
I want to call process input from method from Other controller and send token[1] item as path param
}
}
#RestController
public class OtherController{
#RequestMapping(/token/process)
public processInput(#PathVariable token)
{
}
}
How to send spited token to other param as path param. Could you please advice the calling strategy
It is possible to call another controller. You can simply inject your Controller into the class you would like to make that call in. This allows you to use the OtherController controller as if it was a Service component.
#RestController
class MyController {
private final OtherController otherController;
public MyController(#Autowired OtherController otherController) {
this.otherController = otherController;
}
#RequestMapping(/{token}/add)
public MyDto add(String token){
InputDto input=new InputDto();
otherController.processInput(input);
}
}

How to call a service from a controller

I am trying to call the following service from a controller:
#Service
class MyMailService {
private final SendGrid sendGrid;
#Inject
public SendGridMailService(SendGrid sendGrid) {
this.sendGrid = sendGrid;
}
void sendMail() {
Request request = new Request();
Response response = this.sendGrid.api(request);
}
}
And my controller:
# controller
public String index(Model model) {
MyMailService.sendMail() // how to do this properly?
return "register";
}
What would be the correct way to call this from a controller? Basically, I'm trying to "autoconfigure" sendgrid, so I don't have to initialize the SendGrid object with the API key whenever I call the MyMailService class.
As suggested by others, I do think too you need to spend more time learning Java & Spring basics. But to answer your question, you auto-wire/inject your service singleton object in the controller to use it:
#Controller
public class ControllerA
{
.
.
.
#Autowired
private MyMailService mymailService; //singleton object instance injected to be used/shared by all controllers
public String index(Model model) {
mymailService.sendMail()
return "register";
}
.
.
.
}
You can call your service in below ways
1) Simply adding #Autowired to your class type
#Autowired
MyMailService myMailService;
2) Using Constructor Injection as below,
MyMailService myMailService;
#Autowired
public WebController(MyMailService myMailService) {
this.myMailService = myMailService;
}
- here i assumed my Controller name is WebController
3) Using Setter Injection as below,
MyMailService myMailService;
#Autowired
public void setMyMailService(MyMailService myMailService) {
this.myMailService = myMailService;
}
and finally in your controller you can call your service class methods as below,
myMailService.sendMail();
Note:
Follow naming convention.

calling a method by class level annotated with #RequestMapping that includes an autowired class

I am trying to call a method that is annotated with #RequestMapping(signIn) through a class level (from method: authentication) like so:
#RequestMapping(value = /authenticate, method = RequestMethod.POST)
public #ResponseBody Response authentication(HttpServletRequest request)
{
UserController user = new UserController();
return user.signIn(request, null);
}
and my controller looks like:
#Autowired
private UserManager userManager;
#RequestMapping(value = /signin, method = RequestMethod.POST)
public #ResponseBody Response signIn(HttpServletRequest request) {
JsonObject json = Misc.parseJson(request);
String lang = Misc.getLang(request);
user.setEmail(Misc.getEmail(json));
user.setPassword(Misc.getEncryptedPassword(json));
return ResponseUtils.success(userManager.auth(user, lang));
}
user manager is annotated with #component:
#Component
public class UserManager {
public User auth(User user, String lang) {
....
return user;
}
}
Problem is when I call the method "signIn" and just new-up a UserController instance through "/authenticate" mapping, the UserManager becomes NULL. So now I'm assuming that autowiring doesn't work when it's done this way.
Is there any other way to call the signIn method? I would hate to copy paste an already existing code to another class just to get this to work...
Autowiering only works in spring managed bean. If you create a class with new keyword, it is not a spring managed bean and autowiering would not work.
You can try to autowire the class which contains the method which is annotated or better put the code in a service class which can be used by both methods.
It's not problem with #Autowired .There are two type of Annotation
firstly method base annotation and field level annotation. You just used field level annotation.Check your import class with "org.springframework.beans.factory.annotation.Autowired" or it can be problem with initiation of "UserManager"
I don't know why you not moving logic into separate Service classs, but try this:
UserController.java
public UserController(UserManager userManager) {
this.userManager = userManager;
}
and then inside controller where authentication resource method is located:
#Autowired UserManager userManager;
#RequestMapping(value = /authenticate, method = RequestMethod.POST)
public #ResponseBody Response authentication(HttpServletRequest request) {
UserController user = new UserController(userManager);
return user.signIn(request);
}
So in the end I just separated the logic instead. Though one solution that I tried and I could have used was to just add another mapping to the signIn method instead of adding a new method in the other class since the logic was similar. Still I opted for a separate logic instead since there were a lot of unnecessary code in the signIn method for my purpose.

Spring mvc - #sessionattributes vs #Scope("session") beans which to use?

I'm not fully understanding when to use #SessionAttributes vs #Scope("session") beans.
Currently, I'm doing the following
#ControllerAdvice(assignableTypes = {DashboardController.class, FindingWholeSalersController.class})
public class AuthControllerAdvice {
private IFindWholeSalerService service;
public IFindWholeSalerService getService() {
return service;
}
#Autowired
public void setService(IFindWholeSalerService service) {
this.service = service;
}
//put firstname in session etc..
#ModelAttribute
public void addWholesalerDiscoveryCountToSession(Model model, Principal principal){
if (!model.containsAttribute("firstname")) {
String firstname = service
.findUserFirstName(principal.getName());
model.addAttribute("firstname",
firstname);
}
}
Notice this if test if (!model.containsAttribute("firstname"))
Basically, if the session attribute is already in the model, then I dont want to ask my service layer to make a database request. However, every #RequestMapping call in any of the controllers I'm advising, first makes a call to
#ModelAttribute
public void addWholesalerDiscoveryCountToSession(Model model, Principal principal)
Does the if test, and moves on its marry way.
Is this the right solution for keeping data in the session so you dont have to call your database, OR would #Scope("session") beans be a better choice OR something else?
Thanks for all advice in advance!

Check the state validity of a Spring proxied bean without try-catch

I have a bean being created by a service with the following class:
#Configuration
public class AccessManager {
#Bean(name="access", destroyMethod="destroy")
#Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
#Autowired
public Access create(HttpServletRequest request) {
System.out.println(request.getRemoteAddr());
return new Access();
}
}
Everything works as expected, except that when the application is starting, this method is being called, probably because I have some other singleton beans that use the Access bean. At the start up there is no request bound to the Thread, and it's expected to get a java.lang.IllegalStateException when trying to access any property of the request parameter.
No problem. The question is, is it possible to check if the underlying HttpServletRequest of the proxy request is null before calling a property that raises the exception?
You probably want to take a look at RequestContextHolder#getRequestAttributes(). That will return null if you're not currently in a context where request scope could be used.
#Configuration
public class AccessManager {
#Bean(name="access", destroyMethod="destroy")
#Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
#Autowired
public Access create(HttpServletRequest request) {
if (RequestContextHolder.getRequestAttributes() != null) {
System.out.println(request.getRemoteAddr());
}
return new Access();
}
}
I think the issue here is with separation of concerns. Usually your service layer should not have any dependency on the servlet classes. This is very much a controller/UI concern.
Your service class should be provided with the properties which it needs to do its job. In this case a String. This service method should be called from a controller method which is injected with the servlet request.
Something like the following:
#Controller
public class MyController {
#Autowired
private AccessManager accessManager;
#RequestMapping
public void handleRequest(HttpServletRequest request) {
accessManager.create(request.getRemoteAddr());
}
}
and your service would then look like this:
#Service
public class AccessManager {
public Access create(String remoteAddress) {
return new Access();
}
}
To sum up, anything annotated as #Service shouldn't have access to the Request.

Resources