首页 > 解决方案 > Spring 将 Autowired SessionAttribute 注入服务层

问题描述

有没有办法将@Inject/@AutowiredSessionAttribute 直接放入@Service图层而不通过@Controller?

我正在寻找这样的东西:

@Autowired 
@SessionAttribute("userprincipal") 
UserPrincipal principal;

可能的解决方案:

@Configuration
public class ApplicationConfig {

    @Bean
    @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public UserPrincipal sessionUserPrincipal() {
        // not sure here the user does not exist at creation of bean
    }
}

标签: javaspring

解决方案


我的解决方案,希望这可以节省其他人一些时间。

注意:注入的依赖是隐藏的,如果在会话之外使用会导致问题。Optional<T>在这种情况下使用并在内部处理。如果您共享您的代码,您的团队将不会意识到所需的依赖关系。

测试:在测试时,您需要提供会话 bean 的@Autowired功能。

会话 Bean 类:

public class SessionUserPrincipal implements Serializable {

    private static final long serialVersionUID = 1L;

    private UserPrincipal principal;

    public SessionUserPrincipal() {}

    // mutator methods omitted
}

Optional<T>如果不能保证会话属性可用,则返回

将 Bean 添加到上下文:

@Configuration
public class WebServletContextConfiguration implements WebMvcConfigurer {

    @Bean
    @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public SessionUserPrincipal sessionUserPrincipal() {
        return new SessionUserPrincipal();
    }
}

将 RequestContextListener 添加到 web.xml

<listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>

这是下面的代码工作的要求。它公开了实现会话范围所必需的状态。默认情况下,该状态由 DispatcherServlet 公开,因此在请求进入 DispatcherServlet(Spring Security 过滤器)之前它不可用。@Autowire如果您在会话 bean 可用之前尝试访问它,您将得到一个异常。

成功验证时将会话属性添加到会话@Bean

public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    @Autowired SessionUserPrincipal sessionUserPrincipal;

    @Override
    public void onAuthenticationSuccess(
            HttpServletRequest request,
            HttpServletResponse response,
            Authentication authentication) throws IOException, ServletException
    {
        // find/get userprincipal code omitted
        sessionUserPrincipal.setPrincipal(userprincipal);
    }
}

使用会话 bean:

@Service
public class DefaultSomeService implements SomeService {
    @Autowired private SessionUserPrincipal sessionUserPrincipal;
}

推荐阅读