You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Controller全局添加请求属性:单方法实现登录用户名全局显示?

嘿,这个需求在Spring生态里完全可以轻松实现,而且有几种成熟的方案,我给你详细拆解下:

方案1:使用@ControllerAdvice + @ModelAttribute(最推荐)

这是Spring官方主推的全局Model属性注入方式,完美适配你这种“所有请求都要加属性”的场景。

你只需要创建一个全局控制器增强类,里面定义一个带@ModelAttribute的方法——这个方法会在所有Controller的请求处理逻辑执行前自动调用,把指定属性塞进Model里:

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

@ControllerAdvice
public class GlobalUserAttributeAdvice {

    @ModelAttribute("currentUsername")
    public String injectCurrentUsername() {
        // 从Spring Security上下文拿当前登录用户(如果用了Spring Security的话)
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null && auth.isAuthenticated() 
            && !"anonymousUser".equals(auth.getPrincipal())) {
            // 这里默认Principal是UserDetails,你可以根据自己的登录逻辑调整
            return auth.getName();
        }
        return "Guest"; // 未登录时的默认值,避免空指针
    }
}

关键说明:

  • @ControllerAdvice:让这个类成为全局控制器增强器,作用于所有带@RequestMapping的方法。
  • @ModelAttribute("currentUsername"):指定属性名,之后在模板里直接用${currentUsername}就能访问到用户名。
  • 如果没用Spring Security,把获取用户的逻辑换成你自己的实现就行(比如从HttpSession里取自定义的登录用户对象)。
方案2:使用HandlerInterceptor拦截器(更灵活)

如果你需要更精细的控制(比如只给特定路径的请求加属性,或者在请求处理的不同阶段做操作),拦截器是更好的选择:

首先定义拦截器类:

import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

public class UsernameInjectInterceptor implements HandlerInterceptor {

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, 
                          Object handler, ModelAndView modelAndView) throws Exception {
        // 跳过没有ModelAndView的请求(比如异步接口)
        if (modelAndView != null) {
            String username = getCurrentUser();
            modelAndView.addObject("currentUsername", username);
        }
    }

    private String getCurrentUser() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        return auth != null && auth.isAuthenticated() ? auth.getName() : "Guest";
    }
}

然后把拦截器注册到Spring配置里:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new UsernameInjectInterceptor())
                .addPathPatterns("/**") // 拦截所有请求
                .excludePathPatterns("/login", "/static/**"); // 排除登录接口、静态资源
    }
}

这个方案的优势是可以精准控制拦截范围,还能在请求处理的不同阶段(preHandle/postHandle/afterCompletion)做额外操作,适合复杂场景。

额外小技巧:模板引擎直接访问(比如Thymeleaf)

如果你用的是Thymeleaf模板,其实不用手动加Model属性,直接用Spring Security的表达式就能在模板里获取用户名:

<span th:text="${#authentication.name}"></span>

不过这种方式只限于模板层面,如果需要在Controller或其他业务逻辑里也用到用户名,还是推荐前两种方案。

最后注意点:

  • 确保用户信息获取逻辑是线程安全的:Spring Security的SecurityContextHolder默认用ThreadLocal存储,天生线程安全;如果是自定义Session存储,也要保证线程安全。
  • 一定要处理未登录的情况:给默认值避免空指针异常。

内容的提问来源于stack exchange,提问作者Vadym Borys

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:08:30