9. URL 패턴
@WebServlet에 URL 패턴을 등록하고, 배열로 여러개 등록할 수 있다. servlet은 lazy init이 기본이다. 늦은 초기화를 쓴다. 하지만 loadOnStartup를 사용하면 servlet을 호출하기도 전에 미리 만든다. 뒤에 붙는 숫자는 초기화 하는 우선순위이고 겹쳐도 상관 없다.
servlet의 패턴 종류가 4가지가 있고 숫자는 우선순위이다. exact mapping은 정확히 일치해야 한다. 주소창에 입력한 URL이 패턴과 정확히 일치해야한다. 배열로 URL을 여러개 등록했을 때 exact mapping이 당연히 우선순위가 높다. 만약 /login/hello.do를 입력했는데 이와 일치하는 패턴이 없으면 우선 순위가 2인 path mapping으로 넘어간다. path mapping은 경로 mapping이고 wildcard(*)를 사용한다. '/login/*'은 login 경로로 들어오면 이 패턴으로 등록되어 있는 servlet이 실행된다.
* 와일드카드 문자(wildcard character)는 컴퓨터에서 특정 명령어로 명령을 내릴 때, 여러 파일을 한꺼번에 지정할 목적으로 사용하는 기호를 가리킨다. 이 문자는 어느 곳에서 사용하느냐에 따라 약간의 차이를 보인다. 주로 특정한 패턴이 있는 문자열 혹은 파일을 찾거나, 긴 이름을 생략할 때 쓰인다. - 출처 : wikipedia
URL을 오른쪽과 같이 입력하면 /login/* 패턴에 연결된다.
extension mapping은 확장자로 URL pattern이 mapping되 있는 servlet이 처리한다. 우선순위 1,2,3에 해당되지 않으면 default mapping으로 모든 주소와 mapping이 된다. default라 해서 항상 mapping되는 것이 아니라 우선순위에 매칭되지 않을 때만 default mapping에 연결된다. 즉 /login/hello.do 를 입력했을 때 등록된 패턴이 없으면 순위가 아래로 내려간다. URL mappping으로 servlet은 @WebServlet을 사용하고, spring은 @RequestMapping을 사용한다. spring에서도 URL pattern이 있다.
Servlet Context가 children, servletMappings 멤버를 갖고 있다. 요청이 오면 servletMappings을 먼저 확인한다. servletMappings에 있는 key가 URL pattern이다. 요청과 일치하는 패턴을 찾고 그에 해당하는 value에서 서블릿 이름을 찾는다. children에서 찾은 서블릿 이름에 해당하는 key를 찾고 servlet이 실행된다.
'/hello'를 요청하면 HelloServlet이 실행된다. '/hello.jsp'를 요청하면 서블릿 이름이 jsp이므로 JspServlet이 실행된다. 만약 /hello.do 를 입력하면 어떻게 될까? 정확히 일치하는 exacting mapping도 없고, 확장자인 extension mapping도 없어서 default 서블릿이 처리하게 된다. default가 우선순위가 제일 낮기 때문에, 일치하는 것이 없을 때 맨 나중에 실행이 된다.
위 2가지는 동적 리소스(서블릿)를 등록해서 처리하고, default는 정적 리소스로 image, css, txt파일을 처리한다. 프로그램을 만들었으면 기본적으로 mapping을 해서 동적 리소스로 처리하게 하고, 없으면 default가 정적 리소스로 처리하거나 404 error로 처리한다.
spring은 DefaultServlet을 쓰지 않고 DispatcherServlet을 사용한다. 요청과 matching된 것이 없으면 DispatcherServlet로 연결된다. spring으로 개발할 때는 servlet, jsp를 쓰지 않아(jsp를 사용하지만 등록하지 않는다.) 요청이 왔을 때 무조건 default로 연결되어 있는 DispatcherServlet으로 연결된다. DispatcherServlet 내부에 map을 갖고 있어 @RequestMapping으로 mapping을 처리하게 된다.
Servlet은 Servlet Context에서 서블릿을 등록하면 children Map에 저장이 되고, 또 servletMappings에 URL pattern이 어떤 servlet하고 연결될지를 관리한다. servlet은 이 2개의 Map으로 mapping을 관리하고, spring은 DispatcherServlet을 사용해서 내부에 2개의 Map과 유사한 것을 갖고서 mapping을 관리한다.
web.xml에 DispatcherServlet이 appServlet 이름으로 등록되어 있다. load-on-startup은 호출되었을 때 생성되는 것이 아니라 미리 생성되는 것이다. url-pattern은 '/'로 되어 있는데 모든 요청을 받는 pattern으로 우선순위가 낮다. 다른 pattern에게 우선순위가 밀리지만 matching되는 pattern이 없으면 default로 요청을 받는다. 따라서 spring은 서버로 오는 요청은 무조건 DispatcherServlet으로 받게 되어있다.
Server에 있는 web.xml은 전체설정이고, 프로젝트의 web.xml은 개별설정이다. 톰캣이 실행되면 우선 전체 설정을 적용하고 중복되는 부분은 개별 설정으로 덮는다.
톰캣의 web.xml파일을 보면 default로 되어 있지만 개별설정에서 DispatcherServlet으로 덮어 씌어졌다. 아무튼 spring은 모든 요청을 DispatcherServlet이 받는다.
10. EL (Expression Language)
EL은 기존에 쓰던 '<%=값%>을 '${값}'으로 바꾼 것이다. 간단하게 바꿔준다.
실습으로 https://github.com/castello/spring_basic/blob/main/ch2/el.jsp에 있는 코드를 경로 webapp아래에 만든다.
실행하면 오류 발생한다. line 6를 보면 person 클래스가 없다.
처음에 jsp파일이 열릴 때 시간이 걸린다. jsp 파일을 java파일로 바꾸는데 시간이 걸린다.
변환된 java 파일을 보자. Run configuration의 Arguments에서 deploy 경로를 복사한다.
이 폴더는 spring에서 사용하는 veiws 폴더가 변환된 곳이다. views도 jsp이다.
jsp폴더에 우리가 만든 el.jsp가 el_jsp.java로 변환되어 있다.
_jspService가 핵심 부분이다.
가끔가다 jsp를 바꿨는데 적용이 안될 경우 dir를 찾아 직접 지워도 되고, server 탭에서 'Clean Tomcat Work Directory' 를 클릭한다.
jsp 파일 지워진다. url에서 새로고침을 해서 요청 하면 다시 만들어진다. 이 때, url에서 잠깐의 시간이이 걸리는데 지연된 초기화 때문이다. 수정을 하고나서도 시간이 걸리는데, 수정된 것을 확인하고 새로 java파일 만들고 class파일을 만들기 때문에 시간이 걸린다.
세 문장이 같은 결과를 가져온다. person.car.color를 썻다고 해서 getCar를 안가져오지 않는다. 표현만 이렇게 쓰고, pserson 객체에 getCar가 있어야 한다.
person 객체는 lv이므로 ${lv} 쓸 수 없다. 따라서 request 객체에 저장하고 꺼내써야 한다. request 객체에 Attribute를 가진 Map이 있다.
이렇게 Map형태로 담아줘야 한다. person 객체가 lv이기 때문에 객체를 생성하고 담아주지 않으면 EL을 쓰지 못한다.
name도 EL표기법으로 간단해 질 수 있다.
scope에는 4종류가 있고, 위 코드로 객체를 그려보면 위 그림과 같다. Map의 이름이 requestScope이고 이 Map을 호출하기 위해서는 원래 ${requestScope.name}으로 써줘야한다. 저장소의 Map이름을 찍어줘야 하지만, 생략하고 ${name}을 써도 된다. 그 이유는 Scope이 없으면 page순으로 application까지 data를 찾는다. page가 가장 좁은 범위이고 application이 가장 넓은 범위이다. 아무튼 Scope을 생략하고 바로 Key를 쓰면 알아서 scope를 뒤져서 찾아준다.
request가 가진 객체를 사용하기 위해서는 앞에 Scope를 써줘야 한다. EL에서는 lv를 사용하지 못하기 떄문에 pageContext를 꼭 써줘야한다.
위 코드의 결과인데 jsp 코드는 null을 출력하지만 EL는 null을 출력하지 않는다.
EL에서 "1"은 숫자로 바뀌어서 1+1 = 2 로 출력되고, 만약 11로 쓰고 싶다면 +=를 써줘야 문자열 결합이 가능하다.
'스프링의 정석 > Ch. 02 Spring MVC' 카테고리의 다른 글
17. @RequestParam과 @ModelAttribute (0) | 2023.07.19 |
---|---|
16. 서블릿과 JSP (4) (0) | 2023.07.19 |
14. 서블릿과 JSP (2) (0) | 2023.07.10 |
13. 서블릿과 JSP (1) (0) | 2023.07.09 |
12. 관심사의 분리와 MVC패턴 - 원리(2) -> 다시 듣기 (0) | 2023.07.07 |