반응형

1. 개요

 로그는 시스템의 오류 파악이나 로직 분석을 위해 꼭 필요하다.

 실무를 접하면서 로그가 얼마나 중요한지를 많이 느끼고 있기 때문에 로그 개념을 다시 정리해보고자 글을 쓴다.

 그리고! 그냥 남기면 기억에 오래 남지 않으므로, 좀 특이한? 방식으로 로그를 남겨보았다.


2. 환경

  1) maven

  2) JDK 1.8

  3) Tomcat 8.0 


3. 준비

 1) Maven 라이브러리 추가

 log4j2 관련 라이브러리는 다음과 같다. pom.xml에 추가해주자!

1
2
3
4
5
6
7
8
9
10
11
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.13.0</version>
      </dependency>
      <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.13.0</version>
      </dependency>
     </dependencies>
cs

 2) log4j2.xml 파일 생성

 class 경로인 src/main/resources 경로에 log4j2.xml 파일을 생성한다.

log4j2.xml 파일 생성

 이로써 아~주 기본 환경설정이 벌써 끝나버렸다. @_@;


4. console log

 4.1) 필요 패키지, 클래스 생성

  콘솔에 로그를 찍어보자. 일단, 동작에 필요한 패키지와 클래스를 아래와 다음과 같이 생성한다.

 

패키지, 클래스 생성

   - Main, test 패키지 생성

   - test 패키지에 LogTest 클래스 생성

   - Main 패키지에 MainClass 객체를 생성

   - quartz 패키지도 일단 생성 (활용 부분에서 quartz를 사용해 로그를 예정이며, console 로그를 출력할 때는 사용 X)

 

  4.2) log4j2.xml 파일 코드

   console에 로그를 찍기 위해 아래 코드를 삽입한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
 
<configuration status="debug">
 
    <Appenders>
        <!-- 콜솔 -->
        <Console name="console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd hh:mm:ss} %5p [%c] %m%n"/>
        </Console>
    </Appenders>
    
    <loggers>
        <root level="debug" additivity="true">
            <AppenderRef ref="console"/>
        </root>
    </loggers>
 
</configuration>
cs

 

 3번 줄의 configuration status 구문은 이 설정파일이 로드될 때 발생하는 로그에 대한 레벨을 설정하는 부분이다.

 말이 어렵지 실행화면을 보면 이해가 갈것이다. 

 

configuration status = "DEBUG"

log4j2.xml 의 내부 설정을 로드하면서 발생하는 DEBUG 이상의 로그들을 출력중이다.

status를 info로 설정하면 아~~~무 로그도 출력되지 않는다.

그 이유는 log4j2.xml 설정파일을 로드할 때의 정보는 내부적으로 DEBUG레벨로 찍고 있기 때문이다.

INFO 레벨은 DEBUG레벨보다 상위의 레벨이기 때문에 로그가 찍히지 않게 된다.

 

그렇다면 log4j2.xml 파일을 로드할 때 문제가 생기도록 코드를 바꾼 후 status를 info로 설정한다면?

내부적으로 error 로그가 발생할 것이고, 이는 info 레벨보다 높기 때문에 로그가 찍힐 것이다.

테스트로 5번줄의 Appenders 태그 명을 Appenderss로 바꾼 후 실행시켰다.

제일 아랫줄의 ERROR test.LogTest 부분이 log4j2.xml 을 로드하면서 생긴에러이다.

configuration status ="info" And Appenders -> Appenderss

 

* configuration 부분을 설명하기 위해 먼저 MainClass와 LogTest를 구현하였다. 현재 MainClass와 LogTest 를 생성만 한 상태에서는 위처럼 테스트가 불가능하다. 이런 설정이구나 라고만 이해하고 넘어가자. 

 

Appenders 태그 안에 실질적인 로그 설정 코드를 삽입한다.

현재 콘솔에 로그를 출력시키기 위해 <Console> 태그 관련 코드를 삽입하고 로그로 찍히는 패턴을 PatternLayout 태그를 통해 설정한다.

%d는 로그 시간에 관한 설정을 나타내는데 괄호 안의 형태로 포멧시킬 수 있다.

%p는 로그 레벨, %c는 로그가 발생한 클래스 경로, %m은 로그 메시지, %n은 개행이다. 

%5p는 로그 레벨이 출력되는 기본 문자열 길이를 5로 설정한다는 의미이다.

WARN 앞에 공백 보이시죠?

 

12번 줄의 loggers 는 설정한 로그 코드를 적용하는 부분이다.

root 태그를 사용하면 현재 시스템에서 발생하는 모든 로그를 찍어낼 수 있고, level을 debug로 설정하여 debug 이상의 로그만 출력되도록 한다. Appender를 이용해서 앞서 설정한 console을 적용시키면, 결과적으로 기동하는 시스템내에서 발생하는 모든 로그 중 debug레벨 이상은 모두 찍히게 된다.

 

4.3) 클래스 파일 코드 작성

 - LogTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package test;
 
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
 
 
public class LogTest {
    
    private Logger logger = LogManager.getLogger(LogTest.class);
    
    public void printLog() {
        logger.debug("[debug] log!");
        logger.info("[info] log!");
        logger.warn("[warn] log!");
        logger.error("[error] log!");
    }
}
 
cs

로그 객체를 설정하고, printLog() 메서드에 debug, info, warn, error로그를 출력하는 코드를 삽입한다.

 

 - MainClass.java

1
2
3
4
5
6
7
8
9
10
11
12
13
package Main;
 
import test.LogTest;
 
public class MainClass {
 
    public static void main(String[] args) {
        
        LogTest logTest = new LogTest();
        logTest.printLog();
    }
}
 
cs

앞서 만든 LogTest 객체 생성 후 printLog() 메서드를 호출하는 코드를 삽입한다.

 

이제 MainClass를 실행시켜보자!

이러한 로그가 출력되면 성공!

만약 에러 로그만 출력하고 싶다면 log4j2.xml 의 root level을 error로 설정하면 된다.

 

5. RollingFile log

로그를 파일로 남기는 방법 중 하나로, 날짜, 시간 등에 따라 로그파일을 생성하여 보관하고 싶거나, 로그파일의 용량이 너무 커 압축파일 형태로 로그를 남기고싶다면 이 설정을 사용하면 된다.

 

5.1) log4j2.xml 파일 코드

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
<?xml version="1.0" encoding="UTF-8"?>
 
<configuration status="DEBUG">
 
    <Appenders>
        <!-- 콜솔 -->
        <Console name="console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd hh:mm:ss} %5p [%c] %m%n"/>
        </Console>
        
        <!-- 파일  -->
        <RollingFile name ="RollingFile">
            <FileName>C:/log/mylog.txt</FileName>
            <FilePattern>C:/log/%d{yyyy-MM-dd-hh-mm}/mylog.zip</FilePattern>
            <PatternLayout>
                <Pattern>%d{yyyy-MM-dd HH:mm:ss} %5p [%c] %m%n</Pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy interval = "1" modulate = "true"/>
            </Policies>
        </RollingFile>
        
        <RollingFile name ="RollingFileError">
            <FileName>C:/log/mylog_error.txt</FileName>
            <FilePattern>C:/log/%d{yyyy-MM-dd-hh-mm}/mylog_error.zip</FilePattern>
            <PatternLayout>
                <Pattern>%d{yyyy-MM-dd HH:mm:ss} %5p [%c] %m%n</Pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy interval = "1" modulate = "true"/>
            </Policies>
        </RollingFile>
        
    </Appenders>
    
    <loggers>
        <root level="debug" additivity="true">
            <AppenderRef ref="console"/>
            <AppenderRef ref="RollingFile"/>
            <AppenderRef ref="RollingFileError" level = "ERROR"/>
        </root>
    </loggers>
    
</configuration> 
cs

코드가 갑자기 늘어났는데, 천천히 파악해보자.

일단 이 코드의 기능목표는 다음과 같다.

 가) 모든 로그가 찍히는 mylog.txt 파일 생성

 나) 에러 로그만 찍히는 mylog_error.txt 파일 생성

 다) 1분마다 찍힌 로그파일을 압축파일로 저장

 

 5.2) 코드 설명

 RollingFile 태그를 사용해야한다.

 FileName은 로그가 찍히게 될 파일경로,

 FilePattern은 파일이 Rolling 될때, 즉 조건에 의해 파일이 말릴 때의 파일 패턴. >> 날짜폴더/mylog.zip 형태

 Pattern은 찍히는 로그 형태

 TimeBasedTriggeringPolicy는 Rolling 조건을 시간으로 설정하고, interval은 1분 간격으로 Rolling한다는 의미.

 

 * interval은 앞서 설정한 FilePattern에 따라 1분이 될수도, 1시간이 될수도, 1일이 될수도 있다.

%d{yyyy-MM-dd-hh-mm}.log.zip interval = 1  1분마다 롤링
%d{yyyy-MM-dd-hh}.log.zip interval = 1  1시간마다 롤링
%d{yyyy-MM-dd}.log.zip interval = 1  1일마다 롤링

 

일반적으로 1일마다 롤링을 하지만, 로그 파일이 롤링되는 테스트 결과를 내일 확인할 수 없으니.. 1분마다 생성되도록 설정하였다.

 

위와 같이 일반 로그, 에러 로그에 대한 Rolling 로그 설정을 만들고, 

39 ~ 40번 줄처럼 RollingFile, RollingFileError 를 AppenderRef 태그를 통해 실제로 적용시켜보자.

단, RolingFileError는 ERROR 레벨 이상의 로그만 찍혀야 하기 때문에 level을 따로 ERROR로 설정한다.

 

이제 MainClass를 실행 시켰을 때 설정한 경로로 파일이 생성되어 로그가 찍히고 1분마다 zip파일로 남을까??

 

안남는다. 파일은 생성되고 순간의 로그는 파일에 찍히겠지만, 그게끝이야! 로그가 계속 찍히지 않으니까!

 

때문에 날짜 형식으로 폴더 하나가 생성되고, mylog, mylog_error 코드 안에 각각의 로그가 들어가면 성공이다.

 

"그럼 로그를 계속 찍어주려면 어떻게할까?? 반복문 돌려도 된다! while!

하지만 좀 더 의미있게 해보자...! 1초마다 찍히게 하는거야! 반복문을 통해서가 아닌 잡 스케줄러를 이용해서!!"

 

해서 활용편으로 quartz라는 스케줄러를 사용하여 1초마다 로그를 찍도록 해보겠다. @_@;

 

이 부분은 스프링에 대한 조금의 지식을 갖고 있다면 어렵지 않게 구현할 수 있다.

 

다음 글에서 진행하도록 하겠다.

 

 

반응형
반응형
반응형

목차

1. 개요

2. 환경

3. 라이브러리

4. 예제

5. 실행결과


1. 개요

 log4j2 = log lib

 log를 남기는 이유는 여러 가지가 있는데 대표적으로 [에러 추적, 디버깅] 또는 [통계]나 [기록]을 목적으로 해!

 어쨌든간에 어렵지 않은 내용이니 한번 따라 해 보자고~

 So~~~~~~~ Ez.


2. 환경

이클립스 MARS
JDK 1.7
comcat 7 (그저갓)

3. 라이브러리

 이거 다 받아서 프로젝트의 lib폴더에 넣자. 프로젝트를 컴파일하면 lib폴더에 있는 jar파일을 class파일로 만들어 사용하기 때문에 여기다 넣어도 된단다! 예외가 몇 개 있지만 요 녀석들은 해당되지 않아! 어서 다운로드하으렴

log4j-api-2.0.2.jar
0.12MB
log4j-core-2.0.2.jar
0.75MB
log4j-over-slf4j-1.7.7.jar
0.02MB
log4j-slf4j-impl-2.0.2.jar
0.02MB
log4j-web-2.0.2.jar
0.02MB
slf4j-api-1.7.7.jar
0.03MB
slf4j-ext-1.7.7.jar
0.04MB


4. 예제

 다운로드한 파일을 프로젝트 폴더의 lib(경로는 WEB-INF/lib) 폴더에 넣었다면 본격적인 예제를 작성해볼 건데, 그냥 로그를 뿌리는 것보다 뭔가 상황이 주어지면 맛깔날 것 같아서 대충 시나리오를 준비했어.

 ※ 시나리오

  1) 나는 서버 개발자

  2) x초보 서버 개발자

  3) controller가 아닌! Servlet을 이용.

  4) 클라이언트가 Servlet에 설정된 Url로 요청

  5) log출력.

 

웹 프로젝트는 생성했다고 가정하고 post, get 통신을 받는 서블릿 패키지 및 클래스를 만들어보자.

 

  4.1) 서블릿 생성

  File -> New -> Servlet 클릭

  나는 패키지 이름을 one, 클래스 이름을 andTwo로 설정했어.

서블릿 패키지 및 클래스 생성

   4.2) andTwo.java

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
package one;
 
import java.io.IOException;
 
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
 
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
 
/**
 * Servlet implementation class andTwo
 */
@WebServlet("/andTwo")
public class andTwo extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private Logger logger = LogManager.getLogger(andTwo.class);
    /**
     * Default constructor. 
     */
    public andTwo() {
        // TODO Auto-generated constructor stub
    }
 
    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        response.getWriter().append("Served at: ").append(request.getContextPath());
        logger.error("error message");
        logger.warn("warn message");
        logger.info("info message");
        logger.debug("debug message");
        logger.trace("trace message");
    }
 
    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        response.getWriter().append("Served at: ").append(request.getContextPath());
        logger.error("error message");
        logger.warn("warn message");
        logger.info("info message");
        logger.debug("debug message");
        logger.trace("trace message");
    }
 
}
 
 

코드 설명 대충 하자면 

18번째 줄은 요청 url이야. 그림으로 설명해줄게

포트정보
context path

서버 탭을 자세히 살펴보면 자신의 포트와 contextPath 정보를 확인할 수 있어.

서버를 기동시 키면 http://localhost:port/contextPath 가 루트 url이 되는 거야.

요청 url인 '/andTwo'는 루트 url을 포함한 형태라고 생각해.

정리하면 http://localhost:8080/log/andTwo 경로로 요청이 들어오면 해당 경로와 mapping 된 서블릿에 정의된 코드를 처리한다는 뜻이야.

 

21번째 줄에 logger 객체 LogManger.getLogger() 메서드를 통해 생성해주었어. getLogger의 파라미터 값에 현재 클래스명. class를 넣어줘

 

32번째 줄은 Get방식으로 온 요청에 대한 처리.

 

45번째 줄은 Post방식으로 온 요청에 대한 처리이고, 각각 error, warn, info, debug, trace 로그를 남기게 돼. 이들을 로그 레벨이라고 하고 자세한 건 구글링을 통해 알아보면 좋을 것 같아.

 

간단하게 몇 개만 설명하면

 error는 시스템에 문제를 발생시킬만한 로그정보

 warn는 시스템에 문제가 생기진 않지만 에러를 야기할 수 로그정보

 debug는 디버깅을 위해 남기는 로그정보

 

 상황에 맞게 이 로그들을 사용해야 한다는데.. 나는 아직도 어려워..

 어쨌든 이 서블릿으로 요청이 들어오면 무조건 error ~ tarce까지 로그를 출력하도록 했어.

 이제 log4j2의 설정 파일을 생성해야하는데 생성하기 전에 log4j2의 설정파일 경로를 지정해놓자. 이 작업은 web.xml파일에서 해.

 

 4.3) web.xml 파일 설정

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>log</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <context-param>
    <param-name>log4j2ConfigLocation</param-name>
    <param-value>/WEB-INF/log4j2.xml</param-value>
  </context-param>
</web-app>
 

display-name은 프로젝트명.

welcome-file-list는 프로젝트가 컴파일되면 최초로 보이는 파일 list.

만약 WEB-INF에 이 파일이 없다면? 404 에러가 뜰 거야. 하지만 우리는 저런 html 파일이 필요 없기 때문에 만들지 않아도 돼

 

context-param은 서버의 parameter를 설정해주는 부분이야.

log4 jConfigLocation이라는 변수에 /WEB-INF/log4j2.xml이라는 값을 넣었다고 생각하면 편해.

 

log4j2는 기본적으로 로그에 대한 설정 파일인 log4j2.xml이 필요한데 이 녀석의 경로야.

 

(사실 이 부분이 없어도 되는데 이유는 log4j2는 로드가 될때 설정 파일인 log4j2.xml을 classpath: 경로에서 알아서 찾는다고 하네..)

 

이제 log4j2 설정파일 세팅을 해보자.

 

 4.4) log4j2.xml

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
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <!-- 로그 출력 방식 -->
    <Appenders>
        <!-- 콘솔 출력 방식 -->
        <Console name="STDOUT" target="SYSTEM_OUT">
            <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n" />
        </Console>
        
        <!-- 파일 저장 방식 -->
        <File name="file" fileName="C:/Users/mcnc/Desktop/20191203.log">
              <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
        </File>
    </Appenders>
    
    <Loggers>
        <!-- one 패키지의 'andTwo 클래스의 로그 레벨은 info로 올리고', file로 저장할래 -->
        <!-- additivity는 같은 로그가 있다면 additivity가 설정되어있는 로거에서만 출력하도로 설정하는거야.
        참고로 모든 로거에는 기본 로그가 남는데 아래처럼 따로 설정한 로그 방식을 AppenderRef 해준다면 기본 로그+Append 로그. 총 2개의 로그가 남아.
        기본로그는 최소의 정보만 들어있기때문에 이를 막아야겠지? 로그 자체는 동일하기때문에 additivity를 false로 해 주면 기본로그는 뜨지 않을거야. -->
        <Logger name = "one.andTwo"  level="info" additivity = 'false'>
            <AppenderRef ref="STDOUT"/>
            <AppenderRef ref="file"/>
        </Logger>
    </Loggers>
</Configuration>
 

3번째 줄의 Appenders는 로그 방식에 대한 정의 부분이야.

 

6번째 줄은 Console로 출력하기 위한 설정으로 target="SYSTEM_OUT"으로 설정했어.  name은 이 방식에 대한 이름이야. 맘대로 정해.

 

7번째 줄은 로그 내용에 대한 형식이야. 날짜, 시간, 클래스.. 대충 요런 형식으로 로그 정보가 남는다는 뜻이야. 자세한 건 구글링..

 

11번째 줄부터는 로그를 파일에 저장시키는 방식을 정의한 부분이야.

 

16번째 줄부터는 Appenders에 정의해놓은 로그 방식을 사용하는 부분이야.

 

21번째 줄의 name은 패키지 경로를 포함한 클래스 이름이야. andTwo 클래스에서 발생되는 로그를 콘솔과 파일로 남기겠다는 뜻인데, level이 info로 설정되어 있으니 info레벨 이상의 로그만 남긴다는 의미야.

현재 andTwo 클래스에는 상위부터 error ~ trace까지의 로그를 남긴다고 되어있는데 level속성에 의해 trace와 debug를 제외한 로그만이 console과 파일에 저장되게 되지!

 

이제 서버를 켜고 크롬 창에서 요청 url을 입력해봐. 만약 아래와 같은 화면이 출력된다면 Servlet 호출에 성공한 거고, 콘솔 창, 파일에 로그까지 남는다면 log4j2를 이용한 로그 남기기도 성공한 거야!


5. 실행결과

 

이클립스 콘솔

 

 

파일

 

 

설명이 너무 장황하고 두서없어서 이해하긴 어려울 거야... 공부한다고 생각하고 나 자신과 대화를 한다는 컨셉으로 쓴 거니까 이해해주길..

반응형
반응형

1. oracle 12c 설치

https://www.oracle.com/database/technologies/oracle-database-software-downloads.html

 

2. sqldeveloper 18.4 설치(JDK include ver)

https://www.oracle.com/technetwork/developer-tools/sql-developer/downloads/sqldev-downloads-184-5458710.html

 

3. 두 파일 모두 압축해제

 

4. oracle 설치 파일 실행(비밀번호 입력을 제외한 모든 항목 수정하지 않고 진행)

 

5. oracle 서비스 수동 전환(서비스가 자동 실행 되어있으면 oracle을 사용하지 않을 때에 컴퓨터가 버벅거릴 수 있음)

시작 - 서비스

 1) Oracle ~~ TNSListener - 수동으로 변경

 2) OracleServiceORCL - 수동으로 변경

 컴퓨터를 재부팅하면 해당 서비스는 자동으로 실행이 되지 않음. 때문에 오라클 프로그램에 필요한 서비스가 로드되지 않아 에러가 발생할 수 있음. 때문에 불필요한 메모리 낭비를 하기 싫다면 위의 설정을 따르고, 메모리 낭비가 상관없을 만큼 컴퓨터 사양이 좋다면 위의 설정은 하지 않아도 된다.

 서비스를 재실행시키려면 서비스 탭으로 들어가 서비스를 실행시키거나, bat파일을 만들어 서비스를 실행시키면 된다.

 

6. cmd 실행 후 sqlplus 입력

 

7. 사용자 명에 sys as sysdba를 입력하고 비밀번호는 입력하지 않고 엔터키를 누르면 설치한 Oracle Database 12c에 접속됨.

Oracle Database 12c 접속 성공

9. tablespace 생성

 * tablespace란 데이터를 관리하는 논리적인 저장 구조이다. 쉽게 말하면 테이블을 관리하는 공간을 의미한다. 테이블 데이터의 기본 용량을 설정할 수 있으며, 용량 초과 시 자동적으로 10 mbyte씩 증가한다.

 create tablespace [테이블 스페이스명] datafile 'orcl 경로\[database파일 명.dbf]' size 500m; 입력

 참고로 oracle 12c 버전의 orcl의 경로는 c드라이브의 app에 생성된다.

 

10. user 생성

 데이터베이스 user를 생성한다.

  create user [아이디] identified by [비밀번호] default tablespace [테이블 스페이스명] temporary tablespace temp;

유저 아이디 오류

 사용자 이름에 오류가 생겼다.

 12c 버전부터는 유저 아이디 앞에 c##이라는 문자열을 삽입해줘야 한다. 필자는 그게 귀찮기때문에 아래의 명령어를 추가하여 c##을 입력하지 않고 유저 아이디를 생성하였다.

 

c## 생략 가능하게 하는 명령어

11. user에게 권한 주기

connect, resource, dba 권한 부여

12. sql developer 실행

 경로 설정이 나올시 '아니요' 클릭.

 실행되면 아래 버튼 클릭

 

13. 접속 정보 입력

접속 정보 입력

접속 이름 : 임의의 이름

사용자 이름 : 생성한 유저 이름

비밀번호 : 생성한 유저의 비밀번호

호스트 이름 : 기본값

포트 : 기본값(1521)

SID : 데이터베이스의 전역 DB명. 기본값(orcl)

 

 * SID 확인 방법

 

입력 후 테스트 클릭. 성공 시 저장 후 접속.

성공

워크시트가 생성되면 성공

반응형

'DB > Oracle' 카테고리의 다른 글

[MyBaits] typeAlias 설정  (0) 2021.06.07
반응형

ajax 통신 시 한글이 물음표(???)나 특수문자로 깨지는 현상을 경험하였다.

삽질하지 마시라고 해결책을 올린다.

 

1. html 파일의 charset을 utf-8로 설정한다.

1
<meta charset="utf-8">

 

2. 통신할 Servlet 파일의 doGet 또는 doPost 함수의 상단에 아래의 코드를 추가한다.

1
response.setContentType("application/x-json; charset=UTF-8");

 

3. WAS(tomcat)의 server.xml 파일(Servers 디렉터리 - Tomcat v7.0 Server - server.xml)의 65번째(바뀔 수도 있음) 줄에 코드를 아래의 코드로 수정한다.

1
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/>

 

필자는 3번을 통해 문제를 해결하였다.

반응형
반응형

목차

1. Ajax란

2. 실습 환경

3. 웹 페이지 생성

4. Servlet 생성

5. web.xml 설정

6. 정리

7. 출력 화면


1. Ajax란 (출처 - 위키백과)

 기존의 웹 애플리케이션은 폼을 채우고 이를 제출(submit)하면 웹 서버는 요청된 내용에 따라서 데이터를 가공하여 새로운 웹 페이지를 작성하고 응답으로 되돌려준다. 이때 최초에 폼을 가지고 있던 페이지와 결과물로써 되돌려 받은 페이지는 일반적으로 유사한 내용을 가지고 있는 경우가 많다. 결과적으로 중복되는 HTML 코드를 다시 한번 전송을 받음으로써 많은 대역폭을 낭비하게 된다. 이는 금전적 손실을 야기할 수 있으며 사용자와 대화하는 서비스를 만들기 어렵게도 한다.

 반면에 Ajax는 필요한 데이터만을 웹 서버에 요청해서 받은 후 클라이언트에서 데이터에 대한 처리를 할 수 있다. 웹 서버에서 전적으로 처리되던 데이터 처리의 일부분이 클라이언트 쪽에서 처리되므로 웹 브라우저와 웹 서버 사이에 교환되는 데이터량과 웹 서버의 데이터 처리량도 줄어들기 때문에 애플리케이션의 응답성이 좋아진다.

 

 장점

  - 페이지 이동없이 고속으로 화면을 전환할 수 있다.

  - 서버 처리를 기다리지 않고, 비동기 요청이 가능하다.

  - 수신하는 데이터 양을 줄일 수 있고, 클라이언트에게 처리를 위임할 수도 있다.

 

 단점

  - Ajax를 쓸 수 없는 브라우저에 대한 문제가 있다.

  - HTTP 클라이언트의 기능이 한정되어 있다.

  - 동일-출처 정책으로 인해 다른 도메인과는 통신이 불가능하다.


2. 실습 환경

 - 이클립스

 - jquery-3.4.1

 - tomcat 7.0

  프로젝트 생성 및 tomcat 서버 설정을 마쳤다는 가정 하에 ajax 통신을 하였다.


3. 웹 페이지 생성

 먼저 사용자가 어떠한 입력을 수행할 수 있도록 html과 javascript를 사용하여 웹 페이지를 생성한다. 아래와 같이 ajax폴더에 파일들을 넣어줬다.

웹 페이지 생성

 

 3.1) ajaxCommunication.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
<script type="text/javascript" src = "ajax/jquery-3.4.1.js"></script>
<script type="text/javascript" src = "ajax/ajaxCommunication.js"></script>
</head>
<body>
    <h2>Ajax Communication</h2>
    이름 : <input type="text" id = "ajaxConName"/>
    나이 : <input type="text" id = "ajaxConAge"/>
    <br>
    <input type="button" id = "ajaxConGetButton" value ="Get통신">
    <input type="button" id = "ajaxConPostButton" value ="Post 통신">
    <div id="myDiv"></div>
</body>
</html>
 

 Get, Post 방식의 통신을 구현하기 위해 두 개의 버튼을 생성하였다.

 

 3.2) ajaxCommunication.js

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
$(document).ready(function(){
    $('#ajaxConGetButton').click(function(){
        AjaxConGet();
    })
    
    $('#ajaxConPostButton').click(function(){
        AjaxConPost();
    })
    
})
 
function AjaxConGet(){
    var url = "http://localhost:8080/test/ajaxCon";
    $.ajax({
        type:"GET",
        url:url,
        dataType:"html",
        data:{
            name : $('#ajaxConName').val(),
            age : $('#ajaxConAge').val()
        },
        success : function(data){
            alert('ajax GET 통신 성공');
            var $div = $('<div></div>');
            var text = document.createTextNode(data);
            $div.append(data);
            $div.appendTo($('#myDiv'))
        
        },
        error : function(request,status,error){
            alert('code:'+request.status+"\n"+"message:"+request.responseText+"\n"+"error:"+error); //에러 상태에 대한 세부사항 출력
            alert(e);
        }
    })
    
}
 
function AjaxConPost(){
    var url = "http://localhost:8080/test/ajaxCon";
    $.ajax({
        type:"POST",
        url:url,
        dataType:"html",
        data:{
            name : $('#ajaxConName').val(),
            age : $('#ajaxConAge').val()
        },
        success : function(data){
            alert('ajax POST 통신 성공');
            var $div = $('<div></div>');
            var text = document.createTextNode(data);
            $div.append(data);
            $div.appendTo($('#myDiv'))
        },
        error : function(request,status,error){
            alert('code:'+request.status+"\n"+"message:"+request.responseText+"\n"+"error:"+error); //에러 상태에 대한 세부사항 출력
            alert(e);
        }
    })
    
}
 

 1 ~ 10 : 페이지가 로드되면 위에서 생성했던 두 개의 버튼에 대해 click 이벤트를 부여한다.

 

 12 : Get 방식으로 Ajax와 통신을 시도하는 함수이다.

 

 13 : 통신을 하고자하는 url을 입력한다. ~~test/ajaxCon으로 설정했는데, ajaxCon은 web.xml에서 설정한 서블릿의 url이다.

 

 15 ~ 21 : 통신 방식과 통신할 url, 수신할때의 데이터 타입, Servlet으로 보낼 데이터 정보를 넣어준다. dataType은 서블릿에서 객체 형식이나 두개 이상의 데이터를 송신할 경우 "json"을, 하나의 문장으로 송신할 경우 "html"을 넣어준다. 필자는 out.print()로 하나만 보내기 때문에 html로 해주었다.

 

 22 ~ 27 : Servlet과의 모든 통신이 정상적으로 끝나면 메서드의 매개변수 안에 Servlet이 response 한 데이터가 있게 된다. 이를 출력하기 위해 div태그에 응답 정보가 들어있는 textNode를 상속시키고, 이를 초기 HTML 코드로 생성했던 div 태그에 상속시킨다.

 

 30 ~ 32 : Servlet과의 통신 실패 시 에러 코드 및 내용에 대한 세부사항을 출력시킨다. 만일 에러 코드가 200이 나올 경우 dataType에 대한 수정이 필요하다.

 

 38 ~ 57 : type을 GET에서 POST로만 변경한 코드이다.


4. Servlet 생성

 패키지를 myServlet으로 설정하고 Servlet 이름은 Serv로 하였다. web.xml에서 url과 Servlet을 매핑할 것이기 때문에 WebServlet()을 주석처리하였다.

 

Serv.java

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
package myServlet;
 
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
/**
 * Servlet implementation class Serv
 */
//@WebServlet("/ajaxCon")
public class Serv extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public Serv() {
        super();
        // TODO Auto-generated constructor stub
    }
 
    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        response.setContentType("application/x-json; charset=UTF-8");
        PrintWriter out = response.getWriter();
        String name = request.getParameter("name");
        String age = request.getParameter("age");    
        
        System.out.println("doget :"+name);
        System.out.println("deget :"+age);
            
        out.print("Get 통신 : 안녕 내 이름은 "+name+"이고 나이는 "+age+"란다"); //response    
    }
 
    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        response.setContentType("application/x-json; charset=UTF-8");
        PrintWriter out = response.getWriter();
        String name = request.getParameter("name");
        String age = request.getParameter("age");    
        
        System.out.println("doget :"+name);
        System.out.println("deget :"+age);
            
        out.println("Post통신 : 안녕 내 이름은 "+name+"이고 나이는 "+age+"란다"); //response
    }
}
 

 9 : ajax로 데이터를 전송하기 위한 메서드인 java.io.PrintWrite를 import 하였다.

 

 28 : GET 방식으로 통신할 때의 함수이다.

 

 30 : ajax로 보낼 데이터의 charset을 utf-8로 설정한다. 이 부분이 없을 시 한글이 깨져서 출력될 수 있다.

 

 32 ~ 33 : ajax에서 보낸 name과 age를 읽어 들인다.

 

 38 : 위와 같은 형태로 데이터를 가공하여 ajax에게 전송한다.

 

 44 ~ 54 : POST 방식으로 통신할 때의 함수이다.


5. web.xml 설정

 web.xml은 루트 경로로 진입 시 가장 먼저 읽어오는 파일을 설정하거나 WAS에게 줄 Servlet 정보를 설정하고 url을 매핑하는 역할을 한다.

 

web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>test</display-name>
  <welcome-file-list>
    <welcome-file>ajax/ajaxCommunication.html</welcome-file>  <!-- 루트경로 진입시 가장먼저 읽어오는 파일 -->
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <servlet>
  <!-- 서블릿을 불러오기 위해 WAS에게 주는 정보 -->
  <!-- 1. 배포할 Servlet 2. 해당 Servlet 매핑 URL -->
      <servlet-name>ajaxCon</servlet-name>
      <servlet-class>myServlet.Serv</servlet-class>
  </servlet>
  
  <servlet-mapping>
      <servlet-name>ajaxCon</servlet-name>
      <url-pattern>/ajaxCon</url-pattern>
  </servlet-mapping>
</web-app>
 

 

 5 : <welcome-file> 태그는 루트 경로 진입 시 가장 먼저 읽어오는 파일이다. 읽어올 수 없을 시 순차적으로 아래 입력된 파일을 읽어온다. root경로에서 서버를 돌릴 시 ajaxCommunication.html 파일이 가장 처음 로드되도록 하였다. 그 아래는 기본적으로 입력되어 있는 파일이다.

 

 13 ~ 18 : WAS가 Servlet을 정상적으로 로드하기 위해 WAS에게 주는 Servlet과 url 정보이다. <servlet-name>은 <servlet-mapping>에서 동일한 name을 가진 정보와 매핑시키기 위한 이름이다. 현재 myServlet.Serv(클래스명.서블릿명) 파일을 '/ajaxCon' 이라는 url과 매핑시켰다. 이로써 '~~test/ajaxCon' url로 접속할 시 Serv 파일이 로드된다.


6. 정리

 이렇게 설정하면 ajax 통신이 정상적으로 이루어진다. 과정을 정리하자면

 

 1) 서버를 실행하면 web.xml에서 정의한 파일인 'ajax/ajaxCommunication.html'를 로드하고, WAS에게 서블릿 파일과 url 정보를 알려준다.

 

 2) HTML 파일에서 버튼을 클릭하게 되면 입력한 url과 ajax 통신을 시도하게 된다. url이 web.xml에서 설정한  ~~test/ajaxCon로 설정되었기 때문에 '/ajaxCon'과 매핑된 Serv 서블릿과 통신을 시도하게 된다.

 

 3) Servlet에서 데이터를 받은 후 가공하여 송신한다.

 

 4) ajax는 웹 페이지에 가공된 데이터를 출력시킨다.


 7. 출력 화면

통신 성공 화면

 

반응형
반응형

목차

1. 개요

2. 생성

3. 조회

4. 수정

5. 삭제


1. 개요

 Javascript의 가장 기본이 되는 개념인 객체의 생성, 조회, 수정, 삭제 방법에 대해 알아본다.


2. 생성

1
var foo = { name : 'ssk' };

중괄호 '{ }' 안에 key : value 형식으로 프로퍼티를 저장한다.

프로퍼티란 객체에 속한 데이터를 뜻한다.

 

※ key point

 foo라는 변수가 {name : 'ssk'} 라는 객체 자체에 대한 데이터를 가지고 있는 것이 아닌 객체의 주소를 가지고 있다.

var foo 는 해당 객체의 주소를 저장하고 있다.

 

  예를 들어, var foo2 = foo 라고 초기화시키면 foo2 또한 foo와 동일한 객체를 가리키게 된다.


3. 조회

 객체를 조회하는 방법은 크게 두 가지이다.

 1) 참조 연산자 (.) 사용

 2) 대괄호 ([]) 사용

1
2
3
console.log(foo.name); // 'ssk'
console.log(foo['name']); // 'ssk'
console.log(foo[name]); //undefined

  foo.name은 foo객체의 주소를 참조하고 그 안에 있는 name 값을 조회한다라는 의미이다. 'ssk'가 출련된다.

 

 foo['name']도 직관적으로 해석하면 foo객체의 key가 name인 value값을 조회한다인데, foo['name']과 foo[name]이 자꾸 헷갈려서 메커니즘을 찾아 이해해보았다.

 

 먼저 대괄호란 녀석은 배열에서 값을 참조할 때 쓰는 형식이다.

 javascript에서는 number, boolean, undefined, string, null이라는 기본 타입을 제외하고 모두 객체 타입이다. foo['name']은  객체 타입인 배열과 형식이 같은 것을 알 수 있다. (물론! 차이는 존재한다.)

쉽게 생각하면 foo['name']은 처럼 'name'이라는 key값(index)를 참조한다고 생각하면 이해가 쉽다. 객체의 key값은 String 값이기 때문에 작은 따옴표(')와 함께 입력해 준 것이다. 작은 따옴표가 없으면 name이라는 값은 String이 아닌 하나의 변수로 인식되고, name 변수 안에 있는 값을 참조하게 된다. name 변수는 호출이 된 최상위 객체인 window에 존재하지 않기 때문에 당연히 undefined가 출력된다.

 추가적으로 javascript는 대괄호 안에 데이터가 문자열이 아닐 경우 자동적으로 toString() 메소드를 적용시킨다. toString() 메소드는 어떠한 데이터를 문자열로 변환해주며, 변수.toString() 형식으로 사용할 경우 해당 변수에 들어있는 데이터를 문자열로 변환해주는 역할을 한다.

 즉, 대괄호 안에 있는 name이라는 데이터를 문자열이 아닌 변수로 인식하게 되면 name이라는 변수는 호출된 객체 영역 내에서 정의되지 않았기 때문에 문자열로 변환한들 당연히 값은 존재하지 않는다.

 

1
2
3
4
5
var name = 'name';
 
console.log(foo.name); // 'ssk'
console.log(foo['name']); // 'ssk'
console.log(foo[name]); // 'ssk'

 때문에 변수에 객체의 key값을 넣어 조회할때 위의 방식을 사용한다.

 간단히 name이라는 변수에 'name'이라는 key값을 넣었지만 key값이 많을 경우 반복문과 결합하여 사용할 수 있다.

 

foo['name']과 foo[name]의 차이를 정확히 알았으니 더이상 헷갈리는 일은 없겠지.


4. 수정, 추가

1
2
foo['name'= 'hky';
console.log(foo['name']) //hky

foo.name = 'hky' 라고 해도 동일하다. 

1
2
foo['age'= 25;
console.log(foo['age']) //25

추가도 수정과 동일한 방식이다.


5. 삭제

1
2
delete foo['age'];
console.log(foo['age']); //undefined

 삭제하고자 하는 객체의 키 값을 입력하며, 객체의 프로퍼티를 삭제할 때 사용한다.

 객체 자체를 삭제할 순 없다.

반응형
반응형

목차

1. 정규 표현식이란

2. 정규식 패턴

3. 정규식 메소드

4. 예제


1. 정규 표현식이란

 정규 표현식이란 특정한 규칙을 가진 문자열의 집합을 표현하는 데 사용하는 형식 언어이다.

 형식 언어를 사용하여 특정한 규칙을 가진 문자열의 패턴을 파악한다면 텍스트 편집, 포맷팅, 검색, 치환 등의 문자열 작업이 가능하게 된다. 기본적으로 패턴은 두 개의 '/(슬래시)' 사이에 작성한다. 

 

 예를 들어 '20190809'라는 문자열에서 패턴을 파악하여 '2019''08''09' 형태로 나누고, 그 사이에'-' 문자열을 삽입하여 '2019-08-09' 형태로 만들 수 있고, 저렇게 만든 날짜형 데이터에서 사용 가능한 메소드인 getDay(), getFullYear() 등을 사용할 수 있게 된다. 표현을 위한 포맷팅뿐 아니라 메소드의 사용까지도 가능하게 해주는 좋은 녀석이다.


2. 정규식 패턴

 그렇다면 이 패턴은 어떻게 만들까? 패턴을 만드는 방법은 크게 두 가지이다.

 첫째, 단순 패턴 사용

 둘째, 특수 문자 사용

 

 2.1 단순 패턴 사용

  단순 패턴은 단순히 문자열을 대응시킬 때 사용한다. 예를 들어 /hi/라는 패턴은 문자열에서 hi라는 문자열이 그대로 나타나야 대응된다. "hi, hellow"에서 hi라는 문자열이 대응된다.

 연습이 필요하다고 생각한다면 정규식을 테스트할 수 있는 사이트(https://regexr.com)를 들어가 보길 권한다. 참고로 끝에 있는 'g'는 패턴 속성으로 대상 문자열의 처음부터 끝까지 해당 패턴을 적용시키는 것이다. 이 속성이 없다면 'hi hi hi' 문자열의 대응 부분은 처음의 'hi' 하나뿐이다.

regexr.com

 

 2.2 특수 문자 사용

  단순 패턴을 사용하여 대응하기 힘든 것을 대응시키고자 할 경우 패턴에 특수 문자를 사용한다. 예를 들어, /^hi/ 패턴은 문자열의 시작이 'hi' 문자로 시작되는 것에 대응한다. 만약 'hi, hellow' 문자열에 이 패턴을 적용시킨다면 'hi'가 대응되며, 'oh, hi'라는 문자열에 적용시킨다면 대응되는 문자는 아무것도 없다.

 

특수문자의 종류와 기능이다.

특수 문자 기능 예시
^ 입력의 시작 부분과 대응된다. /^시작/ 시작했다 시작
$ 입력의 끝 부분과 대응된다.  /끝$/ → 끝났다 
* 표현식이 0회 이상 연속으로 반복되는 부분과 대응된다.

/ab*c/ → cbbabbbbcdebc, acbd

+ 표현식이 1회 이상 연속으로 반복되는 부분과 대응된다. /ab+c/ → cbbabbbbcdebc, acbd
? 표현식이 0 또는 1회 등장하는 부분과 대응된다. {0,1} 과 같다. 있어도 ok, 없어도 ok 이라고 생각하면 편하다 /010?/ 01, 010, 011
. 개행 문자를 제외한 모든 단일 문자와 대응된다. /hi./ → hi, hi1, hi2, hi12, hi 
(x) 패턴의 부분을 나누는 것. 포맷팅에 유용하게 쓰인다.

/(a)(b)/ ab

replace(/(a)(b)/,'$1-$2') → a-b

x|y | 는 or 와 동일한 기능을 하며, 하나라도 있을 시 대응된다. /fuck|suck|dick/ fuckyou, suckyou
{n} 표현식이 n번 나타나는 부분에 대응된다. /(hi){2}/ → hi, hihi, hi hi
{n,m} 표현식이 n번~m번 나오는 부분과 대응된다. /(hi){2,3}/ → hi,hihi,hihihi,hihihihi
[abc] 대괄호 안의 문자가 하나라도 있을시 대응된다. /[abc]/g a,ab,abc

https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/%EC%A0%95%EA%B7%9C%EC%8B%9D

 

정규 표현식

정규 표현식은 문자열에 나타는 특정 문자 조합과 대응시키기 위해 사용되는 패턴입니다. 자바스크립트에서, 정규 표현식 또한 객체입니다.  이 패턴들은 RegExp의 exec 메소드와 test 메소드  ,그리고 String의  match메소드 , replace메소드 , search메소드 ,  split 메소드와 함께 쓰입니다 . 이 장에서는 자바스크립트의 정규식에 대하여 설명합니다.

developer.mozilla.org

더 많은 특수 문자에 대해 알아보고 싶다면 위의 링크로 들어가 보길 권한다.


3. 정규식 메소드

 정규식을 만들어 적용시키기 위해서는 정규식 메소드를 사용해야 한다.

 메소드 또한 위의 링크에서 잘 정리되어있기 때문에 많이 사용되는 메소드만 정리하겠다.

메소드 명 사용 방법 기능
exec pattern.exec(String) 패턴을 String에 적용하여 실행시킨다.
test pattern.test(String) 패턴을 String에 적용시킨 결과가 존재하는지 true와 false로 출력시킨다
replace String.replace(pattern,'type') 패턴을 String에 적용시키고 type으로 치환한다.

특정 문자를 제거하고 싶다면 String.replace(/\-/g, '')

 

반대로 String에 구역을 나눠 해당 구역 간격으로 '-' 문자를 넣어주고 싶다면 

 

번호에 '-' 기호 삽입

참고로 replace의 두 번째 인자인 $1, $2, $3는 정규식에서 대응되는 각각의 부분이다.


4. 예제

 입력받은 두 날짜의 시간 차이 계산하기

 

 4.1) 소스코드

  4.1.1) html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <meta http-equiv='X-UA-Compatible' content='IE=edge'>
    <title>Page Title</title>
    <script type="text/javascript" src="3js.js"></script>
</head>
<body>
    <input type="text" id = "date1">
    <input type="text" id = "date2">
    <input type="button" id = "dateButton" value="계산">
</body>
</html>

 

  4.1.2) Script

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
window.onload = function(){  
    document.getElementById("dateButton").addEventListener("click",dateCalcul);
    function dateCalcul(){
        var date1 = document.getElementById("date1").value;
        var date2 = document.getElementById("date2").value;
        var pattern = /(^(19|20)\d{2})(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])$/
        if(pattern.test(date1) && pattern.test(date2)){
            var formatDate1 = date1.replace(/(\d{4})(\d{2})(\d{2})/,'$1-$2-$3'); //YYYYMMDD 형태
            var formatDate2 = date2.replace(/(\d{4})(\d{2})(\d{2})/,'$1-$2-$3');
            var checkDate1 = new Date(formatDate1).getDate(); //1,2,3,4 형태, 메소드 적용 데이터
            var checkDate2 = new Date(formatDate2).getDate();
            checkDate1 = zeroFormat(checkDate1); //D 형태일때 0 추가 = DD형태
            checkDate2 = zeroFormat(checkDate2);
            var formatDate1Date = formatDate1.split('-')[2]; //DD 추출, 순수 입력 데이터
            var formatDate2Date = formatDate2.split('-')[2];
            
            if(formatDate1Date != checkDate1 || formatDate2Date != checkDate2){ //DD 형태 비교
                alert("입력한 날짜는 존재하지 않습니다");
                return;
            }
            var convertDate1 = new Date(formatDate1).getTime();
            var convertDate2 = new Date(formatDate2).getTime();
            var absDate = Math.abs(convertDate1-convertDate2);
            var result = absDate/(24*60*60*1000);
            alert(formatDate1+" 과 "+formatDate2+" 의 사이 날짜는 "+result+"일 입니다.");          
        }else{
            alert("19~20년도 사이의 정확한 날짜를 입력해주세요");
        }
    }
}
function zeroFormat(input){
    if(input<10){
        input = "0"+input;
    }
    return input;
}
 

 2번 라인 - dateButton Click 이벤트 추가 및 함수 실행

 

 4~5번 라인 - 날짜 데이터인 date1, date2의 value 값을 가져옴

 

 6번 라인 - 정규식 패턴 생성(사용자가 YYYYMMDD 형태로 입력했는지 검사)

 (^(19:20)\d{2}) - 제일 앞이 19 아니면 20, 그 뒤 숫자 2개 : 1900~2099

 (0[1-9]|1[0-2]) - '0 다음 1부터 9 사이 값' 또는 '1 다음 0부터 2 사이 값 : 01~12

 (0[1-9]|[12][0-9]|3[01])$ - '0 다음 1부터 9 사이' 또는 '1 또는 2 다음 0부터 9 사이' 또는 '3 다음 0 또는 1' : 01~31

 $ - (YYYYMMDDD와 같이 형식을 오버했을 때 검출함)

 

 7번 라인 - 입력한 두 텍스트 박스의 value에 패턴을 적용시키고 대응 여부를 확인(true or false)

 

 8~9번 라인 - Date 객체를 생성하기 위한 데이터 형식인 (YYYY-MM-DD)를 맞춰주기 위한 포매팅

 

 10-11번 라인 - 객체의 메소드를 적용하여 날짜를 가져옴

 

 12-13번 라인 - 날짜가 1일, 2일 과 같이 한 자리 수일 때 형식이 DD가 아닌 D가 됨. 즉 비교가 안되므로 DD형태로 변경해주기 위한 메소드인 zeroFormat() 호출

 

 ※ DD 형태로 변형해야 하는 이유

   사용자의 입력 날짜가 윤월일 인지 판별하기 위함 (2월 30일처럼 없을 수도 있는 날짜 판별)

   Date 객체의 getDate() 메서드는 입력한 날짜의 '일자'를 받아옴. 그런데 만약 2018년 2월 30일의 일자를 받아오면

   3일이 나오게 됨. 즉, 없는 일자만큼 카운트를 계산하여 가까운 있는 날짜에 더해줌. 2월 31일의 가장 가까운 날짜는

   3월 1일이며, 2월 28일에서 초과된 2일만큼 증가시키면 3월 3일이 나옴. = 계산 오류 발생.

   이러한 오류를 막기 위해 DD 형태로 변형하여 사용자가 입력한 날짜의 일자와 메소드를 적용시킨 일자를 비교하여

   일치할 경우 존재하는 날짜로 판별하고, 불일치할 경우 존재하지 않은 날짜로 판별하기 위함 

 

 14-15번 라인 - split 메소드를 사용하여 '-' 기준으로 나눈 배열의 3번째인 일자가 저장된 값을 읽어옴.

 

 17번 라인 - 사용자가 입력한 일자와 메소드를 적용시킨 일자를 비교

 

 21번 라인 - 입력 날짜에 문제가 없으면 해당 시간의 날짜를 시간으로 변환(milis)

 

 23번 라인 - 밀리 초로 변환된 두 날짜의 시간을 빼고 그 데이터를 절댓값으로 변환

 

 24번 라인 - 밀리초를 날짜로 변환하기 위해 각각의 단위를 곱 연산 후(1000*60*60*24 = 1일) 앞의 계산 결과와 나눔

 

4.2) 실행결과

실행결과 1
실행결과 2
실행결과 3

반응형
반응형
반응형

목차

1. 개요

2. logging이란

3. log4j란

4. log4j 설치 및 설정

5. 예제


1. 개요

 서버는 클라이언트와 정보를 주고받는다. 다양한 이유로 그 과정에서 발생하는 여러 사건이나 정보들을 기록으로 남기는데 이 기록을 log라고 한다. 그리고 log를 남기는 행위를 '로깅'이라고 하는데, 모든 서버에 기본적으로 들어가는 개념이기 때문에 오늘은 이 logging에 대해 공부하는 시간을 가져보도록 하자. 구동 환경은 이클립스와 tomcat 7.0이다.


2. logging이란

 로깅이란 시스템 동작 시 시스템 상태/작동 정보를 시간의 경과에 따라 기록하는 것이다. 그 기록을 '로그'라고 한다.

 한마디로 '로깅 = 로그 기록'이다.

 로깅은 많은 부분에서 사용되는데, 사용자의 패턴이나 시스템 동작 분석에 사용되거나 해킹 사고가 발생할 경우 비정상 동작의 기록을 통해 추적하는 데 사용한다. 백엔드 개발자들의 경우 개발 과정에 있어 디버깅에 활용할 수도 있다. 이 외에도 다방면으로 쓰인다.

 그렇다면 Spring과 같은 Java환경에서 로깅을 하려면 어떻게 해야 할까? 시스템 동작에 대한 기록을 남기는 것이기 때문에 흔히 알고 있는 system.out.println()과 같은 메소드를 사용할 수 있겠다. 하지만 이는 메모리면에서 비효율적인 데다 클라이언트의 접속량이 많아질수록 안정적으로 실행되지 못하는 등 여러 문제를 안고 있다. (문제에 대해 궁금하다면 직접 구글링을 추천)

 이 문제에 대한 솔루션이자 Java 환경의 logging 시스템이 바로 log4j이다. log4j에 대해 본격적으로 알아보도록 하자.


3. log4j란 

 Java 환경의 로깅 시스템을 제공하는 라이브러리.

 Logger, Appender, Layout 등 다양한 컴포넌트가 사용되며, 로그 레벨을 분류하여 로그 정보를 출력시킬 수 있다.

 

 3.1) 컴포넌트

컴포넌트 설명
Logger 로그의 주체, 로그 파일을 작성하는 클래스
Appender 로그를 출력하는 위치
Layout Appender의 출력포맷(일자, 시간 등)을 설정하여 로그 내용으로 지정하는 속성. 

  Layout의 종류는 여러 가지가 있지만 일반적으로 디버깅에 가장 적합한 PattenLayout을 사용한다.

  PattenLayout이란 출력 포맷을 정해진 일련의 패턴을 사용하여 설정하는 것인데 패턴 정보는 아래와 같다.

패턴 설명
C 클래스명 출력
d 로그 시간 출력
F 파일명 출력. 수행한 메소드와 라인번호가 함께 출력.
L 라인 번호 출력
m 로그로 전달된 메시지 출력
M 로그를 수행한 메소드명 출력
n 개행
p 로그 이벤트명 (DEBUG 등)
r 로그 처리시간(milliseconds)
t 로그 이벤트가 발생된 쓰레드 출력

 위의 패턴을 잘 조합하여 로그에 대한 출력 포맷을 설정한다.

 

 3.2) 로그 레벨

 로그는 기본적으로 6개의 레벨을 갖는다. 아래로 갈수록 낮은 레벨이다.

로그 레벨 설명
fatal 시스템 문제와 같은 아주 심각한 에러가 발생한 상태를 나타냄.
error 요청을 처리하는중 문제가 발생한 상태를 나타냄.
warn 처리 가능한 문제이지만, 향후 시스템 에러의 원인이 될 수 있는 경고성 메시지를 나타냄.
info 로그인, 상태변경과 같은 정보성 메시지를 나타냄.
debug 개발시 디버그 용도로 사용한 메시지를 나타냄.
trace 디버그 레벨이 너무 광범위한것을 해결하기위해서 좀더 상세한 상태를 나타냄

 debug(), warn(), error()와 같이 메소드를 사용해서 로그 정보를 얻을 수 있으며, 로그 레벨 설정을 통해 로그를 통제할 수 있다. 이는 Logger의 Level 메소드를 통해 이루어지며, 지정한 로그 레벨보다 낮은 로깅 이벤트는 무시된다이는 뒷부분의 예제를 보면 이해할 수 있을 것이다.


4. log4j 설치 및 설정

 1) http://logging.apache.org/log4j/2.x/download.html 에서 최신버전.zip 파일 다운.

log4j 홈페이지

 2) 압축을 풀면 많은 파일이 있는데 그중 log4j-api-2.x.jar 와 log4j-core-2.x.jar 파일을 복사.

 

 3) 이클립스를 실행시켜 Dynamic Web Project를 생성하고 프로젝트 폴더에 lib 폴더를 생성.

 

 4) lib 폴더에 복사한 두 파일을 붙여넣기.

lib에 파일 붙여넣기

  5) 라이브러리를 추가는 '프로젝트 우클릭 → properties → Java Build Path → Libraries → Add JARs' 클릭

  

  6) lib에 있는 두 파일을 선택 후 Apply 클릭하면 라이브러리 설정이 완료.

프로젝트에 log4j 라이브러리 추가


5. 예제

  1) project  Java Resources → src 경로에 log4j2.xml 파일 생성 후 아래의 소스코드 추가.

     (log4j2.xml은 로깅에 대한 기본 환경 설정 파일)

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Appenders>
        <Console name="STDOUT" target="SYSTEM_OUT">
            <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n" />
        </Console>
    </Appenders>
    <Loggers>
        <Root level="debug">
            <AppenderRef ref="STDOUT" />
        </Root>
    </Loggers>
</Configuration>

  4번 라인 - 로그를 출력하는 위치(Appenders)를 Console로 설정. 로깅 이름은 STDOUT으로 설정.

  5번 라인 - patten을 시간, 로그 이벤트명, 쓰레드, 클래스명, 파일명, 라인 번호, 메시지, 개행으로 설정

  9~10번 라인 - STDOUT에 대한 Root level을 debug로 설정(서블릿에서 호출될 로그 중 debug보다 낮은 로그 레벨은 무시)

  

  2) proejct에 servlet 클래스를 생성하고 아래의 코드를 입력. 

  (servlet 생성 및 기본 개념을 모르겠다면 클릭)

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
package servlet;
 
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
 
/**
 * Servlet implementation class log
 */
@WebServlet("/log")
public class log extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private Logger logger = LogManager.getLogger(log.class);
    /**
     * @see HttpServlet#HttpServlet()
     */
    public log() {
        super();
        // TODO Auto-generated constructor stub
    }
 
    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        response.getWriter().append("Served at: ").append(request.getContextPath());
        logger.error("error message");
        logger.warn("warn message");
        logger.info("info message");
        logger.debug("debug message");
        logger.trace("trace message");
    }
 
    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }
 
}
 

  18번 라인 - log 클래스에 대한 Logger객체 생성

  33~37번 라인 - 5가지의 로그 메소드 호출

 

  3) Servlet 파일 Run

실행 결과

  현재 servlet 파일에서 logger를 error, warn, info , debug, trace 총 5개 레벨에 대한 출력을 시도했으나 제일 낮은 레벨인 trace를 제외한 4개만 console로 출력된 상태이다. 이유는 앞서 언급했던 로그 레벨에 따른 통제와 관련이 있다.   log4j2.xml 파일에서 STDOUT 로깅 데이터에 대한 level이 debug로 설정되었기 때문이다. trace를 출력시키고 싶다면 xml 파일 9번째 줄의 debug 대신 trace를 넣어주면 된다.

 

  4) tomcat 서버 에러 발생 시

   tomcat 서버 에러가 발생할 경우 tomcat에 서버에 대해서도 log4j 라이브러리를 추가시켜줘야 한다. log4j를 사용하여 얻은 로그가 기본적으로 WAS(tomcat)에 남기 때문이다.

   추가 방법은 tomcat Server Overview → Open launch configuration → Classpath → UserEntries → Add JARs를 클릭하여 lib 폴더에 있는 두 라이브러리를 클릭하면 된다.

tomcat Overview
log4j 라이브러리 추가

 

시간이 늦은 관계로 log4j을 통한 롤링은 다음에 포스팅하도록 하겠다.

반응형
반응형

목차

1. 개요

2. Servlet 이란?

3. Servlet 동작 구조

4. 예제 및 실습

5. 실행화면


1. 개요

 저번 게시물에서 Spring MVC 모델에 대해 공부하던 중 Dispacher Servlet이란 개념이 애매모호한것 같아 이를 구조적으로 이해하기위해 선행 학습 개념인 Servlet에 대한 공부를 진행하였다.

 eclipse EE와 tomcat을 연동하여 WAS 구조를 만들고, Servlet을 이용하여 Client - Web Server - Web Container간 통신 구현 및 구조를 이해해보도록 하자.


2. Servlet 이란?

 Servlet이란 JAVA를 이용하여 동적 페이지를 생성하는 서버측 프로그램이다.

 CGI(Common Gateway Interface)라고도 하는데 CGI란 사용자의 입력을 받아 동적 페이지를 만드는 것이다.

 사용자의 입력에 따라 결과가 달라지는 것, 예를들어 쇼핑몰 로그인 후 나오는 자신의 닉네임같은 것이다.

 즉, JAVA로 구현된 CGI라고 생각하면 된다.

 

 개념은 알았으니 Servlet 동작 구조에 대해 살펴보도록 하자. 


3. Servlet 동작 구조

Servlet 동작 구조

 1) 클라이언트의 요청이 있으면 Web Server에게 요청이 전달된다.

 

 2) Web Server는 정적인 데이터(HTML, 이미지, css 등)만을 처리하고, 동적 데이터(Servlet, DB, 로직 등)는 Web Container에게 전달한다.

* Web Container : Servlet 클래스 또는 JSP 파일을 실행하기 위한 실행 환경을 제공하는 컨테이너

 

 3) Web Container는 web.xml파일을 참조하여 해당 Servlet에 대한 쓰레드를 생성한다. 그리고 httpServletRequest와  httpServletResponse 객체를 생성하여 이 쓰레드에게 전달한다.

 쓰레드를 생성하는 이유는 클라이언트에게 효율적으로 웹 페이지를 제공하고, 서버의 부하를 막기 위함이다.

 이로써 통신 객체를 가진 쓰레드가 만들어진다.

* 쓰레드 : 여러가지 작업을 동시에 수행할 수 있도록 복제(나눈)한 것

 

 4) Container가 Servlet을 호출한다. 

 

 5) 호출된 Servlet의 작업을 담당하는 쓰레드(3에서 생성된 쓰레드)는 로직이 정의된 doPost()doGet() 메소드를 호출한다. 이 두 메소드는 Servlet class에 정의되어있다.

 

 6) 호출한 메소드의 로직을 컴파일한 후 생성된 동적 페이지를 (3)번 에서 생성했던 httpServletResponse객체에 담아 Web Container에게 넘겨준다.

 

 7) Web Container는 전달받은 response 객체를 HTTPResponse 형태로 바꿔 웹 서버로 전송함과 동시에 생성했던 쓰레드와 httpServletRequest, httpServletResponse 객체를 종료 및 소멸시킨다.

 (HTTPResponse는 Web Server에서 Client 로의 응답 객체이다.)

 

 8) Web Server는 전송받은 HTTPResponse 객체를 HTTP 통신을 통해 클라이언트에게 전송하여 화면을 출력시킨다.


4. 예제 및 실습 (eclipes EE, tomcat 7.0)

 4.1) Dynamic Web Project 생성(web.xml 체크)

New - Dynamic Web Project
web.xml Check

 4.2) Servlet 생성

  - Package, class 이름을 입력.

  - class이름의 첫글자는 대문자로 입력.

create Servlet

 

 4.3) Servlet 코드 입력(test1.java)

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
package one;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
/**
 * Servlet implementation class Two
 */
@WebServlet("/Two")
public class Two extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public Two() {
        super();
        // TODO Auto-generated constructor stub
    }
    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        response.getWriter().append("Served at: ").append(request.getContextPath());
        PrintWriter out = response.getWriter();
        out.println("<html>"+"<body>"+"<h2>Hello World</h2>"+"</body>"+"</html>");
        
    }
    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }
}
 
 
 

 

4.4) web.xml 코드 입력

 <servlet-name> 태그에는 프로젝트의 이름을, servlet-class에는 클래스의 주소(Package.class형식)를 입력.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
  <display-name>test1</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  
  <servlet>
      <servlet-name>test1</servlet-name>
      <servlet-class>one.Two</servlet-class>
  </servlet>
</web-app>
 

5. 실행화면

Servlet에 들어있던 HTML 코드

 URL의 끝이 test1이 아니라 Servlet 명인 Two를 추가적으로 입력해야한다.

 URL 설정은 해당 Servlet 파일 또는 web.xml 파일 내에서 가능하다.

 

 페이지에 Servlet에서 정의한 로직이 출력되면 성공한 것이며, 이렇게 eclipse, tomcat을 사용한 Servlet 실습을 마치도록 하겠다.

반응형
반응형

목차

1. 개요

2. 스프링이란?

3. POJO란?

4. MVC 패턴이란?

5. MVC 패턴 구조

 

1. 개요

 대부분 웹 개발자들은 JAVA를 사용한다. 많은 기능과 메소드를 제공할 뿐 아니라 분업에 최적회된 OOP 구조이기 때문이다. 하지만 그만큼 복잡하고 어렵고 무겁다. 이러한 무겁고 어려운 웹 개발을 보다 쉽게 하기 위해 등장한 프레임워크가 바로 스프링이다.


2. 스프링이란?

 Java EE의 복잡하고 어려운 사용을 단순화시킨 프레임워크이다. POJO 기반이며, MVC 패턴을 사용한다.


3. POJO란?

 POJO란 Plain Old Java Object의 약자로 그대로 해석하면 (보거나 이해하기)분명한 오래된 자바 객체라는 뜻이다.

 프로그래밍적 용어로 해석하면 복잡하고 어려운 Java라는 녀석을 이해하기 쉽고 가볍게 가공한 것이다.

 Java EE와 같은 기존의 "무거운" 객체를 만들게 된 것에 반발해서 사용되게 된 용어라고 한다.


4. MVC 패턴이란?

 MVC 패턴은 Model, View, Controller의 약자로 각각은 다음의 의미를 갖는다.

약자 원형 의미
M Model 데이터 및 데이터베이스와 관련된 비지니스 로직을 처리하거나 이를 조회, 조작하는 부분 
V View 유저 인터페이스를 정의하는 부분
C Controller 분업된 비지니스 로직 및 DB접근을 효율적으로 관리하고, View와 Model의 연결단 부분

Controller의 '연결단' 이라는 표현이 조금 모호할 수 있으나 MVC패턴의 구조를 보면 이해할 수 있을 것이다.


5. MVC 패턴 구조

 1) Client에서 URL(데이터)을 요청한다.

 

 2) Dispatcher Servlet은 적절한 Controller에게 요청을 전달해야 한다. 이는 Handler Mapping을 이용하여 처리한다.

 

 3) Controller는 board, user, menu 등 하나의 큰 작업단위이다. 그 작업단위를 세분화 시킨 것이 Service인데 앞서 말한것 처럼 Handler Mapping을 이용하여 전달받은 내용을 적절한 Service에게 전달한다.

 

 4) Service는 비지니스 로직을 실행하며 DB에 대한 접근이 필요할 시 DAO라는 ConnectionPool 객체를 호출한다.

 

 5) VO(Value Object)는 DTO(Data Transfer Object)라고도 하며 SQL 쿼리문 담아 DB를 조회, 조작할수 있다.

 

 6) DB 접근을 마치면 결과가 출력되는데 이를 View(.jsp)와 결합한 형태로 Controller에게 다시 전달한다.

 

 7) Dispatcher Servlet에게 위의 정보가 다시 전달되며 이는 View에 접근하여 완성된 View의 정보를 사용자에게 response한다. 단, 회원가입 및 정보 수정 같이 보안상 보여줄 필요가 없는 부분은 다른 View로 대체 가능하다.

 

그렇다면 앞서 말한 연결단은 Model과 View를 연결시키는 의미를 말하며 아래와 같이 정리가 가능하다

 

Controller = 'Model과정을 거친 데이터'+'View'

반응형

+ Recent posts