8

想法:我有一个 Spring Web MVC 动作,应该完成以下一项或两项任务:

  • 从远程服务器下载文件并将输入流写入响应输出流
  • 或者捕获下载异常,设置多个错误消息之一并重定向到 /addresses 页面。地址页面会显示错误

问题:Spring 无法下载文件并在出现问题时重定向 - 不知何故 flash 属性不起作用,因为在重定向中迷路了:

@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 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>

问题:如何在 /addresses 站点中显示错误消息(例如简单字符串)?使用不同的 URL 参数 (error=errora, error=errorb ...) 是一个巨大的痛苦,如果有多种错误类型并将错误消息作为 GET 参数传递看起来不专业并且是编码问题的根源。

4

4 回答 4

9

您需要的是控制器可以用来为重定向场景选择属性RedirectAttributes的专业化。Model因此,对于一个工作示例,请参见下面的代码:

@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";
}
于 2015-11-18T13:49:34.327 回答
2

更新:我认为问题是关于RedirectAttributes不可用的情况,因为否则,解决方案非常明显(使用RedirectAttributes)。

原答案:

在 Spring 不支持的情况下RedirectAttributes(例如在ExceptionHandler方法中),我使用以下代码将消息绑定到闪存映射:

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

其中Feedback/FeedbackContainer是消息的容器,然后通过 JSON 序列化在 JPS 中访问。在您的情况下,您可以仅使用带有键“error”的字符串并直接在 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);
}

使用我自己的消息容器的主要原因是可能有多个具有不同级别的消息和用于,或的附加getInstance方法,因此我不必关心重复的反馈绑定和/或不同的绑定代码。RedirectAttributesModelModelMap

于 2015-11-16T16:09:18.963 回答
1

我无法解释为什么它没有从服务器下载文件而是进入您的第二个查询,您可以通过两种方式重定向,或者将您的方法返回类型作为 ModelAndView 并这样做

ModelAndView mav = new ModelAndView("write here your jsp page name even is will work for remote server");
        try {
            mav.addObject("some key","here you can write any message that will you can show in your jsp page..");

然后返回 mav。像这样,您可以使用 if 条件重定向您想要的页面数量。

第二种方法你可以把你的方法返回类型字符串,你可以直接重定向到你需要的jsp。

于 2015-11-10T06:46:48.813 回答
0

我建议采用以下方法:由于您有一些远程文件作为输入流,因此您无法从发生异常的位置读取它。因此,您可以通过首先将文件下载到本地主机上的临时文件夹来减少错误机会。

如果出现错误,您可以按照您的建议重定向,或者在多次尝试失败后再次尝试并重定向。这样,在您确定文件下载成功之前,您不会向流中写入任何内容。

文件下载到服务器后,您可以将其传递给客户端。例如,您可以读取字节并保存当前位置。假设在写入流的过程中出现异常。您可以从中间的失败点读取恢复写入。

一个小例子

...
    final String localFileName = saveFileLocally(fileaddress)
    if (localFileName == null) {
        response.sendRedirect(request.getContextPath() + "/addresses");
    } else {
        safeWrite(new BufferedInputStream(new FileInputStream(new File(localFileName))), response.getOutputStream());
    }
...

safeWrite应该支持从文件中间读取本地文件读取异常处理。此类操作应该有标准的 java api。

于 2015-11-18T13:52:51.027 回答