Java 将Hibernate、JDBC和SpringSecurity连接在一起时出现问题
我正在开发一个简单的SpringWeb应用程序。我使用SpringSecurity进行用户身份验证,使用Hibernate进行持久化。我希望Spring安全性使用数据库(而不是基本的内存身份验证) 但是,我在运行应用程序时遇到了一个异常Java 将Hibernate、JDBC和SpringSecurity连接在一起时出现问题,java,spring,hibernate,jdbc,Java,Spring,Hibernate,Jdbc,我正在开发一个简单的SpringWeb应用程序。我使用SpringSecurity进行用户身份验证,使用Hibernate进行持久化。我希望Spring安全性使用数据库(而不是基本的内存身份验证) 但是,我在运行应用程序时遇到了一个异常 SEVERE: Servlet /knights threw load() exception java.lang.ClassCastException: org.springframework.web.accept.ContentNegotiatio
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安全性和数据源是用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
AppConfig.java
:
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
:
最后,我的刀(非常简单)
PizzaDAO.java
:
springmvcinInitializer.java
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配置?)
也是@EnableWebMvc
是@EnableTransactionManagement
是@ComponentScan
LocalSessionFactoryBean
注入SessionFactory
bean,因为这是FactoryBean
的全部目的
public class PizzaDAO {
@Autowired private LocalSessionFactoryBean mySessionFactory;
应该是
public class PizzaDAO {
@Autowired private SessionFactory mySessionFactory;
调用代码时应该删除
getObject()
,因为现在有了一个普通的会话工厂
,我认为需要将
添加到servlet上下文.xml中,以便告诉Spring查找@Configuration注释。我设法解决了最初的问题。我不小心混淆了hibernate3和hibernate4类。我已经用我面临的最新问题更新了这个问题-Hibernate古怪。在某个地方,您正试图将工厂类绑定到实际的实现类中。无论您在何处尝试将ContentNegotiationManager
设置为`ContentNegotiationManagerFactoryBean`调用newInstance()
或其他类似方法,感谢您的回复。我用固定的DAO代码和完整的堆栈跟踪更新了这个问题。问题是我自己并没有直接使用ContentNegotiationManager
。它正被其他东西使用,由于异常是在注释处理阶段抛出的,因此我无法找到更多关于它的信息,除了它与handlerExceptionResolver
有关之外。感谢您的回复!我已经用你的建议更新了我的代码,但我仍然得到那个例外。我还发布了一个完整的堆栈跟踪,因为它可能会有所帮助。我把XML和Java混为一谈是因为我刚刚开始使用Spring,并且我依赖于使用XML或Java配置的各种指南。我认为问题在于您有一个
和@EnableWebMvc
。特别是与重复组件扫描相结合。您也可以添加web.xml吗。
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);
}
}
@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");
}
};
}
}
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[] { "/" };
}
}
/** Required to inject the proper security filter. */
public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
@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=?");
}
}
public class PizzaDAO {
@Autowired private LocalSessionFactoryBean mySessionFactory;
public class PizzaDAO {
@Autowired private SessionFactory mySessionFactory;