java - org.hibernate.LazyInitializationException:在春季安全登录期间未能延迟初始化角色集合
问题描述
我正在使用带有 JPA hibernate 和 spring 安全性的 Spring boot。我的项目结构是正常的。我在一个实体中使用了 3 个 @ManytoMany 关系,在用户实体中使用了另外 3 个实体。但是当我登录时,@ManytoMany 关系上的一个显示错误
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.Test.persistance.model.AdminMasterModel.sectorList, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:587)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:204)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:566)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:135)
at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:509)
(1)Web应用程序
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
@SpringBootApplication
public class WebApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(WebApplication.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(WebApplication.class, args);
}
}
(2)WebSecurityConfig
@Configuration
@EnableWebSecurity
//@EnableGlobalMethodSecurity(securedEnabled = true)
@EnableGlobalMethodSecurity(prePostEnabled = true , proxyTargetClass = true )
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Resource(name = "customUserDetailsService")
private UserDetailsService userDetailsService;
@Autowired
MyAuthenticationProvider myAuthenticationProvider;
@Autowired
TestAuthenticationFailureHandler TestAuthenticationFailureHandler;
@Autowired
TestUrlAuthenticationSuccessHandler TestUrlAuthenticationSuccessHandler;
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(myAuthenticationProvider);
}
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/assets/**")
.antMatchers("/bower_components/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/signup","/permitall/**" , "/login").permitAll()
.antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
.anyRequest().authenticated().and().csrf().disable().formLogin()
.loginPage("/login")//
.successHandler(TestUrlAuthenticationSuccessHandler)
.usernameParameter("username")
.passwordParameter("password")
.failureHandler(TestAuthenticationFailureHandler)
.and()
.logout()
.logoutUrl("/logout")
.deleteCookies("JSESSIONID")// Config for Logout Page
.logoutSuccessUrl("/loginpage?logout").and().exceptionHandling()
.accessDeniedPage("/access-denied");
}
@Bean
public BCryptPasswordEncoder encoder(){
return new BCryptPasswordEncoder();
}
@Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
@Bean
public RememberMeServices rememberMeServices() {
CustomRememberMeServices rememberMeServices = new CustomRememberMeServices("theKey", userDetailsService, new InMemoryTokenRepositoryImpl());
return rememberMeServices;
}
}
(3) 数据库配置
@Configuration
@EnableTransactionManagement
@PropertySource( "classpath:database.properties" )
@ComponentScan({ "com.Test.persistance"})
@EnableJpaRepositories(basePackages = "com.Test.persistance.dao")
public class DataBaseConfig {
@Value("${spring.datasource.url}")
private String dbUrl;
@Value("${spring.datasource.username}")
private String dbUserName;
@Value("${spring.datasource.password}")
private String dbPassword;
@Value("${spring.user.datasource.driver-class-name}")
private String dbDriver;
@Bean(name = "dataSource")
public DataSource testDataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(dbDriver);
dataSource.setUrl(dbUrl);
dataSource.setUsername(dbUserName);
dataSource.setPassword(dbPassword);
return dataSource;
}
@Bean
public Properties getHibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
properties.put("hibernate.show_sql", true);
properties.put("hibernate.format_sql", true);
properties.put("hibernate.jdbc.batch_size", 1000);
properties.put("hibernate.hbm2ddl.auto", "update");
return properties;
}
/* @Autowired
@Bean(name = "sessionFactory")
public SessionFactory getSessionFactory(DataSource dataSource) {
LocalSessionFactoryBuilder sessionBuilder = new LocalSessionFactoryBuilder(dataSource);
sessionBuilder.addProperties(getHibernateProperties());
sessionBuilder.scanPackages("com.Test.exam.bean.persistance.model");
return sessionBuilder.buildSessionFactory();
}*/
/*@Autowired
@Bean(name = "transactionManager")
public HibernateTransactionManager getTransactionManager(SessionFactory sessionFactory) {
HibernateTransactionManager transactionManager = new HibernateTransactionManager(sessionFactory);
return transactionManager;
}*/
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(testDataSource());
em.setPackagesToScan(new String[] { "com.Test.persistance.model" });
final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(getHibernateProperties());
return em;
}
@Bean
public JpaTransactionManager transactionManager() {
final JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
}
(4)AdminMasterModel
@Data
@Entity
@Table(name = "tbl_admin_master")
public class AdminMasterModel extends BaseDto {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String adminEmail;
@JsonIgnore
@Column(length = 60)
private String password;
@Column(length = 30)
private String adminSectorDetails;
@Column(length = 30)
private String adminName;
@Column(length = 30)
private String adminMobile;
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinTable(
name = "admin_sector",
joinColumns = @JoinColumn(
name = "admin_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(
name = "sector_id", referencedColumnName = "ssc_id"))
private Collection<SectorMasterModel> sectorList;
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinTable(
name = "admin_roles",
joinColumns = @JoinColumn(
name = "admin_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(
name = "role_id", referencedColumnName = "id"))
private Collection<Role> adminRoles;
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinTable(
name = "admin_job_roles",
joinColumns = @JoinColumn(
name = "admin_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(
name = "job_id", referencedColumnName = "job_id"))
private Collection<JobRoleModel> jobRoleModels;
}
(5)角色
@Data
@Entity
@Table(name = "role_master")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
@ManyToMany(mappedBy = "roles")
private Collection<User> users;
@ManyToMany(mappedBy = "adminRoles")
private Collection<AdminMasterModel> admin;
@ManyToMany(mappedBy = "studentRoles")
private Collection<StudentMasterModel> student;
@ManyToMany(mappedBy = "assessorRoles")
private Collection<AssessorMasterModel> assessor;
@ManyToMany
@JoinTable(name = "roles_privileges", joinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "privilege_id", referencedColumnName = "id"))
private Collection<Privilege> privileges;
public Role() {
super();
}
public Role(final String name) {
super();
this.name = name;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Role role = (Role) obj;
if (!role.equals(role.name)) {
return false;
}
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("Role [name=").append(name).append("]").append("[id=").append(id).append("]");
return builder.toString();
}
}
(6)SectorMasterModel
@Data
@Entity
@Table(name = "sector_master", schema = DBConstants.EXAM_SCHEMA)
public class SectorMasterModel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(length = 3)
private Integer ssc_id;
@Column(length = 60)
private String ssc_name;
@Column(length = 20)
private String short_name;
@ManyToMany(fetch = FetchType.LAZY,mappedBy = "sectorList" , cascade =CascadeType.ALL)
private List<AdminMasterModel> admin;
private Timestamp created_at;
private Long created_by;
private Integer is_active;
@Override
public String toString() {
return "SectorMasterModel{" +
"ssc_id=" + ssc_id +
", ssc_name='" + ssc_name + '\'' +
", short_name='" + short_name + '\'' +
", created_at=" + created_at +
", created_by=" + created_by +
", is_active=" + is_active +
'}';
}
}
我可以从 UI 成功登录,但登录后我发现此错误
2019-07-13 22:41:32.432 ERROR o.s.boot.web.support.ErrorPageFilter.handleCommittedResponse:213 - Cannot forward to error page for request [/adminmain/dashboard] as the response has already been committed. As a result, the response may have the wrong status code. If your application is running on WebSphere Application Server you may be able to resolve this problem by setting com.ibm.ws.webcontainer.invokeFlushAfterService to false
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.Test.persistance.model.AdminMasterModel.sectorList, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:587)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:204)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:566)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:135)
at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:509)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at com.Test.persistance.model.AdminMasterModel.toString(AdminMasterModel.java:15)
at org.springframework.security.authentication.AbstractAuthenticationToken.getName(AbstractAuthenticationToken.java:90)
at org.springframework.web.servlet.FrameworkServlet.getUsernameForRequest(FrameworkServlet.java:1092)
at org.springframework.web.servlet.FrameworkServlet.publishRequestHandledEvent(FrameworkServlet.java:1077)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:347)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:263)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.web.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:115)
at org.springframework.boot.web.support.ErrorPageFilter.access$000(ErrorPageFilter.java:59)
at org.springframework.boot.web.support.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:90)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.boot.web.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:108)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:96)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:800)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1471)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
解决方案
问题很清楚:在持久性上下文关闭后AdminMasterModel.toString()
尝试访问的惰性属性。AdminMasterModel
要解决这个问题,您需要自定义toString()
生成的默认实现@Data
以排除惰性关联。尝试穿上@ToString.Exclude
, sectorList
,adminRoles
和jobRoleModels
。
推荐阅读
- routing - PFsense OpenVPN 端口转发
- python - tensorflow:如何使用 flags.DEFINE_multi_float()
- java - 在 null 问题上找不到属性或字段
- python - 如何根据先前的键值打印字典的值?(其中关键是日期)
- javascript - 当角度选择下拉事件完成时进行计算
- ios - 使用一个 CBManager 连接和写入多个外围设备
- javascript - react js中的日期转换
- sql - 按时间范围谷歌选择不同的用户组 - bigquery SQL
- android - 当应用程序关闭时我需要一个屏幕提醒像这样的示例屏幕图像
- java - 如何在一个 JText 区域中显示大量价值 JTable 选定的行