Dev/JSP & Servlet

Servlet - 서블릿 구조, EL, JSTL, DBCP

창문닦이 2019. 2. 25. 18:47

서블릿 처리구조

클라이언트


웹서버로 html 요청, 서블릿 요청



웹서버


일반적인 html 요청은 웹 서버에서 해당 html을 찾아 응답

서블릿 요청시 서블릿 컨테이너에게 전달

서블릿 컨테이너


해당 서블릿을 찾아 실행 및 처리결과를 응답

- HttpServletRequest 및 HttpServletResponse 객체 생성

- 서블릿 클래스 로딩 및 객체 생성

- 요청에 따라 Servlet class 의 doGet() 또는 doPost() 메소드 호출

서블릿 클래스 상속 구조

GenericServlet 클래스 : 일반적인 네트워크 프로토콜을 위한 추상 서블릿

프로토콜 독립적. 모든 유형의 프로토콜을 처리할 수 있다. (HttpServlet 클래스의 상위 클래스)

Service() 메소드만 지원한다. ServletConfig ,Servlet ,Serializable 인터페이스를 구현하는 추상클래스


ServletConfig 인터페이스 : 서블릿 환경을 위한 인터페이스

Servlet 인터페이스 : 서블릿 기능구현을 위한 인터페이스

Serializable 인터페이스 : 서블릿 직렬화를 위한 인터페이스


HttpServlet 클래스 : Http 프로토콜을 위한 http전용 서블릿

프로토콜 의존적. http 특정 프로토콜만 처리할 수 있다.

doGet (), doPost (), doHead () ,doPut (), doOptions (), doDelete (), doTrace () 메서드를 지원한다.



HttpServletRequest와 HttpServletResponse 

HttpServletRequest

클라이언트의 모든 요청정보

요청HTTP 헤더 정보

서블릿으로 전달된 파라미터 정보

InputStream 형태의 클라이언트로부터 전송된 데이터

세션(Session)과 쿠키(Cookie)와 같은 기타 정보

HttpServletResponse

클라이언트로 보내지는 응답정보

응답HTTP 헤더정보

OutputStream 형태의 클라이언트로 전송되는 데이터

세션과 쿠키설정


서블릿 요청 처리 메서드 호출

1. 클라이언트의 서블릿 링크 클릭

2. 웹서버에서는 들어온 요청이 서블릿이면 컨테이너에게 전달

3. 컨테이너에서는 HttpServletRequest , HttpServletResponse 객체 생성

4. HttpServletRequest,HttpServletResponse를 매개변수로 하는 service 메소드 호출

5. 데이터 전송방식에 따라 doGet(), doPost() 호출

6. 응답결과 전달


데이터를 전송하는 방식

1 .form양식 - getParameter 메소드 활용

2. input type hidden

3. Session (이 세가지 1~3는 모두 jsp에서 jsp로 데이터를 전송해주는 방식)

4. 클래스로 만들어진 데이터를 jsp로 전달하는 방법

(서블릿 활용 Request.setAttribute, / Request.getAttribute  이 경우에는 형변환 작업 반드시 필요.)


서블릿의 장점

1. Class 파일을 만들어 여러 jsp파일의 jsp코드들을 하나로 통일.


2. JSP의 경우 사용자에게 디렉토리의 구조를 전부 보여주게 되어 보안성이 현저히 떨어졌다 서블릿에서는 서버 디렉토리 구조가 보이지 않아 보안성을 띈다.


3. 기존에는 jsp에 데이터를 만들면 html에 가져다가 사용을 했다. 이렇게 진행할 경우 의존성문제가 발생한다. (하나의 파일을 여러 사용자가 나누어 사용할 때 발생하는 문제. 한쪽에 디자인을 맞추면 다른 페이지에서는 디자인이 깨지거나 오류가 발생하는 문제 등 )

사용자가 접근하는 주소에 따라 특정 jsp파일을 접근하도록 매핑해주는 내용이 web.xml에 담겨있다.

이를 통해 우리가 웹에 접근할 때 ,jsp 확장자를 볼 수 없었음 (~/a.jsp -> ~/def.do)

class로 jsp내용을 담게되면서 html이 있는 파일은 만들어야 하지만, jsp만 존재하는 파일의 경우 별도로 만들어줄 필요가 없어짐.


web.xml

톰캣 서버가 시작될 때 web.xml 파일을 찾아서 읽음.  web.xml이 오류날 경우 서버가 시작되지 않음.

시작될 때 한 번만 xml을 읽고 다시 찾아가지 않음. 오라클의 parameter파일과 동일한 개념. 수정 시 반영을 위해서 shutdown 후 restart 해야한다.


서블릿 클래스 생성

web.xml

사용자가 주소란에 hello를 입력하게되면 helloServlet을 찾아가라는 사용자 정의.

/study 프로젝트명이후 검색어를 작성하므로 url pattern에 /를 붙여줘야한다.

<servlet>

<servlet-name>helloServlet</servlet-name>

<servlet-class>com.svt.Test1</servlet-class>

</servlet>

 <servlet-mapping>

<servlet-name>helloServlet</servlet-name>

<url-pattern>/hello</url-pattern>

</servlet-mapping>

</web-app>


GenericServlet 이용한 서블릿 클래스 생성


public class Test1 extends GenericServlet{

private static final long serialVersionUID = 1L;

@Override

public void service(ServletRequest request, ServletResponse response)

throws ServletException, IOException {

//response 객체의 한글 인코딩

//지금부터 클라이언트에게 전달하는 데이터타입은 text나 html형식이고 utf-8 인코딩 방식

response.setContentType("text/html;charset=utf-8");

try {

//서블릿은 객체가 필요하면 요청을 해야함

//JSP의 경우 out.print로 작성하면 됐지만 서블릿은 객체 생성 필요

PrintWriter out = response.getWriter();

out.print("<html>");

out.print("<head>");

out.print("<title>");

out.print("예제프로그램</title></head>");

out.print("<body style='font-size:19pt;'>");

out.print("화면 디자인은 서블릿보다 JSP가 더 편하다.");

out.print("</body>");

out.print("</html>");

} catch (Exception e) {


}

}

}


Servlet API 인식 에러


이클립스를 시작할 때 Servlet API 인식하지 못할경우 수동으로 인식할 수 있도록 등록 진행

프로젝트 마우스우클릭 - build path- configure build path - add external JARs

참조 : https://code.i-harness.com/ko-kr/q/3e3439 (상세 설명 나와있음)



ServletConfig, ServletContext  인터페이스

web.xml파일에는 변하지 않고 공통적으로 사용하는 변수값을 써놓을 수 있다.

Test2 서블릿으로 이동하면서 두개의 변수를 같이 가져가는 것


<!-- 1. ServletConfig 인터페이스 -->

<!-- 해당 Servlet에서만 사용 가능 -->

 <servlet>

<servlet-name>test2Servlet</servlet-name>

<servlet-class>com.svt.test2</servlet-class>

<init-param>

<param-name>name</param-name>

<param-value>배수지</param-value>

</init-param>

<init-param>

<param-name>age</param-name>

<param-value>25</param-value>

</init-param>

</servlet>

 <servlet-mapping>

<servlet-name>test2Servlet</servlet-name>

<url-pattern>/itwill</url-pattern>

</servlet-mapping>


<!-- 2. ServletContext 인터페이스 -->

<!--  동일 웹 프로그램안에 모든 서블릿 또는 JSP에서 사용가능 -->

 <context-param>

<param-name>gender</param-name>

<param-value>여자</param-value>

</context-param>



Test2 ( ServletConfig 인터페이스와 ServletContext 인터페이스)


public class Test2 extends HttpServlet {

private static final long serialVersionUID = 1L;

@Override

protected void doGet(HttpServletRequest req, HttpServletResponse resp)

throws ServletException, IOException {

//1. ServletConfig 인터페이스

ServletConfig config = getServletConfig();

String name = config.getInitParameter("name");

String age = config.getInitParameter("age");

//2. ServletContext 인터페이스

ServletContext context = getServletContext();

String gender = context.getInitParameter("gender");

//한글인코딩

resp.setContentType("text/html;charset=utf-8");

//객체생성

PrintWriter out = resp.getWriter();

out.print("<html><body>");

out.print("name : " +name +"<br/>");

out.print("age : " +age +"<br/>");

out.print("gender : " +gender +"<br/>");

out.print("</body></html>");

}

}



사용자에게 입력값을 받는 웹페이지 생성

<%

String cp = request.getContextPath();

%>


<form action="<%=cp %>/ss1" method="post">

이름 : <input type="text" name="name"/><br/>

나이 : <input type="text" name="age"/><br/>

<input type="submit" value="확인"/><br/>

</form>


실행결과


input 값을 입력하고 확인버튼을 누를 경우, 현재까지는 해당 경로가 존재하지 않음. 404오류가 발생

doGet(), doPost() 메소드

GET방식이나 POST방식이나 실행되는 방식이 동일하다면 메소드를 하나 더 생성해서 호출하는 방법이 있다.

doPost, doGet 모두 해당 메소드를 호출하는 방식으로 진행한다면 메소드 많이 늘어나지 않고 중복되는 내용을 줄일 수 있다. 하기 소스에서는 doPost로 실행되는 소스를 작성하고, doGet에서도 실행소스는 동일하므로 doPost를 호출하는 방식을 활용했다.

web.xml

<servlet>

<servlet-name>test3Servlet</servlet-name>

<servlet-class>com.svt.Test3</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>test3Servlet</servlet-name>

<url-pattern>/ss1</url-pattern>

</servlet-mapping>


Test3.java

public class Test3 extends HttpServlet {

private static final long serialVersionUID = 1L;

@Override

protected void doGet(HttpServletRequest req, HttpServletResponse resp)

throws ServletException, IOException {

doPost(req, resp);

}

@Override

protected void doPost(HttpServletRequest req, HttpServletResponse resp)

throws ServletException, IOException {

req.setCharacterEncoding("UTF-8");

String name = req.getParameter("name");

String age = req.getParameter("age");

String str = name + "의 나이는 "+ age + "살 입니다.";

//한글인코딩

resp.setContentType("text/html;charset=utf-8");

//객체생성

PrintWriter out = resp.getWriter();


//출력

out.print("<html><body>");

out.print("str : " +str +"<br/>");

out.print("</body></html>");

}

}


실행결과







원래 html 태그 작성을 해줘야하지만 소스가 길어지는 단점이 존재하므로 포워딩 방식을 활용해서  jsp 페이지로 전달하여 사용

Test3.java


@Override

protected void doPost(HttpServletRequest req, HttpServletResponse resp)

throws ServletException, IOException {

req.setCharacterEncoding("UTF-8");

String name = req.getParameter("name");

String age = req.getParameter("age");

String str = name + "의 나이는 "+ age + "살 입니다.";

//포워딩 데이터

req.setAttribute("result", str);

//forward

RequestDispatcher rd =req.getRequestDispatcher("/servlet/test3_ok.jsp");

rd.forward(req, resp);

           }


test3_ok.jsp


<%@ page contentType="text/html; charset=UTF-8"%>

<%

request.setCharacterEncoding("UTF-8");

String cp = request.getContextPath();

String str = (String)request.getAttribute("result");

%>

<%=str %><br/>

${result }


실행 결과

HTML태그를 일일이 클래스 파일에 작성하게 되면 복잡하기 때문에 포워드방식을 통해서 전달하여 사용.

/servlet/test3_ok.jsp.로 이동하게 되지만 포워딩으로 처리되므로 주소는 /ss1으로 보여진다.


${result }

EL (Expression Language) 넘어오는 변수를 바로 받음


EL(Expression Language)

표현언어(EL)는 표현식(<%=..)을 대신하는 효과를 가지며null 값을 가지는 변수에 대해 좀 더 관대하고 데이터형을 자동으로 변환해준다.

Test4.jsp

<%@ page contentType="text/html; charset=UTF-8"%>

<%

request.setCharacterEncoding("UTF-8");

String cp = request.getContextPath();

//EL(Expression Language)

//표현언어(EL)는 표현식(<%=..)을 대신하는 효과를 가지며

//null 값을 가지는 변수에 대해 좀 더 관대하고

//데이터형을 자동으로 변환해준다

request.setAttribute("result", "테스트");

%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>Insert title here</title>

</head>

<body>

<form action="" method="post">

수1: <input type="text" name= "su1" /><br/>

수2: <input type="text" name= "su2" /><br/>

<input type="submit" value="결과"/><br/>

</form>

<br/>

<%=request.getAttribute("result") %><br/>

${result }<br/>

<!-- su1의 값 받기 -->

su1 : <%=request.getAttribute("su1") %><br/>

su1 : ${param.su1 }<br/>

결과 : ${param.su1 + param.su2 }<br/>

${param.su1 }은 ${param.su1%2==0?"짝수":"홀수" }<br/>

${10*20 } <br/>

</body>

</html>




JSTL(JSP Standard Tag Library)

JSTL(JSP Standard Tag Library)

JSP는 사용자 정의 태그를 만들수있는 기능이 있다.

아파치에서 프로그래머들이 만든 태그들을 표준화시켜서 배포한 것.


다운로드 페이지 : http://jakarta.apache.org/site/downloads/


zip파일안에 lib에 존재하는 파일들을 복사하여 lib에 추가


라이브러리에 추가 후 JSP페이지에 다음과같이 디렉티브를 작성해야 한다.


<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>



Core Library 태그

test5.jsp


<%@ page contentType="text/html; charset=UTF-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%

request.setCharacterEncoding("UTF-8");

String cp = request.getContextPath();

//JSTL(JSP Standard Tag Library)

//사용자가 만든 태그를 커스텀태그라고 하는데 이들중에

//자주 사용하는 태그를 표준으로 만들어 놓은 것(아파치가 라이브러리 만들어 배포)

//처리영역 4가지

//core, format, xml, sql

%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>Insert title here</title>

</head>

<body>

<form action="" method="post">

수 : <input type="text" name="su" /><br/>

<input type="submit" value="결과" /><br/>

</form>

<br/>

<c:if test="${!empty param.su }">

<c:if test="${param.su%2==0 }">

${param.su } : 짝수<br/>

</c:if>

<c:if test="${param.su%2==1 }">

${param.su } : 홀수<br/>

</c:if>

</c:if>

<br/>

<br/>

<table>

<c:forEach var="i" begin="1" end="9" step="1">

<tr>

<c:forEach var="j" begin="1" end="9" step="1">

<td width="50">${i*j }</td>

</c:forEach>

</tr>

</c:forEach>

</table>

</body>

</html>


실행결과


<c:forEach>태그를 이용하여 반복문 사용하기

DataVO.java

public class DataVO {

private String name;

private int age;

public DataVO(String name, int age){

this.name = name;

this.age = age;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

}



test6.jsp


<%@page import="java.util.ArrayList"%>

<%@page import="com.svt.DataVO"%>

<%@page import="java.util.List"%>

<%@ page contentType="text/html; charset=UTF-8"%>

<%

request.setCharacterEncoding("UTF-8");

String cp = request.getContextPath();

List<DataVO> lists = new ArrayList<DataVO>();

DataVO vo = new DataVO("배수지",25);

lists.add(vo);

vo = new DataVO("안상희",30);

lists.add(vo);

vo = new DataVO("이슬기",32);

lists.add(vo);

vo = new DataVO("천송이",40);

lists.add(vo);

request.setAttribute("lists", lists);

%>

<jsp:forward page="result.jsp"/>


result.jsp


<%@page import="com.svt.DataVO"%>

<%@ page contentType="text/html; charset=UTF-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%

request.setCharacterEncoding("UTF-8");

String cp = request.getContextPath();

%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>Insert title here</title>

</head>

<body>

<table>

<tr>

<td width="100">이름</td>

<td width="100">나이</td>

</tr>

<c:forEach var="vo" items="${lists }"> //게시판 만들때 이 태그를 사용

<tr>

<td>${vo.name }</td>

<td>${vo.age }</td>

</tr>

</c:forEach>

</table>

</body>

</html>


JSTL 이용하여 구구단 만들기

<%@ page contentType="text/html; charset=UTF-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%

request.setCharacterEncoding("UTF-8");

String cp = request.getContextPath();

%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>구구단</title>

</head>

<body>

<form action="" method="post">

단 : <input type="text" name="dan"/>

<input type="submit" value="결과"/><br/>

</form>

<br>

<table>

<c:if test="${!empty param.dan }">

<tr>

<td align="center">${param.dan } 단</td>

</tr>

<c:forEach var="i" begin="1" end="9" step="1">

<tr>

<td>${param.dan } × ${i } = ${param.dan*i }</td>

</tr>

</c:forEach>

</c:if>

</table>

</body>

</html>



<c:set>은 변수를 초기화 시켜주는 역할을 함

<form action="" method="post">

수1: <input type="text" name="su1"/><br/>

수2: <input type="text" name="su2"/><br/>

<input type="submit" value="결과"/><br/>

</form>

<br/><br/>

<c:if test="${!empty param.su1 }">

<c:set var="result" value="1" />

<c:forEach var="a" begin="1" end="${param.su2 }" step="1">

<c:set var="result" value="${result*param.su1 }"/>

${param.su1 }^${a } = ${result }<br/>

</c:forEach>

</c:if>


실행결과


<c : choose>

<c:if test="${!empty param.su}">

<c:choose>

<c:when test="${param.su%3 == 0 && param.su%4 == 0}">

${param.su}는 3과 4의 배수<br/>

</c:when>

<c:when test="${param.su%4 == 0}">

${param.su}는 4의 배수<br/>

</c:when>

<c:when test="${param.su%3 == 0}">

${param.su}는 3의 배수<br/>

</c:when>

<c:otherwise>

${param.su}는 3과 4의 배수가 아니다<br/>

</c:otherwise>

</c:choose>

</c:if>


실행결과


<c : import> 해당 url 페이지를 호출함

<c:set var="url" value="gugudan.jsp"/>

<c:import url="${url }" var="uu">

<c:param name="dan" value="5"/>

</c:import>

<c:out value="${uu}" escapeXml="false"/> //escapeXml이 생략되면 해당 url의 소스가 보여지게 된다.


<c:set var="url" value="https://www.daum.net" />

<c:out value="${url }" /><br/>


<c:import url="${url }" var="u"/>

<c:out value="${u }" escapeXml="false"/>


<pre>

<c:out value="${u }" />

</pre>


실행결과







DBCP(Database Connection Pool)

톰캣서버의 메모리공간에 DB의 연결자를 저장하는 것이 DBCP(pool).

액세스하는 사용자가 많을 경우 DBCP를 사용하는 것이 속도가 훨씬 빠르다


JSP Container, Servlet Container 를 통을어 web Container 라고 부른다.

context.xml

<Resource name="jdbc/myOracle" auth="Container" type="javax.sql.DataSource"

driverClassName="oracle.jdbc.driver.OracleDriver"

url="jdbc:oracle:thin:@192.168.16.16:1521:TestDB"

username="SUZI"

password="A123"

maxActive="20"

maxIdle="10"

maxWait="-1"

/>

maxActive : 사용하는 커넥션 최대수

maxIdle : 사용 안하고있는 커넥션의 최대수

maxWait : 커넥션을 열기 위해 최대 기다리는 시간(-1은 무기한)


web.xml

<!-- DBCP(Database Connection Pool) -->

<resource-ref>

<description>Oracle Datasource</description>

<res-ref-name>jdbc/myOracle</res-ref-name>

<res-type>javax.sql.DataSource</res-type>

<res-auth>Container</res-auth>

</resource-ref>


DBCPConn.java

import java.sql.Connection;

import javax.naming.Context;

import javax.naming.InitialContext;

import javax.sql.DataSource;

public class DBCPConn {

private static Connection conn = null;


public static Connection getConnection(){

if(conn==null){

try {

          //이름과 객체를 바인딩(context.xml에 생성한 소스에 해당)

Context ctx = new InitialContext();

//web.xml에서 환경설정 읽음

Context evt = (Context)ctx.lookup("java:/comp/env");

DataSource ds = (DataSource)evt.lookup("jdbc/myOracle");

conn = ds.getConnection();

} catch (Exception e) {

System.out.println(e.toString());

}

}

return conn;

}

public static void close(){

if(conn!=null){

try {

if(!conn.isClosed())

conn.close();

} catch (Exception e) {

System.out.println(e.toString());

}

}

conn=null;

}

}