【问题标题】:Status messages on the Spring MVC-based site (annotation controller)基于 Spring MVC 的站点(注解控制器)上的状态消息
【发布时间】:2010-04-24 10:28:13
【问题描述】:

使用注释控制器在基于 Spring MVC 的站点上组织状态消息(“您的数据已成功保存/添加/删除”)的最佳方式是什么?

因此,问题在于从控制器中的 POST 方法发送消息的方式。

【问题讨论】:

    标签: java spring-mvc controller annotations


    【解决方案1】:

    正如 muanis 所说,从 spring 3.1 开始,最好的方法是使用 RedirectAttributes。我将 i18n 添加到博客中给出的示例中。所以这将是一个完整的示例。

    @RequestMapping("/users")
    @Controller
    public class UsersController {
    
                @Autowired
                private MessageSource messageSource;
    
                @RequestMapping(method = RequestMethod.POST, produces = "text/html")
                public String create(@Valid User user, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest, Locale locale, RedirectAttributes redirectAttributes) {
                    ...
                    ...
                    redirectAttributes.addFlashAttribute("SUCCESS_MESSAGE", messageSource.getMessage("label_user_saved_successfully", new String[] {user.getUserId()}, locale));
                    return "redirect:/users/" + encodeUrlPathSegment("" + user.getId(), httpServletRequest);
                }
        ...
        ...
    }
    

    在您的消息包中添加适当的消息,例如 messages.properties。

    label_user_saved_successfully=Successfully saved user: {0}
    

    编辑您的 jspx 文件以使用相关属性

    <c:if test="${SUCCESS_MESSAGE != null}">
      <div id="status_message">${SUCCESS_MESSAGE}</div>
    </c:if> 
    

    【讨论】:

    • 如何在控制器中获取messageSource的持有量?
    • // Autowire 消息源。修改了原始答案以反映此更改。 @Autowired private MessageSource messageSource;
    • 我通常不在控制器中渲染 flash 消息,而只是将消息代码存储在 flash 上下文中。然后在呈现 flash 消息的视图中完成对 i18n 消息的解析。
    • 我认为重要的是要提及使用服务器端会话实现的 Spring MVC 闪存范围的含义。这意味着,在您运行多个应用程序实例的情况下(可能适用于大多数人),您将需要启用会话粘性或启用会话复制。我认为在客户端(cookie)而不是依赖于服务器端状态,flash 范围会更好地实现。
    【解决方案2】:

    一种行之有效的方法是对应该保留到下一个 GET 请求之前的消息使用特殊的 flash 范围。

    我喜欢使用会话范围的 flash 对象:

    public interface Flash {
        void info(String message, Serializable... arguments);
        void error(String message, Serializable... arguments);
        Map<String, MessageSourceResolvable> getMessages();
        void reset();
    }
    
    @Component("flash")
    @Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
    public class FlashImpl implements Flash {
        ...
    }
    

    一个特殊的 MVC 拦截器将从 flash 对象中读取 flash 值并将它们放入请求范围内:

    public class FlashInterceptor implements WebRequestInterceptor {
        @Autowired
        private Flash flash;
    
        @Override
        public void preHandle(WebRequest request) {
            final Map<String, ?> messages = flash.getMessages();
            request.setAttribute("flash", messages, RequestAttributes.SCOPE_REQUEST);
    
            for (Map.Entry<String, ?> entry : messages.entrySet()) {
                final String key = "flash" + entry.getKey();
                request.setAttribute(key, entry.getValue(), RequestAttributes.SCOPE_REQUEST);
            }
    
            flash.reset();
        }
    
        ...
    }
    

    现在在您的控制器中,您可以简单地将消息放置在“flash 范围”中:

    @Conteroller
    public class ... {
        @Autowired
        private Flash flash;
    
        @RequestMapping(...)
        public void doSomething(...) {
            // do some stuff...
            flash.info("your.message.key", arg0, arg1, ...);
        }
    }
    

    在您看来,您会遍历 Flash 消息:

    <c:forEach var="entry" items="${flash}">
        <div class="flash" id="flash-${entry.key}">
            <spring:message message="${entry.value}" />
        </div>
    </c:forEach>
    

    希望对你有帮助。

    【讨论】:

    • 既然 Spring 3.1 终于发布了,我将 krishnakumarp 的答案作为我的首选。
    【解决方案3】:

    在我头疼了一会儿之后,我终于成功了。

    我使用的是 spring 3.1,它支持跨重定向传递的 requestFlashAttributes。

    解决我的问题的关键是将返回类型更改为字符串,而不是 ModelAndView 对象。

    这个人发表了一篇关于在 spring 中使用 flash 消息的出色帖子 (http://www.tikalk.com/java/redirectattributes-new-feature-spring-mvc-31)

    【讨论】:

    【解决方案4】:

    您应该保持简单并使用特定的 HTTP 1.1 状态代码。因此,对于成功的呼叫,您将返回 200 OK。在客户端,如果您想在控制器返回 200 时向用户显示特定消息,那么您可以在那里显示。

    【讨论】:

    • 但是如果我想显示不同的消息取决于上下文,如果我只有 200 条 OK 消息,我怎么知道应该显示什么消息?
    • 关键是你只有在状态正常时才返回 200。如果没有找到返回404,如果服务器错误返回500,如果未授权返回403。
    【解决方案5】:

    如果您的意思是在某些 POST 之后重新加载页面,您可以在视图中包含一个标志(JSP 或速度或您使用的任何东西)。例如。像这样的

    <c:if test="${not empty resultMessage}">
     <spring:message code="${resultMessage}" />
    </c:if>
    

    您的消息包应该包含该代码的消息。

    如果您执行 AJAX POST 来提交一些数据(即页面未重新加载并且您需要显示一条消息),您可以

    1) 让您的 JS 文件动态化(再次是 JSP 或 Velocity)并在其中插入 &lt;spring:message&gt; 标签(我不太喜欢这个选项)

    2) 遵循this link 的建议并使用@ResponseBody 将状态对象返回给您的JS。在您标记为@ResponseBody 的对象内,您可以放置​​状态和消息。例如。使用 this case 中的消息包。

    【讨论】:

      【解决方案6】:

      在您的 JSP 上显示消息的最简单方法是拥有一个包含您要显示的消息的作用域(可能是会话,也可能是请求)对象。例如,您可以执行以下操作:

      ... java stuff ...
      List messages = new ArrayList();
      messages.add("some message");
      messages.add("some other message");
      request.addAttribute("NotableMessages", messages);
      ... java stuff ...
      
      ... jsp and JSTL stuff ...
      <c:if test="not empty NotableMessages">
      <ul>
      <c:forEach items="${NotableMessages}" var="item">
      <li>${item}</li>
      </c:forEach>
      </ul>
      </c:if>
      ... jsp stuff ...
      

      【讨论】:

        【解决方案7】:

        除了适当的状态代码外,您始终可以设置带有所需特定消息的标题。当然,如果您可以控制控制器的使用方式(即没有第三方),这确实是一个好主意。

        【讨论】:

          猜你喜欢
          • 2012-04-16
          • 2010-10-27
          • 2012-11-04
          • 1970-01-01
          • 1970-01-01
          • 2020-03-27
          • 1970-01-01
          • 1970-01-01
          • 2012-11-02
          相关资源
          最近更新 更多