提交 17089d60 编写于 作者: B Brian Clozel

Allow RedirectAttributes on ExceptionHandlers

Prior to this commit, `@ExceptionHandler` methods could not be injected
with `RedirectAttributes` arguments. This would make it impossible to
handle an error by redirecting to another view and add flashmap
attributes, to be included in the model when the next view is called.

Here is an example:

```
@ExceptionHandler(MyException.class)
public String handleException(MyException ex, RedirectAttributes
    redirectAttributes) {

  redirectAttributes.addFlashAttribute("errorMessage",
      "This is an error message");
  return "redirect:/";
}
```

This commit adds a new `RedirectAttributesMethodArgumentResolver`
instance in the list of pre-configured `HandlerMethodArgumentResolver`
in `ExceptionHandlerExceptionResolver`.

Issue: SPR-14651
上级 547b9638
......@@ -55,6 +55,8 @@ import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.handler.AbstractHandlerMethodExceptionResolver;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.support.RequestContextUtils;
/**
* An {@link AbstractHandlerMethodExceptionResolver} that resolves exceptions
......@@ -303,6 +305,7 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new RedirectAttributesMethodArgumentResolver());
resolvers.add(new ModelMethodProcessor());
// Custom arguments
......@@ -401,6 +404,11 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
request = webRequest.getNativeRequest(HttpServletRequest.class);
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
return mav;
}
}
......
......@@ -53,8 +53,14 @@ public class RedirectAttributesMethodArgumentResolver implements HandlerMethodAr
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
DataBinder dataBinder = binderFactory.createBinder(webRequest, null, null);
ModelMap redirectAttributes = new RedirectAttributesModelMap(dataBinder);
ModelMap redirectAttributes;
if(binderFactory != null) {
DataBinder dataBinder = binderFactory.createBinder(webRequest, null, null);
redirectAttributes = new RedirectAttributesModelMap(dataBinder);
}
else {
redirectAttributes = new RedirectAttributesModelMap();
}
mavContainer.setRedirectModel(redirectAttributes);
return redirectAttributes;
}
......
......@@ -42,7 +42,10 @@ import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.annotation.ModelMethodProcessor;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.FlashMap;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.util.NestedServletException;
import static org.junit.Assert.*;
......@@ -53,6 +56,7 @@ import static org.junit.Assert.*;
* @author Rossen Stoyanchev
* @author Arjen Poutsma
* @author Kazuki Shimizu
* @author Brian Clozel
* @since 3.1
*/
@SuppressWarnings("unused")
......@@ -82,6 +86,7 @@ public class ExceptionHandlerExceptionResolverTests {
this.resolver = new ExceptionHandlerExceptionResolver();
this.resolver.setWarnLogCategory(this.resolver.getClass().getName());
this.request = new MockHttpServletRequest("GET", "/");
this.request.setAttribute(DispatcherServlet.OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
this.response = new MockHttpServletResponse();
}
......@@ -192,6 +197,20 @@ public class ExceptionHandlerExceptionResolverTests {
assertEquals("IllegalArgumentException", mav.getModelMap().get("exceptionClassName"));
}
@Test // SPR-14651
public void resolveRedirectAttributesAtArgument() throws Exception {
IllegalArgumentException ex = new IllegalArgumentException();
HandlerMethod handlerMethod = new HandlerMethod(new RedirectAttributesController(), "handle");
this.resolver.afterPropertiesSet();
ModelAndView mav = this.resolver.resolveException(this.request, this.response, handlerMethod, ex);
assertNotNull(mav);
assertEquals("redirect:/", mav.getViewName());
FlashMap flashMap = (FlashMap) this.request.getAttribute(DispatcherServlet.OUTPUT_FLASH_MAP_ATTRIBUTE);
assertNotNull("output FlashMap should exist", flashMap);
assertEquals("IllegalArgumentException", flashMap.get("exceptionClassName"));
}
@Test
public void resolveExceptionGlobalHandler() throws Exception {
AnnotationConfigApplicationContext cxt = new AnnotationConfigApplicationContext(MyConfig.class);
......@@ -364,6 +383,18 @@ public class ExceptionHandlerExceptionResolverTests {
}
}
@Controller
static class RedirectAttributesController {
public void handle() {}
@ExceptionHandler
public String handleException(Exception ex, RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("exceptionClassName", ClassUtils.getShortName(ex.getClass()));
return "redirect:/";
}
}
@RestControllerAdvice
@Order(1)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册