Spring 5일차

Shin·2023년 2월 24일
0

spring

목록 보기
5/8

Spring 5일차

  1. log4j
  2. @Controller
  3. @RequestMapping
  4. InternalResourceView
  5. ModelAndView
  6. EL (Expression Language)

1. log4j

console 에 System.out.println() 을 통해 확인하는 것은 여러 측면에서 시스템적 비효율을 불러온다.

성능적인 측면에서, 관리적인 측면에서 좋지 않고, 시스템을 운영할 때에는 반드시 로그를 생성해야 한다. 그래야만 시스템의 문제가 어디인지, 클라이언트의 요청에 어느 시점에 잘못되었는지 알 수 있기 때문이다.

그런데 보안성에 대한 문제가 대두되면서, 확장 버전으로 2가지가 등장했다.

첫번째가 log4j2 (버전 2) 이고, 두번째가 logback (spring boot 에서 사용) 이다.

log4j 의 설정

Appenders

로그의 출력 위치를 정해주는 태그.

로그를 console에 출력할 것인지, 파일에 출력할 것인지 등을 지정할 수 있는 xml 태그이다.

appender 의 속성에 들어가는 class 타입에는 여러 가지가 존재한다.(console, file ... 등등)

  1. CnsoleAppender : 콘솔에 로그를 찍는다. org.apache.log4j.ConsoleAppender
  2. FileAppender : 특정 파일 하나에 로그가 다 찍히게 된다.
  3. RollingFileAppender : 다만 파일 하나에만 로그를 찍게되면 파일의 크긱가 너무나 커지게 된다. 그래서 일정 사이즈를 지정한 뒤, 그걸 넘어가면 파일을 새롭게 만드는 방식이다. 즉 파일의 용량을 제한하는 방식이다.
  4. DailyRollingAppender : 일자 별로 log 파일을 따로따로 만들어서 저장하는 방식이다.

layout

<appender name="appender 고유 식별자" class="target에 따라 이미 지정되어있는 클래스 타입을 명시">
    <param name="Target" value="System.out" />
    -> param 태그의 value 를 통해 어떻게 로그를 출력할 것인지를 지정하게 된다.
    <layout class="지정하려는 출력 패턴에 따라 클래스 타입이 정해져 있다.">
    -> 로그의 출력 형태를 지정해줄 수 있다.
        <param name="클래스 타입에 따라 입력해야 할 name 이 정해 져있다." value="출력 형태를 실제로 지정하는 부분">
    </layout>
</appender>

layout 에 사용하게 되는 약자들

  1. %p : 로그 레벨을 같이 출력하라는 약자
  2. %m : 로그 메세지 출력
  3. %d : 로그 발생 시간을 출력. 형식은 yyyy- MM-dd HH:mm:ss
  4. %c : 어떤 파일/어떤 클래스에서 로그가 발생했는지는 출력

Application Loggers

<logger name="log를 출력할 패키지 명시">
-> 메세지를 appender 에 전달하는 역할을 수행한다. 
    무조건적으로 모든 로그를 전달하는 것이 아니라, 로그의 출력 레벨에 따라서
    출력 여부를 결정하게 된다.
    출력 레벨은 총 6단계가 존재한다. 그 중에서 내가 설정한 레벨에 따라서 로그가 찍히게 된다.
    <level value="출력하고자 하는 로그 레벨 명시">
</logger>

Log Level

6단계 - FATAL : 가장 높은 level 로, 시스템에 심각한 문제가 있다는 의미이다.

5단계 - ERROR : 실행 중 error 가 발생했음을 알려주는 의미이다.

4단계 - WARN : 오류의 원인이 될 수 있는 내용을 출력하는 것

3단계 - INFO : 어플리케이션 운영 단계에서 주로 사용하게 되는 로그

2단계 - DEBUG : 어플리케이션 개발 단계 에서 사용하게 되는 로그로 System.out 대신 사용하는 것을 권장한다.

1단계 : TRACE : DEBUG 의 상세한 내용까지 출력하는 로그

로그 레벨을 지정할 경우, 지정한 로그 이상의 로그들을 모두 출력하게 된다.

Root Logger

root logger 가 작동되는 형식을 정하는 태그이다. 이 중 appender-ref 태그의 속성 값으로 위에서 설정했던 appender 의 name 값을 입력해준다.

2. Controller annotaion

해당 어노테이션이 붙은 클래스가 Controller 역할을 하는 Bean 객체임을 나타내주는 어노테이션으로, @Component 어노테이션을 상속한 어노테이션이다.

WEB-INF 폴더는 사용자에 의해 직접적으로 접근할 수 없는 폴더이다.

jsp 를 설정 잡을 때, WEB-INF 폴더 안에 jsp 파일이 존재하도록 설정을 잡는다. 왜냐하면 외부에서 직접적으로 jsp 파일에 접근하는 것을 막기 위해서이다.

3. RequestMapping

default 값으로 value 가 지정되어 있다.

@RequestMapping("url path") 
// == @RequestMappring(value="url Path") 와 같은 형태이다.

하지만 value

handler 에서 return 이 안이루어지면, reqeust URL 를 이용해서 결과 View Object 를 생성하려고 한다.

즉 아무런 return 이 안이루어지면, url path 를 가지고 jsp 를 찾게 된다.

url path 만을 가지고 dispatcher servlet 에게 전달이 되고,

dispatcher servlet 은 view resolver 에 설정한 값에 따라서

prefix 와 suffix 를 url path 에 추가한 뒤에 해당 view 폴더에 jsp 파일이 있는지 확인한다.

만약 없다면 error 를 내뱉게 된다.

Mappring url 이 동일하더라도, 메소드에 따라 handler 호출을 구분할 수 있다.

일반적으로 @RequestMappring 이라는 어노테이션은 클래스 단위로 사용한다. 클래스 내부의 각 메소드에서는 ET, POST, PUT, DELETE 의 각 방식에 따른 Mapping 어노테이션을 사용할 수 있다.
또한 각각의 어노테이션을 사용할 때 역시 value="url path" 를 통해 추가적인 url path 경로를 설정해줄 수 있다.

params 로 myName 이라는 key 값을 반드시 받겠다는 형태

myName=홍길동

으로 요청한 결과, 정상적으로 호출이 이루어지는 모습.

그러나, 현 Controller 에서는 오직 params=myName 을 받는 handler 딱 하나만 존재하기 때문에, 1) myName 을 받지 않거나, 2) 오타가 났을 경우 잘못된 요청이라는 페이지가 나오게 된다.

만약 동일한 RequestMapping 에 대해, params 설정이 다른 두 메소드가 있다면 어떻게 처리될까

원래라면, myName=신사임당 이라는 vey-value 가 없다면 오류가 나는 것이 당연하겠지만, 위에 있는 메소드에 의해 실행이 이루어졌다. 실제 로그로 확인해보면 myName 로그가 나오는 것을 확인할 수 있다.

반면 myName=신사임당 을 모두 입력한 경우, 앞선 순위의 메소드로 가거나 두 개의 메소드가 실행되는 것이 아니라 하단의 메소드만 실행되는 것을 로그를 통해 확인해볼 수 있다.

다만 이러한 케이스는 절대 권장되는 케이스는 아니며, 가능한한 쓰지 말아야 할 형태이다.

InternalResourceView

기존은, 문자열을 return 하거나, 아예 return 을 안하고 dispatcher servlet 이 url url path 를 참고한 후 view resolver 를 통해 view 객체를 생성받든가의 두 가지 방식이었다.

EL

기존의 jsp 파일에서 사용하던
jsp expreestion <%= %>,
jsp scripter <% %>
들은 유지, 보수가 너무 어렵다.

그 점을 개선한 방법이 아래의 형태이다.

`EL` ${변수명(key 값)}  <- jsp expreestion` <%= %>,
`JSTL` ${} <- jsp scripter` <% %>

이 때, 변수명을 찾는 순서로 jsp의 4단계 scope 를 순차적으로 돌면서 변수명을 찾게 된다.

scope

  1. pageScope
  2. requestScope
  3. sessionScope
  4. applicationScope

각각의 scope 들은 독립적으로 존재하는 공간이기 때문에 각 scope 들은 동일한 key 값을 가지는 케이스가 있을 수도 있다.

  1. pageScope : pageContext 객체를 가르킨다.
  2. reqeustScope : servlet 통신에서 사용하던 httpReqeust 객체는 사실 requestScope를 대표하던 객체였다.
  3. sessionScope : 마찬가지로, Session 객체 역시 해당 scope 내부에서 사용하던 객체
  4. appliactionScope : 모든 서블릿이 공유하며 사용하던 servletContext 객체가 대표적인 객체이다.

spring을 사용할 때 역시 일반적이 servlet 통신 시와 사용하는 객체는 거의 동일하지만, requestScope 단계에서 request 객체 뿐만 아니라 Model 객체를 하나 더 사용하게 된다.

<h1>${myName}</h1>

EL 표기법은 자체적으로 Scope 를 참조하여 변수값을 찾는다. 따라서 jsp expression 에서의 <% request.get~ %> 과 같이 scope(request 객체)를 명시하지 않아도 사용이 가능하다.

물론, EL 표기법은 page->application 순으로 순차적으로 scope 를 탐색하기 때문에 pageScope 와 requestScope 에 동일한 key 가 있다면 pageScope 의 key 가 출력된다.
이 때는 사용하고자 하는 scope 를 직접적으로 명시함으로써 원하는 scope 의 key 를 찾아갈 수 있다.

<h1>${sessionScope.myName}</h1>

EL의 내장 객체

  • scope 객체
    • pageContext
    • requestContext
    • sessionScope
    • applicationScope
  • param : client request parameter의 이름과 값을 가지고 있는 내장 객체
  • header : client reqeust 의 header 정보
  • cookie : client request 에 내포하고 있는 map 형태의 cookie 정보를 담고 있는 내장 객체

pageContext

해당 page 에서만 유효한 scope 를 가지는 객체. 해당 객체에 저장된 데이터는 해당 jsp 파일 내에서만 유효한 데이터로, 다른 페이지에서는 사용이 불가능하다.

Client Reqeust Parameter 처리

일반적인 servlet 방식 : request.getParameter("key")

Spring 방식

spring에서는 controller annotaion 을 사용했을 뿐, 실제 사용하는 것은 POJO, 즉 순수 자바 파일 이기 때문에 굳이 servlet 방식을 따라서 사용하지는 않는다.

@RequestBody

 @PostMapping(value="calc.do")
    public ModelAndView process(@RequestBady int secondNum){
        System.out.println(firstNum + secondNum);
        return null;
    }

@RequestParam

  @PostMapping(value="calc.do")
    public ModelAndView process(
        @RequestParam("firstNum") int num1
        , @RequestParam("secondNum") int num2)
        , @RequestParam("operator") Stirng operator) {
        ...
    }


  @PostMapping(value="calc.do")
    public ModelAndView process(
        @RequestParam int firstNum
        , @RequestParam int secondNum
        , @RequestParam Stirng operator){
        ...
    }


  @PostMapping(value="calc.do")
     public ModelAndView process(int firstNum int secondNum, String operator){
        ...
   }


   @PostMapping(value="calc.do")
     public ModelAndView process(String operator, User user){
        ...

        넘어오는 parameter 가 VO 인 case 가 있을 수 있다.
        이 경우, 앞부분에 생략된 부분은 ModelAttribute 라는 어노테이션이 생략되어 있다.
        즉 parameter 의 데이터 타입에 따라 생략되는 어노테이션의 종류가 다르기 때문에 이 점을 알고, 가능하면 어노테이션을 사용하는 것을 권장한다.
    }

ModelAndView Class

0개의 댓글