웹 프로그래밍
- 웹 프로그래밍은 직접 작성하는 main()을 실행하지도 않고, 단순히 JDK 만으로 모든 개발이 완료되지도 않음.
- 개발자가 모든 처리 과정을 직접 설계하는 방식이 아니라 반대로 개발자의 코드를 정해진 구조에 넣는 방식이기 때문에 전체적인 구조와 흐름 이해 필요
웹 기본 동작 방식
▷ Request (요청) & Response (응답)
⦁ GET 방식 : 주소창에 직접 원하는 데이터를 적거나 링크를 클릭해서 호출
↳ 원하는 웹의 주소를 호출할 때 필요한 데이터를 '?', '&', '=' 등을 이용해서 같이 전송하는 방식. 주소와 필요한 데이터를 한번에 같이 보내기 때문에 단순 링크로 처리되므로 다른 사람들에게 메신저나 SNS 등을 통해서 쉽게 공유가 가능함. GET 방식은 주로 특정한 정보를 조회하는 용도로 사용됨.
⦁ POST 방식 : 입력 화면에서 필요한 내용을 작성한 후에 '전송'과 같은 버튼 등을 클릭해서 호출
↳ 주소와 데이터를 따로 보내는 방식. 보통 회원 가입이나 로그인 등의 처리가 이에 해당함. POST 방식은 웹 화면을 통해서 실제 처리가 필요한 작업을 하기 위해서 사용함.
- 브라우저에서 서버에 위의 방식들로 데이터를 요구하는 것을 '요청(Request)'이라 하고, 서버는 이에 대한 '응답(Response)' 데이터를 만들어서 브라우저로 보내게 된다.
- 서버에서는 브라우저로 응답을 보낼때 정적인 데이터인지 동적인 데이터인지에 따라 다르게 처리함.
↳ 정적 데이터 = 항상 동일하게 고정된 데이터를 전송하는 방식으로 주로 파일로 고정된 HTML, CSS, 이미지 파일 등의 데이터
- 웹 서버 (Web Server) = 항상 같은 정적 데이터를 보내는 역할만을 수행하는 서버
↳ 동적 데이터 = 매번 필요할 때마다 다른 데이터를 동적으로 구성해서 전송하는 방식. 상황에 따라 동적으로 서버에서 데이터를 만들어 보내는 방식, 서버 사이드 프로그래밍이라고도 함.
- 웹 애플리케이션 서버 (WAS) = 동적 데이터를 만들어 보내는 경우의 서버, 웹 서버의 기능도 같이 포함한다.
▷ HTTP라는 약속 (Hyper Text Transfer Protocol)
⦁ 프로토콜 = 브라우저의 요청과 서버의 응답 사이의 중요한 데이터 교환 약속
- HTTP 메시지 구성 : HTTP 메시지는 Request(브라우저에서 전송할 때)와 Response(서버에서 데이터를 전송할 때) 모두 쓰이지만 내용과 구성이 조금 다름. HTTP 메시지는 Header와 Body로 구성됨.
- HTTP는 비연결성(Connectionless) 이라는 방식을 선택하는데 하나의 요청과 응답을 처리한 후에 연결을 종료한다는 것을 의미함. 서버에서는 하나의 Request를 빨리 처리하고 연결을 종료해서 다음 Request를 받을 수 있다면 적은 리소스로 많은 수의 Request를 처리할 수 있음.
▷ 자바 서버 사이드 프로그래밍
- 서버 쪽 프로그래밍 시 고려할 점)
⦁ 동시에 여러 요청이 들어올 때의 처리
⦁ 서버에서의 문제점 처리
⦁ 데이터 전송의 최적화 방법
⦁ 분산 환경과 분산 처리 문제 처리
↳ 새로운 서비스를 개발할 때마다 이런 고민을 매번 해야 한다면 과도한 개발 비용과 시간을 소모시킬 것이므로 자바에서는 JavaEE라는 기술 스펙으로 정리해 둠. Servlet과 JSP는 JavaEE 기술 중 하나.
- 서블릿(Servlet) 기술 : 서블릿 기술이란 서버에서 동적으로 요청과 응답을 처리할 수 있는 API들을 정의한 것. 서블릿을 지원하는 환경에서 개발자들은 서블릿에서 제공하는 API를 이용하여 코드를 작성하고 이를 설정하는 방식으로 서블릿 프로그램을 만든다.
- JSP는 서블릿과 근본적으로 같은 원리지만 좀 더 HTML을 쉽게 이용할 수 있는 방식으로 코드를 작성할 수 있기 때문에 "서블릿으로는 코드를 이용한 처리, JSP로는 화면 개발"과 같이 역할을 분담해서 개발하는 것이 일반적임.
- 서블릿의 실행은 톰캣과 같이 서블릿을 실행할 수 있는 환경에서 실행이 가능한데 이를 서블릿 컨테이너(Servlet Container)라고 함. (톰캣이 컨테이너 역할을 함)
↳ 서블릿 컨테이너를 주체로 실행하는 프로그램이 일반 자바 프로그램과 다른 점 :
① 객체를 생성하거나 호출하는 주체는 사용자가 아닌 서블릿 컨테이너
② 서블릿 클래스에서 생성하는 객체의 관리 자체가 컨테이너에 의해서 관리됨
③ 서블릿/JSP의 코드 개발은 기본적인 자바 API와 더불어 서블릿 API도 같이 사용해야 함. (HttpServlet 클래스에 작성된 init(), doGet(), destory() 등의 메서드는 서블릿 API에서 지정된 메서드. 또한 호출의 주체는 개발자가 아닌 서블릿 컨테이너. 컨테이너가 서블릿들을 관리 및 호출하며 이런 메서드들을 서블릿의 Life-cycle이라 함)
- JSP (Java Server Pages) 기술 : 서블릿 기술과 동일하게 서버에서 동적으로 데이터를 구성하는 기술.
※ 서블릿이 있는데도 불구하고 동일한 목적으로 JSP가 제공되는 이유는 두 기술의 목적 자체가 약간 다르기 때문.
- JSP 기술은 서블릿과 달리 HTML 코드를 그대로 이용하고 필요할때 약간의 자바 코드를 넣는 반면에 서블릿 코드는 자바 코드를 이용해서 HTML 문자열을 만들어내는 방식의 차이를 가짐.
- JSP 코드는 자바 코드가 아님에도 서블릿과 동일하게 처리되는데 이는 JSP 파일도 서블릿 코드로 변환되어서 컴파일 및 실행되기 떄문. JSP 파일은 필요한 순간에 자바 파일로 생성되고, 이를 컴파일하여 class 파일로도 만들어짐.
- JSP는 브라우저에 보내는 HTML데이터를 만들어내는데 좀 더 특화된 기술
<요약>
- 서블릿/JSP 모두 JavaEE 스펙의 일부
- 서블릿/JSP를 실행하기 위해서는 서블릿 컨테이너 필요
- 서블릿 컨테이너가 서블릿/JSP 객체를 생성하고 생명주기 관리
- JSP는 내부적으로 서블릿과 같은 방식의 코드로 변환됨
- JSP는 HTML내에 자바 코드를 추가하는 방식, 서블릿은 자바 코드안에 HTML 코드를 추가하는 방식
▷ JSP를 이용한 GET/POST 처리
☞ GET 방식은 입력과 조회 : 브라우저에서 직접 접근하는 GET 방식은 원하는 데이터 조회할 때나 사용자가 입력할 수 있는 화면의 경우에 주로 사용.
☞ POST 방식은 처리를 위한 용도 : <form> 태그에는 action과 method라는 속성을 이용해서 'Form'을 어디에 어떤 방식으로 전송할 것인지를 결정할 수 있음.
⦁ <form> 태그와 POST 방식
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>SuldenLion</title>
</head>
<body>
<form>
<input type="number" name="num1">
<input type="number" name="num2">
<button type="submit">Send</button>
</form>
</body>
</html>
- <form> 태그는 '입력 양식'을 의미하며 사용자가 입력하는 내용들을 전송하는 용도로 사용.
- <input> 태그는 값을 입력하는 용도로 사용. type이라는 속성을 이용해서 숫자 혹은 문자, 시간 등을 입력할 수 있음.
- <button> 태그는 화면에 버튼을 보여주고 <form> 태그의 전송을 목적으로 하는 경우에는 type="submit"으로 지정.
- 위 코드로 브라우저를 띄워서 Send 버튼을 누르면 "?num1=&num2="와 같은 쿼리스트링이 url에 붙음.
⦁ 쿼리 스트링(Query string)
- 웹에서 주소창 뒤에 '?'로 시작하는 내용물을 쿼리 스트링이라고 함.
- 쿼리 스트링은 "Key=Value"의 형태로 데이터를 전달하는데 여러 개의 데이터가 필요한 경우 '&' 연산자를 사용하여 연결.
⦁ 위 코드에 action, method 속성 추가 방식
<form action="calcResult.jsp" method="post">
<input type="number" name="num1">
<input type="number" name="num2">
<button type="submit">Send</button>
</form>
- <form> 태그의 action을 'calcResult.jsp'로 전송하고, 전송 방식(method)은 post로 변경함
- GET 방식과 달리 num1, num2가 보이지 않는 POST 방식.
- POST 방식은 주소와 전달하고자 하는 데이터를 분리해서 전송하는 방식이므로 브라우저를 통해서는 확인할 수 없고, 개발자 도구를 이용해야만 확인 가능.
GET | POST | |
주 용도 | 조회 | 등록/수정/삭제와 같은 처리 |
구성 | URL 뒤의 '?'와 쿼리 스트링 | URL 전달 후 HTTP Body로 쿼리 스트링 |
효과 | 사용자가 손쉽게 사용할 수 있는 링크 제공가능 | 단순 조회가 아닌 원하는 작업을 처리가능 |
한계 | - 브라우저에 따라 길이 제한 - URL 뒤의 쿼리 스트링으로 모든 정보가 드러나는 단점 - 쿼리 스트링 길이에 대한 제한(브라우저마다 다름. 일반적으로 2kb) |
- GET 방식에 비해 많은 양의 데이터 전송 - 주소창만으로는 테스트가 어려움 |
⦁ 위의 코드에서 전달되는 calcResult.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>SuldenLion</title>
</head>
<body>
<h1>NUM1 ${param.num1}</h1>
<h1>NUM2 ${param.num2}</h1>
</body>
</html>
- "${}"로 처리된 부분은 JSP에서 사용하는 EL(Expression Language)이라는 기술로, 서버의 데이터를 웹에서 출력하는 용도이다.
- EL은 param이라는 이름의 지정된 객체를 이용해서 현재 요청에 전달된 파라미터를 추출할 수 있음.
- 웹의 파라미터는 모두 문자열. 연산 등을 위해서는 파싱작업이 필요함.
⦁ JSP 올바른 사용법
- JSP는 기본적으로 GET/POST 방식의 호출을 구분하지 않기 떄문에 POST 방식으로 접근해야 하는 파일을 GET 방식으로도 얼마든지 호출할 수 있다는 문제가 있음.
- 유지보수 측면에서도 input.jsp파일을 input2.jsp와 같이 다른 JSP 파일로 변경했을 경우 과거의 input.jsp만 알고 있는 사용자들에게 주소가 변경되었다는 것을 알려주어야 하는 작업이 발생함.
> 최근의 JSP 제한적 용도
↳ JSP에서 쿼리 스트링이나 파라미터를 처리하지 않는다 (JSP 대신 서블릿을 통해서 처리)
↳ JSP는 입력 화면을 구성하거나 처리 결과를 보여주는 용도로만 사용
↳ 브라우저는 직접 JSP 경로를 호출하지 않고 서블릿 경로를 통해서 JSP를 보는 방식으로 사용 (Web MVC 방식)
▶ Web MVC 방식
- JSP를 이용한 개발 방식의 경우 유지 보수나 URL 변경 등이 유연하지 못하다는 단점으로 인해 2000년대 중반 이후의 개발은 거의 MVC 형식으로 서블릿과 JSP를 같이 이용하는 형태로 개발.
- 서블릿 코드는 자바 코드를 그대로 이용할 수 있고, 상속이나 인터페이스 처리도 가능. 하지만 HTTP로 전달된 메시지를 구성하는 HTML을 처리할 때는 상당히 많은 양의 코드를 작성해야함.
- JSP의 경우 반대로 HTML 코드를 바로 사용할 수 있으므로 HTTP 메시지 작성에는 적합하지만, 그 안에 자바 코드를 재사용하는 문제나 자바 코드와 HTML이 혼재하는 것과 같은 여러 문제가 생김.
- 브라우저의 요청은 해당 주소를 처리하는 서블릿에 전달되고 서블릿 내부에서는 응답에 필요한 재료 데이터들을 준비함.
서블릿은 준비한 데이터들을 JSP로 전달하고 JSP에서는 EL을 이용해서 최종적인 결과 데이터를 생성함.
- 웹 MVC라는 구조는 'Model', 'View', 'Controller'의 역할을 분리해서 처리하는 구조로 데이터는 컨트롤러에서, 결과는 뷰에서 처리함. (서블릿이 컨트롤러 역할, JSP가 뷰 역할)
- 컨트롤러는 뷰에 필요한 데이터를 가공하는 역할을 하는데 이때 필요한 데이터를 제공하는 객체를 모델이라 함.
⦁ MVC 구조로 프로그램 만들기
설계 원칙)
> 브라우저의 호출은 반드시 컨트롤러 역할을 하는 서블릿을 호출하도록 구성한다.
> JSP는 브라우저에서 직접 호출하지 않도록 하고 Controller를 통해서만 JSP에 접근하도록 구성한다.
GET 입력 화면의 설계)
① 브라우저는 '/input'과 같이 특정한 주소를 호출한다.
② '/input'에 맞는 서블릿을 'InputController'로 작성하고, GET 방식일때만 동작하도록 작성한다.
③ InputController의 화면 처리는 input.jsp를 이용하도록 지정한다.
④ input.jsp에는 HTML 코드를 이용해 브라우저에서 볼 수 있는 결과를 생성한다.
↳ 입력 화면의 경우 브라우저의 호출은 '/input'이고 컨트롤러는 'InputController', 뷰는 'input.jsp'가 됨.
POST 처리의 설계)
① input.jsp의 <form> 태그의 action을 '/calcResult'와 같이 변경하고 이에 해당하는 CalcResultServlet 서블릿을 컨트롤러로 작성한다.
② CalcResultServlet은 <form>으로 전달되는 데이터들(num1, num2)을 읽어내서 결과 데이터를 만들어야 한다
③ 만들어진 결과를 calcResult.jsp와 같이 JSP로 전달해야하고 JSP에서는 결과 데이터를 출력한다.
⦁ Controller에서 View 호출
@WebServlet(name = "inputController", urlPatterns = "/calc/input")
public class InputController extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
RequestDispatcher dispatcher = req.getRequestDispatcher("/WEB-INF/calc/input.jsp");
dispatcher.forward(req, resp);
}
}
- InputController는 브라우저 주소창에서 GET 방식으로 '/calc/input' 경로를 호출했을때를 처리하는 컨트롤러로 HttpServlet을 상속해서 구성
- InputController는 @WebServlet으로 urlPatterns 속성을 지정해서 처리해야하는 경로를 지정함.
- HttpServlet의 doGet()을 Override하고 GET 방식으로 들어오는 요청에 대해서만 처리
☞ RequestDispatcher를 이용한 Request 배포
- RequestDispatcher는 서블릿에 전달된 요청을 다른 쪽으로 전달 혹은 배포하는 역할을 하는 객체.
- RequestDispatcher를 사용하면 InputController는 버스 정류장처럼 '/WEB-INF/calc/input.jsp'라는 목적지로 가는 중간 경유지가 됨.
- WEB-INF는 브라우저에서 직접 접근이 불가능한 경로. (WEB-INF 밑에 jsp 파일을 둔다는 의미는 브라우저에서 jsp로 직접 호출 불가능함을 의미)
⦁ POST 방식을 통한 처리 요청
@WebServlet(name = "calcController", urlPatterns = "/calc/makeResult")
public class CalcController extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String num1 = req.getParameter("num1");
String num2 = req.getParameter("num2");
System.out.println("num1: " + num1);
System.out.println("num2: " + num2);
}
}
- urlPatterns 속성값이 '/calc/makeResult'로 지정. (브라우저에서 form 태그의 submit 경로를 수정한다(action값))
- doPost()를 Override한다. (브라우저에서 POST 방식으로 호출하는 경우에만 호출 가능)
- req.getParameter()라는 메서드를 이용해서 쿼리스트링으로 전달되는 num1, num2 파라미터를 문자열로 처리함.
⦁ sendRedirect()
- POST 방식의 처리는 가능한 빨리 다른 페이지를 보도록 브라우저 화면을 이동시키는게 좋음
- POST 방식으로 처리하고 JSP를 이용해서 결과를 보여주는 방식도 처리 후 다른 경로로 이동시키는것이 일반적임.
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String num1 = req.getParameter("num1");
String num2 = req.getParameter("num2");
System.out.println("num1: " + num1);
System.out.println("num2: " + num2);
resp.sendRedirect("/index");
}
- 브라우저는 Response 헤더(개발자 도구-Network)에 'Location'이 포함되면 브라우저의 주소창을 변경하고 해당 주소를 호출함(GET 방식)
⦁ PRG 패턴 (Post-Redirect-GET)
- PRG 패턴은 웹 MVC 구조에서 가장 흔하게 사용하는 패턴이며 POST 방식과 Redirect를 결합해서 사용한다.
- PRG 패턴은 POST 방식의 처리 후에 바로 다른 주소로 브라우저가 이동하기 때문에 반복적으로 POST 호출이 되는 상황을 막을 수도 있고, 사용자 입장에서도 처리 후 다시 처음 단계로 돌아간다는 느낌을 주게 된다.
> PRG 패턴 흐름
① 사용자는 컨트롤러에 원하는 작업을 POST 방식으로 처리하기를 요청
② POST 방식을 컨트롤러에서 처리하고 브라우저는 다른 경로로 이동하도록 응답
③ 브라우저는 GET 방식으로 이동
▶ HttpServlet
- HttpServlet은 GET/POST 등에 맞게 doGet(), doPost()를 제공하므로, 개발자들은 필요한 메서드를 오버라이드하는 것만으로 GET/POST 방식 처리를 나누어서 할 수 있음
- HttpServlet을 상속받은 클래스 객체는 톰캣과 같은 WAS 내부에서 자동으로 객체를 생성하고 관리하기 때문에 개발자가 객체 관리에 신경 쓸 필요가 없음
- HttpServlet은 멀티 스레드에 의해 동시에 실행될 수 있도록 처리되기 때문에 개발자는 동시에 많은 사용자를 어떻게 처리해야 하는지에 대한 고민을 줄일 수 있음
↳ HttpServlet은 GenericServlet이라는 추상 클래스를 상속받음. (GenericServlet은 HTTP 프로토콜에 특화되지 않는 요청과 응답에 대한 기능을 정의한다)
⦁ HttpServlet의 라이프사이클
① 브라우저가 톰캣에 서블릿이 처리해야 하는 특정한 경로를 호출
② 톰캣은 해당 경로에 맞는 서블릿 클래스를 로딩하고 객체를 생성함. 이 과정에서 init()이라는 메서드를 실행하여 서블릿 객체가 동작하기 전에 수행해야 하는 일들을 처리할 수 있음.
③ 생성된 서블릿 객체는 브라우저의 요청에 대한 정보를 분석해서 GET/POST 등의 정보와 함께 같이 전달되는 파라미터들을 HttpServletRequest라는 타입의 파라미터로 전달받음. 이 과정에서 응답을 처리하는데 필요한 기능들은 HttpServletResponse라는 타입의 객체로 전달받음.
④ 서블릿 내부에서는 GET/POST에 맞게 doGet() / doPost() 메서드 실행. 이후 동일한 주소의 호출이 있을때 서블릿은 동일한 객체 하나만을 이용해서 이를 처리.
⑤ 톰캣이 종료될 떄는 서블릿의 destroy()라는 메서드 실행
@WebServlet(name = "sampleServlet", urlPatterns = "/sample")
public class SampleServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doGet " + this);
}
@Override
public void destroy() {
System.out.println("destroy");
}
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("init");
}
}
↳ 브라우저를 통해 '/sample' 호출시 init() 메서드와 doGet()이 실행됨. doGet()의 this의 결과로 출력되는 값은 항상 같음.(동일한 하나의 객체로 처리된다는 의미)
↳ 톰캣 종료시 destroy() 호출. (init과 destroy는 한번씩만 호출)
⦁ HttpServletRequest 주요 기능
- 서블릿 객체에서 최종적으로 Request를 처리하는 doGet()과 doPost()는 HttpServletRequest와 HttpServletResponse를 파라미터로 전달받음.
기능 | 메서드 | 설명 |
HTTP 헤더 | getHeaderNames() getHeader(이름) |
HTTP 헤더 내용들을 찾아내는 기능 |
사용자 관련 | getRemoteAddress() | 접속한 사용자의 IP주소 |
요청 | getMethod() getRequestURL() getRequestURI() getServletPath() |
GET/POST 정보, 사용자가 호출에 사용한 URL 정보 등 |
쿼리 스트링 | getParameter() getParameterValues() getParameterNames() |
쿼리 스트링 등으로 전달되는 데이터를 추출하는 용도 |
쿠키 | getCookies() | 브라우저가 전송한 쿠키 정보 |
전달 | getRequestDispatcher() | |
데이터 저장 | setAttribute() | 전달하기 전에 필요한 데이터를 저장하는 경우에 사용 |
> getParameter() = HttpServletRequest에서 가장 자주 사용되는 메서드로 "?name=SuldenLion&age=19"와 같은 쿼리스트링에서 'name'과 'age'같은 Key를 이용하여 Value를 얻는 역할로 사용.
- 항상 String으로 얻어오며, 값이 존재하지 않는다면 null 반환.
> getParameterValues() = 동일한 이름의 파라미터가 여러개 있는 경우에 사용. 'name'이라는 파라미터가 여러개 존재한다면 getParameterValues()를 이용해서 String[] 타입으로 반환.
> setAttribute() = JSP로 전달할 데이터를 추가할때 사용.
- Key-Value 형태로 데이터를 저장할 수 있음. (Key는 문자열로 지정하고, Value는 모든 객체 타입 사용 가능)
- JSP에는 서블릿에서 setAttribute()로 전달된 데이터를 화면에 출력함
> RequestDispatcher = 웹 MVC에서는 HttpServletRequest의 getRequestDispatcher()로 RequestDispatcher 타입의 객체를 구할 수 있음. RequestDispatcher는 현재의 요청을 다른 서버의 자원(서블릿이나 JSP)에게 전달하는 용도로 사용.
- RequestDispatcher는 forward()와 include()라는 메서드를 가짐
↳ forward() : 현재까지의 모든 응답 내용은 무시하고 JSP가 작성하는 내용만을 브라우저로 전달
↳ include() : 지금까지 만들어진 응답 내용 + JSP가 만든 내용을 브라우저로 전달
- 실제 개발에서는 거의 forward()만 쓴다고 함.
⦁ HttpServletResponse 주요 기능
기능 | 메서드 | 설명 |
MIME 타입 | setContentType() | 응답 데이터의 종류를 지정 (이미지/html/xml 등) |
헤더 | setHeader() | 특정 이름의 HTTP 헤더 지정 |
상태 | setStatus() | 404, 202, 500 등 응답 상태 코드 지정 |
출력 | getWriter() | PrintWriter를 이용해서 응답 메시지 작성 |
쿠키 | addCookie() | 응답 시에 특정 쿠키 추가 |
전달 | sendRedirect() | 브라우저에 이동을 지시 |
- 웹 MVC 구조에서 HttpServletResponse는 JSP에서 주로 처리되기 때문에 서블릿 내에서 직접 사용되는 일은 많지 않고 주로 sendRedirect()를 이용하는 경우가 많음.
> sendRedirect() = HTTP에서 'Location' 이름의 헤더로 전달되는데 브라우저는 'Location'이 있는 응답을 받으면 화면을 처리하는 대신 주소창에 지정된 주소로 이동하고, 다시 호출함.
- sendRedirect()를 사용하면 브라우저의 주소가 아예 변경되기 때문에 사용자의 '새로고침'과 같은 요청을 미리 방지할 수 있고, 특정한 작업이 끝나고 새로 시작하는 흐름을 만들 수 있음.
▶ 모델 (Model)
- 컨트롤러에 필요한 기능이나 데이터를 처리해 주는 존재
- 모델을 담당하는 영역을 세분화시켜 DB를 담당하는 영역과 비즈니스 로직을 처리하는 영역으로 구분하여 '서비스 계층'과 '데이터 처리 계층'으로 분리하기도 함.
▷ DTO (Data Transfer Object)
- 3 티어 계층과 같이 분리하는 경우 계층이나 객체들 간에 데이터 교환이 반드시 이루어짐. 대부분은 한개 이상의 데이터를 전달할 때가 많기 때문에 여러 개의 데이터를 묶어서 하나의 객체로 전달하는 것을 DTO라고 함.
- DTO는 여러 개의 데이터를 묶어서 필요한 곳에 전달하거나 호출을 결과로 받는 방식으로 사용하기 때문에 특별한 규격이나 제약이 있는 것은 아니지만, 대부분은 Java Beans 형태로 구성하는 경우가 많음. (Java Beans 구성 형식 : 생성자가 없거나 반드시 파라미터가 없는 생성자 함수를 가지는 형태 / 멤버 변수는 private / getter, setter 제공)
▷ 서비스 객체
- 프로그램이 구현해야 하는 기능들의 실제 처리 담당 (로직들의 묶음)
- CRUD 기능들은 모두 서비스 객체에 모아서 구현됨
▷ 컨트롤러에서 모델처리
- 웹 MVC 구조에서는 화면에 필요한 데이터를 처리하고자 컨트롤러는 서비스 객체의 힘을 빌려서 처리함. (화면에서 목록 데이터들이 필요하다면 Service의 getList()의 결과를 받아서 JSP까지 전달하고 이를 JSP에서 보여줌)
▷ JSP - EL (Expression Language)
- JSP 코드에서 사용하는 '${}'는 EL (Expression Language)의 표현식.
- 과거에는 JSP에서 자바 문법을 이용하여 화면에 결과를 출력했지만 최근에는 거의 그렇게 하지 않음.
- JSP는 주로 HTML태그, 자바스크립트, CSS 등을 이용해서 코드 작성. JSP 내부에서 자바 코드가 같이 섞이면 import부터해서 모든 자바 문법이 사용되므로 자바를 모르는 사람은 개발하지 못하기 때문에 EL 개발.
- EL을 이용하면 자바 코드를 몰라도 getter/setter 호출 가능. 또한 약간의 연산도 가능
> EL을 이용한 출력
- 컨트롤러에서 req.setAttribute("list", dtoList); 와 같이 했다면jsp 파일에서 ${list[0].tno}, ${list[2].title}과 같이 작성가능.
- EL은 출력만을 담당하기 때문에 제어문이나 반복문과 같이 'expression'이 아닌 'statement'를 처리하기 위해서는 JSTL 라이브러리가 필요함
▷ JSTL (JavaServer Pages Standard Tag Library)
- JSP에서 동작하는 새로운 태그들의 묶음
- JSTL은 자바 문법보다 조금 더 간결하게 제어문이나 반복문, 선언문 등을 처리할 수 있고, 확장이 가능하도록 설계함.
- JSTL 사용을 위해서는 라이브러리가 존재해야만 하므로 생성시에 의존성 라이브러리를 추가해야 함.
> JSP 파일에서 JSTL 사용
- JSP에서 JSTL을 이용하기 위해서는 파일 상단에 아래와 같은 태그 관련 설정을 추가해야 함
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
↳ JSP에서 '"<%$ %>"로 작성되는 코드를 directives(지시자)라고 함. → 이 선언이 있어야만 JSP에서 JSTL 이용가능
⦁ <c:forEach>
- JSTL에서 가장 많이 사용하는 반복문 처리. 배열이나 리스트 등을 처리함.
var | EL에서 사용될 변수 이름 |
items | List, Set, Map, Enumeration, Iterator 등의 컬렉션 |
begin/end | 반복의 시작/끝 값 |
<!-- list라는 이름으로 List<xxDTO>가 전달되고 있을때 아래와 같이 사용 -->
<ul>
<c:forEach var="dto" items="${list}">
<li>${dto}</li>
</c:forEach>
</ul>
<!-- begin/end 사용의 경우 -->
<ul>
<c:forEach var="num" begin="1" end="10">
<li>${num}</li>
</c:forEach>
</ul>
⦁ <c:if>, <c:choose>
- JSTL의 제어문. <c:if>의 경우 test라는 속성이 존재하고 속성값으로는 true/false로 나올 수 있는 식이나 변수 등이 들어갈수 있음.
- <c:choose>의 경우 자바의 switch 구문과 비슷한 역할을 함. <c:choose>는 내부에 <c:when test="">, <c:otherwise>를 이용해서 'if ~else if ~ else' 처리를 가능하게 함.
<!-- list의 사이즈가 홀수인지 짝수인지 조건문 (if) -->
<c:if test="${list.size() % 2 == 0}">
짝수
</c:if>
<c:if test="${list.size() % 2 != 0}">
홀수
</c:if>
<!-- (choose) -->
<c:choose>
<c:when test="${list.size() % 2 == 0}">
짝수
</c:when>
<c:otherwise>
홀수
</c:otherwise>
</c:choose>
⦁ <c:set>
- EL과 JSTL을 이용해서 반복문과 제어문 처리시 새로운 변수를 생성해야 하는 경우가 발생함. 이런 경우 <c:set>을 이용해서 변수를 생성하고 사용가능.
- var 속성으로 변수명 지정, value 속성으로 값 지정가능
<c:set var="target" value="5"></c:set>
<ul>
<c:forEach var="num" begin="1" end="10">
<c:if test="${num == target}">
num is target
</c:if>
</c:forEach>
</ul>
자바 웹 개발 워크북 참조
댓글