반응형
01. webapp>META-INF>context.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- context.xml : WAS 프로그램 객체 생성 관련 정보를 제공하기 위한 파일 -->
<!-- => WAS 프로그램 실행 시 자동으로 파일을 읽어 필요한 정보를 저장 -->
<!-- Context : context.xml 파일의 최상위 엘리먼트 -->
<Context>
<!-- Resource : 객체 생성 관련 정보를 속성과 속성값으로 제공하는 엘리먼트 -->
<!-- name : Resource 엘리먼트를 구분하기 위한 식별자를 속성값으로 설정 -->
<!-- => 객체 생성에 필요한 정보를 WAS 프로그램으로부터 제공하기 위한 이름 : 중복X -->
<!-- auth : 객체를 생성을 위한 정보를 제공한 사용자를 속성값으로 설정 : 아무렇게나 작명해도 됨 -->
<!-- type : 객체를 생성하여 반환받기 위한 자료형 (클래스 또는 인터페이스를 속성값으로 설정) -->
<!-- factory : 객체를 생성하기 위한 Factory 클래스를 속성값으로 설정 -->
<!-- => Factory 클래스에 필요한 값을 속성명(필드명)과 속성값(필드값)을 사용하여 제공 -->
<Resource name="jdbc/oracle" auth="Container" type="javax.sql.DataSource"
factory="org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory"
driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@localhost:1521:xe" username="scott" password="tiger"
initialSize="10" maxIdle="10" maxTotal="15"/>
<!-- WAS에 등록된 정보 : factory클래스로 객체를 만들며, 객체에 필요한 속성값은 아래처럼 설정했어요.
"jdbc/oracle" 라는 이름으로 객체가 반환될 것이에요 -->
</Context>

02. GUEST테이블&시퀀스 | GuestDTO | GuestDAO
1) GUEST테이블
create table GUEST(no number(10) primary key,
name varchar2(40),
regdate date,
title varchar2(100),
content varchar2(4000));
//Table GUEST이(가) 생성되었습니다.
desc guest;
select * from guest;
2) guest_seq 시퀀스
create sequence guest_seq;
//Sequence GUEST_SEQ이(가) 생성되었습니다.
3) GuestDTO.java
package xyz.itwill.dto;
/*
이름 널? 유형
------- -------- --------------
NO NOT NULL NUMBER(10) - 글번호 : 시퀀스의 자동 증가값
NAME VARCHAR2(40) - 작성자 : 사용자 입력값 (지금은 비로그인, 로그인 다 가능하도록 / 나중에 로그인 기능 추가하면 - 로그인된 사용자이름을 session으로 저장하기)
REGDATE DATE - 작성일자 : 시스템의 현재 날짜(시간)
TITLE VARCHAR2(100) - 제목 : 사용자 입력값
CONTENT VARCHAR2(4000) - 내용 : 사용자 입력값
*/
public class GuestDTO {
//필드
private int no;
private String name;
private String regate;
private String title;
private String content;
//생성자
public GuestDTO() {
// TODO Auto-generated constructor stub
}
//Getter & Setter
public int getNo() {return no;}
public void setNo(int no) {this.no = no;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public String getRegate() {return regate;}
public void setRegate(String regate) {this.regate = regate;}
public String getTitle() {return title;}
public void setTitle(String title) {this.title = title;}
public String getContent() {return content;}
public void setContent(String content) {this.content = content;}
}
4) GuestDAO.java
(부모) JdbcDAO.java
package xyz.itwill.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
//JDBC 기능을 제공하는 DAO 클래스가 상속받기 위해 작성된 부모 클래스
// => 객체 생성이 목적이 아닌 상속으로 목적으로 작성된 클래스 - 추상클래스로 작성하는 것을 권장
// => WAS 프로그램에 등록된 자원을 얻어와 DataSource 객체를 반환받아 저장 - 정적영역을 이용해 1번만 실행
// => DataSource 객체로부터 Connection 객체를 제공받아 반환하는 메소드
// => 매개변수로 JDBC 관련 객체를 제공받아 제거하는 메소드
public abstract class JdbcDAO {
//1.
//WAS 프로그램에 등록된 자원을 얻어와 DataSource 객체를 반환받아 저장 - 정적영역을 이용해 1번만 실행
private static DataSource dataSource; //Connection이 미리 10개 생성됨
//2.
static { //메모리가 로딩되면 자동으로 아래의 명령 실행되어 객체 만들어짐
try {
dataSource = (DataSource)new InitialContext().lookup("java:comp/env/jdbc/oracle");
}catch (NamingException e) {
e.printStackTrace();
}
}
//3.
//DataSource 객체로부터 Connection 객체를 제공받아 반환하는 메소드
public Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
//4.
//매개변수로 JDBC 관련 객체를 제공받아 제거하는 메소드
public void close(Connection con) {
try {
if(con!=null) con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void close(Connection con, PreparedStatement pstmt) {
try {
if(con!=null) con.close();
if(pstmt!=null) pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void close(Connection con, PreparedStatement pstmt, ResultSet rs) {
try {
if(con!=null) con.close();
if(pstmt!=null) pstmt.close();
if(rs!=null) rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
(자식) GuestDAO.java
package xyz.itwill.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import xyz.itwill.dto.GuestDTO;
//DBCP가 만들어져 컨섹션을 제공받고 반환하는 메소드가 작성되어있는 JdbcDAO 상속받아 작성
public class GuestDAO extends JdbcDAO {
//필드
private static GuestDAO _dao;
//싱글톤클래스로만들기위한 private 생성자
private GuestDAO() {
// TODO Auto-generated constructor stub
}
static {
_dao=new GuestDAO();
}
public static GuestDAO getDAO() {
return _dao;
}
//🔥주의 [하나의 메소드] = [하나의 SQL 명령]만을 전달할 수 있도록 만들기
//1. insertGuest()
//게시글을 전달받아 GUEST 테이블에 삽입하고 삽입행의 갯수를 반환하는 메소드
public int insertGuest(GuestDTO guest) {
Connection con=null;
PreparedStatement pstmt=null;
int rows=0;
try {
con=getConnection();
String sql="insert into guest values(guest_seq.nextval,?,sysdate,?,?)";
pstmt=con.prepareStatement(sql);
pstmt.setString(1, guest.getName());
pstmt.setString(2, guest.getTitle());
pstmt.setString(3, guest.getContent());
rows=pstmt.executeUpdate();
} catch (SQLException e) {
System.out.println("[에러]insertGuest() 메소드의 SQL 오류 = "+e.getMessage());
} finally {
close(con, pstmt);
}
return rows;
}
//2. deleteGuest()
//게시글의 글번호를 전달받아 GUEST 테이블에 저장된 해당 글번호의 게시글을 삭제하고
//삭제행의 갯수를 반환하는 메소드
public int deleteGuest(int no) {
Connection con=null;
PreparedStatement pstmt=null;
int rows=0;
try {
con=getConnection();
String sql="delete from guest where no=?";
pstmt=con.prepareStatement(sql);
pstmt.setInt(1, no);
rows=pstmt.executeUpdate();
} catch (SQLException e) {
System.out.println("[에러]deleteGuest() 메소드의 SQL 오류 = "+e.getMessage());
} finally {
close(con, pstmt);
}
return rows;
}
//3. selectGuestList()
//GUEST 테이블에 저장된 모든 게시글을 검색하여 반환하는 메소드
public List<GuestDTO> selectGuestList() {
Connection con=null;
PreparedStatement pstmt=null;
ResultSet rs=null;
List<GuestDTO> guestList=new ArrayList<GuestDTO>();
try {
con=getConnection();
String sql="select * from guest order by no desc";
pstmt=con.prepareStatement(sql);
rs=pstmt.executeQuery();
while(rs.next()) {
GuestDTO guest=new GuestDTO();
guest.setNo(rs.getInt("no"));
guest.setName(rs.getString("name"));
guest.setRegdate(rs.getString("regdate"));
guest.setTitle(rs.getString("title"));
guest.setContent(rs.getString("content"));
guestList.add(guest);
}
} catch (SQLException e) {
System.out.println("[에러]selectGuestList() 메소드의 SQL 오류 = "+e.getMessage());
} finally {
close(con, pstmt, rs);
}
return guestList;
}
}

03. 입력페이지 (insert.html)
- 자바 명령이 필요없으므로 jsp 문서가 아닌 html문서(웹문서)로 만듦
webapp>insert.html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!-- GUEST 테이블에 저장하기 위한 게시글을 사용자에게 입력받기 위한 웹문서 - 입력페이지 -->
<!-- => [방명록 쓰기]를 클릭하면 게시글 저장페이지(insert.itwill)로 이동 - 사용자 입력값(게시글) 전달 -->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Servlet</title>
<link rel="stylesheet" type="text/css" href="css/common.css">
<SCRIPT LANGUAGE="JavaScript" SRC="js/common.js">
</SCRIPT>
<SCRIPT language="JavaScript">
function loading(form)
{
form.name.focus();
}
function form_submit(form, action, method)
{
if(is_null_field(form)) return;
form.action=action;
form.method=method;
form.submit();
}
function is_null_field(form)
{
if(is_null(form.name.value) || is_space(form.name.value))
{
alert("이름을 입력해요.");
form.name.focus();
return true;
}
if(is_null(form.title.value) || is_space(form.title.value))
{
alert("제목을 입력해요.");
form.title.focus();
return true;
}
if(is_null(form.content.value) || is_space(form.content.value))
{
alert("내용을 입력해요.");
form.content.focus();
return true;
}
}
</SCRIPT>
</head>
<body onLoad="loading(guest);">
<form name="guest">
<table width="80%" align="center" border="0" cellspacing="0" cellpadding="0">
<tr bgcolor="#556b2f" valign="middle">
<td height="25" class="t1" align="center">
<b><font color="#FFFFFF">::: 방명록 쓰기 :::</font></b>
</td>
</tr>
<tr>
<td height="20" > </td>
</tr>
<tr>
<td>
<table width="100%" align="center" border=1 cellspacing=0>
<tr>
<td>
<table width="100%" align="center" border="0" cellspacing="0">
<tr>
<td bgcolor="#808000" align="center" height="20" width="20%" class="t1">
<font color="#FFFFFF">이 름</font>
</td>
<td height="20" width="80%" class="t1">
<input type="text" name="name" maxlength="24" size="24" class="TXTFLD">
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table width="100%" align="center" border="0" cellspacing="0">
<tr>
<td bgcolor="#808000" align="center" height="20" width="20%" class="t1">
<font color="#FFFFFF">제 목</font>
</td>
<td height="20" width="80%" class="t1">
<input type="text" name="title" maxlength="80" size="80" class="TXTFLD">
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table width="100%" align="center" border="0" cellspacing="10">
<tr>
<td height="50" width="1000%" class="t1">
<textarea cols="98" name="content" rows="10" class="TXTFLD"></textarea>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td height="50" align="center">
<input type="button" value="방명록 쓰기" class="TXTFLD" onclick="form_submit(guest,'insert.itwill','POST');">
<input type="reset" value="다시 작성하기" class="TXTFLD">
</td>
</tr>
</table>
</form>
</body>
</html>

04. 메인페이지 - 출력페이지 (select.itwill)
- 대부분 검색하는 페이지가 메인일 경우가 많음
- 일반적으로 검색 -> 삽입 -> 변경 -> 삭제 페이지 순으로 만드는 경우 많음
GuestSelectServlet.java - select.itwill
package xyz.itwill.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
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 xyz.itwill.dao.GuestDAO;
import xyz.itwill.dto.GuestDTO;
//GUEST 테이블에 저장된 모든 게시글을 검색하여 클라이언트에게 전달하는 서블릿 - 출력페이지
// => [방명록 쓰기]를 클릭한 경우 게시글 입력페이지(insert.html)로 이동
// => 게시글의 [삭제]를 클릭한 경우 게시글 삭제페이지(delete.itwill)로 이동 - 글번호 전달
@WebServlet("/select.itwill")
public class GuestSelectServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.
response.setContentType("text/html;charset=utf-8");
PrintWriter out=response.getWriter();
//2.
//GUEST 테이블에 저장된 모든 게시글을 검색하여 반환하는 DAO 클래스의 메소드 호출
List<GuestDTO> guestList=GuestDAO.getDAO().selectGuestList();
//3.
//처리결과를 웹문서로 생성하여 클라이언트에게 전달 - 응답
out.println("<!DOCTYPE html PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN' '<http://www.w3.org/TR/html4/loose.dtd>'>");
out.println("<html>");
out.println("<head>");
out.println("<meta http-equiv='Content-Type' content='ext/html; charset=UTF-8'>");
out.println("<title>Servelt</title>");
out.println("<link rel='stylesheet' type='text/css' href='css/common.css'>");
out.println("</head>");
out.println("<body>");
out.println("<table width='80%' align='center' border='0' cellspacing='0' cellpadding='0'>");
out.println("<tr bgcolor='#000080' valign='middle'>");
out.println("<td height='25' class='t1' align='center'>");
out.println("<b><font color='#FFFFFF'>:::방명록 읽기 :::</font></b>");
out.println("</td>");
out.println("</tr>");
out.println("<tr>");
out.println("<td height='30' align='right' valign='bottom' class='t1'>");
out.println("<a href='insert.html'>방명록 쓰기</a></td>");
out.println("</tr>");
//4.
if(guestList.isEmpty()) {//검색된 게시글이 없는 경우
out.println("<tr align='center'>");
out.println("<td>방명록에 저장된 게시글이 하나도 없습니다.</td>");
out.println("</tr>");
//5.
} else {//검색된 게시글이 있는 경우
//List 객체에 저장된 요소값(DTO 객체)를 반복적으로 제공받아 응답 처리
for(GuestDTO guest:guestList) {
out.println("<tr>");
out.println("<td>");
out.println("<table width='100%' align='center' border='1' cellspacing='0' bgcolor='#f5f5f5'>");
out.println("<tr>");
out.println("<td>");
out.println("<table width='100%' align='center' border='0' cellspacing='0'>");
out.println("<tr>");
out.println("<td bgcolor='#808000' align='center' height='20' width='20%' class='t1'>");
out.println("<font color='#FFFFFF'>제 목</font></td>");
out.println("<td height='20' width='80%' class='t1'>");
out.println("<b><font color='#0000FF'> "+guest.getTitle()+"</font></b></td>");
out.println("</tr>");
out.println("</table>");
out.println("</td>");
out.println("</tr>");
out.println("<tr>");
out.println("<td>");
out.println("<table width='100%' align='center' border='0' cellspacing='0'>");
out.println("<tr>");
out.println("<td bgcolor='#808000' align='center' height='20' width='20%' class='t1'>");
out.println("<font color='#FFFFFF'>작 성 자</font></td>");
out.println("<td align='center' height='20' width='30%' class='t1'>"+guest.getName()+"</td>");
out.println("<td bgcolor='#808000' align='center' height='20' width='20%' class='t1'>");
out.println("<font color='#FFFFFF'>작 성 일</font></td>");
out.println("<td align='center' height='20' width='30%' class='t1'>"+guest.getRegdate()+"</td>");
out.println("</tr>");
out.println("</table>");
out.println("</td>");
out.println("</tr>");
out.println("<tr>");
out.println("<td>");
out.println("<table width='100%' align='center' border='0' cellspacing='10'>");
out.println("<tr>");
out.println("<td height='50' width='100%' class='t1'>");
out.println(guest.getContent().replace("\\n", "<br>"));
out.println("</td>");
out.println("</tr>");
out.println("<tr>");
out.println("<td height='50' width='100%' class='t1'>");
out.println("<button type='button' onclick='location.href=\\"delete.itwill?no="+guest.getNo()+"\\"'>삭제</button>");
out.println("</td>");
out.println("</tr>");
out.println("</table>");
out.println("</td>");
out.println("</tr>");
out.println("</table>");
out.println("</td>");
out.println("</tr>");
out.println("<tr>");
out.println("<td height='20'>");
out.println("<hr color='#000077'>");
out.println("</td>");
out.println("</tr>");
}
}
out.println("</table>");
out.println("</body>");
out.println("</html>");
}
}
05. 처리페이지 (insert.itwill)
GuestInsertServlet.java - insert.itwill
package xyz.itwill.servlet;
import java.io.IOException;
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 xyz.itwill.dao.GuestDAO;
import xyz.itwill.dto.GuestDTO;
//입력페이지(insert.html)에서 전달된 게시글을 반환받아 GUEST 테이블에 삽입하고 클라이언트에게
//게시글목록 출력페이지(select.itwill)로 이동하기 위한 URL 주소 전달하는 서블릿 - 처리페이지
@WebServlet("/insert.itwill")
public class GuestInsertServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.
//비정상적인 요청에 대한 처리
if(request.getMethod().equals("GET")) {//클라이언트가 서블릿을 [GET] 방식으로 요청한 경우
//클라이언트에게 에러코드 전달
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);//405
return;
}
//2.
//리퀘스트 메세지의 몸체부에 저장되어 전달되는 값(POST)에 대한 캐릭터셋 변경
request.setCharacterEncoding("utf-8");
//3.
//전달값(게시글)을 반환받아 저장
// => String.trim() 메소드를 호출하여 전달값의 앞 또는 뒤에 존재하는 모든 공백 제거
// => String.replace() 메소드를 호출하여 XSS 공격에 대한 방어를 위해 태그 관련 기호를 회피문자(Escape Character)로 변환
//XSS(Cross Site Scripting) : 입력태그에 악의적인 스트립트를 입력하여 출력페이지를 파괴 시키거나 개인정보를 특정 사이트로 유출하는 웹사이트 공격 방법
String name=request.getParameter("name").trim().replace("<", "<").replace(">",">");
String title=request.getParameter("title").trim().replace("<", "<").replace(">",">");
String content=request.getParameter("content").trim().replace("<", "<").replace(">",">");
//4.
//DTO 객체를 생성하여 전달값으로 필드값 변경
GuestDTO guest=new GuestDTO();
guest.setName(name);
guest.setTitle(title);
guest.setContent(content);
//5.
//게시글(GuestDTO 객체)을 전달받아 GUEST 테이블에 삽입하는 DAO 클래스의 메소드 호출
GuestDAO.getDAO().insertGuest(guest);
//6.
//클라이언트에게 301 상태코드와 URL 주소 전달
response.sendRedirect("select.itwill");//리다이렉트 이동
}
}
06. 처리페이지 (delete.itwill)
GuestDeleteServlet.java - delete.itwill
package xyz.itwill.servlet;
import java.io.IOException;
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 xyz.itwill.dao.GuestDAO;
//게시글목록 출력페이지(select.itwill)에서 전달된 글번호를 반환받아 GUEST 테이블에 저장된 해당
//글번호의 게시글을 삭제하고 게시글목록 출력페이지(select.itwill)로 이동하기 위한 URL 주소 전달
//하는 서블릿 - 처리페이지
@WebServlet("/delete.itwill")
public class GuestDeleteServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.
//비정상적인 요청에 대한 처리
if(request.getParameter("no")==null) { //전달값이 없는 경우
response.sendError(HttpServletResponse.SC_BAD_REQUEST); //400
return;
}
//2.
//전달값(글번호)을 반환받아 저장 - 문자열 >> 정수값
int no = Integer.parseInt(request.getParameter("no"));
//3.
//글번호를 전달받아 GUEST 테이블에 저장된 해당 글번호의 게시글을 삭제하는 DAO 클래스의 메소드 호출
int rows = GuestDAO.getDAO().deleteGuest(no);
if(rows>0) { //삭제행이 있는 경우
response.sendRedirect("select.itwill");
} else {
response.sendError(HttpServletResponse.SC_BAD_REQUEST); //400
}
//3.
//글번호를 전달받아 GUEST 테이블에 저장된 해당 글번호의 게시글을 삭제하는 DAO 클래스의 메소드 호출
int rows = GuestDAO.getDAO().deleteGuest(no);
if(rows>0) { //삭제행이 있는 경우
response.sendRedirect("select.itwill");
} else {
response.sendError(HttpServletResponse.SC_BAD_REQUEST); //400
}
}
}
반응형
'servlet' 카테고리의 다른 글
[servlet] 8. JDBC 프로그램 (0) | 2024.05.26 |
---|---|
[servlet] 7. 바인딩된 세션 전달 프로그램 (session) (0) | 2024.05.25 |
[servlet] 6. 쿠키 생성, 전달, 제거 프로그램 (cookie) (0) | 2024.05.25 |
[servlet] 5. 파일업로드 프로그램 (multipart/form-data) (0) | 2024.05.24 |
[servlet] 4. 회원가입 프로그램 (form) (0) | 2024.05.24 |