Пожалуйста, помогите мне реализовать ленивую инициализацию.
Я написал код Java в Spring Core, Spring Security и Hibernate. Есть две сущности пользователя и роли. Связываю их с @ManyToMany(fetch = FetchType.EAGER)
. Но для задачи мне нужно реализовать ленивую инициализацию.
Если я выставил @ManyToMany(fetch = FetchType.LAZY)
, после успешной авторизации выйдет ошибка:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: web.model.User.roles, could not initialize proxy - no Session
Google направил по этим ссылкам: Первая ссылка / Вторая ссылка
Предлагается добавить user.getAuthorities () method.size();
.
Разве это не обходной путь ???
Тогда авторизация прошла успешно, но при ленивой инициализации я не могу получить доступ к ролям. И они не отображаются на странице jsp.
org.apache.jasper.JasperException: An error occurred during processing [/WEB-INF/pages/admin_panel.jsp] in line [71]
68: <td>${user.lastName}</td>
69: <td>${user.username}</td>
70: <td>${user.password}</td>
71: <td>${user.roles}</td>
72: <td>
Stacktrace:
org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:617)
Ниже я представлю основные части кода. Если чего-то не хватает, дайте мне знать.
Мой код:
Пользователь
@Entity
@Table(name = "users")
public class User implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "firstName")
private String firstName;
@Column(name = "lastName")
private String lastName;
@Column(name = "username")
private String username;
@Column(name = "password")
private String password;
@ManyToMany(fetch = FetchType.LAZY) // there was an EAGER here.
@JoinTable(name="user_role",
joinColumns={@JoinColumn(name="userId")},
inverseJoinColumns={@JoinColumn(name="roleId")})
private Set<Role> roles;
public User() {
}
...
класс UserServiceImp
@Service
public class UserServiceImp implements UserService {
@Autowired
private UserDao userDao;
@Transactional
@Override
public void add(User user) {
userDao.add(user);
}
@Transactional
public List<User> listUsers() {
return userDao.listUsers();
}
@Transactional
public boolean deleteUserById(long id) {
return userDao.deleteUserById(id);
}
@Transactional(readOnly = true)
public User getUserById(long id) {
return userDao.getUserById(id);
}
@Transactional
public void update(User user) {
userDao.update(user);
}
@Transactional
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userDao.getUserByName(username);
if (user == null) {
throw new UsernameNotFoundException("User not found");
}
int size = user.getAuthorities().size(); //added this line as indicated in the links
return user;
}
}
стр. *. jsp
...
<c:forEach items="${users}" var="user">
<tr>
<td>${user.id}</td>
<td>${user.firstName}</td>
<td>${user.lastName}</td>
<td>${user.username}</td>
<td>${user.password}</td>
<td>${user.roles}</td>
<td>
<a href="<c:url value='${pageContext.request.contextPath}/admin/editUser?id=${user.id}'/>" >Edit</a>
|
<a href="<c:url value='${pageContext.request.contextPath}/admin/deleteUser/${user.id}'/>" >Delete</a>
</td>
</tr>
</c:forEach>
...
UserDaoImp
@Repository
public class UserDaoImp implements UserDao {
@PersistenceContext
private EntityManager manager;
...
@Override
@SuppressWarnings("unchecked")
public User getUserByName(String username) {
Query query = manager.createQuery("FROM User u WHERE u.username = : username");
query.setParameter("username", username);
try {
return (User) query.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
...