I would like to use #exceptionhandler to capture an HTTP Status 500 - Expected session attribute. I would like to return a message to the same page i am on showing the user the error.
Can someone point me to an example on how i can handle this exception and return a message to the view instead of redirecting to another page.
This is what i have so far however the item in the view is not getting set with the error message;
#ExceptionHandler(HttpSessionRequiredException.class)
public RedirectView handleHttpSessionRequiredException(Exception ex, HttpServletRequest request) throws Exception
{
logger.info("In the handleHttpSessionRequiredException Handler Method");
String referrer = request.getHeader("referer");
RedirectView redirectView = new RedirectView(referrer);
redirectView.addStaticAttribute("errorMessage","Execute A Query Then Retry");
return redirectView;
}
View
<label id="errorMessage" name="errorMessage">${errorMessage}</label>
You can get the referer and forward or redirect to it. E.g.
#ExceptionHandler(HttpSessionRequiredException.class)
public String (HttpServletRequest request) {
String referrer = request.getHeader("referer");
...
FlashMap flashMap = RequestContextUtils.getOutputFlashMap(request);
flashMap.put("errorMessage","Execute A Query Then Retry");
return "redirect:/my/url";
}
The redirect URL is relative to the application path. You can extract it from the referer.
You can return a ModelAndView from an #ExceptionHandler method by doing something like the following.
#ExceptionHandler(IOException.class)
public ModelAndView handleIOException(IOException ex) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("someObject", new SomeObject());
modelAndView.setViewName("someView");
return modelAndView;
}
The problem is figuring out the current page you were on before. To my knowledge, there isn't a way to get the current model and view from inside an ExceptionHandler method so you won't have a good way of knowing what view to use.
I think your best bet is to catch and handle the Exception in your controller.
Related
I'm new in Spring and also in JSP. I'm working in the project and I needed to create a page where application will be redirected in case of specific exceptions.
I have service's method which throws one of exceptions. This method is called in one of our page controller with #RequestMapping annotation. So to redirect to specific error page, I created two methods with #ExceptionHanlder which handle this exceptions in this controller. How it looks:
#ExceptionHandler(IllegalStateException.class)
public ModelAndView handleIllegalStateException (IllegalStateException ex) {
ModelAndView modelAndView = new ModelAndView("redirect:/error");
modelAndView.addObject("exceptionMsg", ex.getMessage());
return modelAndView;
}
But there wasn't enough. I also need to create ErrorPageController:
#Controller
#RequestMapping("/error")
public class ErrorPageController {
#RequestMapping(method = RequestMethod.GET)
public ModelAndView displayErrorPage() {
return new ModelAndView("error");
}
}
And now works displaying error page. But my problem is, that I can't display error message in JSP...
I have:
<h3>Error page: "${exceptionMsg}"</h3>
But I don't see a message ;/ Instead of it, I see message in URL:
localhost/error?exceptionMsg=Cannot+change+participation+status+if+the+event+is+cancelled+or+it+has+ended.
And it's wrong because in URL I want to have only an "localhost/error" and nothing more. This message I want to display in JSP.
To fix both of your issues (show the message, and have the proper url) you should in original code change you exception handler method to e.g.
#ExceptionHandler(IllegalStateException.class)
public RedirectView handleIllegalStateException(IllegalStateException ex, HttpServletRequest request) {
RedirectView rw = new RedirectView("/error");
FlashMap outputFlashMap = RequestContextUtils.getOutputFlashMap(request);
if (outputFlashMap != null) {
outputFlashMap.put("exceptionMsg", ex.getMessage());
}
return rw;
}
Why? If you want your attributes to persist through redirect, you need to add them to flash scope. The code above uses the FlashMap, from the docs
A FlashMap is saved before the redirect (typically in the session) and
is made available after the redirect and removed immediately.
If it were to be a normal controller method, you could have simply added RedirectAttributes as an argument, but on #ExceptionHandler methods, the arguments of RedirectAttributes are not resolved, so you need to add the HttpServletRequest and use the RedirectView.
You have to change ModelAndView to:
#ExceptionHandler(IllegalStateException.class)
public ModelAndView handleIllegalStateException (IllegalStateException ex) {
ModelAndView modelAndView = new ModelAndView("error");
modelAndView.addObject("exceptionMsg", ex.getMessage());
return modelAndView;
}
And have this part in error.jsp:
<h3>Error page: "${exceptionMsg}"</h3>
I have a very weird problem in my Spring MVC application. I am writing a login form and POSTing the data via AJAX into a Spring MVC controller that looks like this:
#Controller
public class LoginResourceController {
private static final Logger log = Logger.getLogger (LoginResourceController.class.getName());
#RequestMapping (value="/login", method = RequestMethod.POST)
public String checkAccount (HttpServletRequest httpRequest, HttpServletResponse httpResponse,
#RequestHeader (value = "User-Agent") String retrievedUserAgent,
#RequestParam("username") String username,
#RequestParam("password") String password,
#RequestParam("rememberMe") String rememberMe)
{
//Check username and password in DB, and then if OK,
return "redirect:/login/redirectToMain";
}
#RequestMapping (value = "/login/redirectToMainpage", method = RequestMethod.GET)
public String redirectControllerToMainPage (HttpServletRequest httpRequest, HttpServletResponse httpResponse)
{
return "mainPage";
}
Now, the problem is, I have the client (browser) upon redirect requesting a URL that contains the entire contents of mainPage.jsp in the URL. So it looks like:
https://localhost:8443/<!DOCTYPE html><html><head><meta charset=utf-8 /><title>Page that the subscriber sees after login</title>....
I am quite confounded by this error. Is this some servlet setting in WEB-INF/web.xml or mvc-dispatcher-servlet.xml that I need to change? I am using Spring 3.0.5.
BTW, my redirect works flawlessly for GET method controllers in the same Spring MVC application. (e.g., when I re-load the main page of my application, the redirect to the logged in mainPage.jsp above works flawlessly). Moreover, other GET methods on other jsps work correctly too (example, redirect to /login page via login.jsp via a GET of https://localhost:8443/.
I have checked the following and they didn't help: 1 2.
Try not to put the redirect in the return of the controller. This seems to either cause the full page to be rendered as the ajax response, or a redirect header is filled in with an url with the full contents of the page as a string in the response body.
As a first approach, try to make the request a normal HTTP request instead of ajax, and it should just work.
Alternativelly try to make the return body empty, and return an HTTP status code to the client. Either 200 OKif the account is OK or 401 Unauthorized:
#RequestMapping (value="/login", method = RequestMethod.POST)
public ResponseEntity checkAccount (HttpServletRequest httpRequest, HttpServletResponse httpResponse,
#RequestHeader (value = "User-Agent") String retrievedUserAgent,
#RequestParam("username") String username,
#RequestParam("password") String password,
#RequestParam("rememberMe") String rememberMe)
{
//Check username and password in DB
....
HttpStatus returnCode = null;
if(usernameAndPasswordOK) {
returnCode = HttpStatus.OK;
}
else {
returnCode = HttpStatus.UNAUTHORIZED;
}
return new ResponseEntity(returnCode);
}
And then on the client redirect with Javascript accordingly.
This was a little tricky for me to figure out, and being a web development noob doesn't help here. Anyway, #jhadesdev's answer above pointed me to the issue.
On my client, I do this:
$("#loginForm").submit(function(evt)
{
evt.preventDefault();
if (loginFormInputIsValid ())
{
$.ajax ({
type: "POST",
url: "/login",
data: $(this).serialize(),
success: function (response)
{
window.location = response;
}
});
}
}
which was the issue--you see, setting the window.location=response; caused the client (browser) to request the server for the funky URL above. I have to change my client call (this is where #jhadesdev's response helped) to make sure I don't do something so wrong.
Thanks for your time, #jhadesdev.
I have login controller methods like so:
#RequestMapping(value = "/home", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
// do stuff with locale and model
// return an html page with a login form
return "home";
}
#RequestMapping(value = "/account/login", method = RequestMethod.POST)
public String login(Model model, /* username + password params */){
try {
// try to login
// redirect to account profile page
return "redirect:/account/profile";
} catch (LoginException e) {
// log
// here I want to reload the page I was on but not with a url /account/login
// possibly using a forward
model.addAttribute("error", e.getMessage());
return "forward:/home";
}
}
The above code works on successful log-in attempt. However, it fails when the log-in attempt fails because Spring's forward uses the current request with the same HTTP method. So because I used a POST to send my username/password (which caused log-in to fail), the forward will also use POST to go to the handler method for /home, home(), which is expecting a GET.
Is there any way in Spring to redirect to another controller method with a different HTTP method while maintaining the current model (since I want to show the error message)?
This is on Spring 3.2.1.
Do a redirect instead:
return "redirect:/home";
If you need Model attributes to be available after the redirect, you can use flash attributes.
How do I enhance the Controller below to utilize Spring MVC's Flash Attributes? The use case is a copy function.
POST/REQUEST/GET implementation:
client clicks "copy" button in the UI
server sets the response "Location" header
client redirects to "path/to/page?copy"
server provides ModelAndView
client (jQuery success function) sets window.location
FooController redirect method:
#RequestMapping(value = "{fooId}", method = POST, params = { "copy" })
#Transactional
#ResponseStatus(CREATED)
public void getCopyfoo(#PathVariable String fooId,
HttpServletResponse response, RedirectAttributes redirectAttrs) {
response.setHeader("Location", uriPath);
//no worky?!:
redirectAttrs.addFlashAttribute("barKey", "barValue");
}
FooController get method:
#RequestMapping(value = "{fooId}", method = GET)
#Transactional(readOnly = true)
public ModelAndView findFooById(#PathVariable String fooId,
HttpServletRequest request){
Map<String, ?> map = RequestContextUtils.getInputFlashMap(request);
// map is empty...
return modelAndViewFromHelperMethod();
}
I'm affraid that RedirectAttributes work only with RedirectView,
so Your controller should return for example:
1. String: "redirect:/[uriPath]"
2. new RedirectView([uriPath])
If you realy need to handle server response with JS, then maybe handling HTTP status 302 would help.
What is the proper way to forward a request in spring to a different controller?
#RequestMapping({"/someurl"})
public ModelAndView execute(Model model) {
if (someCondition) {
//forward to controller A
} else {
//forward to controller B
}
}
All of the controller have dependencies injected by Spring, so I can't just create them and call them myself, but I want the request attributes to be passed on to the other controllers.
Try returning a String instead, and the String being the forward url.
#RequestMapping({"/someurl"})
public String execute(Model model) {
if (someCondition) {
return "forward:/someUrlA";
} else {
return "forward:/someUrlB";
}
}
You can use view name like "redirect:controllerName" or "forward:controllerName". The latter will reroute request to another controller and former will tell browser to redirect request to another url.
docs: https://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#mvc-redirecting-redirect-prefix
You can use Spring RedirectView to dispatch request from one controller to other controller.
It will be by default Request type "GET"
RedirectView redirectView = new RedirectView("/controllerRequestMapping/methodmapping.do", true);