서블릿과 JSP 요약
- 서블릿/JSP는 JavaEE의 기술 일부
- 서블릿/JSP를 실행하기 위해 서블릿 컨테이너가 필요(톰캣)
- 서블릿 컨테이너가 서블릿/JSP 객체를 생성 및 생명 주기 관리 담당
- JSP는 내부적으로 서블릿과 같은 방식의 코드로 변환 (.java -> .class)
- JSP는 HTML + 자바코드, 서블릿은 자바코드 + HTML
JSP 사용법
- 서블릿에서 쿼리 스트링이나 파라미터 처리
- JSP는 화면 구성 / 처리 결과
- 브라우저는 JSP 경로를 노출하면 안되며 서블릿 경로만 나타내야 한다.
자바 웹 기본 환경
1. 웹 프로젝트 기본 구조
브라우저 - DB - 서버
브라우저 : 서버 전송 결과 렌더링 / 사용자 화면 조작으로 서버에 요청 및 응답
서버 : 정적 데이터 담당하는 웹 서버와 동적 데이터 담당하는 WAS (보통 WAS는 정적 데이터도 포함)
DB : 영구 데이터 보관하고 운영하며 보통 관계형 DB를 사용
# 프로젝트의 경우 여러 라이브러리를 사용하므로 라이브러리를 관리해주는 빌드도구 - 메이븐이나 그레이들을 사용
# 톰캣 한글 깨짐 발생시 -> Help- Edit Custom VM Options - xmx 설정 (최대 메모리)에 두 가지 설정 추가
-Dfile.encoding=UTF-8
-Dconsole.encoding=UTF-8
#'war'는 Web Application Archive의 약자로 현재 프로젝트를 압축파일로 만들어 톰캣에서 실행할 수 있다.
#변경된 코드 반영하는 톰캣 재시작을 최소화하기 위한 설정
-> Edit Configurations - On Update action, On frame deactivation
2. 서블릿 코드 작성하기
- 톰캣에서 작성하는 자바 코드는 HttpServlet이라는 클래스 상속해서 작성해서 서블릿 클래스 생성한다고 표현한다.
-서블릿에서는 @WebServlet 어노테이션을 통해 브라우저 경로와 해당 서블릿을 연결한다
-화면 구성하는 jsp 파일
웹 기본 동작 방식
1. 브라우저에서 원하는 정보를 요청 / 응답 하는 방식으로 동작한다
HTTP 메서드
GET 방식 : 주소창에 원하는 데이터 적거라 링크 클릭
POST 방식 : 입력 화면에서 내용 작성 후 전송
-> 정적 데이터인지 동적 데이터인지에 따라 다르게 처리한다.
HTTP 프로토콜
-> 프로토콜과 도메인으로 구성된 주소
-> HTTP 메시지는 헤더와 몸체로 구성되어 있다.
-> 서로 연결되어 있지 않고 일방적인 비연결성의 특징을 가지고 있다. (한번 전송하면 끝. 따라서 많은 양의 통신을 처리 가능)
자바 서버 사이드 프로그래밍 고려 사항
- 동시 요청 처리
- 서버 에러 발생 처리
- 데이터 전송 최적화
- 분산 환경, 분산 처리 시스템
JavaEE (Enterprise Edition)
- 서블릿 기술 : 서버에서 동적 요청 응답 처리 API
-JSP : HTML를 이용해 화면 개발
-> 톰캣이 서블릿을 실행하는 환경을 제공해서 서블릿 컨테이너 역할을 수행하고 있다.
따라서 톰캣이 서블릿 코드를 실행하는 주체가 되고, 해당 서블릿 컨테이너는
- 객체를 생성, 호출
- 서블릿 클래스에서 생성하는 객체 관리
- 서블릿 API를 사용해 서블릿/JSP 코드 개발 -> javax로 시작하는 서블릿 API를 사용
-> 해당 API를 통해 서블릿 라이프 사이클을 처리한다
JSP는 자바 서버 페이지라는 뜻으로, 서버에서 동적으로 데이터를 구성하는 기술
-> HTML 코드에 약간의 자바 코드로 HTML 문자열 생성
-> JSP 코드 역시 서블릿으로 변환되어 컴파일되고 실행된다.
GET/POST 처리
GET 방식의 경우 원하는 데이터를 조회하거나, 사용자가 입력하는 화면에 사용한다. -> <from>, <input> 태그에서 자주 사용
#웹 주소창에 '?'로 시작하는 부분은 쿼리 스트링으로, 질의 문자열이라고도 한다.
-> 원하는 데이터를 전달하는데 사용하며 '키=값'형태로 데이터 전달하고, 여러 데이터일 경우 &를 사용해 연결한다.
-> '키=값'형태는 보통 파라미터 이름과 값이라고 부른다.
-> 데이터가 노출되는 방식
POST 방식의 경우 양식의 등록/수정/삭제 처리를 수행 -> action, method 속성에서 자주 사용
-> 주소와 전달하고자 하는 데이터를 분리해서 전송하므로, 개발자 도구에서만 확인 가능하다.
-> HTTP 몸체로 쿼리스트링
-> 데이터가 노출되지 않는다.
# EL(Expression Language) 표현 언어기술로 서버에서 데이터를 출력하는 용도 -> '${param.num1}'
-> 원하는 객체를 이용해 현재 요청에 전달된 파라미터를 추출한다.
#웹의 파라미터는 모두 문자열로 처리해야 한다. -> '${Integer.parseInt(param.num1)}'
Web MVC
서블릿과 JSP의 단점을 해결하기위해
-> 브라우저의 요청은 해당 주소를 처리하는 서블릿에 전달하고 서블릿 내부에서 응답에 필요한 데이터를 추출해 JSP로 전달
-> 결과적으로 EL을 이용해 화면을 처리한다.
따라서, 요청이 발생하면 서블릿의 역할
- 응답에 필요한 데이터 완성
- 다른 객체들 연동 협업 처리
- 상속이나 인터페이스 활용
- 코드 재사용
서블릿이 전송한 데이터를 가지고 JSP의 역할
- EL을 이용해 데이터 출력
- HTML 코드 활용
- 브라우저로 전송
-> 웹 MVC 구조로 변화
MVC 구조
- 브라우저 호출은 HttpServlet을 상속한 컨트롤러 역할의 서블릿을 호출
- JSP는 HttpServlet을 상속한 컨트롤러를 통해서만 JSP에 접근
GET 입력 화면 설계 :
GET방식에만 동작하는 URL 패턴을 컨르롤러에서 작성 ->JSP를 통해 화면처리 -> HTML로 화면 결과 생성
POST 처리 설계 :
<form>태그에서 action 속성을 이용해 해당하는 서블릿을 컨르롤러에서 작성 -> <form>으로 전달되는 데이터를 읽어서 결과 데이터 만들기 -> JSP를 통해 화면처리 -> HTML로 화면 결과 생성 -> HttpServletResponse의 sendRediect()를 통해 다른 화면으로 이동 후 reset
#HTTP 요청과 응답 처리
-HttpServletRequest API 이용해 요청 처리
-HttpServletResponse API 이용해 응답 처리
#PRG패턴 (Post-Redirect-GET)
-POST 방식과 Redirect 결합하는 패턴
-POST 방식으로 처리 요청 -> 주소로 이동 -> GET 방식으로 서버 호출
즉, 내용 작성 후 전송 -> 작성한 내용 처리 후 목록으로 이동 -> 목록 화면 결과 보여줌
Todo 애플리케이션 구현 목록
기능 | 동작 방식 | 컨트롤러(org.zerock.w1.todo) | JSP |
목록 | GET | TodoListController | WEB-INF/todo/list.jsp |
등록(입력) | GET | TodoRegisterController | WEB-INF/todo/register.jsp |
등록(처리) | POST | TodoRegisterController | Redirect |
조회 | GET | TodoReadController | WEB-INF/todo/read.jsp |
수정(입력) | GET | TodoModifyController | WEB-INF/todo/modify.jsp |
수정(처리) | POST | TodoModifyController | Redirect |
삭제(처리) | POST | TodoRemoveController | Redirect |
-> POST방식 기능의 경우 PRG패턴 적용
HttpServlet
- HttpServlet이 제공하는 doGet(), doPost()로 필요한 메소드 오버라이딩
- HttpServlet 상속한 클래스 객체는 톰캣에서 자동으로 객체를 생성 관리
- HttpServlet이 멀티 스레드에 대해 동시실행 처리를 담당
서블릿은 요청을 처리해 응답하는 목적으로 설계되었다.
-> 서블릿 클래스의 처리과정
- 톰캣에 서블릿 처리 경로 호출
- 톰캣이 경로에 매핑되어있는 서블릿 클래스 로딩하고 객체 생성
-> init() 메서드 실행해서 서블릿 호출전 수행해야하는 작업 처리 - 생성된 서블릿 객체가 요청과 함께 전달된 파라미터를 HttpServletRequest타입으로 받거나 응답의 경우 HttpServletResponse로 받는다
- 서블릿 내부에서 알맞는 메서드 실행하는데 동일 주소의 경우 동일한 객체 사용해 처리
- 톰캣 종료시 서블릿의 destory() 메서드 실행
HttpServeltRequest
기능 | 메서드 | 설명 |
HTTP헤더 관련 | getHeaderNames() getHeader(이름 ) |
HTTP헤더 내용들을 찾아내는 기능 |
사용자 관련 | getRemoteAddress( ) | 접속한 사용자의 IP주소 |
요청 관련 | getMethod( ) getRequestURL( ) getRequestURI( ) getServletPath( ) |
GET/POST 정보, 사용자가 호출에 사용한 URL정보 등 |
쿼리 스트링 관련 | getParameter( ) getParameterValues( ) getParameterNames( ) |
쿼리 스트링 등으로 전달되는 데이터를 추출하는 용도 |
쿠키 관련 | getCookies( ) | 브라우저가 전송한 쿠키 정보 |
전달 관련 | getRequestDispatcher( ) | RequestDispatcher 타입 객체를 구한다 -> forward() : 현재까지의 모든 응답 무시 JSP 작성한 내용 전달 |
데이터 저장 | setAttribute( ) | 전달하기 전에 필요한 데이터를 저장하는 경우에 사용 |
HttpServletResponse
기능 | 메서드 | 설명 |
MIME타입 | setContentType( ) | 응답 데이터의 종류를 지정(이미지/html/xml 등) |
헤더 관련 | setHeader( ) | 특정 이름의 HTTP 헤더 지정 |
상태 관련 | setStatus( ) | 404, 200, 500등 응답 상태 코드 지정 |
출력 관련 | getWriter( ) | PrintWriter를 이용해서 응답 메시지 작성 |
쿠키 관련 | addCookie( ) | 응답시에 특정 쿠키 추가 |
전달 관련 | sendRedirect( ) | 브라우저에 이동을 지시 |
모델
뷰에서 JSP, 컨트롤러에서 서블릿, 모델은 로직 처리하는 서비스 계층과 데이터를 처리하는 영속 계층으로 나눌 수 있다.
따라서 3티어로 나눈다면
뷰 계층이 JSP와 서블릿, 서비스 계층이 로직 처리, 영속 계층이 데이터 처리로 나눌 수도 있다.
#DTO(Data Transfer Object)
-계층을 분리할 경우 계층이나 객체 간 데이터 교환이 이루어지는데
-> 여러 데이터를 묶어서 하나의 객체로 전달하는 것 DTO
-> 따라서 일반적으로 Java Beans 형태로 구성한다.
#Java Beans
- 생성자가 없거나 파라미터가 없는 생성자 함수를 가진다
- 속성은 private로 작성
- getter/setter를 제공
- 컨트롤러나 서비스 계층을 구성하기 전에 가장 먼저 구성하는 클래스
TodoDTO
- 멤버 변수
- getter/setter
- toString()
package org.zerock.w1.todo.dto;
import java.time.LocalDate;
public class TodoDTO {
private Long tno;
private String title;
private LocalDate dueDate;
private boolean finished;
public Long getTno() {
return tno;
}
public void setTno(Long tno) {
this.tno = tno;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public LocalDate getDueDate() {
return dueDate;
}
public void setDueDate(LocalDate dueDate) {
this.dueDate = dueDate;
}
public boolean isFinished() {
return finished;
}
public void setFinished(boolean finished) {
this.finished = finished;
}
@Override
public String toString() {
return "TodoDTO{" +
"tno=" + tno +
", title='" + title + '\'' +
", dueDate=" + dueDate +
", finished=" + finished +
'}';
}
}
서비스 객체
- 서비스 객체 메소드들의 파리미터나 리턴타입으로 DTO를 사용한다.
- 서비스 객체는 기능들의 묶음 단위로 실제 처리를 담당한다.
- CRUD
TodoService
- enum타입으로 구성한 서비스 객체로 정해진 수만큼 객체 생성가능하다.
- 싱글톤 패턴 : 정해진 수의 객체는 각각 하나의 객체만 가리키는 패턴을 말한다.
- register() 메서드 : 새로운 TodoDTO 객체를 받아서 확인
- getList() 메서드 : 10개의 TodoDTO객체를 만들어 반환
package org.zerock.w1.todo.service;
import org.zerock.w1.todo.dto.TodoDTO;
import java.time.LocalDate;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public enum TodoService {
INSTANCE;
public void register(TodoDTO todoDTO){
System.out.println("DEBUG............" + todoDTO);
}
public List<TodoDTO> getList(){
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());
return todoDTOS;
}
}
컨트롤러
-화면에 필요한 데이터를 처리하기 위해 컨트롤러가 서비스 객체를 호출한다.
-HttpServletRequest의 setAttribute()로 키-값 형식으로 데이터를 보관한다.
package org.zerock.w1.todo;
import org.zerock.w1.todo.dto.TodoDTO;
import org.zerock.w1.todo.service.TodoService;
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.IOException;
import java.util.List;
@WebServlet(name = "todoListController", urlPatterns = "/todo/list")
public class TodoListController extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("/todo/list");
List<TodoDTO> dtoList = TodoService.INSTANCE.getList();
req.setAttribute("list", dtoList);
req.getRequestDispatcher("/WEB-INF/todo/list.jsp").forward(req,resp);
}
}
뷰
- list.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>List Page</h1>
<ul>
<c:forEach var="dto" items="${list}">
<li>${dto}</li>
</c:forEach>
</ul>
</body>
</html>
-> '${}'은 EL 표현식으로 HTML 태그와 자바스크립트, CSS로 코드와 함께 사용하는 출력용 언어
-> getter/setter 호출과 연산이 가능
JSTL
-출력만 담당하는 EL 표현식 언어를 보완하기 위한 라이브러리로
-반복문이나 제어문, 선언문 처리가 가능하다
JSTL을 사용하기 위해 build.gradle에 의존성 추가
dependencies {
compileOnly('javax.servlet:javax.servlet-api:4.0.1')
testImplementation("org.junit.jupiter:junit-jupiter-api:${junitVersion}")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${junitVersion}")
implementation group: 'jstl', name: 'jstl', version: '1.2'
}
JSTL 사용하기 위해 list.jsp 에 태그 설정
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
-> '<%@ %>'는 지시자며, 추가 설정은 태그 라이브러리 지시자 선언이 있어야 JSTL 사용이 가능하다.
JSTL을 이용한 반복문
- <c:forEach>
- <c:if>, <c:choose>
- <c:set>
TodoService에 특정번호 조회 기능 추가
-식별키를 GET 방식으로 요청
-ex) 상품 번호나 회원 아이디 정보를 전달하고, 서비스 객체로 반환하면 JSP로 전달
public TodoDTO get(Long tno){
TodoDTO dto = new TodoDTO();
dto.setTno(tno);
dto.setTitle("Sample Todo");
dto.setDueDate(LocalDate.now());
dto.setFinished(true);
return dto;
}
컨트롤러
-TodoReadController
package org.zerock.w1.todo;
import org.zerock.w1.todo.dto.TodoDTO;
import org.zerock.w1.todo.service.TodoService;
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.IOException;
@WebServlet(name = "todoReadController", urlPatterns = "/todo/read")
public class TodoReadController extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("/todo/read");
// /todo/read?tno=123
Long tno = Long.parseLong(req.getParameter("tno"));
TodoDTO dto = TodoService.INSTANCE.get(tno);
req.setAttribute("dto", dto);
req.getRequestDispatcher("/WEB-INF/todo/read.jsp").forward(req,resp);
}
}
뷰
-read.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<div>${dto.tno}</div>
<div>${dto.title}</div>
<div>${dto.dueDate}</div>
<div>${dto.finished}</div>
</body>
</html>
'Server Programming > Spring Boot Backend Programming' 카테고리의 다른 글
3장. 세션과 필터, 쿠키와 리스너 (+ 한글 깨짐 처리 / Optional<> / 옵저버 패턴) (0) | 2022.11.27 |
---|---|
2장. 웹과 데이터베이스 (0) | 2022.11.25 |
[Spring 부트 - 운동 클럽 프로젝트] 2. 소셜 로그인 연동 (0) | 2022.10.19 |
[Spring 부트 - 운동 클럽 프로젝트] 1. 스프링 시큐리티 연동 (2) CSRF 와 접근 제한 설정 (0) | 2022.10.19 |
[Spring 부트 - 운동 클럽 프로젝트] 1. 스프링 시큐리티 연동 (1) 기본 설정 (0) | 2022.10.19 |