JSP 7일차
JSP 프로그래밍2
데이터베이스
JDBC
개요
- 자바 언어로 다양한 종류의 관계형 데이터베이스에 접속하고 SQL 문을 수행하여 처리하고자 할 때 사용되는 표준 SQL 인터페이스 API
- 접속하는 DBMS 서버에 따라 JDBC 드라이버가 필요
- WAS 설치된 HOME 폴더 밑 lib 폴더 - 현재 WAS에서 실행되는 모든 웹 애플리케이션에서 사용 가능
- 각 웹 애플리케이션의 /WEB-INF/lib - 해당 웹 애플리케이션에서만 사용
구현
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ page import="java.sql.*" %>
<%
//1. JDBC Driver 로딩
Class.forName("oracle.jdbc.driver.OracleDriver");
//2. DB 서버 접속하기
String url = "jdbc:oracle:thin:@localhost:1521:xe";
Connection conn = DriverManager.getConnection(url, "scott", "tiger");
//3. Statement or PreparedSttement 객체 생성
Statement stmt = conn.createStatement();
String id = request.getParameter("id");
String pwd = request.getParameter("pwd");
PreparedStatement pstmt = conn.prepareStatement("insert into test values(?,?)");
pstmt.setString(1, id);
pstmt.setString(2, pwd);
pstmt.executeUpdate();
//4. SQL 실행
stmt.executeUpdate("create table test(id varchar2(5), pwd varchar2(5))");
stmt.executeUpdate("insert into test values('aa', '11')");
stmt.executeUpdate("insert into test values('bb', '22')");
stmt.executeUpdate("insert into test values('cc', '33')");
ResultSet rs = stmt.executeQuery("select * from test");
while(rs.next()) {
out.print("<br>" + rs.getString("id") + ":" + rs.getString(2));
}
//5. 자원해제
rs.close();
stmt.close();
conn.close();
%>
- Statement : 자바 프로그램과 DB가 연결된 길에서 서로에게 데이터를 전달해주는 객체
- PreparedStatement : Statement 객체와 같은 기능. 객체 생성 시 실행할 SQL 문을 ?기호와 함께 작성할 수 있어 동적으로 값을 할당할 때 가독성과 유지 보수성 좋음
DataSource
- 웹 클라이언트로부터 요청이 들어올 때마다 DB 서버와 연결하는 것이 아니라, 미리 서버에서 연결한 후 활용하는 방법
개요
- 웹 프로그램은 동시에 여러 사용자에 의해 요청이 일어날 수 있는 특성이 있으므로 자원 배분과 응답 속도에 대하여 효율적으로 구현해야 함
- 기존 JDBC 사용 시 문제점
- DB 프로그램에서 트랜잭션 처리와 Connection 관리는 시스템의 성능과 안전성에 큰 영향
- Connection 과정은 일정 시간이 필요한 부담되는 작업
- 불필요한 연결에 의한 서버 자원의 낭비 발생
- Connection Pool
- 웹 애플리케이션이 서비스되기 전에 웹서버에서 미리 생성하여 준비한 다음 필요할 때 준비된 Connection 가져다 사용
- Connection 객체는 서버가 시작될 때 서버에서 여러 개 준비 ⇒ Connection 객체들을 가지고 있는 리소스를 Connection Pool 이라고 함
- DataSource
- 여러개의 Connection 객체가 생성되어 운용될 때 각각을 직접 웹 애플리케이션에서 이용하면 체계적인 관리 어려움
- Connection Pool 관리하는 목적으로 DataSource 객체 사용
- JNDI Server에의해 웹 애플리케이션에 전달하는 방식 사용
- 이용방법
- JNDI Server에서 lookup() 메소드를 통해 DataSource 객체 획득
- DataSource 객체의 getConnection() 메소드를 통해서 Connection Pool에서 Free 상태의 Connection 획득
- Connection 객체를 통한 DBMS 작업 수행
- 모든 작업이 끝나면 DataSource 객체를 통해서 Connection Pool에 Connection 반납
- JNDI Server
- 서버나 애플리케이션에서 분산환경에 서비스하고자 하는 자원을 Naming & Directory 서버에 이름값과 실제 자원을 연결하여 등록하면, 해당 자원을 이용하고자 하는 다른 애플리케이션에서 N&D 서버에 접근하여 이름값만 가지고 자원을 연결하여 이용할 수 있게 하는 개념
구현
- server.xml
-
glabalNamingResources 태그 안에 설정
<Resource driverClassName="oracle.jdbc.driver.OracleDriver" url="jdbc:oracle:thin:@127.0.0.1:1521:xe" username="scott" password="tiger" name="jdbc/myoracle" type="javax.sql.DataSource" maxActive="4" mixIdle="2" maxWait="5000" />
-
context.xml
<ResourceLink global="jdbc/myoracle" name="jdbc/myoracle" type="javax.sql.DataSource" />
-
web.xml
<resource-ref> <description>Oracle Database example</description> <res-ref-name>jdbc/myoracle</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref>
-
DataSource 사용해서 DB 작업
<%@ page language="java" contentType="text/html;charset=UTF-8"%> <%@ page import="java.sql.*" %> <%@ page import="javax.sql.*" %> <%@ page import="javax.naming.*" %> <% //1. JDNI 서버 객체 생성 InitialContext ic = new InitialContext(); //2. lookup() DataSource ds = (DataSource)ic.lookup("java:comp/env/jdbc/myoracle"); //3. getConnection() Connection conn = ds.getConnection(); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("select * from test"); while(rs.next()) { out.print("<br>" + rs.getString("id") + ":" + rs.getString(2)); } rs.close(); stmt.close(); conn.close(); %>
EL(Express Language)
개요
구문
- ${ } 내에 표현식으로 표현
- 지정된 문자, 연산자, 변수 사용
- 서버에서 지원하는 서블릿 스펙에 따라 EL 사용법 다를 수 있음
EL 표현식에서 사용 가능
- 문자
- 논리 : true, flase
- 숫자 : 정수, 실수
- 문자열 : “ “ 또는 ‘ ‘
- 연산자
- 산술 연산자 : +, -, /, %, mod
- 논리 연산자 : &&,
||
, and, or, not - 비교 연산자 : ==, !=, <, >, <=, >=, eq, ne, lt, get, le, ge
- empty 연산자 : 값이 null이나 공백 문자열인지 판단
- ${empty “ “} ⇒ true
- ${empty null} ⇒ true
내장 객체
- 필요한 객체는 내장 객체 참조변수 이름으로 바로 사용 가능
정보 추출
- JSP 태그로 작업할 수 있는 기능 모두 EL로 표현 가능
- 코드 간소화
- HttpServletRequest, HttpSession, ServletContext 객체에 등록한 데이터 접근할 때 간단한 코드로 처리
request 정보 추출
- HttpServletRequest 객체는 forward 또는 include를 통해 실행된 페이지 사이에만 공유
- ${book} 같이 표현하면 request ⇒ session ⇒ application 객체 순서로 getAttribute(”book”) 메소드 실행
- 등록된 객체를 찾아 순차적 실행
- 추출된 정보가 있으면 원래 등록된 객체의 타입으로 캐스팅.
- getAttribute() 메소드 실행 중단
session 정보 추출
- 클라이언트 단위로 정보를 유지시킬 때 HttpSession 객체에 정보 등록
application 정보 추출
- 웹 애플리케이션 단위로 정보를 유지할 때 ServletContext 객체에 정보 등록
커스텀 태그
장점
- 재사용성 - 한 번만 작성한 후 JSP 페이지 내에서 언제든지 사용
- 역할 분담 - 개발자와 디자이너
- 유지 보수성
- 가독성
클래스 기반 커스텀 태그
- 태그 기능 자바 클래스 파일에 구현한 다음, JSP 태그와 연결하여 사용
구성 요소
- 태그 핸들러 클래스(Tag Handler Class)
- 커스텀 태그를 사용할 때 호출되는 자바 클래스 파일. 실행문을 구현하고 있는 자바 객체
- Tag 인터페이스를 상속받은 클래스들을 상속받으면 JSP 1.2 버전으로 작성
- SimpleTag 인터페이스를 상속받은 SimpleTagSupport 클래스 상속받으면 JSP 2.0 이상 버전으로 작성
- 태그 라이브러리 디스크립터(Tag Library Descriptor)
- JSP 페이지 내에서 사용할 때 클래스를 직접 사용하는 것이 아니라 JSP 커스텀 태그 이름으로 사용
- JSP 태그 이름을 설정하는 XML 파일
- tld 확장자 사용
- TLD 파일 등록
- 자바 클래스와 JSP 태그 매핑한 정보
- jsp 1.2 버전 ⇒ web.xml에 등록
- jsp 2.0 버전 ⇒ 자동 인식하는 폴더에 넣기 ⇒ WEB-INF 폴더 또는 하위폴더, WEB-INF/lib 폴더의 jar 파일에 위치
- taglib 지시자
- 커스텀 태그를 사용하기 위해서 taglib 지시자를 사용하여 선언해야 함.
- 태그 라이브러리의 uri와 prefix 값을 속성으로 가짐
- TLD와 JSP 파일 연결
JSP 1.2
- Tag 인터페이스 계열을 상속받아 태그 핸들러 클래스 작성
- 실행 시 자동으로 호출되는 메소드
- 시작 태그를 만나면 doStartTag()
- 태그의 몸체가 처리된 후 doAfterBody()
- 끝 태그를 만나면 doEndTag()
- 몸체 처리
-
<body-content>
: 커스텀 태그의 시작과 끝 사이에 있는 내용. 태그의 몸체에 대한 처리를 설정하는 태그- JSP(default) : 몸체의 내용을 JSP 코드로 처리
- tagdependent : 몸체의 내용을 자신의 기능으로 처리
- empty : 몸체가 없음을 선언. empty가 선언된 태그는 몸체를 가질 수 없음.
-
- 실행 제어 - 메소드들이 반환하는 값
- EVAL_BODY_INCLUDE : 메소드가 종료된 후 태그의 몸체를 처리.
- SKIP_BODY : 태그의 몸체를 처리하지 않고 스킵
- EVAL_BODY_AGAIN : 몸체를 다시 실행
- EVAL_PAGE : 메소드가 종료된 후 계속해서 JSP 페이지가 실행
- 속성 정의
- TLD 파일에
<attribute>
태그로 정의 - 태그 핸들러 클래스 객체에 속성과 같은 이름의 멤버변수 선언하고 getter, setter 메소드 선언
- TLD 파일에
- TEI 객체
- TLD 파일에 지정하지 않은 커스텀 태그의 내용을 동적으로 변경하여 복잡성을 없애려고 할 때 사용
JSP 2.1
- SimpleTag 인터페이스 계열을 상속받아 태그 핸들러 클래스 작성
- 1.2와 달라진 점
- SimpleTag 잍너페이스 추가
- SimpleTagSupport 클래스 제공
- doTag() 메소드로 Tag 관련 메소드 통일
- JspFragment를 이용한 body 전달
- 동적 Attribute 추가 방법 제공
태그 기반 커스텀 태그
- JSP 파일에 커스텀 태그의 기능을 구현한 다음, 확장자를 tag로 지정
구성요소
- Tag 파일
- 일반 JSP 페이지에서 사용하던 page 지시자 대신 tag 지시자 사용
- 일반 JSP 페이지에서 사용할 수 없는 지시자 추가로 사용
사용방법
- 태그 파일 작성해서 저장 ⇒ WEB-INF/tags 폴더 또는 하위 폴더만 가능
-
JSP 페이지에서 커스텀 태그를 사용하기 위한 taglib 지시자 선언
<%@ taglib prefix="my" tagdir="/WEB-INF/tags" %>
- 태그 파일을 커스텀 태그로 사용할 대는 taglib의 tagdir 속성에 태그 파일들이 위치한 폴더를 지정
- tagdir 속성에 지정한 폴더의 태그 파일들은 각각 파일 하나당 하나의 커스텀 태그로 사용
지시자
- tag 지시자 : 커스텀 태그에 대한 기본적인 정보 설정
- attribute 지시자 : 속성 정의
- variable 지시자 : EL에서 사용하는 변수를 선언할 때 사용
태그 처리
-
<jsp:doBody>
: 커스텀 태그의 몸체 처리<%@ tag body-content="empty" pageEncoding="utf-8">
- empty
- tagdepent
- scriptless : EL이나 액션 태그가 몸체에 사용되었을 때 처리된 결과를 몸체로 사용한다는 정보
-
동적 속성
-
속성을 미리 정의하지 않고 Map 형태로 받아서 사용
<%@ tag dynamic-attributes=" 변수이름 " %>
-
JSTL
- 태그 라이브러리를 공통으로 사용하기 위해 정해진 표준
Core
- 프로그램 개발 시 사용되는 기본적인 기능
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
formatting
- 날짜, 시간에 관한 형식 처리
<%@ taglib prefix="fmt" uri="http://java.sum.com/jsp/jstl/fmt" %>
sql
- 데이터베이스 작업에 관한 기능들 수행하는 태그
<%@ taglib prefix="fmt" uri="http://java.sum.com/jsp/jstl/sql" %>
xml
- xml 지원하는 기능의 태그들
<%@ taglib prefix="fmt" uri="http://java.sum.com/jsp/jstl/xml" %>
function
- 여러 가지 함수 기능
<%@ taglib prefix="fmt" uri="http://java.sum.com/jsp/jstl/functions" %>
MVC 디자인 패턴
- 애플리케이션을 세가지 영역인 모델, 뷰, 컨트롤러로 구분하여 작업을 분리
- 서로간의 결합도 최소화, 유지보수성 높음
- 개발의 효율성 극대화
MVC 디자인 패턴의 두 가지 모델
Model1
- 컨트롤러를 JSP로 작성
- JSP가 클라이언트의 요청을 처리하면서 동시에 뷰의 역할도 가능
- 컨트롤러와 뷰의 구분 없이 간단하고 빠르게 개발 가능
- 구현 작업이 복잡할 때는 역할이 구분되지 않아서 유지보수 어려움
Model2
- 컨트롤러를 서블릿으로 작성
- 요청 받아 처리하는 페이지는 서블릿이고, 뷰와 분리
뷰(view)
- 클라이언트로부터 요청이 일어나거나 처리된 결과를 보여주는 페이지
- HTML, CSS, JavaScript, JSP로 작성
- 서버와 독립적으로 다양한 UI 사용 가능
컨트롤로(Controller)
- 뷰에서 클라이언트가 서비스를 요청했을 때 실행되는 페이지
- 서비스를 처리하는 메소드를 호출함으로써 클라이언트 요청과 서비스 처리 객체를 연결해주는 중계 역할을 하며 서비스 서리 흐름 제어
- 뷰에서 들어온 요청 받음
- 클라이언트가 전달한 파라미터 추출
- 파라미터 유효성 검사.
- 서비스 객체의 메소드 호출하며 파라미터 서비스 객체로 전달
- 출력 뷰 페이지로 이동
모델(Model)
- 서비스 객체
- 서비스 처리를 하기 위한 내용으로만 구현된 객체
- 일반 자바로 작성
- DAO 객체
- DB 처리 담당
- 일반 자바로 작성
3계층 아키텍처
- 웹 애플리케이션을 개발할 때 구조적인 측면에서 3계층 아키텍처 사용
프레젠테이션 계층
- 최상위에 위치하는 영역
- 클라이언트와 애플리케이션 간에 상호작용 할 수 있게 하는 인터페이스 역할
- 단순히 웹 브라우저를 통해 클라이언트로부터 서비스를 요청받아서 비즈니스 계층의 메소드를 호출해주거나, 클라이언트카 보낸 데이터를 비즈니스 계층으로 전달하는 기능만 구현
- 비즈니스 계층의 작업이 끝난 다음 처리 결과 뷰 페이지로 이동하는 기능
- 프런트엔드 영역 - HTML, CSS, JavaScript, JSP, Servlet, Image 사용
비즈니스 계층
- 클라이언트가 요청한 서비스를 처리하는 비즈니스 로직 구현
- 클라이언트와 직접 연결되지 않으며, 프레젠테이션 계층과 연결되어 실행되는 영역
- 서비스 처리에 관한 기능만 구현
- 일반 자바 코드로 구현
- 백엔드 or 미들웨어 영역
영속 계층
- 데이터베이스 서버, 파일 시스템에 접근하여 데이터를 생성, 관리하는 기능
- 서비스를 처리할 때 영구적으로 저장된 데이터를 추출, 수정, 삭제, 생성하는 작업은 비즈니스 계층이 아닌 영속 계층에서 처리
- 백엔드 영역
프레임워크
- 어느 정도 완성되어 있는 틀을 사용하여 빠르고 효율적으로 개발
장점
- 개발 기간 단축 - 필요한 기능을 프레임워크에서 제공하는 라이브러리 사용해서 빠르고 간편하게 개발
- 성능 향상 - 검증된 효율적인 아키텍처와 설계 사용
- 유지보수성 향상 - 업무 파악 빠르게 할 수 있음. 프레임워크는 유지보수를 고려하여 설계되어 작업 최소화
단점
- 프레임워크 학습 필요
- 프레임워크 선택 어려움 - 잘못된 프레임워크 선택하면 개발 및 운영, 유지보수에 많은 어려움 초래
- 유연성 부족 - 커스터마이징 어려움
프론트 컨트롤러 디자인 패턴
- 뷰에서 들어오는 요청에 대하여 각각의 컨트롤러에서만 처리하면 수많은 뷰의 요청 통제 불가
- 대표 컨트롤러를 두고 뷰에서 들어오는 모든 요청을 담당하게 해서 모든 요청을 일괄적으로 처리
프론트 컨트롤러 설정
- URL 패턴 지정 ⇒ ~.do, ~.action 등
- 프런트 컨트롤러 등록 ⇒ web.xml
<url-pattern>
태그에 등록
서브 컨트롤러 연결
- 프런트 컨트롤러에서 일괄적으로 처리할 기능 구현하고, 처리가 완료된 후에는 반드시 실제 요청한 서비스를 처리하는 컨트롤러 실행
- 어떤 서브 컨트롤러가 실행될지 map 객체에 저장