[TOC]
1. 개요
이전 포스팅에서 legacy 프로젝트
를 준비하면서 좀더 기초에서 시작해 보자 라는 생각이 들었다.
지난 스터디 레포트 연재물에서는 포스팅 회차내 결말을 봐야 한다는 의무감 때문에 대충 넘어간 부분이 많았다.
그래서 본 연재에서는 조금 더디더라도 완전 바닥부터 하나하나 짚어 보면서 가보겠다.
우선 본 프로젝트에서 특징부터 나열해 보자면...
-
JDK-1.8
인 이유 : 현재 최신 JDK 가 21 버젼이 넘어가는데도 아직까지 인프라 문제 때문에 10년도 넘은 구형 JDK-1.8 을 사용하는 곳이 근근히 있다. -
Java EE
vsJakarta EE
변경문제 : 패키지명 때문에 같은 로직을 사용해도 상호 호환성이 없으며 이에 따른 의존모듈이 통째로 바뀐다 이 때문에 구형 Jeus 또는 구형 Weblogic 을 사용하는 인프라 시스템 에서는Java EE
를 사용해야 하는 경우가 생긴다. (초반에 인프라 구성을 잘 알고 시작해야 한다.) -
위 사항에 연계한 패키지 호환성 문제등으로 인해
legacy
환경 (JDK-1.8
,Java EE
)으로 개발하는 것을 목표로 한다. -
추후
상위버젼의 JDK
+Jakarta EE
와Kotlin-DSL
을 활용한 예시도 연재에 추가해 보겠다.
2. 개발툴 내려받기, 설치하기
우선 JDK
를 내려 받아 설치한다. (본 포스팅에서는 1.8 기준)
https://www.oracle.com/java/technologies/javase/javase8u211-later-archive-downloads.html
아래 주소에서 gradle
을 내려받는다. (현시점 v8.14 최신)
wrapper
실행 후에는 재사용 할일이 없으므로 설치는 하지 않고 사용자 다운로드 폴더에 압축 해제해서 사용 하겠다. ( 예시: C:\사용자\XXX\다운로드\
, /home/XXX/Downloads
등 )
3. 프로젝트 초기화
우선 gradle
초기화 부터 시작해 보겠다.
gradle 은 각 사용자 폴더 기준 다운로드
또는 Downloads
폴더에 압축 해제되어 있다고 가정하겠다.
(예시 : C:\Users\사용자\Downloads\gradle-8.14
)
우선 커맨드( 윈도우는 cmd ) 창을 열고
리눅스 커맨드창(bash) 에서 구동시
mkdir sample-proj
cd sample-proj
~/Downloads/gradle-8.14/bin/gradle init
윈도우 커맨드창(cmd) 에서 구동시
md sample-proj
cd sample-proj
%USERPROFILE%\Downloads\gradle-8.14\bin\gradle init
그다음은 프롬프트 순서에 따른다. 4: Basic
-> 2: Groovy
-> no
순서대로 입력한다.
Starting a Gradle Daemon (subsequent builds will be faster)
Select type of build to generate:
1: Application
2: Library
3: Gradle plugin
4: Basic (build structure only)
Enter selection (default: Application) [1..4] 4
Project name (default: sample-proj):
Select build script DSL:
1: Kotlin
2: Groovy
Enter selection (default: Kotlin) [1..2] 2
Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no]
> Task :init
Learn more about Gradle by exploring our Samples at https://docs.gradle.org/8.13/samples
BUILD SUCCESSFUL in 19s
1 actionable task: 1 executed
수행하고 나면 대충 아래 구조대로 파일들이 만들어 진다.
├── build.gradle
├── gradle
│ ├── libs.versions.toml
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
4. 프로젝트 기본 설정
다음 build.gradle
파일을 아래와 같이 수정해 준다.
요점은
-
- gradle 플러그인 설정
-
- JDK 설정
-
- 저장소(Repository) 설정
-
- 의존 모듈(dependency jar) 설정
으로 이루어 진다 (자세한 설명은 주석으로 대신하겠다.)
/** JDK8, javax.servlet 패키지로 설치할 수 있는 SPRING-BOOT 최근 버젼 */
plugins {
id 'org.springframework.boot' version '2.7.18'
id 'io.spring.dependency-management' version '1.1.5'
id 'java'
id 'war'
}
java {
/** 구형 프레임워크를 쓸것이므로 JDK-1.8 기준 */
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
compileJava.options.encoding = 'UTF-8'
compileTestJava.options.encoding = 'UTF-8'
}
repositories {
/** 개인 PC 로컬 저장소 */
mavenLocal()
/** 메이븐 중앙(인터넷) 저장소 */
mavenCentral()
}
dependencies {
/** 기본 Spring 의존모듈 */
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-aop'
implementation 'org.springframework.boot:spring-boot-starter-web'
/** JSP, JSTL */
implementation 'javax.servlet:javax.servlet-api:4.0.1'
implementation 'org.glassfish.web:jakarta.servlet.jsp.jstl'
/** log / log4jdbc */
implementation 'ch.qos.logback:logback-classic:1.2.13'
implementation 'ch.qos.logback:logback-core:1.2.13'
/** 개별 바이너리 파일 모듈 (compiled binary, 추후 JAR 파일 추가 예정) */
implementation fileTree(dir: 'libs', include: [ ])
/** 빌드, 개발 및 테스트 관련 */
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.junit.jupiter:junit-jupiter'
testImplementation 'org.junit.platform:junit-platform-launcher'
testImplementation 'org.junit.vintage:junit-vintage-engine'
}
tasks.named('test') {
useJUnitPlatform()
}
bootRun {
systemProperty('spring.profiles.active', System.properties['spring.profiles.active'])
systemProperty('java.file.encoding', 'UTF-8')
}
이후 소스 폴더를 만들어 준다.
리눅스 에서 실행시
mkdir -p src/main/java
mkdir -p src/main/resources
mkdir -p src/test/resources
mkdir -p src/test/java
mkdir -p src/main/java/sample/proj
윈도우 에서 실행시
md "src\main\java"
md "src\main\resources"
md "src\test\resources"
md "src\test\java"
md "src\main\java\sample\proj"
src/main/resources
폴더에 application.yml
파일을 작성해 준다.
spring:
application:
name: "sample-proj"
mvc:
#$ JSP설정
view:
prefix: "/WEB-INF/views/"
suffix: ".jsp"
servlet:
## 업로드 설정
multipart:
maxFileSize: "50MB"
maxRequestSize: "50MB"
## REST 통신 직렬화 설정
jackson:
default-property-inclusion: "non-empty"
time-zone: "Asia/Seoul"
## 로그설정
logging:
file:
path: "log"
filename: "sample-proj"
level:
root: "DEBUG"
jdbc: "DEBUG"
work: "DEBUG"
같은 폴더에 application-local.yml
파일 (로컬PC 구동용 설정파일) 을 작성해 준다.
debug: "false"
server:
## 로컬에서 구동할 embed-tomcat 포트번호
port: 8080
forward-headers-strategy: "FRAMEWORK"
servlet:
## 서블릿 인코딩
encoding:
charset: "UTF-8"
enabled: "true"
force: "true"
로그 설정파일(/src/main/resources/logback-spring.xml
)을 만들어 준다. (설명은 주석으로 대신한다.)
<?xml version="1.0" encoding="UTF-8"?>
<!-- 60초마다 설정갱신 확인 -->
<configuration scan="true" scanPeriod="60 seconds">
<springProperty scope="context" name="LOG_LEVEL_ROOT" source="logging.level.root"/>
<springProperty scope="context" name="LOG_LEVEL_JDBC" source="logging.level.jdbc"/>
<springProperty scope="context" name="LOG_LEVEL_WORK" source="logging.level.work"/>
<springProperty scope="context" name="LOG_PATH" source="logging.file.path"/>
<springProperty scope="context" name="LOG_FILE_NAME" source="logging.file.filename"/>
<property name="LOG_PATTERN" value="%-5level %d{yy-MM-dd HH:mm:ss}[%thread] [%logger{0}:%line] - %msg%n"/>
<!-- Console Appender -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- File Appender -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 파일경로 설정 -->
<file>${LOG_PATH}/${LOG_FILE_NAME}.log</file>
<!-- 출력패턴 설정-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- Rolling 정책 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/${LOG_FILE_NAME}.%d{yyyy-MM-dd}_%i.log.gz</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- 파일당 최고 용량 kb, mb, gb -->
<maxFileSize>1GB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!-- 일자별 로그파일 최대 보관주기(~일), 해당 설정일 이상된 파일은 자동으로 제거-->
<maxHistory>90</maxHistory>
</rollingPolicy>
</appender>
<!-- root레벨 설정 -->
<root level="${LOG_LEVEL_ROOT}">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
<!-- JDBC 로깅레벨 설정 -->
<logger name="org.apache.ibatis" level="${LOG_LEVEL_JDBC}" additivity="false">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</logger>
<logger name="org.springframework.jdbc.core" level="${LOG_LEVEL_JDBC}" additivity="false">
<appender-ref ref="CONSOLE"/>
</logger>
<logger name="org.mybatis.spring.SqlSessionTemplate" level="${LOG_LEVEL_JDBC}" additivity="false">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</logger>
<logger name="org.springframework.jdbc.core.JdbcTemplate" level="INFO" additivity="false"></logger>
<!-- 비즈니스로직 로깅레벨 설정 -->
<logger name="sample.proj" level="${LOG_LEVEL_WORK}" additivity="false">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</logger>
</configuration>
그리고 src/main/java/sample/proj
폴더에 스프링 부트 구동(Application.java
) 프로그램을 작성해 준다
package sample.proj;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import lombok.extern.slf4j.Slf4j;
@Slf4j @ServletComponentScan @SpringBootApplication
public class Application {
public static void main(String[] args) throws Exception {
/** 기본 프로파일이 없다면 local 프로파일로 실행되도록 */
String profile = System.getProperty("spring.profiles.active");
if (profile == null || "".equals(profile)) {
System.setProperty("spring.profiles.active", "local");
}
SpringApplication.run(Application.class, args);
}
}
톰캣
이나 웹로직
등 서블릿 컨테이너
에서 사용될 서블릿 연계(ServletInitializer.java
) 프로그램을 같은 폴더에 작성해 준다.
package sample.proj;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ServletInitializer extends SpringBootServletInitializer {
@Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
여기까지 완료했으면 대충 아래와 같은 파일들이 만들어 진다.
├── build.gradle
├── gradle
│ ├── libs.versions.toml
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
├── main
│ ├── java
│ │ └── sample
│ │ └── proj
│ │ ├── Application.java
│ │ └── ServletInitializer.java
│ └── resources
│ ├── application-local.yml
│ ├── application.yml
│ └── logback-spring.xml
└── test
├── java
└── resources
5. 빌드 및 구동
이제 빌드를 수행해 보자
./gradlew build
아래와 같이 출력되면 (하단의 BUILD SUCCESSFUL
) 성공이다
Calculating task graph as no cached configuration is available for tasks: build
[Incubating] Problems report is available at: file:///home/coder/documents/ind-works/sample-proj/build/reports/problems/problems-report.html
Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0.
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
For more on this, please refer to https://docs.gradle.org/8.13/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation.
BUILD SUCCESSFUL in 5s
5 actionable tasks: 5 up-to-date
Configuration cache entry stored.
실행은 다음과 같다.
./gradlew bootRun -Dspring.profiles.active=local
실행 결과는 다음과 같을것이다.
Reusing configuration cache.
> Task :bootRun
02:13:59.611 [Thread-0] DEBUG org.springframework.boot.devtools.restart.classloader.RestartClassLoader - Created RestartClassLoader org.springframework.boot.devtools.restart.classloader.RestartClassLoader@11409ea1
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.7.18)
INFO 25-04-30 02:13:59[restartedMain] [Application:55] - Starting Application using Java 17.0.8 on VSCD_A0000 with PID 1272988 (/home/coder/documents/ind-works/sample-proj/build/classes/java/main started by coder in /home/coder/documents/ind-works/sample-proj)
DEBUG 25-04-30 02:13:59[restartedMain] [Application:56] - Running with Spring Boot v2.7.18, Spring v5.3.31
INFO 25-04-30 02:13:59[restartedMain] [Application:638] - The following 1 profile is active: "local"
INFO 25-04-30 02:13:59[restartedMain] [DevToolsPropertyDefaultsPostProcessor:255] - Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
INFO 25-04-30 02:13:59[restartedMain] [DevToolsPropertyDefaultsPostProcessor:255] - For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'
INFO 25-04-30 02:14:00[restartedMain] [TomcatWebServer:108] - Tomcat initialized with port(s): 8080 (http)
INFO 25-04-30 02:14:00[restartedMain] [Http11NioProtocol:173] - Initializing ProtocolHandler ["http-nio-8080"]
INFO 25-04-30 02:14:00[restartedMain] [StandardService:173] - Starting service [Tomcat]
INFO 25-04-30 02:14:00[restartedMain] [StandardEngine:173] - Starting Servlet engine: [Apache Tomcat/9.0.83]
INFO 25-04-30 02:14:00[restartedMain] [[/]:173] - Initializing Spring embedded WebApplicationContext
INFO 25-04-30 02:14:00[restartedMain] [ServletWebServerApplicationContext:292] - Root WebApplicationContext: initialization completed in 687 ms
WARN 25-04-30 02:14:00[restartedMain] [UserDetailsServiceAutoConfiguration:89] -
Using generated security password: df3375fe-60d0-4e3e-94c1-3b55685070e0
This generated password is for development use only. Your security configuration must be updated before running your application in production.
INFO 25-04-30 02:14:00[restartedMain] [DefaultSecurityFilterChain:55] - Will secure any request with [org.springframework.security.web.session.DisableEncodeUrlFilter@6419c353, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@1f97a9e6, org.springframework.security.web.context.SecurityContextPersistenceFilter@3f2061dc, org.springframework.security.web.header.HeaderWriterFilter@f423af6, org.springframework.security.web.csrf.CsrfFilter@4c61dd01, org.springframework.security.web.authentication.logout.LogoutFilter@5c5dec06, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@1740edc3, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@b6bb875, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@1be8e101, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@3e28bba5, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@1ca6be27, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@62551595, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@57e91ec2, org.springframework.security.web.session.SessionManagementFilter@3dc4da31, org.springframework.security.web.access.ExceptionTranslationFilter@65f59562, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@3deb4c5d]
INFO 25-04-30 02:14:01[restartedMain] [OptionalLiveReloadServer:59] - LiveReload server is running on port 35729
INFO 25-04-30 02:14:01[restartedMain] [Http11NioProtocol:173] - Starting ProtocolHandler ["http-nio-8080"]
INFO 25-04-30 02:14:01[restartedMain] [TomcatWebServer:220] - Tomcat started on port(s): 8080 (http) with context path ''
INFO 25-04-30 02:14:01[restartedMain] [Application:61] - Started Application in 1.414 seconds (JVM running for 1.658)
<==========---> 80% EXECUTING [16s]
> :bootRun
이제 브라우저를 열고 주소창에 http://localhost:8080
을 입력해 보자
아래 화면과 같은 화면이 뜨면 성공이다.
6. 다음편에서는..
이번 포스팅에서는 초보자도 따라 할 수 있는 자바 프로젝트 를 목표로
JDK-1.8
Java EE
를 활용해 gradle
로 프로젝트 기초 까지만 작성해 보았다.
생초보는 커맨드창 (cli
) 이 익숙하지 않을수 있으나.... 되도록 익숙해 지길 권장한다 (노파심에서....)
다음 포스팅에서는 기능 덧붙이기 이전에 이클립스 및 VS-CODE 같은 통합 개발환경 에서 프로젝트를 불러오고 폐쇄망 셋팅, 형상관리 연동 및 구동 방법 까지 알아보려 한다.