javaspring-mvchttp-redirectdownloadspring-web

Download or redirect with error message to another controller action in Spring web MVC


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.


Solution

  • 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";
    }