使用 Querydsl 创建自定义存储库时遇到错误。(javax.persistence.NoResultException)

问题描述 投票:0回答:1

我相信我已经正确设置了 Spring Boot 版本 3.1.8 的依赖项,如下面的 build.gradle 代码所示。

我正在尝试实现一项功能,将文章中的唯一主题标签列表发送给用户。

为了实现这一目标,我使用 Querydsl 自定义存储库以从 Article 表中获取此数据

我还将此功能添加到服务层和控制器层。我使用 Thymeleaf 将此数据发送给用户,并且还编写了 HTML。

虽然我的所有测试都通过了,但该功能在实际应用程序中不起作用。有人可以帮我找到解决方案吗?

  • 我确认所有存储库都指定了“最终”,但问题仍然存在。

  • 其他 Querydsl 查询(例如 findByContentContaining)运行良好。

  • 我还尝试更改构建和运行设置。

    • [构建并运行:Intellij,运行并取消:Gradle]

    • [构建并运行:Intellij,运行并取消:Intellij]

    • [构建并运行:Gradle,运行并取消:Gradle]

< build.gradle >

dependencies {

    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    // JSON API
    implementation 'org.springframework.boot:spring-boot-starter-data-rest' 
    implementation 'org.springframework.data:spring-data-rest-hal-explorer' 
    // server side
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    // Auth
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
    // DB
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    runtimeOnly 'com.h2database:h2'
    runtimeOnly 'com.mysql:mysql-connector-j'
    // queryDSL setting
    implementation "com.querydsl:querydsl-jpa:5.0.0"
    implementation "com.querydsl:querydsl-core:5.0.0"
    implementation "com.querydsl:querydsl-collections:5.0.0"
    annotationProcessor(
            "com.querydsl:querydsl-apt:5.0.0:jakarta",
            "jakarta.annotation:jakarta.annotation-api",
            "jakarta.persistence:jakarta.persistence-api"
    )
}

< ArticleRepositoryCustom >

public interface ArticleRepositoryCustom {
List\<String\> findAllDistinctHashtags();
}

< ArticleRepositoryCustomImpl >

public class ArticleRepositoryCustomImpl extends QuerydslRepositorySupport implements ArticleRepositoryCustom {

    public ArticleRepositoryCustomImpl() {
        super(Article.class);
    }
    
    @Override
    public List<String> findAllDistinctHashtags() {
        QArticle article = QArticle.article;
    
        return from(article)
                .select(article.hashtag)
                .fetch();
    }

}

< part of AticleService >

@Slf4j
@RequiredArgsConstructor // 필수 필드에 대한 생성자를 자동 생성
@Transactional
@Service                // 서비스 빈으로 등록
public class ArticleService {

    private final ArticleRepository articleRepository;
    
    // omit
    
    @Transactional(readOnly = true)
    public Page<ArticleDto> searchArticlesViaHashtag(String hashtag, Pageable pageable) {
        log.error("[해시태그 검색] Find Articles With Hashtag = {}", hashtag);
    
        if (hashtag == null || hashtag.isEmpty() || hashtag.isBlank()) {
            log.error("[해시태그 검색] Search Params is Null");
            return Page.empty(pageable);
        }
    
        return articleRepository.findByHashtag(hashtag, pageable).map(ArticleDto::from);
    }
    
    @Transactional(readOnly = true)
    public List<String> getHashtags() {
        List<String> uniqueHashtags = articleRepository.findAllDistinctHashtags();
        log.error("[유니크 해시태그 조회] uniqueHashtags = {}", uniqueHashtags);
        System.out.println(uniqueHashtags);
    
        return uniqueHashtags;
    }

< part of ArticleController >

@Slf4j
@RequiredArgsConstructor
@RequestMapping("/articles")
@Controller
public class ArticleController {

    private final ArticleService  articleService;
    private final PaginationService paginationService;

// omit

    @GetMapping("/search-hashtag")
    public String searchHashtag(
            @RequestParam(required = false) String searchValue,
            @PageableDefault(size = 10, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable,
            ModelMap map
    ) {
        log.error("[컨트롤러] search-hashtag 확인, searchValue: {}", searchValue);
    
        Page<ArticleResponse> articles = articleService.searchArticlesViaHashtag(searchValue, pageable).map(ArticleResponse::from);
        log.error("[컨트롤러] searchArticlesViaHashtag에서 패스");
        
        List<Integer> barNumbers = paginationService.getPaginationBarNumbers(pageable.getPageNumber(), articles.getTotalPages());
        log.error("[컨트롤러] getPaginationBarNumbers에서 패스");
        
        List<String> hashtags = articleService.getHashtags();
        log.error("[컨트롤러] getHashtags에서 패스");
    
        log.error("[컨트롤러] articles: {}, barNumbers: {}, hashtag: {}", articles, barNumbers, hashtags);
    
        map.addAttribute("articles", articles);
        map.addAttribute("hashtags", hashtags);
        map.addAttribute("paginationBarNumbers", barNumbers);
        map.addAttribute("searchType", SearchType.HASHTAG);
    
        return "articles/search-hashtag";
    }

< error content >

2024-02-21T10:31:29.047+09:00 ERROR 18720 --- \[nio-8082-exec-1\] c.f.m.controller.ArticleController       : \[컨트롤러\] searchArticlesViaHashtag에서 패스
2024-02-21T10:31:29.049+09:00 ERROR 18720 --- \[nio-8082-exec-1\] c.f.m.controller.ArticleController       : \[컨트롤러\] getPaginationBarNumbers에서 패스
2024-02-21T10:31:29.094+09:00 ERROR 18720 --- \[nio-8082-exec-1\] o.a.c.c.C.\[.\[.\[/\].\[dispatcherServlet\]    : Servlet.service() for servlet \[dispatcherServlet\] in context with path \[\] threw exception \[Handler dispatch failed: java.lang.NoClassDefFoundError: javax/persistence/NoResultException\] with root cause

java.lang.ClassNotFoundException: javax.persistence.NoResultException
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) \~\[na:na\]
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) \~\[na:na\]
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520) \~\[na:na\]
at org.springframework.data.jpa.repository.support.Querydsl.createQuery(Querydsl.java:84) \~\[spring-data-jpa-3.1.8.jar:3.1.8\]
at org.springframework.data.jpa.repository.support.Querydsl.createQuery(Querydsl.java:100) \~\[spring-data-jpa-3.1.8.jar:3.1.8\]
at org.springframework.data.jpa.repository.support.QuerydslRepositorySupport.from(QuerydslRepositorySupport.java:110) \~\[spring-data-jpa-3.1.8.jar:3.1.8\]
at com.fastcampus.mvcboardproject.repository.querydsl.ArticleRepositoryCustomImpl.findAllDistinctHashtags(ArticleRepositoryCustomImpl.java:21) \~\[classes/:na\]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) \~\[na:na\]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) \~\[na:na\]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) \~\[na:na\]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) \~\[na:na\]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:751) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137) \~\[spring-tx-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:751) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) \~\[spring-aop-6.0.16.jar:6.0.16\]
at com.fastcampus.mvcboardproject.repository.querydsl.ArticleRepositoryCustomImpl$$SpringCGLIB$$0.findAllDistinctHashtags(\<generated\>) \~\[classes/:na\]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) \~\[na:na\]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) \~\[na:na\]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) \~\[na:na\]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) \~\[na:na\]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:288) \~\[spring-data-commons-3.1.8.jar:3.1.8\]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:136) \~\[spring-data-commons-3.1.8.jar:3.1.8\]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:120) \~\[spring-data-commons-3.1.8.jar:3.1.8\]
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:516) \~\[spring-data-commons-3.1.8.jar:3.1.8\]
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:285) \~\[spring-data-commons-3.1.8.jar:3.1.8\]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:628) \~\[spring-data-commons-3.1.8.jar:3.1.8\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:168) \~\[spring-data-commons-3.1.8.jar:3.1.8\]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:143) \~\[spring-data-commons-3.1.8.jar:3.1.8\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:70) \~\[spring-data-commons-3.1.8.jar:3.1.8\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) \~\[spring-tx-6.0.16.jar:6.0.16\]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:391) \~\[spring-tx-6.0.16.jar:6.0.16\]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) \~\[spring-tx-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137) \~\[spring-tx-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:164) \~\[spring-data-jpa-3.1.8.jar:3.1.8\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:244) \~\[spring-aop-6.0.16.jar:6.0.16\]
at jdk.proxy4/jdk.proxy4.$Proxy163.findAllDistinctHashtags(Unknown Source) \~\[na:na\]
at com.fastcampus.mvcboardproject.service.ArticleService.getHashtags(ArticleService.java:101) \~\[classes/:na\]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) \~\[na:na\]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) \~\[na:na\]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) \~\[na:na\]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) \~\[na:na\]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:751) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) \~\[spring-tx-6.0.16.jar:6.0.16\]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:391) \~\[spring-tx-6.0.16.jar:6.0.16\]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) \~\[spring-tx-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:751) \~\[spring-aop-6.0.16.jar:6.0.16\]
spring-boot querydsl
1个回答
0
投票

经过两天的努力,我终于修复了这个错误。这是我的解决方案,以防其他人遇到同样的问题:

确保检查依赖关系。 我通过更改解决了该错误

implementation "com.querydsl:querydsl-jpa"

implementation "com.querydsl:querydsl-jpa:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"

仅指定实现“com.querydsl:querydsl-jpa”时,Querydsl 似乎无法找到 jakarta.persistence.api。

这个调整对我有用。 伙计们,祝您编码愉快!

© www.soinside.com 2019 - 2024. All rights reserved.