在Spring 3中为所有控制器的模型添加属性

at.*_*at. 53 java spring spring-mvc spring-3

我的Spring 3应用程序中的每个视图都有一组可以依赖的属性.所以每个控制器的第一行是这样的:

ControllerHelper.addDefaultModel(model, personManager, request);
Run Code Online (Sandbox Code Playgroud)

在那里我会补充

  • 如果有人登录,则从数据库中检索用户对象和全名
  • 通常设置一次的变量集(例如imagesHost)
  • 访问者可以切换到的一组语言
  • 目前的语言
  • 一些统计数据(例如我们系统中的总人数)

这一切都允许每个视图显示登录用户的名称,轻松引用图像位置,语言列表和一些有关该站点的整体统计信息.

所以问题是,控制器模型对象是存储所有数据的最佳位置还是有一个更方便的地方,使得视图访问这些信息一样容易?

其次,我真的很想不必将ControllerHelper上面的行作为每个控制器的第一行.它实际上并不总是第一行,有时我首先检查是否需要在该控制器中重定向,因为我不想浪费资源填充模型.也许一个过滤器或注释或一些春天的回调机制可以确保ControllerHelper代码被称为后,控制器完成,但正确的视图呈现,跳过此是否返回重定向?

Ral*_*lph 57

你可以写一个org.springframework.web.servlet.HandlerInterceptor.(或其便利子类HandlerInterceptorAdapter)

@See:Spring参考章节:15.4.1拦截请求 - HandlerInterceptor接口

它有这样的方法:

void postHandle(HttpServletRequest request,
                HttpServletResponse response,
                Object handler,
                ModelAndView modelAndView) throws Exception;
Run Code Online (Sandbox Code Playgroud)

在控制器完成之后和呈现视图之前调用此方法.所以你可以使用它来添加一些属性ModelMap

一个例子:

/**
 * Add the current version under name {@link #VERSION_MODEL_ATTRIBUTE_NAME}
 * to each model. 
 * @author Ralph
 */
public class VersionAddingHandlerInterceptor extends HandlerInterceptorAdapter {

    /**
     * The name under which the version is added to the model map.
     */
    public static final String VERSION_MODEL_ATTRIBUTE_NAME =
                "VersionAddingHandlerInterceptor_version";

    /**        
     *  it is my personal implmentation 
     *  I wanted to demonstrate something usefull
     */
    private VersionService versionService;

    public VersionAddingHandlerInterceptor(final VersionService versionService) {
        this.versionService = versionService;
    }

    @Override
    public void postHandle(final HttpServletRequest request,
            final HttpServletResponse response, final Object handler,
            final ModelAndView modelAndView) throws Exception {

        if (modelAndView != null) {
            modelAndView.getModelMap().
                  addAttribute(VERSION_MODEL_ATTRIBUTE_NAME,
                               versionService.getVersion());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

webmvc-config.xml中

<mvc:interceptors>
    <bean class="demo.VersionAddingHandlerInterceptor" autowire="constructor" />
</mvc:interceptors>
Run Code Online (Sandbox Code Playgroud)


bla*_*ank 32

您还可以在方法上使用@ModelAttribute,例如

@ModelAttribute("version")
public String getVersion() {
   return versionService.getVersion();
}
Run Code Online (Sandbox Code Playgroud)

这将为控制器中的所有请求映射添加它.如果你把它放在一个超级类中,那么扩展它的所有控制器都可以使用它.


mic*_*son 12

您可以使用带@ControllerAdvice注释的Controller类

"@ControllerAdvice在3.2中引入了@ExceptionHandler,@ ModelAttribute和@InitBinder方法,这些方法在所有或部分控制器之间共享."

有关它的一些信息,请查看SpringOne2GX 2014期间录制的视频部分 http://www.youtube.com/watch?v=yxKJsgNYDQI&t=6m33s

  • `@ControllerAdvice` 是一个很好的选择 (2认同)
  • 这应该是最好的答案,如果您需要多个控制器的相同模型属性,那么控制器建议注释就是您所需要的。[弹簧文档](http://docs.spring.io/spring-framework/docs/4.1.6.RELEASE/spring-framework-reference/html/mvc.html#mvc-ann-controller-advice) (2认同)

小智 6

就像@blank 为我回答这项工作一样:

@ControllerAdvice(annotations = RestController.class)
public class AnnotationAdvice {

    @Autowired
    UserServiceImpl userService;

    @ModelAttribute("currentUser")
    public User getCurrentUser() {
       UserDetails userDetails = (UserDetails) 
       SecurityContextHolder.getContext().getAuthentication().getPrincipal();
       return userService.findUserByEmail(userDetails.getUsername());
}
}
Run Code Online (Sandbox Code Playgroud)


小智 5

使用 @ModelAttribute 或 HandlerInterceptor 方法时,重定向会出现一个问题。当处理程序返回重定向视图时,以这种方式添加的模型属性将作为查询参数附加。

处理这种情况的另一种方法是创建会话范围的 bean,它可以在基本应用程序控制器中自动装配,或者在需要访问的每个控制器中显式装配。

有关可用范围和用法的详细信息可以在此处找到。