/*
*
* 자바웹개발워크북의 내용을 정리하기 위한 포스팅입니다.
* 서블릿/JSP, GET/POST, PRG패턴, HTTPServlet, EL/JSTL
*/
1. intellij를 통해 프로젝트 생성 시 'Jakarta EE'항목으로 생성하려면 Java Enterprise로 생성합니다.
2. 톰캣9버전을 사용한 이유 : 톰캣10버전은 서블릿 버전이 5버전으로 시작되면서 javax가 아닌 jakarta로 시작되는 형태로 패키지명이 변경되어 서블릿을 작성할 때 문제가 발생할 수 있습니다.
3. intellij에서 exploded된 artifact를 못찾는 문제발생 : 긴 경로를 수정해주기위해 기존 '.war'를 제거하고 artifact를 (exploded)가 포함된 항목으로 지정 후 실행시켰더니 오류가 발생했습니다. 'exploded war not found for the web module'
원인을 찾아본 결과, intellij가 버전업하면서 생긴 문제였습니다.
작동 프로세스는 프로젝트가 Gradle로 설정되어있다 -> Gradle로 실행 -> exploded가 생성되지않음.
문제를 해결하기위해서 Build and run설정을 IntelliJ IDEA로 설정 -> Project Structure대로 실행 -> exploded를 생성
4. 변경된 코드의 반영 : 예제프로젝트는 Gradle을 이용해서 컴파일 등의 작업이 처리되고 프로젝트의 build/libs 폴더안에 내용은 톰캣을 통해서 실행하기 때문에 코드를 변경한 후에는 다시 톰캣을 재시작해야만 합니다. 톰캣의 재시작을 최소화하기 위해서,
톰캣 셀렉트박스를 누르고 'editConfigurations'의 'On Update action'과 'On frame deactivation'설정을 'update classes and resources'로 조정합니다.
(톰캣을 위한 한글설정도 VM options를 이용해서 조정합니다 '-Dfile.encoding=UTF-8')
브라우저에서 새로고침하면 별도의 작업없이도 바로 변경된 코드를 반영하는 것을 확인할 수 있습니다.
5. 웹서버와 웹어플리케이션서버 구분
항상 같은 정적(static)데이터를 보내는 역할만 수행하는 서버는 '웹서버(WebServer)'라 칭하고,
동적(dynamic)데이터를 만들어 보내는 경우는 '웹 애플리케이션 서버(Web Application Server 이하, WAS)'라고 부릅니다.
톰캣의 경우 엄밀하게는 WAS로 보는 것이 좋지만, 대부분의 WAS는 웹서버 기능도 같이 포함하므로 이미지나 CSS/JS파일과 같은
정적인 자원들과 서블릿/JSP 같은 동적인 자원 모두를 처리할 수 있습니다.
6. 서블릿기술
서블릿기술은 쉽게말해서 서버에서 동적으로 요청과 응답을 처리할 수 있는 API들을 정의한것이라고 할 수 있습니다.
서블릿을 지원하는 환경에서 개발자들은 서블릿에서 제공하는 API를 이용해서 코드를 작성하고 이를 설정하는 방식으로
서블릿프로그램을 작성하게 됩니다.
JSP는 근본적으로 서블릿과 같은 원리지만 좀 더 HTML을 쉽게 이용할 수 있는 방식으로 코드를 작성할 수 있기 때문에
'서블릿으로는 코드를 이용한 처리, JSP로는 화면개발'과 같이 역할분담해서 개발하는것이 일반적입니다.
서블릿의 실행은 톰캣과 같이 서블릿을 실행할 수 있는 환경에서 실행이 가능한데 이를 '서블릿 컨테이너(Servlet Container)'라고 합니다. 현재는 톰캣이 바로 '서블릿컨테이너'역할을 하고 있습니다.
7. JSP기술
JSP는 'Java Server Pages'의 약자로 서블릿 기술과 동일하게 서버에서 동적으로 데이터를 구성하는 기술입니다.
JSP기술은 서블릿과 달리 HTML코드를 그대로 이용하고 필요할 때 약간의 자바코드를 넣는 반면에,
서블릿코드는 자바코드를 이용해서 HTML문자열을 만들어내는 방식의 차이가 있습니다.
JSP코드는 자바코드가 아님에도 서블릿과 동일하게 처리되는데, JSP파일도 서블릿코드로 변환되어서 컴파일되고 실행되기 때문입니다. JSP파일은 필요한 순간에 자바파일로 생성되고, 이를 컴파일해서 class파일로도 만들어 집니다.
정리해보자면 서블릿/JSP는 다음과 같이 요약할 수 있습니다.
▶ 서블릿/JSP 모두 Java EE스펙의 일부
▶ 서블릿/JSP를 실행하기 위해서는 서블릿 컨테이너가 필요함
▶ 서블릿컨테이너가 서블릿/JSP 객체를 생성하고 생명주기를 관리함
▶ JSP는 내부적으로 서블릿과 같은 방식의 코드로 변환됨
▶ JSP는 HTML내에 자바코드를 추가하는 방식, 서블릿은 자바코드안에 HTML코드를 추가하는 방식임
8. GET/POST
GET | POST | |
주용도 | 조회 | 등록/수정/삭제와 같은 처리 |
구성 | URL뒤의 "?"와 쿼리스트링 | URL전달 후 HTTP몸체(Body)로 쿼리스트링 |
효과 | 사용자가 손쉽게 사용할 수 있는 링크를 제공할 수 있음 |
단순 조회가 아니라 원하는 작업을 처리할 수 있게 됨 |
한계 | 브라우저에 따라 길이의 제한 URL뒤의 쿼리스트링으로 모든 정보가 전달됨 쿼리스트링길이에 대한 제한 (일반적으로 2kb 혹은 브라우저마다 차이가 있음) |
GET방식에 비해서 많은 양의 데이터를 전송 주소창만으로는 테스트가 어려움 |
최근에 JSP는 다음과 같이 제한적인 용도로 사용됩니다.
▶ JSP에서 쿼리스트링이나 파라미터를 처리하지 않는다. - JSP대신에 서블릿을 통해 처리
▶ JSP는 입력화면을 구성하거나 처리결과를 보여주는 용도로만 사용
▶ 브라우저는 직접 JSP경로를 호출하지않고 서블릿경로를 통해서 JSP를 보는 방식으로 사용
9. MVC구조와 서블릿/JSP
웹MVC구조는 'Model - View - Controller'의 역할을 분리해서 처리하는 구조로 데이터는 컨트롤러에서, 결과는 뷰에서 처리합니다. 앞선 설명에서는 서블릿이 바로 컨트롤러 역할이고 JSP가 뷰역할이라고 할 수 있습니다.
컨트롤러 역할을하는 서블릿은 JSP에 필요한 데이터를 가공하는 역할을 하는데 이때 필요한 데이터를 제공하는 객체를 모델이라고 합니다.
10. sendRedirect()
post방식으로 처리하고 JSP를 이용해서 결과를 보여주는 방식을 이용할 때도 브라우저 창에서 앞선 방법과 같이 다시 호출할 수 있기 때문에 처리가 끝난 후에 다를 경로로 이동하게 하는것이 일반적입니다. 이때 사용하는 메소드가 HttpServletResponse의 sendRedirect()입니다.
11. PRG패턴(Post-Redirect-GET)
웹MVC구조에서 가장 흔하게 사용하는 패턴은 POST방식과 Redirect를 결합해서 사용하는 PRG패턴입니다.
PRG패턴은 다음과 같은 흐름으로 정리할 수 있습니다.
▶ 사용자는 컨트롤러에 원하는 작업을 POST방식으로 처리하기를 요청
▶ POST방식을 컨트롤러에서 처리하고 브라우저는 다른 경로로 이동(GET)하라는 응답(Redirect)
▶ 브라우저는 GET방식으로 이동
12. HttpServlet
▶ HttpServlet은 GET/POST 등에 맞게 doGet(), doPost()등을 제공하므로, 개발자들은 본인에게 필요한 메소드를 오버라이드하는 것만으로 GET/POST방식처리를 나누어서 처리할 수 있습니다.
▶ HttpServlet을 상속받은 클래스 객체는 톰캣과 같은 WAS의 내부에서 자동으로 객체를 생성하고 관리하기 때문에 개발자가 객체관리에 신경 쓸 필요가 없습니다.
▶ HttpServlet은 멀티스레드에 의해서 동시에 실행될 수 있도록 처리되기 때문에 개발자는 동시에 많은 사용자를 어떻게 처리해야 하는지에 대한 고민을 줄일 수 있습니다.
13. HttpServlet의 라이프사이클
1) 브라우저가 톰캣에 서블릿이 처리해야 하는 특정한 경로를 호출합니다.
2) 톰캣은 해당 경로에 맞는 서블릿 클래스를 로딩하고 객체를 생성합니다. 이 과정에서 init()라는 이름의 메소드를 실행해서 서블릿 객체가 동작하기전에 수행해야 하는 일들을 처리할 수 있습니다(최초 필요한 시점에 서블릿 클래스를 로딩하는 대신에 톰캣 실행 시에 로딩하도록 하는 load-on-startup이라는 옵션도 있습니다).
3) 생성된 서블릿 객체는 브라우저의 요청(Request)에 대한 정보를 분석해서 GET/POST 등의 정보와 함께 같이 전달되는 파라미터(쿼리 스트링의 내용)들을 HttpServletRequset라는 타입의 파라미터로 전달받습니다. 이 과정에서 응답을 처리하는 데 필요한 기능들은 HttpServletResponse라는 타입의 객체로 전달받습니다.
4) 서블릿 내부에서는 GET/POST에 맞게 doGet()/doPost()등의 메소드를 실행합니다. 이 후 동일한 주소의 호출이 있을 때 서블릿은 동일한 객체 하나만을 이용해서 이를 처리합니다.
5) 톰캣이 종료될 때는 서블릿의 destroy()라는 메소드가 실행됩니다.
▶ 서블릿의 객체는 경로에 맞게 하나만 만들어진다 / 매번 호출시에는 자동으로 doGet()/doPost()를 이용해서 처리된다.
14. HttpServletRequest의 주요기능(주로 읽기)
기능 | 메소드 | 설명 |
HTTP 헤더 관련 | getHeaderNames() getHeader(이름) |
HTTP헤더 내용들을 찾아내는 기능 |
사용자 관련 | getRemoteAddress() | 접속한 사용자의 IP주소 |
요청관련 | getMethod() getRequestURL() getRequestURI() getServletPath() |
GET/POST정보, 사용자가 호출에 사용한 URL정보 등 |
쿼리스트링 관련 | getParameter() getParameterValues() getParameterNames() |
쿼리스트링 등으로 전달되는 데이터를 추출하는 용도 |
쿠키 관련 | getCookies() | 브라우저가 전송한 쿠키정보 |
전달 관련 | getRequestDispatcher() | |
데이터 저장 | setAttribute() | 전달하기 전에 필요한 데이터를 저장하는 경우에 사용 |
getParameter : '?name=AAA&age=30'과 같은 쿼리스트링에서 'name'이나 'age'라는 키를 이용해서 값을 얻을때 사용합니다.
명심해야 하는 점은 getParameter()의 결과는 항상 String이라는 점입니다. 만일 해당 파라미터가 존재하지 않는다면 null을 반환할 수 있습니다. 이때문에 항상 null체크를 주의해야 합니다. 문자열로 반환되기 때문에 숫자를 처리할 때는 예외가 발생할 수 있으므로 주의해야 합니다.
getParameterValues() : 동일한 이름의 파라미터가 여러개 있는 경우에 사용합니다.예를 들어 name이라는 이름의 파라미터가 여러개 존재한다면 getParameterValues()를 이용해서 String[]타입으로 반환됩니다.
seAttribute() : JSP로 전달할 데이터를 추가할 때 사용합니다. serAttribute()는 키와 값의 형태로 데이터를 저장할 수 있습니다.
이때 키는 문자열로 지정하고, 값은 모든 객체타입을 이용할 수 있습니다. JSP에서는 서블릿에서 setAttribute()로 전달된 데이터를 화면에 출력합니다.
RequestDispatcher
웹MVC구조에서는 HttpServletRequest의 getRequestDispatcher()를 이용해서 RequestDispatcher타입의 객체를 구할 수 있습니다. RequestDispatcher는 현재의 요청을 다른 서버의 자원(서블릿 혹은 JSP)에게 전달하는 용도로 사용합니다. RequestDispatcher에는 2개의 메소드가 존재합니다.
▶ Forward(): 현재까지 모든 응답내용은 무시하고 JSP가 작성하는 내용만을 브라우저로 전달
▶ include(): 지금까지 만들어진 응답내용 + JSP가 만든 내용을 브라우저로 전달
하지만 실제 개발에서는 거의 forward()만을 이용합니다.
15. HttpServletResponse의 주요기능(주로 쓰기)
기능 | 메소드 | 설명 |
MIME 타입 | setContentType() | 응답 데이터의 종류를 지정(이미지/html/xml 등) |
헤더 관련 | setHeader() | 특정 이름의 HTTP 헤더 지정 |
상태 관련 | setStatus() | 404, 200, 500 등 응답상태 코드 지정 |
출력 관련 | getWriter() | PrintWriter를 이용해서 응답메시지 작성 |
쿠키 관련 | addCookie() | 응답 시에 특정 쿠키 추가 |
전달 관련 | sendRedirect() | 브라우저에 이동을 지시 |
sendRedirect(): 브라우저에세 '다른곳으로 가라'는 응답메시지를 전달합니다. HTTP에서 location헤더로 전달되는데, 브라우저는 location이 있는 응답을 받으면 화면을 처리하는 대신에 주소창에 지정된 주소로 이동하고, 다시 호출하게 됩니다.
sendRedirect()를 사용하면 브라우저의 주소가 아예 변경되기 때문에 사용자의 '새로고침'과 같은 요청을 미리 방지할 수 있고, 특정한 작업이 완전히 끝아고 새로 시작하는 흐름을 만들 수 있습니다.
16. 서비스객체
▶ enum타입으로 클래스를 작성하는 경우 가장 큰 장점은 정해진 수만큼만 객체를 생성할 수 있습니다.
▶ 객체를 하나만 생성해서 사용하는 패턴을 '싱클톤 패턴(singleton pattern)'이라고 합니다.
▶ 원칙적으로 서비스객체는 절대 System.out.println()과 같이 출력하면 안되지만, 디버깅을 위한 용도로는 사용할 수도 있습니다.
List<TodoDTO> todoDTOS = IntStream.range(0, 10).mapToObj(i -> {
TodoDTO dto = new TodoDTO();
dto.setTno((long) i);
dto.setTitle("Todo.." + i);
dto.setDueDate(LocalDate.now());
return dto;
}).collect(Collectors.toList());
IntStream.range(0, 10) : 자바8부터 추가된 라이브러리로 일종의 반복문 처럼 사용됩니다.
두번째 파라미터는 범위에서 제외되며, 위같은 경우 0 ~ 9까지 반복됩니다.
for문과의 차이가 있다면 IntStream같은 경우 중간에 break문을 만나도 빠져나가지 않고 끝까지 실행됩니다.
말그대로 멈추지않는 물줄기인셈입니다.
mapToObj(): mapToObj() 사용해서 IntStream을 Stream<String>으로 변환합니다.
collect(Collectors.toList()): Stream을 List로 변환합니다.
java 8 에서는 collect(Collectors.toList()) 를 사용을 할 수 밖에 없지만, List가 변경될 수 있다는 점을 주의해야 할 거 같습니다.
java 버전을 올려 collect(Collectors.toUnmodifiableList()) 를 사용할 수는 있지만 NPE 로부터 안전하지 못한다는 점을 주의해야할 거 같고, Stream.of.toList() 가 지원되는 LTS java17을 사용하여 NPE와 수정가능한 취약점을 보완 할 수 있을 거 같습니다.
17. EL/JSTL
EL: JSP코드에서 사용한 '${}'는 EL(Expression Language)의 표현식입니다.
과거의 JSP에서는 자바코드를 직접 사용했는데 내부에서 자바코드가 같이 섞이면 import부터 시작해서 모든 자바문법이 사용되어야 하기 때문에 자바를 모르는 사람도 간단하게 사용할 수 있는 출력용 언어인 EL을 개발했습니다. EL이 출력만을 담당하기 때문에 제어문이나 반복문과 같이 '식(expression)'이 아닌 '문(statement)'를 처리하기 위해서는 JSTL 라이브러리가 필요합니다.
JSTL: JSTL(JavaServer Pages Standard Tag Library)은 JSP에서 동작하는 새로운 태그들의 묶음이라고 할 수 있습니다.
JSTL은 자바문법보다 조금 더 간결하게 제어문이나 반복문, 선언문 등을 처리할 수 있고, 확장이 가능하도록 설계되었습니다.
▶ <c:forEach> :
배열이나 리스트 등의 처리에 사용됩니다. 반복문의 경우, begin/end속성을 이용하여 반복수를 지정할 수 있습니다.
▶ <c:if>, <c:choose> :
<c:if>의 경우 test라는 속성이 존재하는데 test속성값으로 true/false로 나올 수 있는 식이나 변수등이 들어갈 수 있습니다.
<c:choose>는 내부에 <c:when test=..>, <c:otherwise>를 이용해서 'if ~else if ~ else'의 처리가 가능합니다.
▶ <c:set> :
EL과 JSTL을 이용해서 반복문이나 제어문을 처리하다보면 새로운 변수를 생성해야 하는 경우가 발생합니다.
이런 경우에는 <c:set>을 이용해서 변수를 생성하고 사용할 수 있습니다. var속성으로 변수명을 지정하고, value속성으로 값을 지정할 수 있습니다.
'개발 > JAVA' 카테고리의 다른 글
[자바웹개발워크북] 스프링 MVC 구현 - 환경설정, CRUD (0) | 2023.01.17 |
---|---|
[자바웹개발워크북] 4-2. 스프링 Web MVC (0) | 2023.01.14 |
[자바웹개발워크북] 4-1.스프링과 MyBaits (0) | 2023.01.02 |
[자바웹개발워크북] 3. 세션/쿠키/필터/리스너 (0) | 2022.12.28 |
[자바웹개발워크북] 2. 웹과 데이터베이스 (0) | 2022.12.24 |