프로그래밍

[Web] 웹 사이트 개발(Tomcat, Servlet)

RainIron 2021. 6. 16. 18:23
반응형

※ 개요

- 웹 서버가 실행할 수 있는 자바 프로그램

- 모든 웹 서비스는 웹 서버로부터 웹 클라이언트에게 정보 제공

- 정보 제공 형태는 HTML, CSS, Java Script(클라이언트로 도착해서 실행되는 코드)

- 웹 브라우저가 프로그램이 실행되는 플랫폼이 되어가는 추세

 

* 정보 교환 과정

- 웹 브라우저(웹 클라이언트)를 사용해 구글 웹 서버에 접속한다.

- 웹 브라우저 주소창에 http://google.com을 입력하고 엔터(웹 서버 접속)

- Domain Name: google.com

* 구성

- 물리적인 웹 서버 컴퓨터

- 접속 요청에 응답할 웹 서버 소프트웨어

- 웹 클라이언트

- 웹 서버 간의 통신 규약(HTTP)

* Web Server SW 종류

- Apache Web Server: Java를 실행할 수는 없다.

- Tomcat: Java를 실행할 수 있는 웹 서버

  설치 후, 서버 안에 Java 프로그램을 만들어 놓으면 웹 서버에 요청이 들어오면 실행이 가능하도록 한다.

  웹 서버에서 Java가 실행되기 위해서 Servlet 클래스, JSP(Java Server Page)가 필요하다.

  웹 클라이언트의 요청이 있을 때만 서버측 프로그램이 실행되어 그 결과가 클라이언트에 출력된다.

  예) 빅데이터 프로그램, 데이터베이스 활용 프로그램, 게시판 프로그램 

 

* 동적/정적 컨텐츠

- HTML: 내용 그대로 화면에 표시되는 정적인 콘텐츠를 보여주고자 할 때 ex) 단순 화면 출력

- 조건(상황)에 따라 다른 화면을 보여줄 때, 동적 콘텐츠, ex) 로그인(아이디, 암호 입력)


※ Tomcat 설치

- 웹 애플리케이션 서버

- 웹 서버와 연동하여 실행할 수 있는 자바 환경을 제공하여 자바 서버 페이지(JSP)와 자바 서블릿이 실행할 수 있는 환경을 제공한다.

- 대규모 사용자가 사용하는 시스템을 구축하려면 웹 서버와 연동되는 안정적인 시스템을 구축해야 한다. 

- Java Servlet을 사용하게 하기 위한 WAS

- JSP와 Servlet을 구동하기 위한 서블릿 컨테이너 역할을 수행

 

www.apache.org 에서 Tomcat 다운로드

자바 버전에 맞춰 설치

- 실행 여부 파악: http://localhost:8080 접속

 

로그인을 하라고 하는 오류가 발생

위와 같은 로그인창이 나오는 이유는 이미 8080 포트로 실행되는 프로그램이 있는 것이라 추측

따라서, Tomcat의 conf 폴더에 있는 server.xml에서 8080으로 지정된 번호를 8081로 변경하고 접속

나도 뜬다!

* Eclipse 연동(메뉴 창 순서 [Window]-[Show view]-[Servers])

설치한 Tomcat 위치를 지정하여 Eclipse와 연결

기본으로 만든 HTML문서를 실행했더니 오류가 발생!

" The server cannot be started because one or more of the ports are invalid. Open the server editor and correct the invalid ports. "

Tomcat admin port: 8005 번으로 변경한다

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My Web</title>
</head>
<body>
	<h1>Hello World!</h1>
</body>
</html>

짜잔!

위와 같이 실행한 코드가 외부 브라우저에서 보이고 싶은 경우

메뉴 창에 [Window]-[Web Browser]-[원하는 브라우저창]을 선택한다.


※ Servlet 생성 및 활용 (웹브라우저에서 Java Class를 호출)

- Servlet

  1) 자바를 사용하여 웹을 만들기 위해 필요한 기술

  2) 클라이언트의 요청을 처리하고 그 결과를 클라이언트에게 전송하기 위해 필요한 프로그램

  3) 자바를 사용하여 웹페이지를 동적으로 생성하는 서버측 프로그램 혹은 그 사양

  4) Java Code 안에 HTMl을 포함하고 있음(JSP는 HTML 문서 안에 Java Code가 있음)

  5) 외부 요청마다 프로세스보다 가벼운 스레드로써 응답(가벼움)

  6) 웹 기반 요청에 대해 동적으로 처리가 가능한 클래스

  7) 애플리케이션 컴포넌트 중에 Controller 역할

  8) CGI(Common Gateway Interface): 웹 서버 상에서 사용자 프로그램을 동작시키기 위한 프로그램

 

- 동작 과정

  1) Client의 URL 요청(Browser로 입력)

  2) HTTP 요청을 처리하기 위한 HttpServletRequest request, HttpServletResponse response 생성

  3) 요청한 URL을 Deplyment Descriptor 분석을 통해 요청된 Servlet 클래스를 찾음

  4) 서블릿 컨테이너에서 실행된 적이 있거나 메모리에 생성된 인스턴스가 있는지 확인

    if) 처음 then) 인스턴스를 새로 생성한 후, init() 호출, 초기화 후 스레드 생성

    if) !처음 then) 기존 인스턴스에 스레드 생성

  (cf) 서블릿 컨테이너 당 하나의 서블릿 인스턴스만 존재

  5) 각 스레드의 service(), doGet(), doPost() 호출

    => 2)의 request, response 객체에 데이터 전달

  6) service(), doGet(), doPost()를 통해 생성된 결과물이 response에 전달

  7) response 객체가 서블릿 컨테이너에서 HTTP 형태로 바뀌어 웹 서버로 전송

  8) request, response 객체의 메모리 소멸 및 스레드 종료

 

웹 브라우저에서 요청할 수 있게 URL Mapping이 되어있다.
service 메서드가 가장 먼저 실행됨(브라우저에게 데이터를 제공하는 기능)

* service()로 요청한 클라이언트에게 데이터 제공

package com.tjoeun;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/MyServlet")
public class MyServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setCharacterEncoding("utf-8");
		response.setContentType("text/html; charset=utf-8");
		PrintWriter out = response.getWriter();
		out.println("Hello World!");
		out.flush();
	}

}

* Servlet 예제(구구단 1)

- request.getParameter를 사용해 원하는 변수를 입력받을 수 있다.

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/MyServlet")
public class MyServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setCharacterEncoding("utf-8");
		response.setContentType("text/html; charset=utf-8");
		PrintWriter out = response.getWriter();
		int dan = 0;
		String gg = "";
		String strDan = request.getParameter("dan");
		
		if(strDan != null && !strDan.equals("")) {
			dan = Integer.parseInt(strDan);
			
			for(int i = 1; i<10 ; i++) {
				gg += String.format("%d * %d = %d<br>", dan, i, dan*i);
			}
		}
		
		out.println(gg); // Web Browser 출력
		out.flush();
	}

}

입력하고자 하는 변수는 url 다음에 "?"다음에 변수 입력

* Servlet 예제(구구단 2)

- HTML 문법을 도입해 화면에 출력

package com.tjoeun;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/MyServlet")
public class MyServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setCharacterEncoding("utf-8");
		response.setContentType("text/html; charset=utf-8");
		PrintWriter out = response.getWriter();
		int dan = 0;
		String gg = "";
		String strDan = request.getParameter("dan");
		
		if(strDan != null && !strDan.equals("")) {
			dan = Integer.parseInt(strDan);
			
			for(int i = 1; i<10 ; i++) {
				gg += String.format("%d * %d = %d<br>", dan, i, dan*i);
			}
		}
		
		String html = "<!doctype html>";
		html += "<html>";
		html += "<head><title>Gugudan</title></head>";
		html += "<body><h3>구구단 보기</h3>";
		html += "<div id = 'gg'>"+ gg + "</div>";
		html += "</body></html>";
		
		out.println(html); // Web Browser 출력
		out.flush();
	}

}

위의 코드를 보면, Java 코드와 HTML 코드가 한 파일에 써있는 것을 알 수 있다. 이럴 경우, 프론트엔드와 백엔드의 분업이 어려워진다. 따라서 이를 위해, JSP를 활용한다.

구구단의 경우

1) 구구단을 계산하여 결과를 리턴하는 파트 - 일반 JAVA Class 생성, 객체 활용(Business Logic)

2) 리턴한 결과를 HTML 형식으로 출력하게 만들 파트 - JSP(Presentation Logic)

3) 1), 2)를 연결할 파트 - Servlet(연결)

 

(JSP: Java Server Pages, HTML내에 자바 코드를 삽입하여 웹 서버에서 동적으로 웹 페이지를 생성하여 웹 브라우저에 돌려주는 서버 사이드 스크립트 언어)

(JSP <-> Java Script)

-> Java Script는 클라이언트에서 실행되는 스크립트 언어로 동적 웹페이지 표현, Java와 별개이며 웹 브라우저에서 바로 실해오디기 때문에 페이지의 새로고침이 없음

-> JSP는 서버측에서 실행되는 Java 기반의 언어(웹 브라우저의 요청에 따라 Servlet 활용)

 

* Servlet 예제(구구단 3)

= (1)Servelt 사용 Java File + (2)Java Gugudan Class File + (3)JSP File

(1)Servelt 사용 Java File

package com.tjoeun;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;

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 com.tjoeun.bean.GuguService;

@WebServlet("/MyServlet")
public class MyServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	// response에는 응답 받은 사용자의 주소가 들어있음
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setCharacterEncoding("utf-8");
		response.setContentType("text/html; charset=utf-8");
		PrintWriter out = response.getWriter();
		
		// Business Logic
		GuguService gs = new GuguService(request);
		List<String> list = gs.getGugu();
		
		// Presentation Logic
		request.setAttribute("data", list);
		// getServletContext(): Servlet 실행환경
		// getRequestDispathcer(): 파라미터 위치로 forward 메서드를 활용해 request, response를 전달
		getServletContext().getRequestDispatcher("/gugu.jsp").forward(request, response);
	}

}

- getServletContext(): Servlet 실행환경

- getRequestDispatcher(): 파라미터 위치로 forward 메서드를 활용해 request, response를 전달

 

(2)Java Gugudan Class File

package com.tjoeun.bean;

import java.util.*;
import javax.servlet.http.HttpServletRequest;

public class GuguService {
	
	private HttpServletRequest request;
	
	public GuguService(HttpServletRequest request) {
		this.request = request;
	}
	
	public List<String> getGugu() {
		int dan = 0;
		String strDan = request.getParameter("dan");
		
		ArrayList<String> list = new ArrayList<>();
		
		if(strDan != null && !strDan.equals("")) {
			dan = Integer.parseInt(strDan);
			
			for(int i = 1; i<10 ; i++) {
				list.add(String.format("%d * %d = %d", dan, i, dan*i));
			}
		}
		return list;
	}
}

(3)JSP File(Tomcat에 의해 Servlet으로 실행)

<%@ page import = "java.util.List"%>
<%@ page contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
    
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Gugudan</title>
</head>
<body>
	<div id = 'gugu'>
		<% // Scriptlet(Java Code 영역)
			List<String> list = (List<String>)request.getAttribute("data");
			if(list!=null && list.size() != 0){
				for(int i = 0; i<list.size(); i++){ %>
					<%=list.get(i) %> <br>
<% 			// '<%='(Expression)는 브라우저에 출력하는 역할
				}
			}
		%>
	</div>
</body>
</html>

 

=> 3가지 파일 ≒ MVC 패턴

- Model(Java Class File, POJO(Plain Object Java Object))

- View(JSP file)

- Controller(Servlet))

 

* 위 패턴의 장점: 분업이 쉽고, 유지보수에 좋다.

* 위 패턴의 단점: 시간이 오래 걸리고, 단순한 업무에는 비효율적, 개발 비용이 많이 든다.

* 사용하는 이유: 개발 비용보다 유지보수 비용이 더 많이 드는 것이 프로그램 개발할 때 당연시 되기 때문에, 유지보수 비용을 낮추는 것을 목표로 프로그램을 개발한다. 따라서 유지보수 비용을 낮출 수 있는 MVC 패턴을 주로 사용한다.

 

* Servlet 예제(구구단 4) - JSP File로만 만들기

<%@ page contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<%
	String strDan = request.getParameter("dan");
	int dan = 0;
	String gugu = "";
	
	if(strDan != null && !strDan.equals("")){
		dan = Integer.parseInt(strDan);
		for(int i = 1; i<=9; i++){
			gugu += String.format("%d * %d = %d<br>", dan, i, dan*i);
		}
	}
	
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
	#gugu{ color: blue;}
</style>
<title>Controller를 포함한 구구단 보기</title>
</head>
<body>
<h2>요청한 구구단 보기</h2>
<div id = 'gugu'>
	<%=gugu	%>
</div>
</body>
</html>

* Servlet 예제(구구단 5) - JSP File, Java Class File을 활용해 똑같이 만들기

<%@page import="java.util.List"%>
<%@page import="com.tjoeun.bean.GuguService"%>
<%@ page contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<%
	GuguService gs = new GuguService(request);
	List<String> list = gs.getGugu();
	String gugu="";
	
	for(int i = 0; i< list.size(); i++){
		gugu += list.get(i) +"<br>";
	}
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
	#gugu{ color: blue;}
</style>
<title>Controller를 포함한 구구단 보기</title>
</head>
<body>
<h2>요청한 구구단 보기</h2>
<div id = 'gugu'>
	<%=gugu	%>
</div>
</body>
</html>

* Servlet 예제(구구단 6) - JSP File, Java Class File을 활용해 똑같이 만들기 + 다른 객체 생성 방식 도입

<%@page import="java.util.List"%>
<%@page import="com.tjoeun.bean.GuguService"%>
<%@ page contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<jsp:useBean id = "gs" class = "com.tjoeun.bean.GuguService" scope="page"/>    
<%
	// GuguService gs = new GuguService(request);
	// 위의 <jsp:useBean id = "gs" class = "com.tjoeun.bean.GuguService" scope="page"/>이 같은 역할을 수행
	// 단, 해당 클래스의 기본 생성자, get, set method가 있어야 한다.
	
	// gs.setRequest(request);가 있어야 기본 생성자 생성이 완료된다.
	// 이 방법으로 할 경우, 위의 scope에서 사용 범위를 조절할 수 있다는 장점이 있다.
	gs.setRequest(request);
	List<String> list = gs.getGugu();
	String gugu="";
	if(list != null && list.size() != 0){
	for(int i = 0; i< list.size(); i++){
		gugu += list.get(i) +"<br>";
		}
	}
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
	#gugu{ color: blue;}
</style>
<title>Controller를 포함한 구구단 보기</title>
</head>
<body>
<h2>요청한 구구단 보기</h2>
<div id = 'gugu'>
	<%=gugu	%>
</div>
</body>
</html>

(JSP file 추가 내용)

<jsp:useBean id = "gs" class = "com.tjoeun.bean.GuguService" scope="page"/>    

(Class file 추가 내용)

public GuguService() {
}
    
public HttpServletRequest getRequest() {
		return request;
}

public void setRequest(HttpServletRequest request) {
		this.request = request;
}

(JSP file 변경 내용)

// GuguService gs = new GuguService(request);
gs.setRequest(request);

 

<jsp:useBean id = "gs" class = "com.tjoeun.bean.GuguService" scope="page"/> 은 GuguService gs = new GuguService(request);과 같은 역할을 수행한다.

이 방법을 사용할 경우, 위의 scope에서 사용 범위를 조절할 수 있다는 장점이 있다.

 


※ Post 방식

이전까지 주소창에 입력한 방식은 Get방식이고, 다음부터 진행할 방식은 Post 방식이다.

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>구구단 요청 폼</title>
	<style type= "text/css">
		form {border: 1px solid black;
			width: 300px;
			padding: 10px;}
		button {margin-top: 10px;}
	</style>
</head>
<body>
	<form action="cont.jsp" method="post">
		구구단 수<input type="text" name = "dan" placeholder = "단수 입력">
		<button type="submit">구구단 보기</button>
	</form>
</body>
</html>

위 파일을 실행하면, 주소창에 입력하지 않아도 파일이 실행된다.

 

* 예제) 로그인 창 제작

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>로그인 폼</title>
</head>
<body>
	<h3>로그인</h3>
	<form action="/login" method="post">
		<div>
			ID: <input type = "text" name = "id">
		</div>
		<div>
			Password: <input type = "password" name = "pwd">
		</div>
		<div>
			<button type = "submit">확인</button>
		</div>
	</form>
</body>
</html>

반응형