Servlet - JDBC (JNDI:객체 생성에 필요한 정보를 식별자로 구분하여 저장하고, 필요시 제공받아 객체를 생성하여 사용)

woom·2022년 12월 1일
0

Servlet

목록 보기
3/3
post-thumbnail

🎀 회원정보 검색

  • JDBC 프로그램을 작성하기 위해 JDBC 관련 라이브러리 파일을 다운로드 받아 프로젝트에 빌드 처리
    • ojdbc11.jar 빌드
    • webapp(웹자원)의 라이브러리에 ojdbc11.jar 파일 붙여넣기 → Java Resources Libraries안에 있는 Web App Libraries에 자동 빌드처리 됨
    • 빌드 처리해야 라이브러리 명령을 사용해서 sql명령을 전달하고 검색가능

🐣 JDBC Servlet (권장x)

  • PHONEBOOK 테이블에 저장된 모든 회원정보를 검색하여 클라이언트에게 전달하는 서블릿 (JDBC)
package xyz.itwill.servlet;

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

	protected void service(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out=response.getWriter();
		
		//JDBC 관련 객체를 저장하기 위한 참조변수 선언
		Connection con=null;
		PreparedStatement pstmt=null;
		ResultSet rs=null;
		try {
			//1.OracleDriver 클래스를 읽어 메모리에 저장
			//→ OracleDriver 객체를 생성하여 DriverManager 클래스의 JDBC 드라이버로 등록
			Class.forName("oracle.jdbc.driver.OracleDriver");
			
			//2.DriverManager 클래스의 JDBC 드라이버로 DBMS 서버에 접속하여
            //Connection 객체를 반환받아 저장
			String url="jdbc:oracle:thin:@localhost:1521:xe";
			String user="scott";
			String password="tiger";
			con=DriverManager.getConnection(url, user, password);
			
			//3.접속된 DBMS 서버에 전달되어 실행될 SQL 명령이 저장된 PreparedStatement
            //객체를 Connection 객체로부터 반환받아 저장
			String sql="select * from phonebook order by phone";
			pstmt=con.prepareStatement(sql);
			
			//4.PreparedStatement 객체에 저장된 SQL 명령을 전달하여 실행하고 결과를 반환받아 저장
			rs=pstmt.executeQuery();
			
			//5.반환받은 SQL 명령을 실행 결과를 이용하여 처리 작업
			//→ SQL 명령의 실행 결과를 HTML 문서로 생성하여 클라이언트에게 전달
			out.println("<!DOCTYPE html>");
			out.println("<html>");
			out.println("<head>");
			out.println("<meta charset='UTF-8'>");
			out.println("<title>Servlet</title>");
			out.println("</head>");
			out.println("<body>");
			out.println("<h1>전화번호부</h1>");
			out.println("<hr>");
			out.println("<table border='1' cellspacing='0'>");
			out.println("<tr>");
			out.println("<th width='200'>전화번호</th>");
			out.println("<th width='200'>이름</th>");
			out.println("<th width='300'>주소</th>");
			out.println("</tr>");
			//ResultSet 객체에 저장된 모든 행의 컬럼값을 client에게 전달(반복 처리) 		
			while(rs.next()) {//ResultSet 커서를 다음행으로 이동하여 처리행이 존재할 경우 반복
				out.println("<tr align='center'>");
				//ResultSet 커서가 위치한 처리행의 컬럼값을 반환받아 클라이언트에게 전달
				out.println("<td>"+rs.getString("phone")+"</td>");
				out.println("<td>"+rs.getString("name")+"</td>");
				out.println("<td>"+rs.getString("address")+"</td>");
				out.println("</tr>");
			}
			out.println("</table>");
			out.println("</body>");
			out.println("</html>");
		} catch (ClassNotFoundException e) {
			System.out.println("[에러]OracleDriver 클래스를 찾을 수 없습니다.");
		} catch (SQLException e) {
			System.out.println("[에러]JDBC 오류 = "+e.getMessage());
		} finally {
			//6.JDBC 관련 객체 제거
			try {
				if(rs!=null) rs.close();
				if(pstmt!=null) pstmt.close();
				if(con!=null) con.close();
			} catch (SQLException e) {}
		}
	}
}





🐣 DBCP Servlet

  • DBCP(DataBase Connection Pool) : DBMS 서버에 미리 접속하여 다수의 Connection 객체를 저장하여 제공하기 위한 기능의 클래스(객체)

    • JDBC 프로그램의 가독성이 높아지고 유지보수의 효율성 증가
    • DBCP 기능을 제공하는 클래스는 일반적으로 DataSource 인터페이스를 상속받아 작성
  • Apache Tomcat 라이브러리에서 제공하는 DBCP 기능의 클래스를 사용하여 Connection 객체를 미리 생성하고 생성된 Connection 객체를 제공받아 접속정보를 클라이언트에게 전달하는 서블릿

package xyz.itwill.servlet;

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

	protected void service(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out=response.getWriter();
		
		//BasicDataSource 객체(DataSource 객체 - DBCP) 생성
		BasicDataSource dataSource=new BasicDataSource();
		
		//BasicDataSource 객체에 저장될 다수의 Connection 객체 생성 관련 정보
        //메소드를 호출하여 객체 필드값 변경
		dataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
		dataSource.setUrl("jdbc:oracle:thin:@localhost:1521:xe");
		dataSource.setUsername("scott");
		dataSource.setPassword("tiger");
		dataSource.setInitialSize(10);//최초 생성될 Connection 객체의 갯수 변경
		dataSource.setMaxIdle(10);//대기상태의 Connection 객체의 최대 갯수 변경
		dataSource.setMaxTotal(10);//생성 가능한 최대 Connection 객체의 최대 갯수 변경
		
		out.println("<!DOCTYPE html>");
		out.println("<html>");
		out.println("<head>");
		out.println("<meta charset='UTF-8'>");
		out.println("<title>Servlet</title>");
		out.println("</head>");
		out.println("<body>");
		out.println("<h1>DBCP(DataBase Connection Pool)</h1>");
		out.println("<hr>");
		try {
			//BasicDataSource 객체에 저장된 다수의 Connection 객체 중 하나를 반환받아 저장
			Connection con=dataSource.getConnection();
			out.println("<p>con = "+con+"</p>");
			out.println("<hr>");
			out.println("<h3>Connection 객체 제공 후</h3>");
			out.println("<p>Active Connection="+dataSource.getNumActive()+"</p>");
			out.println("<p>Idle Connection="+dataSource.getNumIdle()+"</p>");
			con.close();
			out.println("<hr>");
			out.println("<h3>Connection 객체 제거 후</h3>");
			out.println("<p>Active Connection="+dataSource.getNumActive()+"</p>");
			out.println("<p>Idle Connection="+dataSource.getNumIdle()+"</p>");
			
			dataSource.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		out.println("</body>");
		out.println("</html>");
	}
}





📌 META-INF / WEB-INF

  • 웹과 관련되지 않은 파일은 META-INF폴더에 new → other... → xml폴더 → xml file로 작성

  • 웹에 관련된 파일은 WEB-INF폴더에 작성 (web.xml, lib)


📕 context.xml

  • context.xml : WAS 프로그램에 객체 생성 관련 정보를 제공하기 위한 파일

    • WAS 프로그램 실행시 자동으로 파일을 읽어 필요한 정보를 저장
  • Context : context.xml 파일의 최상위 엘리먼트

  • Resource : 객체 생성 관련 정보를 속성과 속성값으로 제공하는 엘리먼트

    • name : Resource 엘리먼트를 구분하기 위한 식별자를 속성값으로 설정
      (객체 생성에 필요한 정보를 WAS 프로그램으로부터 제공하기 위한 이름)
    • auth : 객체 생성을 위한 정보를 제공한 사용자를 속성값으로 설정
    • type : 객체를 생성하여 반환받기 위한 자료형(클래스 또는 인터페이스)을 속성값으로 설정
    • factory : 객체를 생성하기 위한 Factory 클래스를 속성값으로 설정
    • Factory 클래스에 필요한 값을 속성명(필드명)과 속성값(필드값)을 사용하여 제공
      (driverClassName, url, username, password, initialSize, maxIdle, maxTotal 등)

<?xml version="1.0" encoding="UTF-8"?>
<Context>
	
	<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"/>
</Context>

📕 JNDI Servlet

  • JNDI(Java Naming Directory Interface) : WAS 프로그램에 객체 생성에 필요한 정보를 이름(식별자)으로 구분하여 저장하고 필요한 경우 객체 생성 정보를 제공받아 객체를 생성하여 사용하는 기능

    • 객체 생성에 필요한 정보를 제공하는 파일 필요
    • src/main/webapp/META-INF/context.xml
    • WAS 프로그램에 등록된 자원(Resource)을 이용하여 DataSource 객체를 생성하고 DataSource 객체에 저장된 다수의 Connection 객체중 하나를 제공받아 클라이언트에게 접속정보를 전달하는 서블릿
  • InitialContext 객체 생성

    • WAS 프로그램에 등록된 자원을 이용하여 객체를 생성하여 제공하기 위한 객체
    • NamingException(이름에 대한 자원 정보가 없는 경우 발생되는 예외) 발생 (예외처리)
    • InitialContext ic=new InitialContext();
  • InitialContext.lookup(String name) : 매개변수로 전달받은 이름의 자원을 WAS 프로그램에게 제공받아 객체를 생성하여 반환하는 메소드

    • Object 타입의 객체를 반환하므로 반드시 명시적 객체 형변환하여 사용
    • DataSource dataSource=(DataSource)ic.lookup("java:comp/env/jdbc/oracle");
    • java:comp/env/jdbc/oracle : 자바 자원으로 등록되어있으며 (comp/env)폴더에 있는 환경에 대한 정보로 등록되어있고 자원의 이름이 jdbc/oracle인 자원을 제공
    • 직접 객체를 생성하는 것보다 initialcontext에서 필요한 정보를 제공받아(웹자원) WAS에게 대신 만들어달라 하는 것이 가독성, 유지 보수 효율성에 좋아

package xyz.itwill.servlet;

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

	protected void service(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out=response.getWriter();//client에게 웹문서를 주겠다.
		
		try {//NamingException 예외 발생 (예외처리)
			//WAS 프로그램에 등록된 자원을 이용하여 InitialContext 객체 생성
			InitialContext ic=new InitialContext();
			
			//InitialContext.lookup(String name) : 매개변수로 전달받은 이름의
            //자원을 WAS 프로그램에게 제공받아 객체를 생성하여 반환(명시적 객체 형변환)
			DataSource dataSource=(DataSource)ic.lookup("java:comp/env/jdbc/oracle");
			
			Connection con=dataSource.getConnection();
						
			out.println("<!DOCTYPE html>");
			out.println("<html>");
			out.println("<head>");
			out.println("<meta charset='UTF-8'>");
			out.println("<title>Servlet</title>");
			out.println("</head>");
			out.println("<body>");
			out.println("<h1>DBCP(JNDI)</h1>");
			out.println("<hr>");
			out.println("<p>con = "+con+"</p>");
			out.println("</body>");
			out.println("</html>");
			
			con.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}





💡 oracle에서 phonebook table 생성

create table phonebook(phone varchar2(20) primary key,
name varchar2(20), address varchar2(50));
INSERT INTO phonebook values('010-1111-1111','홍길동','서울시 송파구');
INSERT INTO phonebook values('010-2222-2222','임꺽정','서울시 강남구');
INSERT INTO phonebook values('010-3333-3333','전우치','부천시 원미구');
INSERT INTO phonebook values('010-4444-4444','일지매','수원시 팔달구');
INSERT INTO phonebook values('010-5555-5555','장길산','인천시 월미구');
commit;

select * from phonebook;

desc phonebook;



📙 PhonebookDTO (VO클래스)

  • DTO(Data Transfer Object) 클래스 : 테이블의 행정보를 저장하여 전달하기 위한 클래스
    (VO 클래스)

package xyz.itwill.dto;

/*
이름      널?       유형           
------- -------- ------------ 
PHONE   NOT NULL VARCHAR2(20) 
NAME             VARCHAR2(20) 
ADDRESS          VARCHAR2(50) 
*/

//PHONEBOOK 테이블의 회원정보를 저장하기 위한 클래스
public class PhonebookDTO {
	private String phone;
	private String name;
	private String address;

	//기본 생성자 : [Ctrl]+[Space] >> Constructor 선택
	public PhonebookDTO() { }

	//생성자 : [Alt]+[Shift]+[S] >> [O] >> 필드 선택 >> Generate
	public PhonebookDTO(String phone, String name, String address) {
		super();
		this.phone = phone;
		this.name = name;
		this.address = address;
	}
	//Getter & Setter : [Alt]+[Shift]+[S] >> [R] >> 필드 선택 >> Generate
	public String getPhone() {
		return phone;
	}
	public void setPhone(String phone) {
		this.phone = phone;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
}





📙 JDBCDAO (공통된 메소드)

  • JDBC 기능을 제공하는 DAO 클래스가 상속받기 위해 작성된 부모클래스

    • 객체 생성이 목적이 아닌 상속을 목적으로 작성된 클래스
      (추상클래스로 작성하는 것을 권장)
  • WAS 프로그램에 등록된 자원을 얻어와 DataSource 객체를 반환받아 저장

    • 정적영역을 이용하여 한번만 실행
    • 1) DataSource 객체로부터 Connection 객체를 제공받아 반환하는 메소드
    • 2) 매개변수로 JDBC 관련 객체를 제공받아 제거하는 메소드
package xyz.itwill.dao;

public abstract class JdbcDAO {
	private static DataSource dataSource;
	
	static {//WAS프로그램에 등록된 자원을 얻어와
		try {//DataSource 객체를 반환받아 저장(명시적 객체 형변환)
			dataSource=(DataSource)new InitialContext().lookup("java:comp/env/jdbc/oracle");
		} catch (NamingException e) {
			e.printStackTrace();
		}
	}
	
	public Connection getConnection() throws SQLException {
		return dataSource.getConnection();
	}
	
	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(pstmt!=null) pstmt.close();
			if(con!=null) con.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	public void close(Connection con, PreparedStatement pstmt, ResultSet rs) {
		try {
			if(rs!=null) rs.close();
			if(pstmt!=null) pstmt.close();
			if(con!=null) con.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}





📙 PhonebookDAO (회원정보 검색)

  • DAO(Data Access Object) 클래스 : 테이블에 행 삽입, 변경, 삭제, 검색 명령(SQL)을 전달하여 실행하고 처리 결과를 Java 객체(값)으로 반환하는 기능을 제공하는 클래스

    • 싱글톤 클래스(프로그램에 객체를 하나만 생성하여 제공하는 클래스)로 작성하는 것을 권장
  • PHONEBOOK 테이블에 회원정보를 삽입, 변경, 삭제, 검색하는 기능을 제공하는 클래스

package xyz.itwill.dao;

public class PhonebookDAO extends JdbcDAO {
	private static PhonebookDAO _dao;
	
	private PhonebookDAO() {
		// TODO Auto-generated constructor stub
	}
	
	static {
		_dao=new PhonebookDAO();
	}
	
	public static PhonebookDAO getDAO() {
		return _dao;
	}
	
	//PHONEBOOK 테이블에 저장된 모든 회원정보를 검색하여 반환하는 메소드
	public List<PhonebookDTO> selectPhonebookList() {
		Connection con=null;
		PreparedStatement pstmt=null;
		ResultSet rs=null;
		List<PhonebookDTO> phonebookList=new ArrayList<PhonebookDTO>();
		try {
			con=getConnection();
			
			String sql="select * from phonebook order by phone";
			pstmt=con.prepareStatement(sql);
			
			rs=pstmt.executeQuery();
			
			while(rs.next()) {
				PhonebookDTO phonebook=new PhonebookDTO();
				phonebook.setPhone(rs.getString("phone"));
				phonebook.setName(rs.getString("name"));
				phonebook.setAddress(rs.getString("address"));
				phonebookList.add(phonebook);
			}
		}catch (SQLException e) {
			System.out.println("selectPhonebookList 메소드의 SQL오류="+e.getMessage());
		} finally {
			close(con, pstmt, rs);
		}
		return phonebookList;
	}
}





📙 Servlet (회원정보 검색)

  • PHONEBOOK 테이블에 저장된 모든 회원정보를 검색하여 클라이언트에게 전달하는 서블릿
    • DAO
  • PHONEBOOK 테이블에 저장된 모든 회원정보를 검색하여 반환하는 DAO 클래스의 메소드 호출
  • List<PhonebookDTO> phonebookList=PhonebookDAO.getDAO().selectPhonebookList();
package xyz.itwill.servlet;

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

	protected void service(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out=response.getWriter();
		
		//PHONEBOOK테이블에 저장된 회원정보를 검색하여 반환하는 DAO클래스의 메소드 호출
		List<PhonebookDTO> phonebookList=PhonebookDAO.getDAO().selectPhonebookList();
		
		out.println("<!DOCTYPE html>");
		out.println("<html>");
		out.println("<head>");
		out.println("<meta charset='UTF-8'>");
		out.println("<title>Servlet</title>");
		out.println("</head>");
		out.println("<body>");
		out.println("<h1>전화번호부</h1>");
		out.println("<hr>");
		out.println("<table border='1' cellspacing='0'>");//외곽선, 셀간격
		out.println("<tr>");
		out.println("<th width='200'>전화번호</th>");
		out.println("<th width='200'>이름</th>");
		out.println("<th width='300'>주소</th>");
		out.println("</tr>");
		//List 객체에 저장된 요소를 반복적으로 제공받아 클라이언트에게 전달
		for(PhonebookDTO phonebook:phonebookList) {
			out.println("<tr align='center'>");
			out.println("<td>"+phonebook.getPhone()+"</td>");
			out.println("<td>"+phonebook.getName()+"</td>");
			out.println("<td>"+phonebook.getAddress()+"</td>");
			out.println("</tr>");
		}
		out.println("</table>");
		out.println("</body>");
		out.println("</html>");
	}
}
          
          
          
          
          

💡 oracle에서 GUEST 테이블 생성

create table GUEST(no number(10) primary key,
		name varchar2(40),
		regdate date,
		title varchar2(100),
		content varchar2(4000));

create sequence guest_seq;

desc guest;

select * from guest;



🎀 방명록 작성


📒 GuestDTO (VO클래스)

  • oracle에서 테이블 생성 후 작성

package xyz.itwill.dto;

/*
이름      널?       유형             
------- -------- -------------- 
NO      NOT NULL NUMBER(10)      - 글번호 : 시퀸스의 자동 증가값
NAME             VARCHAR2(40)    - 작성자 : 사용자 입력값
REGDATE          DATE            - 작성일자 : 시스템의 현재 날짜(시간)
TITLE            VARCHAR2(100)   - 제목 : 사용자 입력값
CONTENT          VARCHAR2(4000)  - 내용 : 사용자 입력값
*/

public class GuestDTO {
	private int no;
	private String name;
	private String regdate;
	private String title;
	private String content;
	
	public GuestDTO() { }

	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 getRegdate() {
		return regdate;
	}
	public void setRegdate(String regdate) {
		this.regdate = regdate;
	}
	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;
	}
}





📒 GuestDAO (삽입,삭제,검색)

  • DAO(Data Access Object) 클래스 : 테이블에 행 삽입, 변경, 삭제, 검색 명령(SQL)을 전달하여 실행하고 처리 결과를 Java 객체(값)으로 반환하는 기능을 제공하는 클래스
    • 싱글톤 클래스(프로그램에 객체를 하나만 생성하여 제공하는 클래스)로 작성하는 것을 권장
  • 게시글을 전달받아 GUEST 테이블에 삽입하고 삽입행의 갯수를 반환하는 메소드
  • 게시글의 글번호를 전달받아 GUEST 테이블에 저장된 해당 글번호의 게시글을 삭제하고 삭제행의 갯수를 반환하는 메소드
  • GUEST 테이블에 저장된 모든 게시글을 검색하여 반환하는 메소드


package xyz.itwill.dao;

public class GuestDAO extends JdbcDAO {//싱글톤 클래스
	private static GuestDAO _dao;
	
	private GuestDAO() {
		// TODO Auto-generated constructor stub
	}
	
	static {
		_dao=new GuestDAO();
	}
	
	public static GuestDAO getDAO() {
		return _dao;
	}
	
	//게시글을 전달받아 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;
	}
	
	//게시글의 글번호를 전달받아 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;
	}
	
	//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; 
	}
}





📒 select.itwill - 출력페이지

  • GUEST 테이블에 저장된 모든 게시글을 검색하여 클라이언트에게 전달하는 서블릿 (출력페이지)

  • [방명록 쓰기]를 클릭한 경우 게시글 입력페이지(insert.html)로 이동

  • 게시글의 [삭제]를 클릭한 경우 게시글 삭제페이지(delete.itwill)로 이동 (글번호 전달)

    • 쿼리스트링을 이용해서 값(no) 전달
    • <button type='button' onclick='location.href=\"delete.itwill?no="+guest.getNo()+"\"'>
  • GUEST 테이블에 저장된 모든 게시글을 검색하여 반환하는 DAO 클래스의 메소드 호출

    • List<GuestDTO> guestList=GuestDAO.getDAO().selectGuestList();
  • 처리결과를 웹문서로 생성하여 클라이언트에게 전달 (응답)

    • out.println("<....>");



package xyz.itwill.servlet;

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

	protected void service(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out=response.getWriter();
		
		//GUEST 테이블에 저장된 모든 게시글을 검색하여 반환하는 DAO 클래스의 메소드 호출
		List<GuestDTO> guestList=GuestDAO.getDAO().selectGuestList();
		
		//처리결과를 웹문서로 생성하여 클라이언트에게 전달 (응답)
		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>");

		if(guestList.isEmpty()) {//검색된 게시글이 없는 경우
			out.println("<tr align='center'>");
			out.println("<td>방명록에 저장된 게시글이 하나도 없습니다.</td>");
			out.println("</tr>");
		} 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'>제&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;목</font></td>");
				out.println("<td height='20' width='80%' class='t1'>");
				out.println("<b><font color='#0000FF'>&nbsp;&nbsp;"+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>");
	}

}





📒 insert.html - 입력페이지

  • GUEST 테이블에 저장하기 위한 방명록 게시글을 사용자에게 입력받기 위한 문서 (입력페이지)

  • [방명록 쓰기]를 클릭하면 처리페이지(insert.itwill)로 이동

    • 웹프로그램 요청하여 사용자 입력값(방명록 게시글) 전달


<!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>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" >&nbsp;</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">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>
								</td>
								<td height="20" width="80%" class="t1">&nbsp;
								<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">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>
								</td>
								<td height="20" width="80%" class="t1">&nbsp;
								<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');">&nbsp;
		<input type="reset" value="다시 작성하기"  class="TXTFLD">
		</td>
	</tr>
</table>
</form>

</body>
</html>





📒 insert.itwill - 처리페이지

  • 입력페이지(insert.html)에서 전달된 게시글을 반환받아 GUEST 테이블에 삽입하고 클라이언트에게 게시글목록 출력페이지(select.itwill)로 이동하기 위한 URL 주소 전달 (처리페이지)
  • 전달값(게시글)을 반환받아 저장

    • String.trim() 메소드를 호출하여 전달값의 앞 또는 뒤에 존재하는 모든 공백 제거
    • String.replace() 메소드를 호출하여 XSS 공격에 대한 방어를 위해 태그 관련 기호를 회피문자(Escape Character)로 변환 (회피문자로 변환하면 문자값으로 인식)
    • XSS(Cross Site Scripting) : 입력태그에 악의적인 스트립트를 입력하여 출력페이지를 파괴 시키거나 개인정보를 특정 사이트로 유출하는 웹사이트 공격 방법
    • String name=request.getParameter("name").trim().replace("<", "&lt;").replace(">","&gt;");
  • DTO 객체를 생성하여 전달값으로 필드값 변경

  • 게시글(GuestDTO 객체)을 전달받아 GUEST 테이블에 삽입하는 DAO 클래스의 메소드 호출

  • 클라이언트에게 301 상태코드와 URL 주소 전달




package xyz.itwill.servlet;

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

	protected void service(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
		//비정상적인 요청에 대한 처리
		if(request.getMethod().equals("GET")) {
        //클라이언트가 서블릿을 [GET] 방식으로 요청한 경우 클라이언트에게 에러코드 전달
			response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);//405
			return;
		}
		
		//리퀘스트 메세지의 몸체부에 저장되어 전달되는 값(POST)에 대한 캐릭터셋 변경
		request.setCharacterEncoding("utf-8");
		
		//전달값(게시글)을 반환받아 저장
		String name=request.getParameter("name").trim().replace("<", "&lt;").replace(">","&gt;");
		String title=request.getParameter("title").trim().replace("<", "&lt;").replace(">","&gt;");
		String content=request.getParameter("content").trim().replace("<", "&lt;").replace(">","&gt;");
		
		//DTO 객체를 생성하여 전달값으로 필드값 변경
		GuestDTO guest=new GuestDTO();
		guest.setName(name);
		guest.setTitle(title);
		guest.setContent(content);
		
		//게시글(GuestDTO 객체)을 전달받아 GUEST 테이블에 삽입하는 DAO 클래스의 메소드 호출
		GuestDAO.getDAO().insertGuest(guest);
		
		//클라이언트에게 301 상태코드와 URL 주소 전달
		response.sendRedirect("select.itwill");//리다이렉트 이동
	}

}





📒 remove.itwill - 처리페이지

  • 게시글목록 출력페이지(select.itwill)에서 전달된 글번호를 반환받아 GUEST 테이블에 저장된 해당 글번호의 게시글을 삭제하고 게시글목록 출력페이지(select.itwill)로 이동하기 위한 URL 주소 전달하는 서블릿 (처리페이지)


package xyz.itwill.servlet;

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

	protected void service(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
		//비정상적인 요청에 대한 처리
		if(request.getParameter("no")==null) {//전달값이 없는 경우
			response.sendError(HttpServletResponse.SC_BAD_REQUEST);//400
			return;
		}
		
		//전달값(글번호)을 반환받아 저장 - 문자열 >> 정수값
		int no=Integer.parseInt(request.getParameter("no"));
		
		//글번호를 전달받아 GUEST 테이블에 저장된 해당 글번호의 게시글을 삭제하는 DAO 클래스의 메소드 호출
		int rows=GuestDAO.getDAO().deleteGuest(no);
		
		if(rows>0) {//삭제행이 있는 경우
			response.sendRedirect("select.itwill");
		} else {//삭제행이 없는 경우 - 비정상적인 요청
			response.sendError(HttpServletResponse.SC_BAD_REQUEST);
		}
	}

}





profile
Study Log 📂

0개의 댓글