👉 기본 환경

- Language: Java

- DB: MySQL

- IDE: IntelliJ

 

 

1. Spring Initializer에서 기본 설정 구축

https://start.spring.io/

 

- Project

    - Gradle - Groovy: 환경 설정 파일 build.gradle

    - Gradle - Kotlin: JVM에서 실행되는 다목적 프로그래밍 언어로, Java와 호환성이 뛰어남

    - Maven: 환경 설정 파일 pom.xml

 

- Spring Boot

    - SNAPSHOT: 실험 중인 버전

    - 3.XX버전을 사용할 땐 JAVA 17 이상으로 사용

 

- Project Metadata

    - Group: 기업 도메인명

    - Artifact : 빌드 결과물
    - Name : 프로젝트명 (일반적으로 Artifact와 동일하게 설정)
    - Package name : Group과 Artifact에 따라 자동으로 생성

    - packaging: JAVA의 jar 툴을 이용하여 생성된 압축(아카이브) 파일, 어플리케이션을 쉽게 배포하고 동작시킬 수 있도록 있도록 관련 파일(리소스, 속성파일 등)들을 패키징

        - Jar

            - JAVA 어플리케이션이 동작할 수 있도록 자바 프로젝트를 압축한 파일

            - 원하는 구성을 할 수 있음

        - War

            - 웹 어플리케이션(Web Application) 압축 파일 포맷

            - WAR은 WEB-INF 및 META-INF 디렉토리로 사전 정의 된 구조를 사용

            - JAVA의 JAR 옵션( java - jar)을 이용해 생성하는 JAR파일의 일종으로 웹어플리케이션 전체를 패키징하기 위한 JAR파일

 

- Dependencies

    - Spring Web

        - Build web, including RESTful, applications using Spring MVC.

        - Uses Apache Tomcat as the default embedded container

    - Lombok

        - Java annotation library

    - Spring Boot DevTools

        - Provides fast application restarts, LiveReload, and configurations for enhanced development experience

 

* 필요한 Depencency 추가 후, Generate 클릭

 

 

2. IntelliJ

압축 파일 해제 후, IntelliJ에서 Open 클릭 후 압축 해제한 폴더 선택

    - Java Version 확인

    File / Project Structure / Project / Project SDK / Initializer에서 선택한 버전과 동일한 Java Version

    - Gradle 설정

    Preferences(Settings) / Build, Execution, Deployment / Build Tools / Gradle

        - Gradle JVM: Java Version과 동일하게 설정

        - Build and run using, Run tests using: IntelliJ IDEA ▶ Gradle

 

 

3. Database 설정

- build.gradle

    - dependencies{ ... } 안에 runtimeOnly 추가하여, DB 설정(MySQL ver.)

        - runtimeOnly 'com.mysql:mysql-connector-j'

- application.yml (⭐ 띄어쓰기 주의)

    - application.properties와 동일한 기능을하지만, 문법이 다름

 

spring:
  datasource:
  driver-class-name: com.mysql.cj.jdbc.Driver
  url: jdbc:mysql://localhost:3306/mydb?serverTimezone=Asia/Seoul
  username: DB 생성 시, 작성한 username
  password: DB 생성 시, 작성한 password

 

 

4. Application.java 실행

 

 

 

📚 참고 자료

 

[Java] JAR WAR 차이점 및 특징 ( + EAR )

JAR (Java Archive) WAR (Web Application Archive) 모두 JAVA의 jar 툴을 이용하여 생성된 압축(아카이브) 파일이며 어플리케이션을 쉽게 배포하고 동작시킬 수 있도록 있도록 관련 파일(리소스, 속성파일 등)들

ifuwanna.tistory.com

 

[Spring Boot] 프로젝트 생성 (start.spring.io)

목차 0. 환경 windows10 openjdk version "11" 2018-09-25 IntelliJ Tool Spring Boot 2.5.6 Gradle Project MyBatis + Mysql + HikariCp를 이용해 DB(Mysql) 연동할 프로젝트입니다. 1. Spring Boot 프로젝트 생성 1. https://start.spring.io/ 에

veneas.tistory.com

 

'Java > Spring' 카테고리의 다른 글

[SpringBoot] WebClient  (0) 2023.08.23
[SpringBoot_JPA_1] resources/static and templates  (0) 2023.05.20

이 글은 김영한의 [자바 ORM 표준 JPA 프로그래밍 - 기본편] 수강하며 정리한 글입니다.

 

👉 기본 환경

- Language: Java

- DB: H2 Database

- IDE: IntelliJ

 

 

ERD

 

1. JOINED

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import javax.persistence.*;
 
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn
public abstract class Item {
 
    @Id @GeneratedValue
    private Long id;
 
    private String name;
    private int price;
 
}
 
 
 

 

🖨️ 실행 결과

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
Hibernate: 
    
    create table Album (
       artist varchar(255),
        id bigint not null,
        primary key (id)
    )
 
Hibernate: 
    
    create table Book (
       ISBN varchar(255),
        author varchar(255),
        id bigint not null,
        primary key (id)
    )
 
Hibernate: 
    
    create table Item (
       DTYPE varchar(31not null,
        id bigint not null,
        name varchar(255),
        price integer not null,
        primary key (id)
    )
 
Hibernate: 
    
    create table Movie (
       actor varchar(255),
        director varchar(255),
        id bigint not null,
        primary key (id)
    )
 
 
Hibernate: 
    
    alter table Album 
       add constraint FKcve1ph6vw9ihye8rbk26h5jm9 
       foreign key (id) 
       references Item
 
Hibernate: 
    
    alter table Book 
       add constraint FKbwwc3a7ch631uyv1b5o9tvysi 
       foreign key (id) 
       references Item
 
Hibernate: 
    
    alter table Movie 
       add constraint FK5sq6d5agrc34ithpdfs0umo9g 
       foreign key (id) 
       references Item
 
 
 

 

📑 특징

- 장점

    - 외래 키 참조 무결성 제약조건 활용가능

    - 저장공간 효율화

- 단점

    - 조회 시, 조인 사용으로 인한 성능 저하

    - 데이터 저장 시, INSERT Query 2번 실행

 

🖨️ INSERT + ITEM 중심 SELECT 실행 결과

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
Hibernate: 
    /* insert jpa_basic.Movie
        */ insert 
        into
            Item
            (name, price, DTYPE, id) 
        values
            (?, ?, 'Movie', ?)
 
Hibernate: 
    /* insert jpa_basic.Movie
        */ insert 
        into
            Movie
            (actor, director, id) 
        values
            (?, ?, ?)
Hibernate: 
    select
        item0_.id as id2_2_0_,
        item0_.name as name3_2_0_,
        item0_.price as price4_2_0_,
        item0_1_.artist as artist1_0_0_,
        item0_2_.ISBN as isbn1_1_0_,
        item0_2_.author as author2_1_0_,
        item0_3_.actor as actor1_4_0_,
        item0_3_.director as director2_4_0_,
        item0_.DTYPE as dtype1_2_0_ 
    from
        Item item0_ 
    left outer join
        Album item0_1_ 
            on item0_.id=item0_1_.id 
    left outer join
        Book item0_2_ 
            on item0_.id=item0_2_.id 
    left outer join
        Movie item0_3_ 
            on item0_.id=item0_3_.id 
    where
        item0_.id=?
 
 
 

 

 

2. SINGLE_TABLE (DEFAULT)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import javax.persistence.*;
 
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn
public abstract class Item {
 
    @Id @GeneratedValue
    private Long id;
 
    private String name;
    private int price;
 
}
 
 
 

 

🖨️ 실행 결과

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Hibernate: 
    
    create table Item (
       DTYPE varchar(31not null,
        id bigint not null,
        name varchar(255),
        price integer not null,
        artist varchar(255),
        ISBN varchar(255),
        author varchar(255),
        actor varchar(255),
        director varchar(255),
        primary key (id)
    )
 
 
 

 

📑 특징

- 장점

    - 조회 시, 조인이 필요없으므로 성능이 빠름

    - Query가 단순함

- 단점

    - 자식 엔티티가 매핑한 컬럼은 모두 null을 허용해야 함

    - 단일 테이블에 모든 것을 저장하므로 테이블이 과하게 커질 수 있음

    ▶ 그로 인해 성능 저하가 발생할 수 있음

 

🖨️ INSERT + ITEM 중심 SELECT 실행 결과

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Hibernate: 
    /* insert jpa_basic.Movie
        */ insert 
        into
            Item
            (name, price, actor, director, DTYPE, id) 
        values
            (?, ?, ?, ?, 'Movie', ?)
 
Hibernate: 
    select
        item0_.id as id2_0_0_,
        item0_.name as name3_0_0_,
        item0_.price as price4_0_0_,
        item0_.artist as artist5_0_0_,
        item0_.ISBN as isbn6_0_0_,
        item0_.author as author7_0_0_,
        item0_.actor as actor8_0_0_,
        item0_.director as director9_0_0_,
        item0_.DTYPE as dtype1_0_0_ 
    from
        Item item0_ 
    where
        item0_.id=?
 
 
 

 

 

3. TABLE_PER_CLASS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import javax.persistence.*;
 
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@DiscriminatorColumn
public abstract class Item {
 
    @Id @GeneratedValue
    private Long id;
 
    private String name;
    private int price;
 
}
 
 
 

 

🖨️ 실행 결과

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Hibernate: 
    
    create table Album (
       id bigint not null,
        name varchar(255),
        price integer not null,
        artist varchar(255),
        primary key (id)
    )
 
Hibernate: 
    
    create table Book (
       id bigint not null,
        name varchar(255),
        price integer not null,
        ISBN varchar(255),
        author varchar(255),
        primary key (id)
    )
 
Hibernate: 
    
    create table Movie (
       id bigint not null,
        name varchar(255),
        price integer not null,
        actor varchar(255),
        director varchar(255),
        primary key (id)
    )
 
 
 

 

🖨️ INSERT + ITEM 중심 SELECT 실행 결과

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
Hibernate: 
    /* insert jpa_basic.Movie
        */ insert 
        into
            Movie
            (name, price, actor, director, id) 
        values
            (?, ?, ?, ?, ?)
 
Hibernate: 
    select
        item0_.id as id1_2_0_,
        item0_.name as name2_2_0_,
        item0_.price as price3_2_0_,
        item0_.artist as artist1_0_0_,
        item0_.ISBN as isbn1_1_0_,
        item0_.author as author2_1_0_,
        item0_.actor as actor1_4_0_,
        item0_.director as director2_4_0_,
        item0_.clazz_ as clazz_0_ 
    from
        ( select
            id,
            name,
            price,
            artist,
            null as ISBN,
            null as author,
            null as actor,
            null as director,
            1 as clazz_ 
        from
            Album 
        union
        all select
            id,
            name,
            price,
            null as artist,
            ISBN,
            author,
            null as actor,
            null as director,
            2 as clazz_ 
        from
            Book 
        union
        all select
            id,
            name,
            price,
            null as artist,
            null as ISBN,
            null as author,
            actor,
            director,
            3 as clazz_ 
        from
            Movie 
    ) item0_ 
where
    item0_.id=?
 
 
 

 

📑 특징

- 장점

    - Not Null 제약 조건 활용 가능

- 단점

    - 여러 자식 테이블을 함께 조회할 때 성능이 느림(UNION SQL 필요)

    - 자식 테이블을 통합해서 쿼리하기 어려움

 

 

 

 

👉 기본 환경

- Language: Java

- DB: MySQL

- IDE: IntelliJ

 

 

⌨️ 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
 
@Configuration
public class QuerydslConfiguration {
 
    @PersistenceContext
    private EntityManager entityManager;
 
    @Bean
    public JPAQueryFactory jpaQueryFactory() {
        return new JPAQueryFactory(entityManager);
    }
 
}
 
 
 

 

 

🖨️오류

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:98)
    at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:124)
    at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:190)
    at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:132)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:248)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:227)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:246)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
    at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
    at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
    at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:42)
    at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:80)
    at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:72)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
    at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:110)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:90)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:85)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:62)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
    at jdk.proxy1/jdk.proxy1.$Proxy2.stop(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker$3.run(TestWorker.java:193)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
    at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
    at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:113)
    at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:65)
    at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
    at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
Caused by: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'jpaQueryFactory' defined in com.example.demo.DemoApplication: Cannot register bean definition [Root bean: class [null]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=demoApplication; factoryMethodName=jpaQueryFactory; initMethodName=null; destroyMethodName=(inferred); defined in com.example.demo.DemoApplication] for bean 'jpaQueryFactory': There is already [Root bean: class [null]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=querydslConfiguration; factoryMethodName=jpaQueryFactory; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [com/example/demo/config/QuerydslConfiguration.class]] bound.
    at app//org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(DefaultListableBeanFactory.java:1006)
    at app//org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(ConfigurationClassBeanDefinitionReader.java:295)
 
 
 

 

 

📡 원인

오류 구문: "Caused by: org.springframework.beans.factory.support.BeanDefinitionOverrideException"

    - 두 개의 동일한 이름의 빈(Bean)이 스프링 컨텍스트 내에 중복으로 등록되었을 때 발생

 

👓 자세히

 Caused by: org.springframework.beans.factory.support.BeanDefinitionOverrideException:

Invalid bean definition with name 'jpaQueryFactory' defined in com.example.demo.DemoApplication:

Cannot register bean definition for bean 'jpaQueryFactory':

There is already  defined in class path resource [com/example/demo/config/QuerydslConfiguration.class] bound.

    - DemoApplication 내에 jpaQueryFactory 빈을 등록하려고 했으나, QuerydslConfiguration에서 이미 동일한 이름의 빈을 등록

 

 

📰 해결 방법

jpaQueryFactory 빈 등록을 DemoApplication 또는 QuerydslConfiguration에서 한 번만 등록

 

 

👉 기본 환경

- Language: Java

- DB: MySQL

- IDE: IntelliJ

 

 

⌨️ 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import com.example.demo.dao.srt.SrtFcstInfoDAO;
import com.example.demo.dao.srt.SrtFcstInfoRepository;
import com.example.demo.dto.srt.RqstParams;
import com.example.demo.entity.srt.UltraSrtFcst;
import com.example.demo.entity.srt.UltraSrtNcst;
import com.example.demo.entity.srt.VilageFcst;
import com.example.demo.service.srt.SrtFcstInfoServiceImpl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;
 
import java.util.List;
 
import static org.junit.Assert.*;
 
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class srtFcstInfoServiceTest {
 
    @Autowired
    SrtFcstInfoService srtFcstInfoService;
 
    @Autowired
    SrtFcstInfoRepository srtFcstInfoRepository;
 
 
    // UltraSrtNcst
    @Test
    public void 초단기실황조회() throws Exception {
 
        // given
        RqstParams rqstParams = createRqstParams();
 
        // when
        srtFcstInfoService.getUltraSrtNcst(rqstParams);
 
        // then
        List<UltraSrtNcst> savedDataList = srtFcstInfoRepository.findAllUltraSrtNcst();
        assertEquals(Integer.parseInt(rqstParams.getNumOfRows()), savedDataList.size());
 
    }
 
}
 
 
 

 

 

🖨️오류

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
org.gradle.api.internal.tasks.testing.TestSuiteExecutionException: Could not execute test class 'com.example.demo.service.srtFcstInfoServiceTest'.
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:54)
    at java.base@17.0.7/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base@17.0.7/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base@17.0.7/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base@17.0.7/java.lang.reflect.Method.invoke(Method.java:568)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
    at jdk.proxy1/jdk.proxy1.$Proxy2.processTestClass(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:176)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
    at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
    at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:113)
    at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:65)
    at app//worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
    at app//worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
Caused by: org.gradle.internal.UncheckedException: java.lang.ClassNotFoundException: com.example.demo.service.srtFcstInfoServiceTest
    at org.gradle.internal.UncheckedException.throwAsUncheckedException(UncheckedException.java:68)
    at org.gradle.internal.UncheckedException.throwAsUncheckedException(UncheckedException.java:41)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.loadClass(JUnitPlatformTestClassProcessor.java:137)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.access$100(JUnitPlatformTestClassProcessor.java:58)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.execute(JUnitPlatformTestClassProcessor.java:100)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.execute(JUnitPlatformTestClassProcessor.java:90)
    at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:60)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:52)
    ... 18 more
Caused by: java.lang.ClassNotFoundException: com.example.demo.service.srtFcstInfoServiceTest
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
    at java.base/java.lang.Class.forName0(Native Method)
    at java.base/java.lang.Class.forName(Class.java:467)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.loadClass(JUnitPlatformTestClassProcessor.java:135)
    ... 23 more
 
 
 

 

 

📡 원인

1. test class 이름의 시작이 소문자로 시작

 

😮 대문자로 변경해도 동일한 오류 발생

 

2. 프로젝트 파일 경로에 한글이 있을 경우, 인코딩 문제로 오류 발생

    - IntelliJ에서 콘솔창에 한글 설정을 위해 idea64.exe.vmoptions에 -Dfile.encoding=UTF-8를 추가한 부분에서 문제 발생

    - 📚 IntelliJ에서 콘솔창에 한글 설정 참고 자료

 

[IntelliJ] 콘솔 한글깨짐 처리 (console log encoding .. with tomcat)

IntelliJ 에서 프로젝트 생성 및 Tomcat 을 이용한 서버 시작 시.. console 로그에서 한글이 깨지는 현상이 확인되었다. 웹상 많이 검색되는 2가지 방법과 내가 해결한 다른 1가지 방법, 총 3가지 방법에

thingsthis.tistory.com

 

 

📰 해결 방법

1. test class 이름의 시작이 대문자로 변경

 

😮 대문자로 변경해도 동일한 오류 발생 시,

 

2. 프로젝트 파일 경로를 모두 영문으로 변경

 

👉 기본 환경

- Language: Java

- DB: MySQL

- IDE: IntelliJ

 

 

⌨️ 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package com.example.demo.controller;
 
import com.example.demo.service.mid.MidFcstInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
 
@RestController
public class ApiController {
 
    String midFcstInfo_url = "https://apis.data.go.kr/1360000/MidFcstInfoService/{fcst}";
    UriComponents uri = UriComponentsBuilder
            .fromHttpUrl(midFcstInfo_url)
            .queryParam("serviceKey""")
            .queryParam("numOfRows"5)
            .queryParam("pageNo"1)
            .queryParam("dataType""XML")
            .queryParam("stnId""108")
            .queryParam("tmFc""202308210600")
            .build();
 
 
    @GetMapping(value = "/getMidFcst")
    public void getMidFcst() {
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
 
        UriComponents modifiedUri = UriComponentsBuilder
                .fromUri(uri.toUri())
                .buildAndExpand("getMidFcst");
 
        ResponseEntity<String> result = restTemplate.exchange(modifiedUri.toUriString(), HttpMethod.GET, new HttpEntity<String>(headers), String.class);
 
    }
 
}
 
 
 

😮 http://localhost:8080/getMidFcst 호출

 

 

🖨️오류

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
There was an unexpected error (type=Internal Server Error, status=500).
500 Internal Server Error: "<?xml version="1.0" encoding="UTF-8"?><EOL><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><EOL> <soapenv:Body><EOL> <soapenv:Fault><EOL> <faultcode>soapenv:Server</faultcode><EOL> <faultstring>Policy Falsified</faultstring><EOL> <faultactor>https://apis.data.go.kr/1360000/MidFcstInfoService/%257Bfcst%257D?serviceKey=&amp;numOfRows=5&amp;pageNo=1&amp;dataType=XML&amp;stnId=108&amp;tmFc=202308210600</faultactor><EOL> <detail><EOL> <l7:policyResult<EOL> status="Service Not Found. The request may have been sent to an invalid URL, or intended for an unsupported operation." xmlns:l7="http://www.layer7tech.com/ws/policy/fault"/><EOL> </detail><EOL> </soapenv:Fault><EOL> </soapenv:Body><EOL></soapenv:Envelope><EOL>"
org.springframework.web.client.HttpServerErrorException$InternalServerError: 500 Internal Server Error: "<?xml version="1.0" encoding="UTF-8"?><EOL><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><EOL>    <soapenv:Body><EOL>        <soapenv:Fault><EOL>            <faultcode>soapenv:Server</faultcode><EOL>            <faultstring>Policy Falsified</faultstring><EOL>            <faultactor>https://apis.data.go.kr/1360000/MidFcstInfoService/%257Bfcst%257D?serviceKey=&amp;numOfRows=5&amp;pageNo=1&amp;dataType=XML&amp;stnId=108&amp;tmFc=202308210600</faultactor><EOL>            <detail><EOL>                <l7:policyResult<EOL>                    status="Service Not Found.  The request may have been sent to an invalid URL, or intended for an unsupported operation." xmlns:l7="http://www.layer7tech.com/ws/policy/fault"/><EOL>            </detail><EOL>        </soapenv:Fault><EOL>    </soapenv:Body><EOL></soapenv:Envelope><EOL>"
    at org.springframework.web.client.HttpServerErrorException.create(HttpServerErrorException.java:100)
    at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:170)
    at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:122)
    at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63)
    at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:825)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:783)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:717)
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:608)
    at com.example.demo.controller.ApiController.getMidFcst(ApiController.java:212)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1072)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:965)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:529)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:623)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:209)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:481)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:130)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:926)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1791)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:833)
 
 
 

 

 

 

📡 원인

ServiceKey와 동적 할당을 위한 {fcst} 부분이 인코딩 시 문제 발생

예상 URL: /getMidFcst?serviceKey=...&numOfRows=5&pageNo=1&...

실제 URL: /%257Bfcst%257D?serviceKey=&amp;numOfRows=5&amp;pageNo=1&...

 

    - fcst에 getMidFcst가 대입되지 않음

    - { ▶ %257B, } ▶ %257D는 변수 인식을 위한 기호지만, uri에 입력됨

    - queryParam에서 사용되는 & ▶ &amp;로 인코딩됨

 

 

📰 해결 방법

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package com.example.demo.controller;
 
import com.example.demo.service.mid.MidFcstInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
 
@RestController
public class ApiController {
 
    public UriComponents buildUriComponents(String type) {
        String midFcstInfo_url = "https://apis.data.go.kr/1360000/MidFcstInfoService/";
 
        return UriComponentsBuilder
                .fromHttpUrl(midFcstInfo_url + type)
                .queryParam("serviceKey""K191VdXCbr8NWPrKcAnq1uzT01WQHRPglu0oJzfYyzYD2sjner2RWLyEB8peuW2v7E46s28axdc9EAYncGUX7A==")
                .queryParam("numOfRows"5)
                .queryParam("pageNo"1)
                .queryParam("dataType""XML")
                .queryParam("stnId""108")
                .queryParam("tmFc""202308210600")
                .build();
    }
 
    @GetMapping(value = "/{type}")
    public Object getMidFcst(@PathVariable String type) {
        UriComponents uriComponents = buildUriComponents(type);
 
        UriComponents modifiedUri = UriComponentsBuilder
                .fromUri(uriComponents.toUri())
                .build();
 
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
 
        ResponseEntity<String> result = restTemplate.exchange(modifiedUri.toUriString(), HttpMethod.GET, new HttpEntity<String>(headers), String.class);
 
        return result;
    }
 
}
 
 
 

1. @GetMapping(value = "/{type}"), @PathVariable String type

    - value를 동적으로 할당받기

 

2. UriComponents uriComponents = buildUriComponents(type);

    - buildUriComponents에 pathVar를 전달하여 UriComponentsBuilder 생성

 

3. UriComponents modifiedUri

    - 새로운 UriComponents 생성