How to call one controller to another controller URL in Spring MVC? - spring

Hi I am new to Spring MVC ,I want to call method from one controller to another controller ,how can I do that .please check my code below
#Controller
#RequestMapping(value="/getUser")
#ResponseBody
public User getUser()
{
User u = new User();
//Here my dao method is activated and I wil get some userobject
return u;
}
#Controller
#RequestMapping(value="/updatePSWD")
#ResponseBody
public String updatePswd()
{
here I want to call above controller method and
I want to update that user password here.
how can I do that
return "";
}
any one help me .

Can do like this:
#Autowired
private MyOtherController otherController;
#RequestMapping(value = "/...", method = ...)
#ResponseBody
public String post(#PathVariable String userId, HttpServletRequest request) {
return otherController.post(userId, request);
}

You never have to put business logic into the controller, and less business logic related with database, the transactionals class/methods should be in the service layer. But if you need to redirect to another controller method use redirect
#RequestMapping(value="/updatePSWD")
#ResponseBody
public String updatePswd()
{
return "redirect:/getUser.do";
}

A controller class is a Java class like any other. Although Spring does clever magic for you, using reflection to examine the annotations, your code can call methods just as normal Java code:
public String updatePasswd()
{
User u = getUser();
// manipulate u here
return u;
}

You should place method getUser in a service (example UserService class) .
In the getUser controller, you call method getUser in the Service to get the User
Similarly, in the updatePswd controller, you call method getUser in the Service ,too

Here no need to add #reponseBody annotation as your redirecting to another controller
Your code will look like
#Controller
class ControlloerClass{
#RequestMapping(value="/getUser",method = RequestMethod.GET)
#ResponseBody
public User getUser(){
User u = new User();
//Here my dao method is activated and I wil get some userobject
return u;
}
#RequestMapping(value="/updatePSWD",method = RequestMethod.GET)
public String updatePswd(){
//update your user password
return "redirect:/getUser";
}
}

Related

Add attribute to wildcard Requestmapping path?

Is there a way to add an attribute to all paths of a certain user?
I.e I am trying to reach the current logged in administrator on all pages the administrator can reach, but I don't want to add this attribute to every single controller.
Something like this, where I don't need to return anything:
#RequestMapping(value = {"admin/**"}, method = RequestMethod.GET)
public void adminPaths(ModelMap model) {
model.addAttribute("user", getPrincipal());
}
You can use #ModelAttributes on a method in a controller. An #ModelAttribute on a method indicates the purpose of that method is to add one or more model attributes to all controller methods:
#Controller
#RequestMapping("/admin")
public class AdminController {
...
#ModelAttribute
public void populateModel(Model model) {
model.addAttribute("user", getPrincipal());
// add more ...
}
...
}
#ModelAttribute methods in a controller are invoked before #RequestMapping methods, within the same controller.
For truly wildcard matching, you can use ControllerAdvice and ModelAttributes on methods together. Something like following:
#ControllerAdvice(annotations = Controller.class)
public class AdminPopulatorAdvice {
#ModelAttribute
public void populateModel(HttpServletRequest request, Model model) {
// examine the request
// if its path contains /admin, then add attribute
model.addAttribute("user", getPrincipal());
// add more ...
}
}
I forgot to mention that I was using Spring security.
Bohuslav pointed me into the right direction and ended up here: https://docs.spring.io/spring-security/site/docs/current/reference/html/taglibs.html

Spring MVC, Controllers design

I am building a web application in Spring MVC with combination of Spring Security. My question regards to inner design of application. To be more specific - how to set up controllers. I got inspired a lot by Pet Clinic example where there is one controller per domain object (Owner controller, Pet controller, Vet Controller and so on).
I would like to introduce an admin backend interface to my application. This would mean to create admin - specific methods and #RequestMappings in each controller. Request mapping paths are secured by intercept-url pattern so I do not have to care where they are. However I find this solution little bit inelegant.
On pet clinics example would it look like:
#Controller
#SessionAttributes(types = Owner.class)
public class OwnerController {
private final ClinicService clinicService;
// Front end method
#RequestMapping(value = "/owners/find", method = RequestMethod.GET)
public String initFindForm(Map<String, Object> model) {
model.put("owner", new Owner());
return "owners/findOwners";
}
// Admin method
#RequestMapping(value = "/admin/owners/find", method = RequestMethod.GET)
public String initFindForm(Map<String, Object> model) {
model.put("owner", new Owner());
//Admin view
return "admin/owners/findOwners";
}
}
Other choice is to have one controller for each #RequestMapping (or per action)
#Controller
#RequestMapping(value = "/admin", method = RequestMethod.GET)
public class AdminController {
private final ClinicService clinicService;
// Admin method
#RequestMapping(value = "/owners/find", method = RequestMethod.GET)
public String initFindForm(Map<String, Object> model) {
model.put("owner", new Owner());
//Admin specific view
return "admin/owners/findOwners";
}
}
This would in my opinion lead to really robust controllers with many methods.
Third option would be to have some kind of mix of those.
#Controller
#SessionAttributes(types = Owner.class)
public class AdminOwnerController {
private final ClinicService clinicService;
// Admin method
#RequestMapping(value = "/admin/owners/find", method = RequestMethod.GET)
public String initFindForm(Map<String, Object> model) {
model.put("owner", new Owner());
//Admin view
return "admin/owners/findOwners";
}
}
My question is what is a standard approach for that?
Usually I use a hybrid approach of AdminOwnerController, in which I end up having approximately 5-10 methods max per Controller.
If you end up having 1-2 methods per controller. I would consider grouping them together based on the admin domain.

How to get a session variable in a Spring Controller?

I have a Controller configured on Spring, and I have to workout a DB connection through it to call DAO operations.
This connection is actually available in a session variable, which is not accessible at the momment to the Spring Controller due to it is not HttpServlet inherited.
What is the right way to this Controller access the session variables? Must I implement methods doGet and doPost, inherited from HttpServlet, in order to manipulate the request object? Can it rattle Spring controll over the class?
Thanks for responding.
#Controller
public class SpringController {
#RequestMapping("/create")
public String form(MyCar myCar) {
/*That's where I have to retrieve hibernateSession from
* HttpSession and pass to DAO class do its work.
*/
MyCarDAO myCarDao = new MyCarDAO(session);
myCarDao.saveOrUpdate(myCar);
return "WEB-INF/views/projeto/novo.jsp";
}
}
You can add a HttpSession parameter to your method:
#RequestMapping("/create")
public String form(MyCar myCar, HttpSession session) {
...
}
Spring will automatically add the session parameter when the method is called.
Check the documentation of RequestMapping for possible parameters
Suppose that you declare 3 session attributes, but use only 1 of them in your handler method parameters, so:
#SessionAttributes({ "abc", "def", "ghi" })
public class BindingTestController {
#ModelAttribute("abc")
public String createABC() {
return "abc";
}
#RequestMapping(method = RequestMethod.GET)
public void onGet(#ModelAttribute("abc") String something) {
// do nothing :)
}
#RequestMapping(method = RequestMethod.POST)
public void onPost(#ModelAttribute("abc") String something, BindingResult bindingResult, SessionStatus sessionStatus) {
sessionStatus.setComplete();
}
}
There are lots of example if hit it in google
IMO Right way should be to store the connection in a session-scoped bean instead of a session variable.
Use
#Scope(value = "session")
(cf. http://static.springsource.org/spring/docs/3.0.0.M3/reference/html/ch04s04.html)

Injecting custom parameter to request mapping method in Spring MVC

In Spring MVC, I can wire session with my method. That's OK.
#RequestMapping(value = "/{cid}/read")
public #ResponseBody
boolean markAsRead(#PathVariable("cid") Comment comment, HttpSession session) {
User user = ((User) session.getAttribute("user"));
... }
Can I wire above user definition to the method definition? I mean instead of wiring session
#RequestMapping(value = "/{cid}/read")
public #ResponseBody
boolean markAsRead(#PathVariable("cid") Comment comment, User user) {
//No need to inject HttpSession and
//no need to call user = ((User) session.getAttribute("user"));
... }
You should be able to retrieve it using the #ModelAttribute tag, and annotating the user as a session attribute, this way:
#SessionAttributes("user")
public class MyController {
#RequestMapping(value = "/{cid}/read")
public #ResponseBody
boolean markAsRead(#PathVariable("cid") Comment comment, #ModelAttribute("user") User user) {
//No need to inject HttpSession and
//no need to call user = ((User) session.getAttribute("user"));
... }
}

Intercepting the #responsebody in spring mvc

I have a Spring MVC web application with conroller like below :
#Controller
public class ActionRestController {
#RequestMapping(value = "/list", method = GET)
#ResponseBody
public List<Action> list(Action action, SearhCriteria searchCriteria) {
List<Action> ret = new ArrayList<Action>();
// Call a service method to get the records
// Copy the records into the list
// return the list of objects
return ret;
}
The Controller is invoked when the user does a search. There are several such controllers in the app, one for each searchable entity.
For reasons that I cannot explain very well, here, I cannot modify these controllers in anyway.
But now, I have requirement in the UI to display the search criteria and the no. of records and paging details, as well. This information is not returned by the controller. The JSON returned by the Controller contains just the list of records.
I have put up a different controller which will handle the request, gets and puts the extra info in the model and forwards the request to the existing controller like below :
#Controller
public class ActionExtendedController {
#RequestMapping(value = "/searchlist", method = GET)
#ResponseBody
public List<Action> list(Action action, SearhCriteria searchCriteria, Model model) {
model.addAttribute("searchParameters", searchCriteria);
return "forward:/list";
}
Upto this point, all is well.
What I want to do is intercept the request at a point where the List is returned from the controller, before it is converted to JSON, and return a map containing the list and the search parameters.
Now since the 'immutable' controller users ResponseBody the control goes to the JacksonMessageConverter amd the response goes out from there. I have already tried the following paths and they do not work.
Interceptor - By the time I get here, the response is already written out, so there is no way to change it.
Custom ObjectMapper for the JasksonMessageConverter - Will not work, since I do not have access to the model object inside the mapper, I only have access to the list returned by the controller.
Aspect #After pointcut for the controller - I think this technique will work, but I cannot get it to work. The advise does not fire and I am sure I am missing something in the configuration.
Is there a way to get Spring AOP to fire on a annotated controller, handler method or
can anyone suggest another method of intercepting the handler return value (along with the model) ?
How about a simple delegation to the base controller in your extended controller:
#Controller
public class ActionExtendedController {
#Autowired ActionRestController baseRestController;
#Autowired MappingJacksonJsonView mappingJacksonJsonView;
#RequestMapping(value = "/searchlist", method = GET)
public View list(Action action, SearhCriteria searchCriteria, Model model) {
List<Action> actions = baseRestController.list(action, searchCriteria, model);
model.addAttribute("actions", actions);
model.addAttribute("searchParameters", searchCriteria);
return mappingJacksonJsonView;
}
this way you are delegating to the original controller, but using this new controller for the view. Just register a mappingJacksonJsonView as a bean also which will serialize all model objects (searchcriteria and actions) into the json view. You need not even return a view but can also use #ResponseBody, with a type that can hold the responses and search criteria.
Why don't you change the return type to a Map? Like:
#Controller
public class ActionRestController {
#RequestMapping(value = "/list", method = GET)
#ResponseBody
public Map<String, Object> list(Action action, SearhCriteria searchCriteria) {
Map<String, Object> map = new HashMap<String, Object>();
List<Action> ret = new ArrayList<Action>();
// Call a service method to get the records
// Copy the records into the list
// return the list of objects
map.put("searchResult",ret);
map.put("searchCriteria", searchCriteria);
return map;
}

Resources