본문 바로가기

Server Programming/Spring Boot Backend Programming

1장. 웹 프로그래밍 시작

반응형

서블릿과 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 메시지는 헤더와 몸체로 구성되어 있다.

-> 서로 연결되어 있지 않고 일방적인 비연결성의 특징을 가지고 있다. (한번 전송하면 끝. 따라서 많은 양의 통신을 처리 가능)

 

자바 서버 사이드 프로그래밍 고려 사항

  1. 동시 요청 처리
  2. 서버 에러 발생 처리
  3. 데이터 전송 최적화
  4. 분산 환경, 분산 처리 시스템

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이 멀티 스레드에 대해 동시실행 처리를 담당

서블릿은 요청을 처리해 응답하는 목적으로 설계되었다.

-> 서블릿 클래스의 처리과정

  1. 톰캣에 서블릿 처리 경로 호출
  2. 톰캣이 경로에 매핑되어있는 서블릿 클래스 로딩하고 객체 생성
    -> init() 메서드 실행해서 서블릿 호출전 수행해야하는 작업 처리
  3. 생성된 서블릿 객체가 요청과 함께 전달된 파라미터를 HttpServletRequest타입으로 받거나 응답의 경우 HttpServletResponse로 받는다
  4. 서블릿 내부에서 알맞는 메서드 실행하는데 동일 주소의 경우 동일한 객체 사용해 처리
  5. 톰캣 종료시 서블릿의 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>
반응형