java - 将 Hibernate、JDBC 和 SpringSecurity 连接在一起时出现问题

标签 java spring hibernate jdbc

我正在开发一个简单的 Spring Web 应用程序。我使用 Spring Security 进行用户身份验证,使用 Hibernate 进行持久化。我希望 Spring Security 使用数据库(而不是基本的内存中身份验证)。

但是,我在运行应用程序时遇到异常。

    SEVERE: Servlet /knights threw load() exception
java.lang.ClassCastException: 
org.springframework.web.accept.ContentNegotiationManagerFactoryBean$$EnhancerByCGLIB$$fae0dbb8 cannot be cast to org.springframework.web.accept.ContentNegotiationManager

我不知道是什么原因造成的。这可能是 Hibernate 生成的代理的问题吗?问题是,由于我是 Spring 新手,并且正在学习各种在线教程,因此我的配置是 XML 和 Java 配置文件的混合。我的Spring Security和DataSource是用Java配置的,Hibernate是使用XML配置的。

这是完整的堆栈跟踪:

SEVERE: Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'handlerExceptionResolver' defined in class org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.web.servlet.HandlerExceptionResolver org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.handlerExceptionResolver()] threw exception; nested exception is java.lang.ClassCastException: org.springframework.web.accept.ContentNegotiationManagerFactoryBean$$EnhancerByCGLIB$$6412755f cannot be cast to org.springframework.web.accept.ContentNegotiationManager
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:581)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1025)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:921)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:487)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
    at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:651)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:599)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:665)
    at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:518)
    at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:459)
    at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
    at javax.servlet.GenericServlet.init(GenericServlet.java:160)
    at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1280)
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1193)
    at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1088)
    at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5176)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5460)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.web.servlet.HandlerExceptionResolver org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.handlerExceptionResolver()] threw exception; nested exception is java.lang.ClassCastException: org.springframework.web.accept.ContentNegotiationManagerFactoryBean$$EnhancerByCGLIB$$6412755f cannot be cast to org.springframework.web.accept.ContentNegotiationManager
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:181)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:570)
    ... 30 more
Caused by: java.lang.ClassCastException: org.springframework.web.accept.ContentNegotiationManagerFactoryBean$$EnhancerByCGLIB$$6412755f cannot be cast to org.springframework.web.accept.ContentNegotiationManager
    at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerByCGLIB$$fe413563.mvcContentNegotiationManager(<generated>)
    at org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.addDefaultHandlerExceptionResolvers(WebMvcConfigurationSupport.java:632)
    at org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.handlerExceptionResolver(WebMvcConfigurationSupport.java:596)
    at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerByCGLIB$$fe413563.CGLIB$handlerExceptionResolver$14(<generated>)
    at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerByCGLIB$$fe413563$$FastClassByCGLIB$$71eb2090.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:286)
    at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerByCGLIB$$fe413563.handlerExceptionResolver(<generated>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:160)
    ... 31 more

servlet-context.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">

    <!-- Expose the resources folder -->
    <mvc:resources mapping="/resources/**" location="/resources/"/>

    <!-- Map simple view name such as "test" into /WEB-INF/test.jsp -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>

AppConfig.java:

@EnableWebMvc
@Configuration
@ComponentScan("com.siegedog.browsergame")
public class AppConfig extends WebMvcConfigurerAdapter {

}

PersistenceConfig.java:

包 com.siegedog.browsergame.config;

@Configuration
@EnableTransactionManagement
@ComponentScan({ "com.siegedog.browsergame" })
public class PersistenceConfig {

    @Bean(name = "dataSource")
    public DriverManagerDataSource dataSource() {
        DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
        driverManagerDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        driverManagerDataSource.setUrl("jdbc:mysql://localhost:3306/knights");
        driverManagerDataSource.setUsername("root");
        driverManagerDataSource.setPassword("");
        return driverManagerDataSource;
    }

    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean fb = new LocalSessionFactoryBean();
        fb.setPackagesToScan("com.siegedog.browsergame");
        fb.setDataSource(dataSource());
        fb.setHibernateProperties(hibernateProperties());
        return fb;
    }

    @Bean
    @Autowired
    public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
        HibernateTransactionManager txManager = new HibernateTransactionManager();
        txManager.setSessionFactory(sessionFactory);

        return txManager;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }

    Properties hibernateProperties() {
        return new Properties() {
            {
                setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
                setProperty("hibernate.globally_quoted_identifiers", "true");
            }
        };
    }
}

SecurityConfig.java:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    DataSource dataSource;

    @Autowired
    public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication().dataSource(dataSource)
            .usersByUsernameQuery("select name, password_hash from users where name = ?")
            .authoritiesByUsernameQuery("select name, role from users where name = ?");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
        .antMatchers("/dashboard").hasRole("USER")
        .anyRequest().anonymous()
        .and()
            // Generate a form login if none is explicitly provided
            .formLogin()//.failureUrl("/login?error")
            //.usernameParameter("name").passwordParameter("password_hash")
        .and()
            .logout().logoutSuccessUrl("/login?logout")
        .and()
            .exceptionHandling().accessDeniedPage("/403")
        .and()
            .csrf();

    }
}

最后是我的 DAO(非常简单)。

PizzaDAO.java:

import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Repository
@SuppressWarnings({"unchecked"})
public class PizzaDAO {
    @Autowired private SessionFactory sessionFactory;

    /**
     * @Transactional annotation below will trigger Spring Hibernate
     * transaction manager to automatically create a hibernate session. 
     * See src/main/webapp/WEB-INF/servlet-context.xml
     */
    @Transactional
    public List<Pizza> findAll() {
        Session session = sessionFactory.getCurrentSession();
        List<Pizza> pizzas = session.createQuery("from Pizza").list();
        return pizzas;
    }

    @Transactional
    public void save(Pizza pizza) {
        Session session = sessionFactory.getCurrentSession();
        session.save(pizza);
    }
}

编辑:

我最终删除了所有 XML 配置并将其替换为完整的 Java 配置。 我的最终配置由 AppConfig.javaSpringMvcInitializer.javaSpringSecurityInitializer.javaWebSecurityConfig.java 组成。这是我的最终工作配置,以防有人感兴趣:

AppConfig.java

@EnableWebMvc
@EnableTransactionManagement
@Configuration
@ComponentScan( {"com.siegedog.knights"} )
public class AppConfig extends WebMvcConfigurerAdapter {

    @Bean(name = "dataSource")
    public DriverManagerDataSource dataSource() {
        DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
        driverManagerDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        driverManagerDataSource.setUrl("jdbc:mysql://localhost:3306/knights");
        driverManagerDataSource.setUsername("root");
        driverManagerDataSource.setPassword("");
        return driverManagerDataSource;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/assets/**").addResourceLocations(
                "classpath:/assets/");
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/img/**").addResourceLocations("/img/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
    }

    @Bean
    public InternalResourceViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/WEB-INF/jsp/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }

    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean fb = new LocalSessionFactoryBean();
        fb.setPackagesToScan("com.siegedog.knights");
        fb.setDataSource(dataSource());
        fb.setHibernateProperties(hibernateProperties());
        return fb;
    }

    @Bean
    @Autowired
    public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
        HibernateTransactionManager txManager = new HibernateTransactionManager();
        txManager.setSessionFactory(sessionFactory);
        return txManager;
    }

    Properties hibernateProperties() {
        return new Properties() {
            {
                setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
                setProperty("hibernate.globally_quoted_identifiers", "true");
            }
        };
    }
}

SpringMvcInitializer.java

public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] { AppConfig.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return null;
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }

}

SpringSecurityInitializer.java(参见评论)

/** Required to inject the proper security filter. */
public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {

}

WebSecurityConfig.java

此代码只是设置正确的路由身份验证规则。它还使用 AppConfig.java 中定义的数据源对注册用户进行身份验证。

@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    DataSource dataSource;

    /**
     * Important: csrf prevention is on by default.
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/dashboard").hasRole("USER")
                .antMatchers("/forest").hasRole("USER")
                .antMatchers("/arena").hasRole("USER")
                .antMatchers("/store").hasRole("USER")
                .anyRequest().permitAll();

        http
            .formLogin().loginPage("/login").failureUrl("/login?error").defaultSuccessUrl("/dashboard")
            .permitAll()
        .and()
            .logout()
            .permitAll()
        .and()
            .exceptionHandling().accessDeniedPage("/403");
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication().dataSource(dataSource)
            .usersByUsernameQuery("select name, password_hash, enabled from users where name=?")
            // Hash passwords with sha-256
            .passwordEncoder(new ShaPasswordEncoder(256))
            .authoritiesByUsernameQuery("select name, role from users where name=?");
    }
}

最佳答案

对于初学者来说,您有相当多的重复(为什么要混合 xml 和 java 配置?)。

  • <mvc:annotation-driven />也是@EnableWebMvc
  • <tx:annotation-driven />@EnableTransactionManagement .
  • <context:component-scan />@ComponentScan

您注入(inject)了错误的bean,而不是 LocalSessionFactoryBean注入(inject)SessionFactory bean,因为这就是 FactoryBean 的全部目的.

public class PizzaDAO {
@Autowired private LocalSessionFactoryBean mySessionFactory;

应该是

public class PizzaDAO {
@Autowired private SessionFactory mySessionFactory;

您调用的代码应该删除 getObject()因为你现在有一个简单的 SessionFactory .

关于java - 将 Hibernate、JDBC 和 SpringSecurity 连接在一起时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23685597/

相关文章:

java - 验证后 Spring 返回

java - Spring Hibernate Template 执行方法为 Oracle 上的计数查询返回什么对象类型?

hibernate - Tomcat 启动失败

java - Java的 "this"中 ".addActionListener(this)"关键字指的是什么

java - 在 Android 上移动数据库

java - Spring Boot Security 中 OAuth2Client 中的 SSO

mysql - 酒店预订申请 客房供应情况

java - Spring 4+ hibernate 4 : Could not obtain transaction-synchronized Session for current thread

Java ProbeContentType

java - 如何在 Single 方法中为不同的端点创建对象,而不是在 java 中使用 if 循环