通常如何从 class 中获取会话对象?

How to get the session object in general from within a class?

有一个 class :

@Configuration
@ComponentScan("com.ambre.pta")
@EnableTransactionManagement
@PropertySources({
    @PropertySource("classpath:fr/global.properties"),
    @PropertySource("classpath:fr/main.properties"),
    @PropertySource("classpath:fr/admin.properties"),
    @PropertySource("classpath:fr/referentiel.properties"),
    @PropertySource("classpath:fr/departement.properties"),
    @PropertySource("classpath:fr/exercice.properties"),
    @PropertySource("classpath:fr/defi.properties")
})
public class ApplicationContextConfig {

    @Bean
    public static PropertySourcesPlaceholderConfigurer properties() {
        return new PropertySourcesPlaceholderConfigurer();
    }

    @Bean(name = "viewResolver")
    public InternalResourceViewResolver getViewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }

    @Bean(name = "dataSource")
    public DataSource getDataSource() {

        BasicDataSource bds = new BasicDataSource();

        bds.setDriverClassName("oracle.jdbc.driver.OracleDriver");
        bds.setUrl("jdbc:oracle:thin:@localhost:1521:xe");

        bds.setUsername("pta");
        bds.setPassword("pta");

        return bds;

    }

    @Autowired
    @Bean(name = "sessionFactory")
    public SessionFactory getSessionFactory(DataSource dataSource) {

        LocalSessionFactoryBuilder sessionBuilder = new LocalSessionFactoryBuilder(dataSource);

        sessionBuilder.scanPackages("com.ambre.pta.model");

        return sessionBuilder.buildSessionFactory();

    }

    @Autowired
    @Bean(name = "transactionManager")
    public HibernateTransactionManager getTransactionManager(SessionFactory sessionFactory) {

        HibernateTransactionManager transactionManager = new HibernateTransactionManager(sessionFactory);

        return transactionManager;

    }

    @Autowired
    @Bean(name = "utilisateurDao")
    public UtilisateurDAO getUtilisateurDao(SessionFactory sessionFactory) {
        return new UtilisateurDAOImpl(sessionFactory);
    }

}

我们可以通过这种方式在这个class中获取request对象:

HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();

那么有没有办法获取 session ( HttpSession ) 对象?

使用控制器类

您可以将 HttpSession 定义为控制器方法的参数:

@RequestMapping("/my-path")
public String doStuff(HttpSession session) {
    // do stuff...
}

这也是访问 HttpRequest 的推荐方式,而不是通过 RequestContextHolder,因为模拟会话以进行测试更容易。

the Spring MVC docs for more detail.

不使用控制器类

另一种选择是使用 @SessionScope bean 并相应地改变它:

@Component
@SessionScope
public class MySessionScopedBean {
    String attribute;
}

public class MyOtherClass {
    @Autowired
    private MySessionScopedBean myBean;

    public void doStuff() {
        // myBean accesses a bean instance isolated in the user session
        myBean.attribute = "test";
    }

}

如果您想在控制器方法之外访问 HttpSession,有两种可能的答案:

  1. 不要这样做,这是邪恶的。
  2. 如果你真的真的很想做(我以前也做过,我又能怪谁),那么最简单的方法就是写一个class来保持会话,以及一个拦截器来设置和取消设置它。但为了让事情更简单,我将使用 HttpServletRequest 对象,您可以从中提取会话:

    public class RequestHolder {
    
        private static final ThreadLocal<HttpServletRequest> REQUEST =
                                 new ThreadLocal<>();
    
        public static HttpServletRequest getCurrentRequest() {
            return REQUEST.get();
        }
    
        public static HttpSession getCurrentSession() {
            HttpServletRequest request = REQUEST.get();
            return request == null ? null : request.getSession();
        }
    
        public static void setCurrentRequest(HttpServletRequest request) {
            REQUEST.set(request);
        }
    
        public static void unsetCurrentRequest() {
            REQUEST.remove();
        }
    
    }
    
    public class RequestHolderInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) {
            RequestHolder.setCurrentRequest(request);
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object o, ModelAndView mav) {
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object o, Exception e){
            RequestHolder.unsetCurrentRequest();
        }
    }