下载或重定向到 Spring web MVC 中的另一个控制器操作并显示错误消息
Download or redirect with error message to another controller action in Spring web MVC
想法:我有一个 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 参数传递看起来不专业并且是编码问题的根源。
我无法解释为什么它不是从服务器下载文件而是进入你的第二个查询,你可以通过两种方式重定向,要么采用你的方法 return 输入 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..");
然后 return mav。
像这样,您可以使用 if 条件重定向您想要的页面数。
第二种方法你可以采用你的方法 return 类型字符串,你可以直接重定向到你需要的 jsp.
更新: 我认为问题是关于 RedirectAttributes
不可用的情况,否则,解决方案非常明显(使用 RedirectAttributes
).
原答案:
在 Spring 不支持 RedirectAttributes
的情况下(例如在 ExceptionHandler
方法中),我使用以下代码将消息绑定到 flash 地图:
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);
}
使用我自己的消息容器的主要原因是可能有多个不同级别的消息和 RedirectAttributes
、Model
或 ModelMap
的其他 getInstance
方法,所以我不必关心重复的反馈绑定 and/or 不同的绑定代码。
您需要的是 RedirectAttributes
Model
的专门化,控制器可以使用 select 重定向方案的属性。
因此,对于一个工作示例,请参见下面的代码:
@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";
}
我建议采用以下方法:
由于您有一些远程文件作为输入流,因此您无法从发生异常的地方读取它。因此,您可以通过先将文件下载到本地主机上的临时文件夹来减少出错的机会。
此处如果出现错误,您可以按照您的建议重定向,也可以重新尝试,在多次尝试失败后重定向。这样,在确定文件下载成功之前,您不会向流中写入任何内容。
文件下载到服务器后,您可以将其传递给客户端。例如,您可以读取字节并保存当前位置。假设在写入流的过程中发生了异常。可以从中间读取失败点恢复写入。
一个小例子
...
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
应该支持从文件中间读取的本地文件读取异常处理。这样的操作应该有标准的javaapi
想法:我有一个 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 参数传递看起来不专业并且是编码问题的根源。
我无法解释为什么它不是从服务器下载文件而是进入你的第二个查询,你可以通过两种方式重定向,要么采用你的方法 return 输入 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..");
然后 return mav。 像这样,您可以使用 if 条件重定向您想要的页面数。
第二种方法你可以采用你的方法 return 类型字符串,你可以直接重定向到你需要的 jsp.
更新: 我认为问题是关于 RedirectAttributes
不可用的情况,否则,解决方案非常明显(使用 RedirectAttributes
).
原答案:
在 Spring 不支持 RedirectAttributes
的情况下(例如在 ExceptionHandler
方法中),我使用以下代码将消息绑定到 flash 地图:
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);
}
使用我自己的消息容器的主要原因是可能有多个不同级别的消息和 RedirectAttributes
、Model
或 ModelMap
的其他 getInstance
方法,所以我不必关心重复的反馈绑定 and/or 不同的绑定代码。
您需要的是 RedirectAttributes
Model
的专门化,控制器可以使用 select 重定向方案的属性。
因此,对于一个工作示例,请参见下面的代码:
@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";
}
我建议采用以下方法: 由于您有一些远程文件作为输入流,因此您无法从发生异常的地方读取它。因此,您可以通过先将文件下载到本地主机上的临时文件夹来减少出错的机会。
此处如果出现错误,您可以按照您的建议重定向,也可以重新尝试,在多次尝试失败后重定向。这样,在确定文件下载成功之前,您不会向流中写入任何内容。
文件下载到服务器后,您可以将其传递给客户端。例如,您可以读取字节并保存当前位置。假设在写入流的过程中发生了异常。可以从中间读取失败点恢复写入。
一个小例子
...
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
应该支持从文件中间读取的本地文件读取异常处理。这样的操作应该有标准的javaapi