Servlet

brave_chicken·2024년 4월 16일

잇(IT)생 챌린지

목록 보기
30/90

서버 지우고 다시 까는 법

  • 세 가지 곳에서 지우기
    하단 서비스, 프로젝트 익스플로러, 윈도우 프리퍼런스
  • 다시 깔기
    하단 추가 클릭하고 포트넘버 8005
    톰캣 10.1
    다이나믹 웹모듈 4.0(타이트하게 6.0으로 잡을 필요없음)
    generate web.xml daployment descriptor 체크


DB에서 데이터를 가져와서 화면에 뿌려주는것까지 서블릿이함(이걸 꾸미는게 프론트)

WAS는 웹서버가 아님. Servlet,webapp 실행하는 역할, 웹서버를 포함하고있음

웹서버 역할 : 요청을 받고 분석할수있음, 클라이언트로 응답메세지를 보내기
서블릿 컨테이너는 웹서버에서 넘긴 정보로 뭐해서 Servlet으로 넘기고 실행이됨. 우리가만든 DAO클래스 로그인 호출, 리퀘스트에 쿠키, 데이터, 쿼리스트링,ip 등 넘김,
db요청 실행해줌, db요청 들어가는 건 다 Servlet..

xml로 변환(이기종간의 데이터교환)
자바에는 xml 파서가 있음
xml무거워서 json이 나옴

xml이변경되면 서버를 리스타트해야함

http://192.168.0.152:8088/serverweb/gugu.html

서블릿 개요

실행방법에 따라 자바 클래스를 구분

  • Application : main 메소드를 만들어서 실행
    java 클래스명
    java인터프리터가 public static void main (String[] args)스펙이 메소드를 찾아서 실행
  • Applet : html태그에 삽입(지금은 무거워서 안쓴다.)
  • Servlet

Servlet

  • 클라이언트의 요청을 처리하기 위한 자바기술
    (클라이언트의 요청 : 클릭, 엔터, 마우스포인터 올려놓기 등)
  • 서버에서 클라이언트의 요청을 처리하고 응답할 수 있도록 만들어진 객체
  • 클라이언트가 요청하면 서버에서 실행되면서 <DB에 대한 처리, 서버의 리소스를 이용해서 만들어진 결과>를 클라이언트에 응답
  • 클라이언트가 요청하면 서버가 알아서 요청한 서블릿을 찾아서 실행하므로, 서버가 찾을 수 있는 위치에 있어야한다.

서버가 찾을 수 있는위치
=> Servlet 디렉토리(classes폴더) : 서버가 서블릿을 찾는 위치
C:\backend23\work\webwork.metadata.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\serverweb\WEB-INF
표준화된 폴더 구조의 classes폴더
여기에 없으면 못찾음, 에러응답코드 404뜸

  • 서버 내부에서 우리가 만들어 놓은 서블릿 클래스에서 실행되도록 하려면, 서버가 서블릿이라고 인지할 수 있어야 한다.

    서버 내부에서 우리가 만들어 놓은
    = 서버가 서블릿을 찾아서 자동으로 실행되도록 하려면
    = 서버의 많은 기능들이 서블릿에서 자동실행될 수 있도록 하려면

  • html 문서 내에서 실행된다. 근데 html문서는 자바코드를 작성할 수 없다.
  • 따라서 서버와 약속된 특정 방법을 적용해서 서블릿이 실행되도록 해야한다.
    => 서블릿을 만드는 방법도 정해져있고 서블릿을 실행하는 방법도 정해져있다.
    서버가 서블릿을 생성하고 서블릿의 메소드를 호출함(생성도 호출도 서버가하니, 서버가인식할수있게 규칙에 맞게 작성해야함)
    (서블릿은 만드는데도 호출하는데도 규칙이있다)

1. 서블릿 작성규칙

  • 서버가 찾아서 실행할 수 있도록 규칙에 맞게 서블릿을 작성해야 한다.
    (서버에 셋팅된 타입으로 서블릿을 만들어야함)

1) 표준화된 폴더구조 안에 서블릿 클래스가 위치해야한다

2) 서버가 호출할 것이므로 무조건 public class 로 작성해야한다.

3) 서버가 서블릿 클래스로 인식하고 실행해야 하므로 무조건 상속해야하는 클래스가 존재한다. (63p 서블릿규칙과상속구조 참고)

=> 서블릿클래스가 되기위해서 무조건 서블릿클래스를 상속해야한다.

Servlet --- 인터페이스

GenericServlet --- 추상클래스(서블릿의 일반적인 내용이 정의된 서블릿클래스)

HttpServlet http(https) --- 프로토콜에 특징적인 내용이 정의된 서블릿클래스(쿠키,세션)

MyServlet --- 사용자가 만든서블릿

4) 서버가 호출할 메소드를 오버라이딩(다형성과 통함)

  • 사용자가 임의로 메소드를 만들면 서버가 알수없다.
  • 서버가 자동으로 찾아서 호출하기 위해서 상속받은 클래스가 갖고있는 메소드를 오버라이딩 해서 내가 실행하고싶은 명령문을 구현한다.
  • 서버가 적절한 시점에 호출하는 메소드를 callback메소드라한다.
  • 클라이언트가 요청하면 서버가 요청을 분석을해서 서블릿 디렉토리에 위치한 서블릿을 찾아 적절한 시점에 오버라이딩된 메소드를 찾아서 자동으로 호출한다.
    따라서 상황에 맞게 실행하고싶은 메소드를 오버라이딩해서 내용을 정의한다.

[오버라이딩해야하는 메소드]

  • init : 서블릿객체가 초기화될때 호출
  • service : 클라이언트가 요청할 때 호출(get,post 모든 방식으로 요청해도 실행되는 메소드)
    =>클라이언트의 요청을 처리하는 메소드로 요청을 받고 처리할 내용을 구현
    ex. 로그인, 로그아웃,회원가입,게시판목록보기,장바구니,예약하기...
  • doGet : 클라이언트가 get방식으로 요청할때 호출되는 메소드
  • dePost : 클라이언트가 post방식으로 요청할때 호출되는 메소드
  • destroy : 서블릿객체가 소멸될때 호출
package basic;

import java.io.IOException;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

public class FirstServlet extends HttpServlet{
	public void service(HttpServletRequest req, HttpServletResponse res) 
			throws ServletException, IOException{
		System.out.println("First 서블릿...");
	}
}

5) 서블릿등록

  • 서버가 서블릿을 찾을 수 있도록 정확한 경로를 등록
  • 서버가 요청정보를 분석해서 서블릿디렉토리에서 서블릿을 찾아서 실행할 수 있도록 등록
  • 어떤 요청에 대해서 어떤 서블릿이 실행될지를 명확하게 등록
  • 설정파일에 등록(web.xml)
  • 실제 작업은 annotation을 이용해서 설정
  • web.xml파일은 xml형식의 파일이므로 사용할 엘리먼트가 이미 정의되어있고 작성규칙이 정해져있으므로 맞게 작업해야한다.
    작성규칙 => dtd - xml안에서 정의하고 사용할 엘리먼트의 명세(엘리먼트 순서, 타입, 값, 하위엘리먼트...)

(1) 서블릿을 등록

실제 어떤 패키지에 어떤 클래스를 실행할 것인지 등록 : 무엇을

<servlet>
  	<servlet-name>서블릿명(alias)</servlet-name>
  	<servlet-class>서블릿의 실제 클래스명과 위치(패키지명)</servlet-class>
</servlet>

ex. basic패키지의 FirstServlet을 first 이름으로 등록

<servlet>
  	<servlet-name>first</servlet-name><!-- alias느낌, 이름붙여주기 -->
  	<servlet-class>basic.FirstServlet</servlet-class>
</servlet>

(2) 서블릿을 매핑

등록된 서블릿을 어떻게 요청했을때 실행할 것인지를 등록(어떤 url로 요청할 것인지)
반드시 < servlet>엘리먼트 다음에 정의해야 한다.
< servlet>엘리먼트와 한쌍으로 정의해야 한다.
먼저 등록한 서블릿을 어떻게 요청해서 실행할 것인지 등록

  <servlet-mapping>
  	<servlet-name>위에서 정의한 서블릿 이름</servlet-name>
  	<url-pattern>요청할 서블릿의 path(경로이므로 반드시 /로 시작하거나 .으로 시작)</url-pattern>
  </servlet-mapping>

ex. first라는 이름으로 등록된 서블릿을 /first.multi로 요청하면 실행되도록 등록

  <servlet-mapping>
  	<servlet-name>first</servlet-name>
  	<url-pattern>/first.multi</url-pattern>
  </servlet-mapping>

서블릿등록-서블릿매핑이 세트

2. 서블릿을 요청하는방법

  • 서블릿을 어떻게 실행해야 하는지 알 수 있어야한다.
  • html형식의 문서 내에서 서블릿을 요청하므로 규칙이 있다.
    http://서버ip:port/context명/서블릿매핑명
    서블릿매핑명=>web.xml에 < url-pattern>에 등록하거나 annotation에 설정한 경로
    http://192.168.0.152:8088/serverweb/first.multi
    프로토콜------ip------port--context명--매핑명
  • 어떤 방법(rest api에서의 요청은 제외)으로 요청하냐에 따라 get방식과 post방식으로 요청할 수 있다.

1) get방식으로 요청

=> 클라이언트가 입력한 내용이 요청헤더에 저장되어 서버로 전송되는 방식
주로 서버에 저장된 데이터를 가져오는 경우 사용

(1) 주소표시줄에 직접 입력해서 요청하는 방식

=> 테스트용으로 사용되거나 첫번째 페이지에서 요청하는 경우
http://192.168.0.152:8088/serverweb/gugu.html

(2) 하이퍼링크로 요청

=>텍스트나 이미지를 클릭해서 서블릿을 요청하는 경우
< a href="/serverweb/life.do">< /a>

(3)< form>태그의 method속성에 get을 정의하고 submit버튼을 눌러 요청하는 경우

=> < form>태그의 submit버튼을 누르면 action에 정의한 application이 요청되어 실행되며 양식태그를 통해서 클라이언트가 입력한 혹은 선택한 모든 name과 value가 전송된다.
양식태그를 통해서 클라이언트가 입력한 => < form>< /form>사이의 모든 양식태그를 통한 작업
이때 method속성에 정의한 요청방식으로 요청된다.

2) post방식으로 요청

=> form태그의 method에 post를 정의하고 submit버튼을 눌러 요청하는 경우

3) 자바스크립트로 get/post로 요청하기

3. 서블릿에서 요청정보추출

http://localhost:8088/serverweb/life.do?id=1234&pass=1234
서블릿객체가 생성되고 쓰레드로 service(doGet,doPost)가 실행될때 서버가 클라이언트의 요청정보를 HttpServletRequest객체로 만들어서 매개변수에 호출할 때 전달한다.
request객체가 갖고있는 많은 메소드를 이용해서 요청정보를 추출할 수 있다.

실습

xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">
  <display-name>serverweb</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.jsp</welcome-file>
    <welcome-file>default.htm</welcome-file>
  </welcome-file-list>
  
  <servlet>
  	<servlet-name>first</servlet-name><!-- alias느낌, 이름붙여주기 -->
  	<servlet-class>basic.FirstServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>first</servlet-name>
  	<url-pattern>/first.multi</url-pattern>
  </servlet-mapping>
  
   <servlet>
  	<servlet-name>gugu</servlet-name>
  	<servlet-class>basic.SecondServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>gugu</servlet-name>
  	<url-pattern>/gugu.html</url-pattern>
  </servlet-mapping>
  
   <servlet>
  	<servlet-name>life</servlet-name>
  	<servlet-class>basic.LifeCycleTestServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>life</servlet-name>
  	<url-pattern>/life.do</url-pattern>
  </servlet-mapping>
  
</web-app>

FirstServlet

public class FirstServlet extends HttpServlet{
	public void service(HttpServletRequest req, HttpServletResponse res) 
			throws ServletException, IOException{
		System.out.println("First 서블릿...");
	}
}

SecondServlet

public class SecondServlet extends HttpServlet{
	public void service(HttpServletRequest req, HttpServletResponse res) 
			throws ServletException, IOException{
		for(int i=1;i<=9;i++) {
			System.out.println("7 * "+i+"="+7*i);
		}
	}
}


console창에 찍힘, 웹에서 새로고침 할때마다 다시찍힘(웹은 비어있음)

LifeCycleTestServlet

public class LifeCycleTestServlet extends HttpServlet{
	public LifeCycleTestServlet(){
		System.out.println("LifeCycleTestServlet생성");
	}
	
	@Override
	public void init() throws ServletException {
		System.out.println("init()");
	}
	
	@Override
	public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		System.out.println("service():"+req.getMethod());
		if(req.getMethod().equals("GET")) {
			doGet(req, res);
		}else {
			doPost(req, res);
		}
	}
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		System.out.println("doGet()");
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		System.out.println("doPost()");
	}

	@Override
	public void destroy() {
		System.out.println("destroy()");
	}
}

새로고침하면 밑에부분만 다시 찍힘


html태그로 서블릿 요청

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h2>서블릿을 요청하는 방법</h2>
	<h2>1. get 방식으로 요청</h2>
	<h3>1)하이퍼링크로 요청하기</h3>
	<a href="http://192.168.0.152:8088/serverweb/first.multi">서블릿요청</a>
	<a href="/serverweb/gugu.html">구구단요청</a><!-- 절대경로 -->
	<a href="/serverweb/life.do">
	<img alt="" src="/serverweb/images/c1.jpg" width="300">
	</a>
	<a href="/serverweb/life.do">
	<img alt="" src="/serverweb/images/c2.jpg" width="300">
	</a>
	<a href="/serverweb/life.do">
	<img alt="" src="/serverweb/images/bts.jpg" width="300">
	</a>
	<h3>2) submit버튼으로 요청 - form태그의 method속성을 get으로 정의</h3>
	<form method="get" action="/serverweb/life.do">
		아이디 : <input type="text" name="id"/><br/>
		패스워드 : <input type="password" name="pass"/><br/>
		<input type="submit" name="로그인"/>
	</form>
	
	<h3>메소드를 생략하면 겟방식으로 요청</h3>
	<form action="/serverweb/life.do">
		아이디 : <input type="text" name="id"/><br/>
		패스워드 : <input type="password" name="pass"/><br/>
		<input type="submit" name="로그인"/>
	</form>
	
	<h3>2. post방식으로 요청하기</h3>
	<form method="post" action="/serverweb/life.do">
		아이디 : <input type="text" name="id"/><br/>
		패스워드 : <input type="password" name="pass"/><br/>
		<input type="submit" name="로그인"/>
	</form>
</body>
</html>

자바스크립트로 서블릿 호출하기

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
	<script type="text/javascript">
		function calltest1() {
			//get방식으로 요청
			location.href="/serverweb/life.do";
		}
		function calltest2() {
			//post방식으로 요청
			//버튼이나 이미지를 클릭했을때 submit버튼을 누른 것과 같은 동일한 효과를 주기 위해서 사용하는 방법
			let loginform = document.getElementById("myform");
			loginform.action = "/serverweb/life.do";//서블릿 path
			loginform.method = "Post";//요청방식
			loginform.submit();
		}
	</script>
</head>
<body>
	<form id="myform">
		<input type="text" name="id">
		<input type="button" value="자바스크립트로 서블릿 호출하기-get" onclick="calltest1()">
		<input type="button" value="자바스크립트로 서블릿 호출하기-post" onclick="calltest2()">
	</form>
</body>
</html>

Servlet을 등록하기 위한 annotation

  • @WebServlet은 서블릿을 등록하기 위한 어노테이션
  • @WebServlet의 속성을 정의할 수 있다.
  • @WebServlet의 name속성은 서블릿의 이름을 등록하기 위한 속성
  • @WebServlet의 urlPatterns은 서블릿을 요청하기 위한 path를 등록, 여러개를 등록할 수 있어서 배열{}로 관리
  • 어노테이션을 이용해서 서블릿을 등록하는 것도 xml에 내용을 변경하는 것과 동일하게 서버를 restart
  • 서블릿명이 중복되면 실행되지 않는다.
@WebServlet(name = "anno_servlet",urlPatterns = {"/test/anno.html"})
public class AnnotationServlet extends HttpServlet{

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
			throws ServletException, IOException {
		System.out.println("어노테이션으로 서블릿 등록하기");
	}
}



login.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form method="post" action="/serverweb/paramTest">
		아이디 : <input type="text" name="id"/><br/>
		패스워드 : <input type="text" name="pass"/><br/>
		<input type="submit" name="로그인"/>
	</form>
</body>
</html>

ParamTestServlet

@WebServlet(name = "paramTest", urlPatterns = { "/paramTest" })
public class ParamTestServlet extends HttpServlet {

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//요청정보에 한글 설정하기(한글 인코딩 적용)
		//요청정보를 추출하기 전에 한글 인코딩을 등록
		request.setCharacterEncoding("UTF-8");
		//응답정보를 생성해서 response하기
		//1.응답데이터의 형식과 인코딩을 설정
		//=>응답정보에 한글을 설정 - 출력될 응답의 형식을 지정(MIME타입 - text/html)
		response.setContentType("text/html;charset=UTF-8");
		//2.클라이언트에 응답할 스트림객체를 생성(네트워크통신에서 소켓으로부터 통신할 스트림을 얻는 과정과 동일한 과정)
		PrintWriter out = response.getWriter();
		String id = request.getParameter("id");
		String pass = request.getParameter("pass");
		System.out.println("아이디:"+id);
		System.out.println("패스워드:"+pass);
		
		out.print("<h1>응답데이터</h1>");
		out.println("<hr/>");
		out.print("<h3>아이디:"+id+"</h3>");
		out.print("<h3>패스워드:"+pass+"</h3>");
	}

}


postForm.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
  </head>
  <body>
    <h1>customer</h1><br/>
    <form method="post" action="/serverweb/post.do">
      <table>
        <tr>
          <td>user ID</td>
          <td><input type="text" name="userId" size="10"/></td>
        </tr>
        <tr>
          <td>name </td>
          <td><input type="text" name="userName" size="10"/></td>
        </tr>
        <tr>
          <td>password </td>
          <td><input type="password" name="passwd" size="10"/></td>
        </tr>
        <tr>
          <td>gender</td>
          <td><input type="radio" name="gender" value="male"/>male
              <input type="radio" name="gender" value="female"/>female</td>
        </tr>
        <tr>
          <td>JOB</td>
          <td><select name="job">
                <option value="salary">Salary</option>
                <option value="houseKeeper" selected >HouseKeeper</option>
                <option value="student">Student</option>
                <option value="other">Other</option>
              </select></td>
        </tr>
        <tr>
          <td>Favorites</td>
          <td><input type="checkbox" name="item" value="시사"/>시사
              <input type="checkbox" name="item" value="경제"/>경제
              <input type="checkbox" name="item" value="정치"/>정치
              <input type="checkbox" name="item" value="연예"/>연예
              <input type="checkbox" name="item" value="스포츠"/>스포츠
              <input type="checkbox" name="item" value="광고"/>광고</td>
        </tr>
      </table><p/>
      <input type="submit" value="입력완료"/>
      <input type="reset" value="재입력"/>
    </form>
  </body>
</html>

PostFormServlet

@WebServlet(name = "post", urlPatterns = { "/post.do" })
public class PostFormServlet extends HttpServlet {
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//한글셋팅과 출력스트림 구하기
		request.setCharacterEncoding("UTF-8");
		response.setContentType("text/html;charset=UTF-8");
		
		PrintWriter out = response.getWriter();
		
		//클라이언트가 입력한 요청정보를 추출
		String userId = request.getParameter("userId");
		String userName = request.getParameter("userName");
		String passwd = request.getParameter("passwd");
		String gender = request.getParameter("gender");
		String job = request.getParameter("job");
		String[] item = request.getParameterValues("item");
		System.out.println("아이디:"+userId);
		System.out.println("성명:"+userName);
		System.out.println("패스워드:"+passwd);
		System.out.println("성별:"+gender);
		System.out.println("직업:"+job);
		System.out.println("좋아하는 항목:"+item);
		
		//응답메세지를 생성
		out.print("<h1>customer</h1>");
		out.println("<hr/>");
		out.print("<h3>아이디:"+userId+"</h3>");
		out.print("<h3>성명:"+userName+"</h3>");
		out.print("<h3>패스워드:"+passwd+"</h3>");
		out.print("<h3>성별:"+gender+"</h3>");
		out.print("<h3>직업:"+job+"</h3>");
		out.print("<h3>좋아하는 항목:");
		for(String it:item) {
			out.print(it+", ");
		}
		out.print("</h3>");
	}
}


https://blog.naver.com/heaves1/223418520792

calc.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form method="post" action="/serverweb/calc.do">
		<input type="text" name="num1"/>
		<select name="method">
			<option value="+">+
			<option value="-">-
			<option value="*">*
			<option value="/">/
		</select>
		<input type="text" name="num2"/>
		<input type="submit" value="전송"/>
	</form>
</body>
</html>

CalcServlet

@WebServlet(name = "calc", urlPatterns = { "/calc.do" })
public class CalcServlet extends HttpServlet {
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		response.setContentType("text/html;charset=UTF-8");
		PrintWriter out = response.getWriter();
		
		int num1 =	Integer.parseInt(request.getParameter("num1"));
		int num2 = Integer.parseInt(request.getParameter("num2"));
		String method = request.getParameter("method");
		
		int result=0;
		
		switch(method) {
		case "+" : 
			result=num1+num2;
			break;
		case "-" : 
			result=num1-num2;
			break;
		case "*" : 
			result=num1*num2;
			break;
		case "/" : 
			result=num1/num2;
			break;
		}
		out.print("<h1>계산결과</h1>");
		out.print("<hr/>");
		out.print("<h3>num1의 "+num1+"과 num2의 "+num2+"를 "+method+" 연산한 결과는 "+result+"</h3>");
	}
}

7장,11장 미리보고오기

4. 서블릿의 lifecycle

66p~ 사이클, 69p 그림 더 쉽게 있는듯
68,69표시한곳 기억하기 정리하기
70p 콜백메소드->>디스트로이?
저장을 하면 이클립스는 컴파일이 돼서 서블릿 객체 메모리에 리로딩됨

5. 서블릿과 DB연동(4,7장)

본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.

0개의 댓글