Spring Initializr를 통해 신규 프로젝트 생성하기
Spring Initializr에서는 Spring Boot 프로젝트를 아주 간단히 생성할 수 있도록 도와줍니다. Spring Initializr에 접속하여 다음과 같이 ADD DEPENDNECIES 버튼을 클릭한 후 Spring Web을 추가합니다. 그리고 GENERATE 버튼을 누르면 소스코드가 생성되고 자동 다운로드합니다.
컴파일하기
이제 컴파일이 정상적으로 되는지 커맨드 라인으로 Maven을 이용하여 진행하겠습니다. mvn package
커맨드를 실행하면 소스코드 컴파일 > 테스트 > 패키징 순서대로 진행이 됩니다.
$ unzip demo.zip Archive: demo.zip creating: demo/ creating: demo/.mvn/ creating: demo/.mvn/wrapper/ inflating: demo/.mvn/wrapper/maven-wrapper.jar inflating: demo/.mvn/wrapper/maven-wrapper.properties inflating: demo/.mvn/wrapper/MavenWrapperDownloader.java inflating: demo/mvnw.cmd inflating: demo/mvnw inflating: demo/pom.xml creating: demo/src/ creating: demo/src/main/ creating: demo/src/main/java/ creating: demo/src/main/java/com/ creating: demo/src/main/java/com/example/ creating: demo/src/main/java/com/example/demo/ inflating: demo/src/main/java/com/example/demo/DemoApplication.java creating: demo/src/main/resources/ inflating: demo/src/main/resources/application.properties creating: demo/src/main/resources/templates/ creating: demo/src/main/resources/static/ creating: demo/src/test/ creating: demo/src/test/java/ creating: demo/src/test/java/com/ creating: demo/src/test/java/com/example/ creating: demo/src/test/java/com/example/demo/ inflating: demo/src/test/java/com/example/demo/DemoApplicationTests.java inflating: demo/HELP.md inflating: demo/.gitignore $ cd demo $ mvn package [INFO] Scanning for projects... [INFO] [INFO] --------------------------< com.example:demo >-------------------------- [INFO] Building demo 0.0.1-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ demo --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] Copying 1 resource [INFO] Copying 0 resource [INFO] [INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ demo --- [INFO] Nothing to compile - all classes are up to date [INFO] [INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ demo --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] skip non existing resourceDirectory /Users/fharenheit/Downloads/demo/src/test/resources [INFO] [INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ demo --- [INFO] Nothing to compile - all classes are up to date [INFO] [INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ demo --- [INFO] [INFO] ------------------------------------------------------- [INFO] T E S T S [INFO] ------------------------------------------------------- [INFO] Running com.example.demo.DemoApplicationTests 21:45:08.101 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating CacheAwareContextLoaderDelegate from class [org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate] 21:45:08.110 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating BootstrapContext using constructor [public org.springframework.test.context.support.DefaultBootstrapContext(java.lang.Class,org.springframework.test.context.CacheAwareContextLoaderDelegate)] 21:45:08.133 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating TestContextBootstrapper for test class [com.example.demo.DemoApplicationTests] from class [org.springframework.boot.test.context.SpringBootTestContextBootstrapper] 21:45:08.145 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Neither @ContextConfiguration nor @ContextHierarchy found for test class [com.example.demo.DemoApplicationTests], using SpringBootContextLoader 21:45:08.148 [main] DEBUG org.springframework.test.context.support.AbstractContextLoader - Did not detect default resource location for test class [com.example.demo.DemoApplicationTests]: class path resource [com/example/demo/DemoApplicationTests-context.xml] does not exist 21:45:08.148 [main] DEBUG org.springframework.test.context.support.AbstractContextLoader - Did not detect default resource location for test class [com.example.demo.DemoApplicationTests]: class path resource [com/example/demo/DemoApplicationTestsContext.groovy] does not exist 21:45:08.149 [main] INFO org.springframework.test.context.support.AbstractContextLoader - Could not detect default resource locations for test class [com.example.demo.DemoApplicationTests]: no resource found for suffixes {-context.xml, Context.groovy}. 21:45:08.149 [main] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils - Could not detect default configuration classes for test class [com.example.demo.DemoApplicationTests]: DemoApplicationTests does not declare any static, non-private, non-final, nested classes annotated with @Configuration. 21:45:08.176 [main] DEBUG org.springframework.test.context.support.ActiveProfilesUtils - Could not find an 'annotation declaring class' for annotation type [org.springframework.test.context.ActiveProfiles] and class [com.example.demo.DemoApplicationTests] 21:45:08.224 [main] DEBUG org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider - Identified candidate component class: file [/Users/fharenheit/Downloads/demo/target/classes/com/example/demo/DemoApplication.class] 21:45:08.225 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Found @SpringBootConfiguration com.example.demo.DemoApplication for test class com.example.demo.DemoApplicationTests 21:45:08.292 [main] DEBUG org.springframework.boot.test.context.SpringBootTestContextBootstrapper - @TestExecutionListeners is not present for class [com.example.demo.DemoApplicationTests]: using defaults. 21:45:08.292 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener, org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener, org.springframework.test.context.event.EventPublishingTestExecutionListener] 21:45:08.300 [main] DEBUG org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Skipping candidate TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener] due to a missing dependency. Specify custom listener classes or make the default listener classes and their required dependencies available. Offending class: [org/springframework/transaction/interceptor/TransactionAttributeSource] 21:45:08.300 [main] DEBUG org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Skipping candidate TestExecutionListener [org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener] due to a missing dependency. Specify custom listener classes or make the default listener classes and their required dependencies available. Offending class: [org/springframework/transaction/interceptor/TransactionAttribute] 21:45:08.301 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@2d96543c, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@73a2e526, org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener@7d64e326, org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener@13f95696, org.springframework.test.context.support.DirtiesContextTestExecutionListener@cd1d761, org.springframework.test.context.event.EventPublishingTestExecutionListener@68be8808, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener@32193bea, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener@6b8d96d9, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener@69653e16, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener@758705fa, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener@ebaa6cb] 21:45:08.303 [main] DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - Before test class: context [DefaultTestContext@1e8ce150 testClass = DemoApplicationTests, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@604f2bd2 testClass = DemoApplicationTests, locations = '{}', classes = '{class com.example.demo.DemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@5340477f, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@69504ae9, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@2d0399f4, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@565f390], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> true]], class annotated with @DirtiesContext [false] with mode [null]. 21:45:08.324 [main] DEBUG org.springframework.test.context.support.TestPropertySourceUtils - Adding inlined properties to environment: {spring.jmx.enabled=false, org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true, server.port=-1} . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.2.6.RELEASE) 2020-04-07 21:45:08.541 INFO 67626 --- [ main] com.example.demo.DemoApplicationTests : Starting DemoApplicationTests on fharenheitui-iMac.local with PID 67626 (started by fharenheit in /Users/fharenheit/Downloads/demo) 2020-04-07 21:45:08.542 INFO 67626 --- [ main] com.example.demo.DemoApplicationTests : No active profile set, falling back to default profiles: default 2020-04-07 21:45:09.421 INFO 67626 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2020-04-07 21:45:09.611 INFO 67626 --- [ main] com.example.demo.DemoApplicationTests : Started DemoApplicationTests in 1.279 seconds (JVM running for 2.033) [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.837 s - in com.example.demo.DemoApplicationTests 2020-04-07 21:45:09.899 INFO 67626 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor' [INFO] [INFO] Results: [INFO] [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] [INFO] --- maven-jar-plugin:3.1.2:jar (default-jar) @ demo --- [INFO] Building jar: /Users/fharenheit/Downloads/demo/target/demo-0.0.1-SNAPSHOT.jar [INFO] [INFO] --- spring-boot-maven-plugin:2.2.6.RELEASE:repackage (repackage) @ demo --- [INFO] Replacing main artifact with repackaged archive [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 4.530 s [INFO] Finished at: 2020-04-07T21:45:10+09:00 [INFO] ------------------------------------------------------------------------
실행하기
Maven Spring Boot Plugin으로 실행하기
컴파일이 완료되면 Maven Spring Boot Plugin을 이용하여 커맨드 라인으로 직접 실행해 보겠습니다. 커맨드를 실행하면 실제로 실행이 되며 8080 포트로 웹 서비스가 가능하도록 실행됩니다. 정확히 Apache Tomcat이 8080 포트로 동작하게 됩니다.
$ mvn spring-boot:run 21:45:53 [INFO] Scanning for projects... [INFO] [INFO] --------------------------< com.example:demo >-------------------------- [INFO] Building demo 0.0.1-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] >>> spring-boot-maven-plugin:2.2.6.RELEASE:run (default-cli) > test-compile @ demo >>> [INFO] [INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ demo --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] Copying 1 resource [INFO] Copying 0 resource [INFO] [INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ demo --- [INFO] Nothing to compile - all classes are up to date [INFO] [INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ demo --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] skip non existing resourceDirectory /Users/fharenheit/Downloads/demo/src/test/resources [INFO] [INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ demo --- [INFO] Nothing to compile - all classes are up to date [INFO] [INFO] <<< spring-boot-maven-plugin:2.2.6.RELEASE:run (default-cli) < test-compile @ demo <<< [INFO] [INFO] [INFO] --- spring-boot-maven-plugin:2.2.6.RELEASE:run (default-cli) @ demo --- [INFO] Attaching agents: [] . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.2.6.RELEASE) 2020-04-07 21:46:00.528 INFO 67696 --- [ main] com.example.demo.DemoApplication : Starting DemoApplication on fharenheitui-iMac.local with PID 67696 (/Users/fharenheit/Downloads/demo/target/classes started by fharenheit in /Users/fharenheit/Downloads/demo) 2020-04-07 21:46:00.530 INFO 67696 --- [ main] com.example.demo.DemoApplication : No active profile set, falling back to default profiles: default 2020-04-07 21:46:00.995 INFO 67696 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2020-04-07 21:46:01.002 INFO 67696 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2020-04-07 21:46:01.002 INFO 67696 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.33] 2020-04-07 21:46:01.047 INFO 67696 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2020-04-07 21:46:01.047 INFO 67696 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 492 ms 2020-04-07 21:46:01.138 INFO 67696 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2020-04-07 21:46:01.225 INFO 67696 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2020-04-07 21:46:01.228 INFO 67696 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 0.919 seconds (JVM running for 1.163)
JAR 파일로 실행하기
mvn package
커맨드를 이용하여 빌드를 하면 .jar
파일이 생성됩니다. 이 파일은 java -jar demo.jar
커맨드로 실행할 수 있습니다. 앞서 Maven Spring Boot Plugin을 실행한 것과 동일한 결과가 나옴을 알 수 있습니다.
$ cd target $ java -jar demo-0.0.1-SNAPSHOT.jar 21:47:14 . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.2.6.RELEASE) 2020-04-07 21:47:23.392 INFO 67782 --- [ main] com.example.demo.DemoApplication : Starting DemoApplication v0.0.1-SNAPSHOT on fharenheitui-iMac.local with PID 67782 (/Users/fharenheit/Downloads/demo/target/demo-0.0.1-SNAPSHOT.jar started by fharenheit in /Users/fharenheit/Downloads/demo/target) 2020-04-07 21:47:23.396 INFO 67782 --- [ main] com.example.demo.DemoApplication : No active profile set, falling back to default profiles: default 2020-04-07 21:47:24.243 INFO 67782 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2020-04-07 21:47:24.253 INFO 67782 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2020-04-07 21:47:24.254 INFO 67782 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.33] 2020-04-07 21:47:24.305 INFO 67782 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2020-04-07 21:47:24.305 INFO 67782 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 845 ms 2020-04-07 21:47:24.438 INFO 67782 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2020-04-07 21:47:24.595 INFO 67782 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2020-04-07 21:47:24.599 INFO 67782 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 1.563 seconds (JVM running for 1.957)
IntelliJ IDEA에서 Import하기
이제 소스코드 수정 및 추가를 위해서 IntelliJ IDEA에서 이 demo project를 import 해보겠습니다. 일단 IntelliJ IDEA를 실행하고 다음과 같이 나오면 Import Project를 선택합니다.
demo project가 있는 디렉토리로 이동하여 Maven 프로젝트 파일인 pom.xml
파일을 다음과 같이 선택합니다.
이제 Maven POM(pom.xml
) 파일을 로딩하고 관련 dependency를 다운로드하게 되며, 그 이후 dependency 및 소스코드의 인덱스를 생성하는 과정을 거치면 다음과 같이 소스코드를 작성할 수 있는 상태가 됩니다.
IntelliJ IDEA에서 실행하기
앞서 Maven 및 JAR 파일로 직접 실행하였습니다만, 여기에서는 IntelliJ IDEA를 통해서 실행하는 방법을 알아보겠습니다. 다음과 같이 DemoApplication
클래스에서 마우스 오른쪽 버튼을 눌러서 Run 메뉴가 표시되는 것을 확인합니다. 아무 클래스나 Run 메뉴가 표시되는 것은 아니며 실행가능한 클래스에서만 표시됩니다.
이제 Maven 또는 JAR로 실행된 결과와 마찬가지로 실행됨을 확인할 수 있습니다.
간단한 컨트롤러 추가하기
이제 Hello World를 표시하는 간단한 REST 방식의 웹 요청을 처리하는 컨트롤러를 작성해보겠습니다. 다음과 같이 com.example.demo 패키지에서 마우스 오른쪽 버튼을 눌러 New > Java Class를 선택합니다.
그리고 나서 다음과 같이 Class를 선택한 후에 HelloWorldController
로 클래스명을 지정합니다.
이제 다음과 같이 코드를 작성합니다. 아래 코드는 /rest/helloworld로 웹 브라우저에서 호출하면 Hello World를 웹 브라우저로 리턴하는 예제 코드입니다.
웹 브라우저로 호출하기
이제 프로그램을 재시작한 후 Chrome에서 http://localhost:8080/rest/helloworld를 주소창이 입력합니다. 다음은 Firefox에서 호출한 결과이며 Chrome에서도 동일한 결과를 볼 수 있습니다.
다음은 Chrome의 개발자 도구를 활성화 하고 호출한 결과입니다. 하단에 호출한 상세한 정보가 표시됩니다. 개발자들은 보통 이 정보를 보고 디버깅을 합니다.