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

时间:2011-09-09 11:12:48

标签: java spring spring-mvc spring-3

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

ControllerHelper.addDefaultModel(model, personManager, request);

在那里我会添加

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

这一切都允许每个视图显示登录用户的名字,轻松引用图像位置,语言列表和一些关于网站的整体统计数据。

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

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

6 个答案:

答案 0 :(得分:57)

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

@See:Spring Reference chapter: 15.4.1 Intercepting requests - the HandlerInterceptor interface

它有方法:

void postHandle(HttpServletRequest request,
                HttpServletResponse response,
                Object handler,
                ModelAndView modelAndView) throws Exception;

在控制器完成之后和渲染视图之前调用此方法。因此,您可以使用它来向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());
        }
    }
}

webmvc-config.xml中

<mvc:interceptors>
    <bean class="demo.VersionAddingHandlerInterceptor" autowire="constructor" />
</mvc:interceptors>

答案 1 :(得分:32)

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

@ModelAttribute("version")
public String getVersion() {
   return versionService.getVersion();
}

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

答案 2 :(得分:11)

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

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

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

答案 3 :(得分:4)

像@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());
}
}

答案 4 :(得分:3)

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

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

可以找到有关可用范围和用法的详细信息here

答案 5 :(得分:1)

如果你需要添加一些全局变量,每个视图都可以解析这些变量, 为什么不定义成属性或地图? 然后使用spring DI,参考视图解析器bean。 它非常有用,例如静态可靠,例如resUrl

<property name="viewResolvers">
        <list>
            <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                <property name="viewClass"
                    value="org.springframework.web.servlet.view.JstlView" />
                <property name="attributes" ref="env" />
                <property name="exposeContextBeansAsAttributes" value="false" />
                <property name="prefix" value="${webmvc.view.prefix}" />
                <property name="suffix" value="${webmvc.view.suffix}" />
            </bean>
        </list>
    </property>