Configure multiple controllers in Spring MVC, and call one controller's method from another controller - spring-mvc

I am trying to configure multiple controller in my application and also trying to redirect from one controller to other.
Error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#0': Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping found. Cannot map 'nc' bean method.
EDIT :
First Controller
#Controller
#RequestMapping(value = "/nc")
public class StockController {
#RequestMapping(value = "/testMap", method = RequestMethod.GET)
public String redirectToStockList(#RequestParam(value = "testInput") String testInput) {
System.out.println("In StockController..!!");
return "SampleTamplate";
}
}
Second Controller
#Controller
public class WelcomeController {
#Autowired
private UsersServiceImpl serviceImpl;
private String redirectedURL;
private static final Logger logger = LoggerFactory
.getLogger(WelcomeController.class);
#RequestMapping(value = { "/", "/login" }, method = RequestMethod.GET)
public String login(#RequestParam(value = "username") String username) {
logger.debug("In login() method.");
System.out.println("In WelcomeController..!!");
return "Login";
}
}
jsp:
First Form:
<form action="testMap" method="post">
<input type="text" class="form-control" name="testInput"/>
</form>
Second Form:
<form action="login" method="post">
<input type="text" class="form-control" name="username"/>
</form>
When I submit both forms one by one, control goes to 'WelcomeController' every time. And for first form, It gives 'resources not found' error that's OK because there is no mapping present as "/testMap" in welcome controller.
So what I want is, to call specific controller on my form submission and also call one controller's method from another controller.
Any help would be appreciated.

I will try to answer this question in both Grails and Spring way as this is the best time to introduce Grails here.
In spring when call is leaving from controller then RequestDispatcher actually helps to catch the call or to check the exact view resolver. Now, as you want to transfer call to another controller here sping provides API (http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#mvc-redirecting) Inshort you have to use view name like "forward:controllerName" like
#RequestMapping({"/someurl"})
public String execute(Model model) {
if (someCondition) {
return "forward:/someUrlA";
} else {
return "forward:/someUrlB";
}
In grails there is forward method you can find in controller API which does things for you (http://grails.github.io/grails-doc/2.0.4/api/org/codehaus/groovy/grails/plugins/web/api/ControllersApi.html). It actually passes the same session to next requested controller.
Request you to please try to use it. Hope this help.

In the below example the LoginController redirects to the /menu URL if there are validation errors upon submitting a login form by calling the menuMapping() method that resides within the MenuController class.
(NOTE: I have included the use of the BindingResult class and a hypothetical form as this would be a valid reason for wanting to redirect to another controller. However, below solution would still work as well without the BindingResult and if statement without the use of a form).
#Controller
public class LoginController {
MenuController menuController;
#RequestMapping(value = "/login")
public String loginMapping(BindingResult result){
if(result.hasErrors) {
return "login";
}
else {
return menuController.menuMapping();
}
}
With your MenuController in another class like so:
#Controller
public class MenuController {
#RequestMapping(value = "/menu")
public String menuMapping(){
return "menu";
}
}
(EDIT: if you wanted to apply the redirect and the controller methods were within the same class then the loginMapping return statement would simply be return menuMapping(); rather than return menuController.menuMapping();

Related

How to add model attributes to the default error page

What is the best way to handle default page not found error when a user requests a url that doesn't have any mapping in the application (e.g. a url like /aaa/bbb that there is no mapping for it in the application) while be able to add model attributes to the page?
There is some anserws in SO but those have caused me other problems and more importantly they don't state how to add model attributes to the error page.
The best solution I have found is this:
Create a controller that implements ErrorController and overrides
its getErrorPath() method.
In that controller create a handler method annotated with
#RequestMapping("/error")
It's in this method that you can add whatever model attributes you want and return whatever view name you want:
#Controller
public class ExceptionController implements ErrorController {
#Override
public String getErrorPath() {
return "/error";
}
#RequestMapping("/error")
public String handleError(Model model) {
model.addAttribute("message", "An exception occurred in the program");
return "myError";
}
}
Now if you want to handle other specific exceptions you can create #ExceptionHandler methods for them:
#ExceptionHandler(InvalidUsernameException.class)
public String handleUsernameError(Exception exception, Model model) {
model.addAttribute("message", "Invalid username");
return "usernameError";
}
Notes:
If you add specific exception handlers in the class, don't forget to annotate the controller with #ControllerAdvice (along with the #Controller)
The overridden getErrorPath() method can return any path you want as well as /error.

Why do we need RedirectAttributes.addAttribute()?

Spring provides the following option to pass attributes(params) to the redirect page by using RedirectAttributes.
#Controller
#RequestMapping("/")
public class RedirectController {
#GetMapping("/redirectWithRedirectView")
public ModelAndView redirectWithUsingRedirectView(RedirectAttributes attributes) {
attributes.addAttribute("attribute", "redirectWithRedirectView");
return new ModelAndView("redirect:redirectedUrl");
}
}
The same can be achieved even if we simply append attribute to redirect URL, like the following
#Controller
#RequestMapping("/")
public class RedirectController {
#GetMapping("/redirectWithRedirectView")
public ModelAndView redirectWithUsingRedirectView() {
return new ModelAndView("redirect:redirectedUrl?attribute=redirectWithRedirectView");
}
}
Both do the same job. Do we get any benefits in terms of memory if we use RedirectAttributes? I am guessing, in the second case, we would be constructing separate ModelAndView object if the attribute value changes for each request.

Combining POST and GET in SpringMvc

For a user registration form (registration.html) I created a view controller through:
#Configuration
#EnableWebMvc
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(final ViewControllerRegistry registry) {
super.addViewControllers(registry);
registry.addViewController("/user/registration").setViewName("registration");
}
This works fine, and if I go to /user/registration (i.e. GET), I can see the registration form.
However if I now want to create a controller for POST requests at the same uri through:
#Controller
public class RegistrationController {
#RequestMapping(value = "/user/registration", method = RequestMethod.POST)
#ResponseBody
public GenericResponse registerUserAccount(#Valid final UserDto accountDto, final HttpServletRequest request) {
// some code
}
}
I get an error message at the /user/registration uri saying:
Request method 'GET' not supported
So it seems that my post controller is somehow overriding the GET controller which was working before. Why is that? Is it possible to make the two work together or do I have to write my own GET controller in the same way as my post controller?

How do I route my login controller

I am using a homegrown (developers no longer around) web framework that has built in Spring security.
There is a LoginController that every request is redirected to until the user logs in.
The LoginController is mapped to use the context URL, e.g. my-company/login.do
public class LoginController {
public LoginController() {
}
#RequestMapping(
value = {"/login.do"},
method = {RequestMethod.GET}
)
public String showLogin() {
return "login";
}
For my application, I need to change that mapping to my-company/admin/login.do
The LoginController is coming in from a Maven dependency, so I CANNOT MODIFY that class
Is there any way to modify the existing LoginController to route to the extended url?
It seems that if you want it to be located at "my-company/admin/login.do" when it is located at "my-company/login.do", I would start by changing
#RequestMapping(
value = {"/login.do"},
method = {RequestMethod.GET}
)
public String showLogin() {
return "login";
}
to
#RequestMapping(
value = {"/admin/login.do"},
method = {RequestMethod.GET}
)
public String showLogin() {
return "login";
}
However, if you still need the old location too, you might be better of copying the class and making a specific one for your admin login.
Also, this is just where I would start. Odds are that the rest of your application expects this code to be located where it is, so you could easily break the integration with the rest of your code by doing this.

spring mvc application to navigate flow from controller to jsp or servlet of another application

I am using spring mvc application. I want to redirect from controller or jsp to my second application that was developed in plain servlet and jsps.
How can I navigate flow from one apps servlet/jsps to another apps jsp.
I have used following lines in my controller to navigate:
First:
return new ModelAndView("redirect:/http://localhost:9090/MarathiInput/test.jsp");
Second:
response.sendRedirect("http://localhost:9090/MarathiInput/test.jsp");
Currently my controller is :
#RequestMapping(value = "/transferCertificate", method = RequestMethod.GET)
public ModelAndView get(ModelMap map ,HttpServletResponse response) {
response.sendRedirect("localhost:9090/MarathiInput/test.jsp");
}
and in my jsp i am calling :
Generate TC this link
You have small errors in both tries, but both can be used.
Assuming method controller is declared to return a ModelAndView you can use :
return new ModelAndView("redirect:http://localhost:9090/MarathiInput/test.jsp");
If it is declared to return a String :
return "redirect:http://localhost:9090/MarathiInput/test.jsp";
Alternatively provided the controller method has the response as parameter, you can do the redirect in controller, but as you have already processed the response, the method must return null :
response.sendRedirect("http://localhost:9090/MarathiInput/test.jsp");
return null;
So you could use :
#RequestMapping(value = "/transferCertificate", method = RequestMethod.GET)
public ModelAndView get(ModelMap map ,HttpServletResponse response) {
response.sendRedirect("http://localhost:9090/MarathiInput/test.jsp");
return null;
}
or simply :
#RequestMapping(value = "/transferCertificate", method = RequestMethod.GET)
public String get(ModelMap map ,HttpServletResponse response) {
return "redirect:http://localhost:9090/MarathiInput/test.jsp");
}
But make sure that the link includes the servlet context and servlet path :
Generate TC this link

Resources