티스토리 뷰

728x90
SMALL

이번 포스팅에서는 Spring Boot 프로젝트의 구조에 대해 살펴보도록 하겠습니다.

지난 포스팅은 다음을 참고하시기 바랍니다.

 

[Spring Boot] git clone을 활용한 Spring Boot 프로젝트 repository 이관

[Spring Boot] gitlab & Eclipse 연동을 통한 Spring Boot 개발 프로젝트 구축

[Spring Boot] Spring Boot Maven Repo 구축(Nexus2 OSS 내부 저장소)

[Spring Boot] Spring Boot Maven Repo 연동(Nexus2 OSS 내부 저장소)

 

Spring Boot Structre

Spring Boot 프로젝트를 생성하면 크게 다음과 같은 구조로 구성되어 있습니다.

주요 구성 요소는

- src/main/java

- src/main/resources

- src/main/webapp/WEB-INF/jsp

- JRE System Library

- Maven Dependencies

- pom.xml

등이 있습니다.

하나씩 구성요소를 살펴보도록 하겠습니다.

지금부터 살펴보는 구성은 누구나 변경이 가능하고 위치를 지정할 수 있으며, 파일명 및 패키지 구조 모두 원하는 방식대로 재 정의 할 수 있습니다. 아래 내용은 단순히 Sample을 제공하고 어떠한 구조로 Spring Boot가 구성되어 있고, 활용 방안은 어떤게 있는지 알아보는 수준으로 작성되었음을 말씀드립니다.

1) src/main/java

디렉토리는 Java 클래스가 위치하는 경로입니다.

기본으로 생성한 구조는 위와 같습니다.

src/main/java 하위에

- nrson/ServletInitializer.java

- nrson/TemplateApplication.java

- nrson/config

- nrson/sample

- nrson/common

- nrson/springboot/Hello.java

 

a) nrson/ServletInitializer.java & nrson/TemplateApplication.java

Spring Boot에서 웹 애플리케이션을 배포하기 위해서는 SpringBootServletInitializer 상속해야하는데 ServletInitializer는 SpringBootServletInitializer를 상속하는 클래스로 정의합니다.

SpringApplicationBuiler는 애플리케이션 실행코드를 작성하기 위해 configure를 오버라이드합니다.

[ServletInitializer.java]

package nrson;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

public class ServletInitializer extends SpringBootServletInitializer {

	@Override
	protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
		return application.sources(TemplateApplication.class);
	}

}

[TemplateApplication.java]

package nrson;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.ImportResource;

@SpringBootApplication
@ImportResource("classpath:applicationContext.xml")
@EnableAutoConfiguration(exclude={MongoAutoConfiguration.class})
public class TemplateApplication {
	
	public static void main(String[] args) {
		SpringApplication.run(TemplateApplication.class, args);
		
		System.out.println("SpringApp");
	}

}

TemplateApplication.java에서는 비즈니스 로직이 포함된 구현부가 들어갑니다.

 

다음으로 TemplateApplication.java 파일을 실행해 보도록 하겠습니다.

TemplateApplication.java 위치에서 Ctrl + F11 또는 Run As + Spring Boot App 을 실행합니다.

Spring Boot에서는 spring-boot-starter-web에 Default로 Embed Tomcat을 제공하여 가볍고 빠르게 기동할 수 있습니다.


SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/C:/Users/user/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/Users/user/.m2/repository/org/apache/logging/log4j/log4j-slf4j-impl/2.11.2/log4j-slf4j-impl-2.11.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.4.RELEASE)

2019-07-29 02:00:06.023  INFO 93072 --- [           main] nrson.TemplateApplication                : Starting TemplateApplication on DESKTOP-SDT0PVK with PID 93072 (C:\Users\user\git\hellogitrepo\target\classes started by nrson in C:\Users\user\git\hellogitrepo)
2019-07-29 02:00:06.025  INFO 93072 --- [           main] nrson.TemplateApplication                : No active profile set, falling back to default profiles: default
2019-07-29 02:00:06.608  INFO 93072 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2019-07-29 02:00:06.624  INFO 93072 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2019-07-29 02:00:06.624  INFO 93072 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.17]
2019-07-29 02:00:06.673  INFO 93072 --- [           main] o.a.c.c.C.[.[localhost].[/template]      : Initializing Spring embedded WebApplicationContext
2019-07-29 02:00:06.673  INFO 93072 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 623 ms
2019-07-29 02:00:06.780  INFO 93072 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2019-07-29 02:00:06.885  INFO 93072 --- [           main] .s.s.UserDetailsServiceAutoConfiguration : 

Using generated security password: 3709152a-a423-49f2-887d-ba9caea205d8

2019-07-29 02:00:06.928  INFO 93072 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@5eeedb60, org.springframework.security.web.context.SecurityContextPersistenceFilter@710d7aff, org.springframework.security.web.header.HeaderWriterFilter@7b60c3e, org.springframework.security.web.csrf.CsrfFilter@60baef24, org.springframework.security.web.authentication.logout.LogoutFilter@7b44b63d, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@25d958c6, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@6ac97b84, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@40021799, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@ddf20fd, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@65327f5, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@2e3a5237, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@4a1c0752, org.springframework.security.web.session.SessionManagementFilter@6569dded, org.springframework.security.web.access.ExceptionTranslationFilter@312afbc7, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@7c211fd0]
2019-07-29 02:00:06.962  INFO 93072 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path '/template'
2019-07-29 02:00:06.963  INFO 93072 --- [           main] nrson.TemplateApplication                : Started TemplateApplication in 1.101 seconds (JVM running for 1.455)
SpringApp


위와 같이 Spring Boot가 기동되며 손쉽게 Application을 실행해 볼 수 있습니다.

b) nrson/config

nrson/config에서는 기존 Spring Framework에서 사용되던 Config File을 Class 내부로 전환하는 설정 + 공통으로 적용될 설정에 대한 명시, 전역 변수등을 포함합니다.

c) nrson/sample

nrson/sample에서는 Mybatis Sample 등 개발자들이 사용할 수 있는 샘플을 작성하여 제공합니다. 운영 패키지에는 포함하지 않도록 합니다.

d) nrson/common

nrson/common은 공통 모듈이 위치하는 패키지입니다.

e) nrson/springboot/Hello.java

마지막으로 실제 개발 소스들이 위치할 nrson/springboot package입니다.

Hello.java 클래스를 기본으로 작성하였습니다.

728x90

2) src/main/resources

다음으로 살펴볼 디렉토리는 resources 디렉토리입니다. resources 디렉토리는 정적 파일 즉 static 파일이 위치하며, 각종 Spring Boot 관련 설정들이 모여 있는 디렉토리입니다. 대표적으로 application.properties, application.yml 파일이 위치합니다. 또한 Mybatis 관련 각종 설정들 역시 해당 공간에 위치하게 됩니다.

위와 같은 구조로 실제 이루어져 있으며,

- mybatis

- static/css

- static/html

- static/js

- templates

- application.properties

- applicationContext.xml

- log4j2-spring.xml

등의 파일로 구성되어 있습니다.

 

a) Mybatis

Mybatis 디렉토리에는 Mybatis에서 사용할 각종 Config 파일과 Mapper 파일이 위치합니다.

b) static/css, static/html, static/js

정적 파일이 위치하는 폴더입니다.

c) templates

template engine 사용 시 view 코드들을 위치하기 위한 공간입니다.

d) application.properties

Spring Boot 공통 설정 파일인 application.properties입니다. 공통 Properties 및 Database 설정등이 위치합니다.

e) applicationContext.xml

Spring Framework Bean create 설정 파일입니다.

f) log4j2-spring.xml

로그 설정을 위한 log4j2 설정 파일입니다.

3) src/main/webapp/WEB-INF/jsp

다음으로 살펴볼 src/main/webapp/WEB-INF/jsp는 jsp 파일들이 위치하는 폴더입니다.

해당 위치가 jsp의 Context-Root/ 경로가 됩니다.

4) JRE System Library & Maven Dependencies

Spring Boot 기동을 위한 라이브러리입니다. 이는 Spring Framework와 동일한 구조입니다.

Java Runtime Environment Library와 Maven Dependency로 인해 등록된 라이브러리들이 위치하는 공간입니다.

5) pom.xml

pom.xml은 앞서도 지속적으로 설명되었지만, Maven Dependency 관리 매니저를 수행하기 위한 정의 파일이라고 볼 수 있습니다. 다양한 Dependency 모듈을 추가하는 것은 물론 빌드 방식, 리포지토리 위치 저장, 버전 관리 등 다양한 라이브러리와 배포 과정을 설정할 수 있습니다.

Spring Boot Project Structure

다음으로 실제 Spring Boot Project가 실행될 경우 구조는 어떻게 설계되어지는지 살펴보도록 하겠습니다.

Spring Boot Project를 설계하기 위해 고려해야 하는 클래스 설계 구조는 크게

1. DTO

2. Controller

3. Service

4. VO

5. DAO

다섯가지를 들 수 있습니다.

이를 통해 Client의 요청과 응답이 주고 받는 과정을 알아보자면,

Client의 Request → DTO → Controller → DTO → Service → VO → DAO

Client의 Response  DTO  Controller  DTO  Service  VO ← ResultSet

대충 이런 순으로 데이터의 흐름이 흘러 갈 것이라고 볼 수 있다.

1) DTO

먼저 DTO는 Data Transfer Object로 Data를 Object로 변환하는 역할을 한다. 즉 데이터를 처리하기 위한 Object로 전환하기 위해 setter를 구성한다.

또한 Front로 부터의 데이터가 처음으로 저장되는 오브젝트로 Data의 Validation을 체크하는 역할을 하기도 한다.

DTO를 인자값으로 사용하는(대체로 Controller Method) Method에서 @Valid를 추가하고, DTO에서는 각 변수에 대해 Validation을 추가한다. 다양한 Validation이 존재하지만, 대표적으로 NotBlank, NotEmpty, Email 등의 어노테이션이 있다.

www.baeldung.com/javax-validation

2) Controller

Controller는 데이터를 전달한 Mapping 정보가 저장되는 클래스이다. 쉽게 설명하자면, Client의 Data를 비지니스 로직이 처리되는 Service로 전달하는 중계 Proxy와 같은 역할을 담당한다.

음식 배달을 예로 들어보자면,

Client의 Request : 음식

DTO : 음식을 포장할 용기

Controller : 음식을 배달할 주소 정보도 생각해 볼 수 있겠다.

Validation의 경우 DTO에 정의되어 있지만, 실제 실행은 Controller에서 동작한다고 볼 수 있다. 따라서 Validation을 처리한 후 결과가 실패 일 경우 반환하기 위한 Error를 정의하고 관리해야 한다.

3) Service

Service 레벨에서는 비지니스 로직이 처리되는 클래스이다. Service는 Controller에 의해 호출되며, DTO를 파라미터로 받는다. Service는 앞선 DTO와 Controller가 입력값에 대한 Server Side Validation을 처리했다면, 비지니스 로직에 대한 처리 결과에 대한 Validation 로직이 추가된다.

4) DAO

DAO는 Data Access Object로 데이터 접근을 처리하는 오브젝트이다. 즉 데이터베이스에 접근하는 오브젝트라고 볼 수 있다.

DAO는 SQL과 SQL Mapping을 정의하여 이를 통해 호출되는 SQL Query에 접근하는 또 하나의 Proxy 역할을 한다고 볼 수 있다. 이를 Driver Manager나 ibatis, mybatis 등으로 구현할 수 있으며, 각각의 Query는 Mapper를 통해 상세화 된다.

이때 동적 파라미터 매핑을 위해 Query를 변수화 할 수 있다.

5) VOVO는 바로 Query의 파라미터를 구성하는 RequestVO 또는 Query 결과를 받아주는 ResponseVO로 구분된다.

728x90
LIST
댓글
댓글쓰기 폼