Spring全局Model属性配置与Thymeleaf3.1替代#session等方案咨询
一、Spring中统一为所有Model提供属性的实现方式
最简洁且原生的方案是使用@ControllerAdvice配合@ModelAttribute注解,无需手动编写拦截器即可全局注入属性:
@ControllerAdvice public class GlobalModelAdvice { @ModelAttribute public void addGlobalAttributes(Model model, HttpServletRequest request, HttpSession session) { // 注入全局通用属性,比如当前用户、系统配置等 model.addAttribute("currentUser", session.getAttribute("currentUser")); model.addAttribute("contextPath", request.getContextPath()); } }
这个类会在所有Controller的方法执行前,自动将属性添加到Model中,覆盖所有请求场景,比拦截器实现更轻量,完全依托Spring原生机制。
如果需要在请求前后做额外逻辑(比如权限校验),也可以通过实现HandlerInterceptor接口,在postHandle方法中往ModelAndView里添加属性,但这种方式代码量更大,优先级低于@ControllerAdvice方案。
二、Thymeleaf 3.1移除#session、#httpServletRequest后的优化方案
你当前用拦截器填充属性的思路可行,但可以结合Spring原生特性进一步优化,以下是几种更优方案:
方案1:全局注入Web对象到Model(最小改造量)
借助上面的@ControllerAdvice,直接把HttpServletRequest、HttpSession注入到Model中,模板里用${request}、${session}替代原有的#httpServletRequest、#session:
@ControllerAdvice public class ThymeleafWebAttributeAdvice { @ModelAttribute public void addWebObjects(Model model, HttpServletRequest request, HttpSession session) { model.addAttribute("request", request); model.addAttribute("session", session); } }
模板使用示例:
<!-- 替代 #httpServletRequest.getContextPath() --> <a href="${request.contextPath}/dashboard">控制台</a> <!-- 替代 #session.getAttribute('currentUser').username --> <span>${session.currentUser.username}</span>
这种方式几乎不需要修改原有模板的逻辑,只是把#xxx换成${xxx},适合大规模项目快速迁移。
方案2:自定义Thymeleaf方言(保留原有语法)
如果想完全保留#session、#request的原有语法,可以自定义Thymeleaf方言,注册自己的表达式对象:
@Configuration public class CustomThymeleafDialect { @Bean public Dialect webObjectDialect() { return new AbstractDialect() { @Override public String getName() { return "customWeb"; } @Override public Set<IExpressionObjectFactory> getExpressionObjectFactories() { return Collections.singleton(new IExpressionObjectFactory() { @Override public Set<String> getAllExpressionObjectNames() { return Set.of("session", "request"); } @Override public Object buildObject(IExpressionContext context, String name) { WebRequest webRequest = (WebRequest) context.getVariable("webRequest"); if ("session".equals(name)) { return webRequest.getSession(); } else if ("request".equals(name)) { return ((ServletWebRequest) webRequest).getRequest(); } return null; } @Override public boolean isCacheable(String name) { return true; } }); } }; } }
配置完成后,模板可以继续使用${#session.currentUser}的原有语法,完全不需要修改模板代码,适合对代码一致性要求高的大规模项目。
方案3:使用Thymeleaf内置webRequest变量
Thymeleaf 3.1保留了webRequest内置变量(类型为org.springframework.web.context.request.WebRequest),可以直接用它获取request、session属性:
<!-- 获取session属性 --> ${webRequest.getAttribute('currentUser', WebRequest.SCOPE_SESSION)} <!-- 获取request属性 --> ${webRequest.getAttribute('pageTitle', WebRequest.SCOPE_REQUEST)}
这种方式无需额外编写Java代码,但模板写法稍长,适合小范围调整的场景。
总结
- 统一填充Model属性优先选择
@ControllerAdvice + @ModelAttribute,比拦截器更简洁高效。 - Thymeleaf 3.1迁移时,方案1实现成本最低,方案2能完全保留原有语法,可根据项目规模和需求选择。
内容的提问来源于stack exchange,提问作者leachim

