쭈쌤
쭈쌤 Hello World

[Spring] 스프링 프로젝트 초기 설정

크리에이티브 커먼즈 라이선스 ITPAPER(호쌤,쭈쌤)에 의해 작성된 ≪[Spring] 스프링 프로젝트 초기 설정≫은(는) 크리에이티브 커먼즈 저작자표시-비영리-동일조건변경허락 4.0 국제 라이선스에 따라 이용할 수 있습니다.
이 라이선스의 범위 이외의 이용허락을 얻기 위해서는 leekh4232@gmail.com으로 문의하십시오.

[Spring] 스프링 프로젝트 초기 설정

JU쌤과 HO쌤의 수업시간에 진행되는 Spring 수업에서 이클립스를 기반으로 프로젝트를 생성하고 그에 대한 초기 설정 방법을 정리한 글 입니다. 수업시간에 작성되는 Helper 클래스들의 소스코드가 필요합니다.

#01. 프로젝트 기본 설정

1) 새 프로젝트 생성

  1. 새 프로젝트 생성 창에서 Spring > Spring Legacy Project 선택
  2. 프로젝트 이름을 입력하고 Template은 Spring MVC Project를 선택
  3. 패키지 이름을 입력 (반드시 3단계 이상 지정되어야 함)

    ex) {자신의_패키지_이름}

  4. Eclipse가 Spring 관련 템플릿 파일들을 내려받는 동안 기다려야 함 (우측 하단의 프로그래스바에 대한 진행 상황 확인)

2) Java, JSP 모듈 버전 지정하기

  1. 프로젝트 환경 설정 > Project Facets 선택
  2. Java 항목에 대해 1.8 버전 지정
  3. Dynamic Web Mobule 항목에 대해 3.1버전 지정
    • Tomcat 8.5를 사용할 경우 3.1
    • Tomcat 9를 사용할 경우 4
  4. Dynamic Web Mobule을 선택한 상태에서 화면 우측의 Runtime탭에서 설정된 톰켓 지정함.
    1. 여기서 지정되는 Tomcat은 이클립스 환경 설정의 Server > Runtime Environments에서 등록한 항목이 표시됨.

project_facets

3) Java Compiler 버전 선택

  1. 프로젝트 환경 설정 > Java Compiler 선택
  2. 1.8 버전 지정

compiler

4) web.xml 설정

src > main > webapp > WEB-INF > web.xml을 열고 수정한다.

JSP 버전 설정

  • 2라인의 <web-app>태그에서 version속성의 값을 3.1로 수정
  • 2라인의 <web-app>태그에서 xsi:schemaLocation속성의 뒷부분 버전을 포함한 파일이름을 web-app_3_1.xsd로 설정
1
2
3
4
5
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_1.xsd">
    ... 생략 ...

UTF-8, beans 관련 설정

마지막 라인의 </web-app>태그 직전에 다음을 추가

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
<!-- UTF-8 관련 파라미터 설정 -->
<filter>
    <filter-name>encodingFilterUTF8</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encodingFilterUTF8</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<!-- beans 관련 설정 -->
<context-param>
    <param-name>spring.profiles.active</param-name>
    <param-value>dev</param-value>
</context-param>
<context-param>
    <param-name>spring.profiles.default</param-name>
    <param-value>dev</param-value>
</context-param>
<context-param>
    <param-name>spring.liveBeansView.mbeanDomain</param-name>
    <param-value>dev</param-value>
</context-param>

5) Maven 기본 설정

pom.xml파일을 열고 다음 과정 진행

라이브러리의 버전값에 대한 변수 설정 부분 수정

  • 10~15라인 부근의 다음 코드를 찾아 버전값들을 수정한다.
    • 19.11.10현재 Maven Repository에 등록된 최신 버전들
  • <org.slf4j-version>~</org.slf4j-version>부분은 유지한다.
    • slf4j 모듈의 경우 1.6.x 이후 버전부터 버전충돌이 발생하여 Log4j가 동작하지 않는 문제가 있기 때문에 유지한다.
1
2
3
4
5
6
<properties>
    <java-version>1.8</java-version>
    <org.springframework-version>5.2.1.RELEASE</org.springframework-version>
    <org.aspectj-version>1.9.4</org.aspectj-version>
    <org.slf4j-version>1.6.6</org.slf4j-version>
</properties>

Maven Plugin에 플러그인들에 대한 버전 정보 수정

pom.xml의 마지막 부분에 있는 <build>태그에 포함되어 있는 항목들에 대해서 다음을 수정한다.

a) 자바 버전값 수정

org.apache.maven.plugins항목에 대해 1.6으로 설정되어 있는 버전값을 앞에서 설정한 버전값인 ${java-version}으로 대체한다. (맨 아랫부분에 위치하고 있음)

b) 플러그인 버전값 수정

pom.xml파일의 하단에 명시된 <build>태그 안에서 <version>태그를 찾아 버전값들을 항목별로 수정한다.

groupId artifactId version
X maven-eclipse-plugin 2.10
org.apache.maven.plugins maven-compiler-plugin 3.8.1
org.codehaus.mojo exec-maven-plugin 1.6.0
결과

위의 a,b 과정을 처리하면 아래와 같이 수정된다.

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
<build>
    <plugins>
        <plugin>
            <artifactId>maven-eclipse-plugin</artifactId>
            <version>2.10</version>
            <configuration>
                <additionalProjectnatures>
                    <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
                </additionalProjectnatures>
                <additionalBuildcommands>
                    <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
                </additionalBuildcommands>
                <downloadSources>true</downloadSources>
                <downloadJavadocs>true</downloadJavadocs>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>${java-version}</source>
                <target>${java-version}</target>
                <compilerArgument>-Xlint:all</compilerArgument>
                <showWarnings>true</showWarnings>
                <showDeprecation>true</showDeprecation>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>1.6.0</version>
            <configuration>
                <mainClass>org.test.int1.Main</mainClass>
            </configuration>
        </plugin>
    </plugins>
</build>

여기까지 진행하고 모든 파일을 저장한 후 실행해 본다. 중간 과정에서 잘못된 내용이 있다면 페이지가 표시되지 않을 것이다.

6) Maven 의존성 라이브러리 설정

저장소 URL 추가

UserAgent값에 대한 분석을 위해 사용하는 uap-clj 라이브러리를 위해 새로운 저장소를 추가한다.

1
2
3
4
5
6
7
8
<!-- 저장소 주소 추가 -->
<repositories>
    <!-- UserAgent 모듈 -->
    <repository>
        <id>clojars</id>
        <url>http://clojars.org/repo/</url>
    </repository>
</repositories>

버전 교체가 필요한 라이브러리 설정 삭제

아래의 항목들은 새로 추가될 내용이므로 삭제한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- Servlet -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    ... 중략 ...
</dependency>
<dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>jsp-api</artifactId>
    ... 중략 ...
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    ... 중략 ...
</dependency>

Spring을 구성하기 위한 기본 라이브러리들 추가

아래의 소스코드를 사용하여 라이브러리 의존성을 추가한다.

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
<!-- ========== Spring을 구성하기 위한 기본 라이브러리들 추가 ========== -->
<!-- 1) Spring Context Support -->
<!-- https://mvnrepository.com/artifact/org.spring50-spring-context-support -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>${org.springframework-version}</version>
</dependency>

<!-- 2) Java Servlet API -->
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
</dependency>

<!-- 3) JavaServer Pages(TM) API -->
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
<dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>javax.servlet.jsp-api</artifactId>
    <version>2.3.3</version>
    <scope>provided</scope>
</dependency>

<!-- 4) JavaServer Pages(TM) Standard Tag Library -->
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl-api -->
<dependency>
    <groupId>javax.servlet.jsp.jstl</groupId>
    <artifactId>jstl-api</artifactId>
    <version>1.2</version>
</dependency>

<!-- 5) Apache Standard Taglib Implementation -->
<!-- https://mvnrepository.com/artifact/org.apache.taglibs/taglibs-standard-impl -->
<dependency>
    <groupId>org.apache.taglibs</groupId>
    <artifactId>taglibs-standard-impl</artifactId>
    <version>1.2.5</version>
</dependency>

<!-- ========== JSP 수업에서 활용한 라이브러리들에 대한 의존성 설정 ========== -->
<!-- Lombok (2019-11-20일 기준 최신버전) -->
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.10</version>
    <scope>provided</scope>
</dependency>

<!-- JavaMail API (2019-11-20일 기준 최신버전) -->
<!-- https://mvnrepository.com/artifact/com.sun.mail/javax.mail -->
<dependency>
    <groupId>com.sun.mail</groupId>
    <artifactId>javax.mail</artifactId>
    <version>1.6.2</version>
</dependency>

<!-- Apache Commons IO (2019-11-20일 기준 최신버전) -->
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>

<!-- Apache Commons FileUpload (2019-11-20일 기준 최신버전) -->
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>

<!-- Thumbnailator (2019-11-23일 기준 최신버전) -->
<!-- https://mvnrepository.com/artifact/net.coobird/thumbnailator -->
<dependency>
    <groupId>net.coobird</groupId>
    <artifactId>thumbnailator</artifactId>
    <version>0.4.8</version>
</dependency>

<!-- OkHttp -->
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.0.1</version>
</dependency>

<!-- Logging Interceptor -->
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/logging-interceptor -->
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>logging-interceptor</artifactId>
    <version>4.0.1</version>
</dependency>

<!-- Retrofit2 -->
<!-- https://mvnrepository.com/artifact/com.squareup.retrofit2/retrofit -->
<dependency>
    <groupId>com.squareup.retrofit2</groupId>
    <artifactId>retrofit</artifactId>
    <version>2.6.0</version>
</dependency>

<!-- Gson -->
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.5</version>
</dependency>

<!-- Converter: Gson -->
<!-- https://mvnrepository.com/artifact/com.squareup.retrofit2/converter-gson -->
<dependency>
    <groupId>com.squareup.retrofit2</groupId>
    <artifactId>converter-gson</artifactId>
    <version>2.6.0</version>
</dependency>

<!-- MySQL Connector/J (2019-11-28 기준 최신 버전) -->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.18</version>
</dependency>

<!-- MyBatis (2019-11-28 기준 최신 버전) -->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.3</version>
</dependency>

<!-- Log4Jdbc Log4j2 JDBC 4 1 (2019-11-28 기준 최신 버전) -->
<!-- https://mvnrepository.com/artifact/org.bgee.log4jdbc-log4j2/log4jdbc-log4j2-jdbc4.1 -->
<dependency>
    <groupId>org.bgee.log4jdbc-log4j2</groupId>
    <artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>
    <version>1.16</version>
</dependency>


<!-- ========== JDBC,MyBatis Spring 지원 기능 ========== -->
<!-- Spring JDBC -->
<!-- https://mvnrepository.com/artifact/org.spring50-spring-jdbc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${org.springframework-version}</version>
</dependency>

<!-- Spring MyBatis -->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.3</version>
</dependency>

<!-- ========== Maven 이외의 외부 저장소에서 가져오는 모듈 ========== -->
<!-- User Agent 파서 -->
<!-- https://github.com/russellwhitaker/uap-clj -->
<dependency>
    <groupId>org.clojure</groupId>
    <artifactId>clojure</artifactId>
    <version>1.8.0</version>
</dependency>
<dependency>
    <groupId>uap-clj</groupId>
    <artifactId>uap-clj</artifactId>
    <version>1.3.3</version>
</dependency>

여기까지 진행하고 모든 파일을 저장한 후 실행해 본다. 중간 과정에서 잘못된 내용이 있다면 페이지가 표시되지 않을 것이다.

7) Log4j 설정

log4j.xml

JDBC, MyBatis 관련 설정도 포함되어 있다.

src > main > resources > log4j.xml 파일을 아래의 내용과 같이 수정한다.

Application Loggers 부분의 프로젝트 패키지 이름은 상황에 맞게 수정해야 한다.

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

    <!-- 이클립스 콘솔에 출력되는 설정 -->
    <appender name="console" class="org.apache.log4j.ConsoleAppender">
        <param name="Target" value="System.out" />
        <layout class="org.apache.log4j.PatternLayout">
            <!-- 출력패턴 정의 -->
            <param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss.SSS}][%-5p] %C{1}.%M(%F:%L) %m%n" />
        </layout>
    </appender>

    <!-- 파일로 기록되는 로그 설정 -->
    <appender name="rollingFile" class="org.apache.log4j.RollingFileAppender">
        <!-- 로그 파일 생성위치 -->
        <param name="file" value="{자신의_Workspace_경로}/logs/web.log" />
        <param name="Append" value="true" />
        <!-- 로그 파일 하나당 사이즈 100m -->
        <param name="MaxFileSize" value="100mb" />
        <!-- 최대 생성 파일수 ( 50개가 넘으면 순차적으로 파일이 삭제됨 ) -->
        <param name="MaxBackupIndex" value="50" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss.SSS}][%-5p] %C{1}.%M(%F:%L) %m%n" />
        </layout>
    </appender>

    <!-- 날짜별 에러 로그 생성 -->
    <appender name="errorFile" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="Threshold" value="ERROR" />
        <param name="File" value="{자신의_Workspace_경로}/logs/error.log" />
        <param name="Append" value="true" />
        <param name="DatePattern" value="'.'yyMMdd" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss.SSS}][%-5p] %C{1}.%M(%F:%L) %m%n" />
        </layout>
    </appender>

    <!-- Application Loggers -->
    <logger name="{자신의_프로젝트_패키지_이름}">
        <level value="debug" />
    </logger>

    <!-- 3rdparty Loggers -->
    <logger name="org.springframework.core">
        <level value="info" />
    </logger>

    <logger name="org.springframework.beans">
        <level value="info" />
    </logger>

    <logger name="org.springframework.context">
        <level value="info" />
    </logger>

    <logger name="org.springframework.web">
        <level value="info" />
    </logger>

    <!-- DATABASE 연동 관련 로그 설정 시작 -->
    <logger name="org.apache.ibatis">
        <level value="DEBUG" />
    </logger>

    <logger name="jdbc.sqlonly">
        <level value="INFO" />
    </logger>

    <logger name="jdbc.sqltiming">
        <level value="OFF" />
    </logger>

    <logger name="jdbc.audit">
        <level value="OFF" />
    </logger>

    <logger name="jdbc.resultset">
        <level value="ERROR" />
    </logger>

    <logger name="jdbc.resultsettable">
        <level value="DEBUG" />
    </logger>

    <logger name="jdbc.connection">
        <level value="ERROR" />
    </logger>

    <logger name="log4jdbc.debug">
        <level value="ERROR" />
    </logger>
    <!-- DATABASE 연동 관련 로그 설정 끝 -->

    <!-- Root Logger -->
    <root>
        <appender-ref ref="console" />
        <appender-ref ref="rollingFile" />
        <appender-ref ref="errorFile" />
    </root>

</log4j:configuration>

log4jdbc.log4j2.properties

/src/main/resources/log4jdbc.log4j2.properties 경로에 추가한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
log4jdbc.auto.load.popular.drivers=false
log4jdbc.drivers=com.mysql.cj.jdbc.Driver
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator
log4jdbc.dump.sql.maxlinelength=0

log4jdbc.debug.stack.prefix=sql
log4jdbc.sqltiming.warn.threshold=0
log4jdbc.sqltiming.error.threshold=0
log4jdbc.dump.booleanastruefalse=false
log4jdbc.dump.fulldebugstacktrace=false
log4jdbc.statement.warn=false
log4jdbc.dump.sql.select=true
log4jdbc.dump.sql.insert=true
log4jdbc.dump.sql.update=true
log4jdbc.dump.sql.delete=true
log4jdbc.dump.sql.create=true
log4jdbc.dump.sql.addsemicolon=false
log4jdbc.trim.sql=true
log4jdbc.trim.sql.extrablanklines=true
log4jdbc.suppress.generated.keys.exception=false

여기까지 진행하고 모든 파일을 저장한 후 실행해 본다. 중간 과정에서 잘못된 내용이 있다면 페이지가 표시되지 않을 것이다.

8) Intercepter 설정

클래스 정의

적절한 패키지를 생성하고 AppInterceptor 클래스를 정의한다. (클래스이름은 변경 가능함)

필요에 따라 출력되는 로그 형식을 수정할 수 있다.

중요!!!
WebHelper 클래스의 init 메서드를 이 클래스에서 호출하는 것으로 모든 페이지마다 request와 response객체의 초기화가 이루어진다는 점이 중요하게 작용한다.

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package {자신의_패키지_이름}.interceptor;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import lombok.extern.slf4j.Slf4j;
import {자신의_패키지_이름}.helper.WebHelper;
import uap_clj.java.api.Browser;
import uap_clj.java.api.Device;
import uap_clj.java.api.OS;

@Slf4j
public class AppInterceptor extends HandlerInterceptorAdapter {
    long startTime=0, endTime=0;
    
    /** WebHelper 객체 주입 */
    // --> import {자신의_패키지_이름}.helper.WebHelper;
    @Autowired
    WebHelper webHelper;

    /**
     * Controller 실행 요청 전에 수행되는 메서드
     * 클라이언트의 요청을 컨트롤러에 전달 하기 전에 호출된다.
     * return 값으로 boolean 값을 전달하는데 false 인 경우 controller를 실행 시키지 않고 요청을 종료한다.
     * 보통 이곳에서 각종 체크작업과 로그를 기록하는 작업을 진행한다.
     */
    @SuppressWarnings("unchecked")
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //log.debug("AppInterceptor.preHandle 실행됨");
        
        // WebHelper의 초기화는 모든 컨트롤러마다 개별적으로 호출되어야 한다.
        // Interceptor에서 이 작업을 수행하면 모든 메서드마다 수행하는 동일 작업을 일괄처리할 수 있다.
        webHelper.init(request, response);

        // 컨트롤러 실행 직전에 현재 시각을 저장한다.
        startTime = System.currentTimeMillis();

        /** 1) 클라이언트의 요청 정보 확인하기 */
        // 현재 URL 획득
        String url = request.getRequestURL().toString();

        // GET방식인지, POST방식인지 조회한다.
        String methodName = request.getMethod();

        // URL에서 "?"이후에 전달되는 GET파라미터 문자열을 모두 가져온다.
        String queryString = request.getQueryString();

        // 가져온 값이 있다면 URL과 결합하여 완전한 URL을 구성한다.
        if (queryString != null) {
            url = url + "?" + queryString;
        }

        // 획득한 정보를 로그로 표시한다.
        log.debug(String.format("[%s] %s", methodName, url));

        /** 2) 클라이언트가 전달한 모든 파라미터 확인하기 */
        Map<String, String[]> params = request.getParameterMap();

        for (String key : params.keySet()) {
            String[] value = params.get(key);
            log.debug(String.format("(p) <-- %s = %s", key, String.join(",", value)));
        }

        /** 3) 클라이언트가 머물렀던 이전 페이지와 이전 페이지에 머문 시간 확인하기 */
        // 이전에 머물렀던 페이지
        String referer = request.getHeader("referer");

        // 이전 종료 시간이 0보다 크다면 새로운 시작시간과의 차이는 이전 페이지에 머문 시간을 의미한다.
        if (referer != null && endTime > 0) {
            log.debug(String.format("- REFERER : time=%d, url=%s", startTime - endTime, referer));
        }

        /** 4) 접속한 클라이언트의 장치 정보를 로그로 기록 */
        // 접근한 클라이언트의 HTTP 헤더 정보 가져오기

        // "uap" 라이브러리의 기능을 통해 UserAgent 정보 파싱
        String ua = request.getHeader("User-Agent");
        // -> import uap_clj.java.api.Browser;
        Map<String, String> browser = Browser.lookup(ua);
        // -> import uap_clj.java.api.OS;
        Map<String, String> os = (Map<String, String>) OS.lookup(ua);
        // -> import uap_clj.java.api.Device;
        Map<String, String> device = (Map<String, String>) Device.lookup(ua);

        // 추출된 정보들을 출력하기 위해 문자열로 묶기
        String browserStr = String.format("- Browser: {family=%s, patch=%s, major=%s, minor=%s}", 
            browser.get("family"), browser.get("patch"), browser.get("major"), browser.get("minor"));

        String osStr = String.format("- OS: {family=%s, patch=%s, patch_minor=%s, major=%s, minor=%s}",
            os.get("family"), os.get("patch"), os.get("patch_minor"), os.get("major"), os.get("minor"));

        String deviceStr = String.format("- Device: {family=%s, model=%s, brand=%s}", 
            device.get("family"), device.get("model"), device.get("brand"));

        // 로그 저장
        log.debug(browserStr);
        log.debug(osStr);
        log.debug(deviceStr);

        return super.preHandle(request, response, handler);
    }

    /**
     * view 단으로 forward 되기 전에 수행.
     * 컨트롤러 로직이 실행된 이후 호출된다. 
     * 컨트롤러 단에서 에러 발생 시 해당 메서드는 수행되지 않는다. 
     * request로 넘어온 데이터 가공 시 많이 사용된다.
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        //log.debug("AppInterceptor.postHandle 실행됨");

        // 컨트롤러 종료시의 시각을 가져온다.
        endTime = System.currentTimeMillis();
        
        // 시작시간과 종료시간 사이의 차이를 구하면 페이지의 실행시간을 구할 수 있다.
        log.debug(String.format("running time: %d(ms)\n", endTime-startTime));

        super.postHandle(request, response, handler, modelAndView);
    }

    /**
     * 컨트롤러 종료 후 view가 정상적으로 랜더링 된 후 제일 마지막에 실행이 되는 메서드.
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //log.debug("AppInterceptor.afterCompletion 실행됨");
        super.afterCompletion(request, response, handler, ex);
    }

    /**
     * Servlet 3.0부터 비동기 요청이 가능해짐에 따라 비동기 요청 시 
     * PostHandle와 afterCompletion메서드를 수행하지 않고 이 메서드를 수행하게 된다.
     * 거의 사용 안함.
     */
    @Override
    public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //log.debug("AppInterceptor.afterConcurrentHandlingStarted 실행됨");
        super.afterConcurrentHandlingStarted(request, response, handler);
    }
}

Intercepter 클래스 bean 설정

/src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml 파일에 다음의 구문을 추가한다.

설정이 완료되면 컨트롤러가 실행될 때마다 페이지의 실행정보가 로그로 기록된다.

1
2
3
4
5
6
7
<!-- 인터셉터 등록 -->
<interceptors>
    <interceptor>
        <mapping path="/**" />
        <beans:bean id="appInterceptor" class="{자신의_패키지_이름}.interceptor.AppInterceptor" />
    </interceptor>
</interceptors>

여기까지 진행하고 모든 파일을 저장한 후 실행해 본다. 중간 과정에서 잘못된 내용이 있다면 페이지가 표시되지 않을 것이다.

9) 웹 페이지의 리소스 경로 지정하기

CSS, JS, IMG를 위한 디렉토리 설정하기

  • /src/main/webapp/WEB-INF/views/assets 디렉토리를 생성한다. (이 폴더에 img,css,js가 포함된다.)
  • /src/main/webapp/resources 디렉토리는 삭제한다. (/src/main/resources 와의 혼동을 피하기 위함)
  • /src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml 파일에서 resource 설정을 수정한다.
변경전
1
<resources mapping="/resources/**" location="/resources/" />
변경후
1
<resources mapping="/assets/**" location="/WEB-INF/views/assets/" />
사용방법

설정한 디렉토리 하위에 웹 페이지에서 사용할 리소스들을 보관한다.

웹 페이지에서 URL을 통해 접근할 때 다음과 같이 절대경로 형식으로 사용한다.

${pageContext.request.contextPath}/assets/파일경로

여기까지 진행하고 모든 파일을 저장한 후 실행해 본다. 중간 과정에서 잘못된 내용이 있다면 페이지가 표시되지 않을 것이다.

10) 컨트롤러가 배치될 패키지 정의하기

임의의 패키지를 추가한다.

ex) {자신의_패키지_이름}.controllers

해당 패키지의 경로를 servlet-context.xml 파일에 정의한다. (기본적으로 명시되어 있는 경로를 수정해도 된다.)

변경전
1
<context:component-scan base-package="{자신의_패키지_이름}" />
변경후
1
<context:component-scan base-package="{자신의_패키지_이름}.controllers" />

#02. 의존성 주입 설정 (root-context.xml)

Helper 클래스 및 데이터베이스 관련 라이브러리 설정을 아래와 같이 처리한다.

아래의 소스코드는 수업시간에 진행되는 Helper 클래스들이 작성되어 있다는 가정 하에 진행되는 내용입니다. 기본 환경설정 값들을 확인하세요.

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd">

    <!-- Helper 구동에 필요한 환경설정 값 -->
    <util:properties id="config">
        <!-- 기본 인코딩 타입 -->
        <prop key="encType">UTF-8</prop>
        <!-- 업로드 디렉토리 -->
        <prop key="uploadDir">{자신의_workspace_경로}/upload</prop>
        <!-- 업로드 디렉토리에 대한 WebPath -->
        <prop key="uploadPath">/upload</prop>
        <!-- 최대 업로드 가능 용량 (-1인 경우 무제한)-->
        <prop key="uploadMaxFileSize">-1</prop>
        <!-- 기본 도메인(쿠키설정용) -->
        <prop key="domain">localhost</prop>
        <!-- 메일발송 서버 주소 -->
        <prop key="smtpHost">smtp.gmail.com</prop>
        <!-- 메일발송 서버 포트 -->
        <prop key="smtpPort">465</prop>
        <!-- 메일발송 서버 계정 -->
        <prop key="smtpUsername">leekh4232@gmail.com</prop>
        <!-- 메일발송 서버 비밀번호 -->
        <prop key="smtpPassword">wcythwfazyzzjhjh</prop>
    </util:properties>

    <!-- DB연동에 필요한 환경설정 값 -->
    <util:properties id="dbConfig">
        <!-- 데이터베이스 호스트 이름 -->
        <prop key="dbHost">localhost</prop>
        <!-- 데이터베이스 포트번호 -->
        <prop key="dbPort">3306</prop>
        <!-- 데이터베이스 이름 -->
        <prop key="dbName">{데이터베이스이름}</prop>
        <!-- 데이터베이스 문자셋 -->
        <prop key="dbCharset">utf8</prop>
        <!-- 데이터베이스 계정명 -->
        <prop key="dbUsername">{계정명}</prop>
        <!-- 데이터베이스 비밀번호 -->
        <prop key="dbPassword">{계정비밀번호}</prop>
        <!-- Mapper 파일들이 위치할 '/src/main/resources' 하위의 경로 -->
        <prop key="mapperPath">/mappers/**/*Mapper.xml</prop>
    </util:properties>

    <!-- WebHelper 주입 설정 -->
    <bean id="webHelper" class="{자신의_패키지_이름}.helper.WebHelper">
        <property name="encType" value="#{config['encType']}" />
        <property name="uploadDir" value="#{config['uploadDir']}" />
        <property name="uploadPath" value="#{config['uploadPath']}" />
        <property name="uploadMaxFileSize">
            <value type="java.lang.Long">
                #{config['uploadMaxFileSize']}
            </value>
        </property>
        <property name="domain" value="#{config['domain']}" />
    </bean>

    <!-- RegexHelper 주입 설정 -->
    <bean id="regexHelper" class="{자신의_패키지_이름}.helper.RegexHelper" />

    <!-- RetrofitHelper 주입 설정 -->
    <bean id="retrofitHelper" class="{자신의_패키지_이름}.helper.RetrofitHelper" />

    <!-- 메일 발송에 필요한 정보를 저장하는 객체 정의 -->
    <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
        <property name="host" value="#{config['smtpHost']}" />
        <property name="port" value="#{config['smtpPort']}" />
        <property name="username" value="#{config['smtpUsername']}" />
        <property name="password" value="#{config['smtpPassword']}" />
        <property name="defaultEncoding" value="#{config['encType']}" />
        <property name="javaMailProperties">
            <props>
                <prop key="mail.smtp.starttls.enable">true</prop>
                <prop key="mail.smtp.auth">true</prop>
                <prop key="mail.smtp.debug">true</prop>
                <prop key="mail.smtp.socketFactory.port">#{config['smtpPort']}</prop>
                <prop key="mail.smtp.socketFactory.class">javax.net.ssl.SSLSocketFactory</prop>
                <prop key="mail.smtp.socketFactory.fallback">false</prop>
            </props>
        </property>
    </bean>

    <!-- Mail Helper 주입 설정 -->
    <bean id="mailHelper" class="{자신의_패키지_이름}.helper.MailHelper">
        <constructor-arg ref="mailSender" />
    </bean>

    <!-- Upload를 위한 Multipart 지원 라이브러리 주입 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 업로드 최대 용량 (-1로 지정할 경우 제한없음) -->
        <property name="maxUploadSize" value="#{config['uploadMaxFileSize']}" />
        <!-- 업로드를 처리할 인코딩 방식 -->
        <property name="defaultEncoding" value="#{config['encType']}" />
        <!-- 업로드에서 사용할 최대 메모리 크기 (-1로 지정할 경우 제한없음) -->
        <property name="maxInMemorySize" value="-1" />
    </bean>

    <!-- ======= DATABASE 연동 설정 ======= -->
    <!-- JDBC 객체 생성 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy" />
        <property name="url"
            value="jdbc:log4jdbc:mysql://#{dbConfig['dbHost']}:#{dbConfig['dbPort']}/#{dbConfig['dbName']}?characterEncoding=#{dbConfig['dbCharset']}&amp;serverTimezone=UTC" />
        <property name="username" value="#{dbConfig['dbUsername']}" />
        <property name="password" value="#{dbConfig['dbPassword']}" />
    </bean>

    <!-- SQLSessionFactory 객체 생성 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- JDBC 객체를 dataSource에 대한 setter 메서드를 통해 주입 -->
        <property name="dataSource" ref="dataSource" />
        <!-- MyBatis Mapper 파일들에 대한 경로 패턴 주입 -->
        <property name="mapperLocations" value="classpath:#{dbConfig['mapperPath']}" />
    </bean>

    <!-- SQLSession 객체 생성. 이 객체가 Service 패턴에 주입된다. -->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate" destroy-method="clearCache">
        <!-- 생성자를 통해 SQLSessionFactory 객체 주입 -->
        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory" />
    </bean>

</beans>

#03. 데이터베이스 연동 설정

1) Service 패턴에 대한 패키지 추가하기

인터페이스와 구현체, Model 클래스가 포함될 패키지를 정의한다.

ex)

구분 이름
DTO 클래스(Model) {자신의_패키지_이름}.model
서비스 인터페이스 {자신의_패키지_이름}.service
서비스 구현체 {자신의_패키지_이름}.service.impl

2) Service 구현체에 대한 컴포넌트 스캔 등록 (servlet-context.xml)

1
<context:component-scan base-package="{자신의_패키지_이름}.service.impl" />
Rating:

크리에이티브 커먼즈 라이선스 ITPAPER(호쌤,쭈쌤)에 의해 작성된 ≪[Spring] 스프링 프로젝트 초기 설정≫은(는) 크리에이티브 커먼즈 저작자표시-비영리-동일조건변경허락 4.0 국제 라이선스에 따라 이용할 수 있습니다.
이 라이선스의 범위 이외의 이용허락을 얻기 위해서는 leekh4232@gmail.com으로 문의하십시오.

comments powered by Disqus