【问题标题】:Could not initialize proxy - no Session, inside Spring interceptor无法初始化代理 - 没有会话,在 Spring 拦截器内
【发布时间】:2019-09-05 04:01:53
【问题描述】:

我的配置中有一个拦截器,我想禁止访问其他用户的资源。在 WebMvcConfig(实现 WebMvcConfigurer)内部,我有:

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new FolderInterceptor(userService, folderService))
            .addPathPatterns(Mapping.FOLDER_MAPPING + "/{id}",
                    Mapping.UPDATE_FOLDER_MAPPING + "/{id}",
                    Mapping.DELETE_FOLDER_MAPPING + "/{id}",
                    Mapping.DOWNLOAD_FOLDER_MAPPING + "/{id}");

}

在我的 FolderInterceptor 中,我有一个 preHandle 方法获取访问的文件夹并检查其所有者:

Map pathVariables = (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
Long id = Long.valueOf((String) pathVariables.get("id"));

User user = userService.getLoggedAccount();

if (folderService.existsById(id)) {
    Folder folder = folderService.findById(id);

    if (folder.getOwner().getId().equals(user.getId())) {
        return true;
    }
    else {
        response.sendError(403, "Unauthorized");
        return false;
    }
}
else {
    response.sendError(404, "Folder does not exist");
    return false;
}

如果我打印文件夹对象,那一行也会出现同样的错误。

org.hibernate.LazyInitializationException: could not initialize proxy.

感谢您的帮助。

【问题讨论】:

  • 没有 tx,因此没有 session/entitymanager,因此没有这个例外。您在拦截器中的代码属于单个事务服务方法。而不是调用拦截器中的所有不同方法。
  • 我应该补充一点,我的一个朋友向我展示了他完美运行的项目,我采用了与他完全相同的拦截器方法,只重命名了他与我的对象(文件夹)。
  • 它适用于另一个项目的事实并不意味着它会自动运行。您有他拥有的不同设置(可能没有打开的会话/实体管理器)。他没有延迟加载,你可能有。无论如何,理想情况下,它应该在一个单一的事务方法中,这将解决问题。或者修改您的对象模型以不使用延迟加载(但这可能会影响应用程序的其他部分)。
  • 我的模型中没有延迟加载,我确定了这一点。而且除了依赖的版本不同,我们两个项目在结构上非常相似。如果不是版本的原因,我看不出来是什么。
  • get 永远不会访问数据库,并且总是使用 LAZY 代理直接返回。因此,即使实际实体不存在,它也会为您提供Folder,并在您尝试对其调用 getter/setter 时立即导致问题,然后将转到数据库。查找将查询数据库并在未找到时返回实际的Foldernull。因此,您正在使用延迟加载...

标签: java spring session lazy-evaluation interceptor


【解决方案1】:

您很可能正在检索Folder 实体,而此处的一个事务下没有任何依赖项获取:

Folder folder = folderService.findById(id);

然后,当您尝试访问 folder.getOwner() 时,没有获取 Owner 依赖项,并且持久性提供程序尝试从数据库中延迟加载它:

if (folder.getOwner().getId().equals(user.getId())) {
    return true;
}

问题是folder 超出了事务范围并且是一个分离的实体。

我建议在folderService.findById(id) 方法中获取Owner,或者将查询和条件放在相同的事务方法下。

【讨论】:

    【解决方案2】:

    我使用 getOne 方法在我的服务中按 id 检索我的文件夹。现在使用 folderRepository.findById(id) 并且现在可以使用:

    public Folder findById(Long id) {
    
        Optional<Folder> folder = folderRepository.findById(id);
    
        if (!folder.isPresent())
            return null;
    
        return folder.get();
    }
    

    【讨论】:

      猜你喜欢
      • 2013-05-22
      • 1970-01-01
      • 1970-01-01
      • 2013-03-03
      • 1970-01-01
      相关资源
      最近更新 更多