Idea: I have a Spring web MVC action that should accomplish one or both of these taks:
Problem: Spring is unable to download a file and redirect in case of a problem - somehow flash attributes don't work because the get lost in the redirect:
@ResponseBody
@RequestMapping(value = "/download/{fileaddress}", method = RequestMethod.GET)
public void download(HttpServletRequest request, HttpServletResponse response, @PathVariable(value = "fileaddress") String fileaddress) throws Exception
{
if(fileaddress != null && fileaddress.length() > 0)
{
try
{
// Get the remove file based on the fileaddress
RemoteFile remotefile = new RemoteFile(fileaddress);
// Set the input stream
InputStream inputstream = remotefile.getInputStream();
// Write the input stream to the output stream or throw an exception
Utils.writeTo(inputstream, response.getOutputStream());
}
catch(MyExceptionA)
{
// TODO: Define error message a and pass it to /addresses
// PROBLEM: Flash attributes that contain all critical error information don't work
response.sendRedirect(request.getContextPath() + "/addresses");
}
catch(MyExceptionB)
{
// TODO: Add another error message and redirect
response.sendRedirect(request.getContextPath() + "/addresses");
}
catch(MyExceptionC)
{
// TODO: Add another error message and redirect
response.sendRedirect(request.getContextPath() + "/addresses");
}
catch(MyExceptionN)
{
// TODO: Add another error message and redirect
response.sendRedirect(request.getContextPath() + "/addresses");
}
}
else
{
// TODO: Add error message
response.sendRedirect(request.getContextPath() + "/addresses");
}
}
JSP page of /addresses:
<%@ page pageEncoding="UTF-8" %>
<%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %>
<%@ taglib prefix="core" uri="http://java.sun.com/jsp/jstl/core" %>
<tags:index>
<jsp:attribute name="content">
<core:if test="${not empty error}">
<div class="alert alert-danger">
<p>${error}</p>
</div>
</core:if>
<p>Page under construction!</p>
</jsp:attribute>
</tags:index>
Question: How I am able to display the error message (Simple string for example) in the /addresses site? Working with different URL parameter (error=errora, error=errorb ...) is a huge pain, if there are multiple error types and passing the error message as GET parameter looks unprofessional and is the root of encoding problems.
What you need is the RedirectAttributes
a specialization of the Model
which controllers can use to select attributes for a redirect scenario.
So for a working example see below code:
@ResponseBody
@RequestMapping(value = "/download/{fileaddress}", method = RequestMethod.GET)
public Object download(@PathVariable(value = "fileaddress") String fileaddress, RedirectAttributes redirectAttrs) throws Exception {
if(StringUtils.hasText(fileaddress)){
try{
// Get the remove file based on the fileaddress
RemoteFile remotefile = new RemoteFile(fileaddress);
// Set the input stream
InputStream inputstream = remotefile.getInputStream();
// asume that it was a PDF file
HttpHeaders responseHeaders = new HttpHeaders();
InputStreamResource inputStreamResource = new InputStreamResource(inputStream);
responseHeaders.setContentLength(contentLengthOfStream);
responseHeaders.setContentType(MediaType.valueOf("application/pdf"));
return new ResponseEntity<InputStreamResource> (inputStreamResource,
responseHeaders,
HttpStatus.OK);
} catch (MyExceptionA | MyExceptionB | MyExceptionC | MyExceptionD ex) {
redirectAttrs.addFlashAttribute("error", ex.getMessage());
}
} else {
redirectAttrs.addFlashAttribute("error", "File name is required");
}
return "redirect:/addresses";
}
Update: I've thought the question is about situations where RedirectAttributes
are not available because otherwise, the solution is pretty obvious (use RedirectAttributes
).
Orignal answer:
I'm using the following code to bind messages to the flash map in situations where Spring doesn't support RedirectAttributes
(e.g. in ExceptionHandler
methods):
public static Feedback getInstance(HttpServletRequest request, HttpServletResponse response) throws IllegalArgumentException {
FlashMap flashMap = RequestContextUtils.getOutputFlashMap(request);
Object o = flashMap.get(KEY);
if (o != null) {
if (o instanceof Feedback) {
return Feedback.class.cast(o);
} else {
throw new IllegalArgumentException(...);
}
} else {
FeedbackContainer feedbackContainer = new FeedbackContainer();
flashMap.put(KEY, feedbackContainer);
FlashMapManager flashMapManager = RequestContextUtils.getFlashMapManager(request);
flashMapManager.saveOutputFlashMap(flashMap, request, response);
return feedbackContainer;
}
where Feedback
/ FeedbackContainer
is a container for messages which is then accessed in JPSs via JSON serialization. In your case you may use a mere String with key "error" and access it directly in the JSP:
void storeErrorMsg(HttpServletRequest request, HttpServletResponse response, String message) {
FlashMap flashMap = RequestContextUtils.getOutputFlashMap(request);
flashMap.put("error", message);
FlashMapManager flashMapManager = RequestContextUtils.getFlashMapManager(request);
flashMapManager.saveOutputFlashMap(flashMap, request, response);
}
The main reason for using my own message container is the possibility to have multiple messages with different levels and additional getInstance
methods for RedirectAttributes
, Model
or ModelMap
, so I don't have to care about duplicate feedback bindings and/or the different binding code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With