You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Data投影中@Value调用UserUtil方法报错求助

问题:Spring Data投影中SpEL无法调用UserUtil服务

需求与实现代码

我想在Spring Data投影接口Quiz中添加isOwner字段,用于判断当前登录用户ID与对应记录的用户ID是否相等,相关实现代码如下:

投影接口Quiz

public interface Quiz {

    @Value("#{userUtil.equalsLoggedInUser(target.appUser)}")
    Boolean isOwner();

}

UserUtil服务类

专门编写UserUtil服务类,用于获取当前登录用户并完成ID比较:

@Service
public class UserUtil {

    private final AppUserRepository appUserRepository;

    @Autowired
    public UserUtil( AppUserRepository appUserRepository) {
        this.appUserRepository = appUserRepository;
    }

    public AppUserEntity getLoggedInAppUserEntity() {
        String uid = ServiceUtil.getUidFromPrincipal();
        return this.appUserRepository.findUserByFirebaseUuid(uid)
                .orElseThrow(() -> new UsernameNotFoundException("Invalid or unknown \"uid\"."));
    }

    public Boolean equalsLoggedInUser(AppUserEntity appUserEntity) {
        return Objects.equals(appUserEntity.getId(), this.getLoggedInAppUserEntity().getId());
    }
}

配置类

@Configuration
public class UtilBeans {
    @Bean
    public UserUtil getUserUtil(AppUserRepository appUserRepository) {
        return new UserUtil(appUserRepository);
    }
}

报错信息

运行代码时出现找不到userUtil的错误:

Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: EL1008E: Property or field 'userUtil' cannot be found on object of type 'org.springframework.data.projection.SpelEvaluatingMethodInterceptor$TargetWrapper' - maybe not public or not valid?]

尝试改用静态调用方式,依然报相同错误:

@Value("#{T(server.service.UserUtil).equalsLoggedInUser(target.appUser)}")
Boolean isOwner();

解决方案

问题根源是Spring Data投影的SpEL默认上下文仅能访问target(实体对象)和projection(投影对象),无法直接引用Spring容器中的Bean。以下两种方式可解决该问题:

方式一:通过@Bean名称引用Spring容器中的Bean

修改投影接口的@Value注解,使用@userUtil直接引用容器中的Bean(Bean名称默认与@Bean方法名对应,此处为userUtil):

@Value("#{@userUtil.equalsLoggedInUser(target.appUser)}")
Boolean isOwner();

方式二:将UserUtil方法改为静态实现(不推荐)

若要使用T()方式调用,需将UserUtil中的相关方法改为静态方法,同时确保依赖的AppUserRepository能被静态访问:

@Service
public class UserUtil {

    private static AppUserRepository appUserRepository;

    @Autowired
    public UserUtil(AppUserRepository appUserRepository) {
        UserUtil.appUserRepository = appUserRepository;
    }

    public static AppUserEntity getLoggedInAppUserEntity() {
        String uid = ServiceUtil.getUidFromPrincipal();
        return appUserRepository.findUserByFirebaseUuid(uid)
                .orElseThrow(() -> new UsernameNotFoundException("Invalid or unknown \"uid\"."));
    }

    public static Boolean equalsLoggedInUser(AppUserEntity appUserEntity) {
        return Objects.equals(appUserEntity.getId(), getLoggedInAppUserEntity().getId());
    }
}

之后投影接口的SpEL即可正常使用:

@Value("#{T(server.service.UserUtil).equalsLoggedInUser(target.appUser)}")
Boolean isOwner();

注意:第二种方式属于静态依赖注入,并非Spring推荐的最佳实践,优先选择第一种方式。

内容的提问来源于stack exchange,提问作者Stefan Falk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 14:07:55