Issue
In a Spring Boot controller, is it possible to access RedirectAttributes
in a method without RedirectAttributes
in its signature? In other words, can it be accessed from the framework as a "bean" or context variable?
My motivation for doing this is to be able to refactor several request mapping methods (à la Clean Code) to move exception handling out of those methods. So, for example, I have several methods with a catch
block like this:
@GetMapping("/security/user/{uid}")
public String showEditUserForm(@PathVariable("uid") String uid, Model model, RedirectAttributes redirectAttributes) {
try {
model.addAttribute("userAccount", userAccountService.findByUsername(uid));
return "/security/edituser";
} catch(UserDoesntExistException e) {
redirectAttributes.addFlashAttribute("flashstatus","danger");
redirectAttributes.addFlashAttribute("flashmessage","User doesn't exist");
return "redirect:/security";
}
}
Instead, I'd like to do something like this:
@GetMapping("/security/user/{uid}")
public String showEditUserForm(@PathVariable("uid") String uid, Model model) {
try {
model.addAttribute("userAccount", userAccountService.findByUsername(uid));
return "/security/edituser";
} catch(UserDoesntExistException e) {
return redirectWithMessage("danger","User doesn't exist");
}
}
// and several other mappings that also call redirectWithMessage()
public String redirectWithMessage(String status, String message) {
// obtain RedirectAttributes somehow!
redirectAttributes.addFlashAttribute("flashstatus",status);
redirectAttributes.addFlashAttribute("flashmessage",message);
return "redirect:/security";
}
So the question is, how can the utility method ("redirectWithMessage
") obtain a pointer to RedirectAttributes
without every method in the class having to have it in its signature and pass it along via injection?
Solution
You have a couple of ways with RequestContextUtils
:
Call
RequestContextUtils#getOutputFlashMap
to get access to the flash map and update them (attributes + target redirect)Call convenient method
RequestContextUtils#saveOutputFlashMap
You can get instance of
FlashMapManager
Invoke this method to write flash attributes:
Save the given FlashMap, in some underlying storage and set the start of its expiration period. NOTE: Invoke this method prior to a redirect in order to allow saving the FlashMap in the HTTP session or in a response cookie before the response is committed.
void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response)
You can gain access to current request/response by @Autowire
them into the bean.
For your usecase, stick with #1 is OK (just add the attributes, the redirect location is set on your return string already)
Example:
@Autowired
HttpServletRequest request;
public String redirectWithMessage(String status, String message) {
FlashMap flashMap = RequestContextUtils.getOutputFlashMap(request);
flashMap.put("flashstatus",status);
flashMap.put("flashmessage",message);
return "redirect:/security";
}
Answered By - Mạnh Quyết Nguyễn
Answer Checked By - Willingham (JavaFixing Volunteer)