본문 바로가기

programming/Gukbi

국비 교육 44일차 - 오라클 연동 (게시판 만들기)

728x90
반응형

드디어 오라클을 연동해서 글을 쓰고, 삭제하고, 수정하고 지울 수 있는 CRUD 프로그램 만드는 법을 배우게 됐다.

 

생각보다는 빨리 배우게 되서 설레는 맘이 더 컸다. 

예상대로 쉽지는 않았지만 또 못할건 아니라는 생각이 들었다. 아예 처음부터 새로 만들어 주는거라 오라클에 테이블을 먼저 만들어주면서 시작했다. 

 

/*
 *  NO      NOT NULL NUMBER         
	NAME    NOT NULL VARCHAR2(34)   
	SUBJECT NOT NULL VARCHAR2(2000) 
	CONTENT NOT NULL CLOB           
	PWD     NOT NULL VARCHAR2(10)   
	REGDATE          DATE           
	HIT              NUMBER 
	========= 오라클의 컬럼명과 자바의 변수명 일치 
 */

 위와 같이 간단하게 이름, 제목, 내용, 비밀번호, 작성일, 조회수의 변수가 있는 테이블을 각 데이터 형에 맞게 만들었다.

 

primary키로는 게시물의 번호를 매겨줬고, 이름, 제목, 내용, 비밀번호는 null 값이 되지 않도록 not null 제약조건을 걸어주었다. 

 

regdate는 sysdate로 default를, hit는 0으로 먼저 default값을 잡아주었다. 이 테이블을 토대로 VO 파일을 만들어 준다

import java.util.Date;

import lombok.Getter;
import lombok.Setter;

import java.sql.*;
@Setter
@Getter
public class BoardVO {
	
	private int no;
	private String name;
	private String subject;
	private String content;
	private String pwd;
	private Date regdate;
	private int hit;
}

 근데 getter/setter을 직접 생성해주는 대신 lombok을 이용해서 생성없이 바로 만드는 법을 배웠다. 

lombok 사용하는거 잊지말기

 

 

VO파일을 완성해주었으면 DAO 파일을 다시 완성해주러 가면 된다. 

package com.sist.dao;
import java.util.*;
import java.sql.*;
public class BoardDAO {
	// 1. 오라클 연결 객체
	private Connection conn;
	// 2. SQL문장 송수신 개체
	private PreparedStatement ps; // BufferedReader, OutputStream
	// JDBC => TCP를 이용하는 프로그램
	// 3. URL (오라클 주소)
	private final String URL="jdbc:oracle:thin:@localhost:1521:XE";
	
	// 오라클 연결 드라이버 설치 (한번만 설치) - 생성자
	public BoardDAO()
	{
		try 
		{
			// 리플랙션 => 클래스의 정보를 읽어서 메모리 할당
			Class.forName("oracle.jdbc.driver.OracleDriver"); // Class.forName("패키지명.클래스명");
		}
		catch (Exception ex) 
		{
		
		}
	}
	
	// 오라클 연결 = 닫기 
	// 1. 연결 conn hr/happy
	public void getConnection()
	{
		try 
		{
			conn=DriverManager.getConnection(URL, "hr", "happy");
			/*
			 * 	 DriverManager (Factory Pattern)
			 * 	 => DML (ANSI) LIKE '%' 
			 */
		} 
		catch (Exception ex)
		{
			
		}
	}
	
	// 2. exit
	public void disConnection()
	{
		try
		{
			if(ps!=null)
				ps.close();
			if(conn!=null)
				conn.close();
		}
		catch (Exception ex) {
			System.out.println(ex.getMessage());
		}
		finally
		{
			
		}
	}
	// 3. 게시판 기능
	// 3-1. 목록 => 인라인뷰 (페이지 나누기) => ArrayList<BoardVO>
	public ArrayList<BoardVO> boardListData(int page)
	{
		ArrayList<BoardVO> list=new ArrayList<BoardVO>();
		
		try 
		{
			// 1. 연결
			getConnection();
			//2. sql문장
			String sql="SELECT no, subject, name, regdate, hit, num "
					+"FROM (SELECT no, subject, name, regdate, hit, rownum as num "
					+"FROM (SELECT no, subject, name, regdate, hit "
					+"FROM webBoard ORDER BY no DESC)) "
					+"WHERE num BETWEEN ? AND ?";
			int rowSize=10;
			int start=(rowSize*page)-(rowSize-1);
			int end=(rowSize*page);
			ps=conn.prepareStatement(sql);
			
			// ?에 값을 채운다
			ps.setInt(1, start);
			ps.setInt(2, end);
			
			// SQL문장 실행요청 => 결과값을 받는다
			ResultSet rs=ps.executeQuery();
			//rs에 존재하는 데이터를 list에 추가
			while(rs.next())
			{
				BoardVO vo=new BoardVO();
				vo.setNo(rs.getInt(1));
				vo.setSubject(rs.getString(2));
				vo.setName(rs.getString(3));
				vo.setRegdate(rs.getDate(4));
				vo.setHit(rs.getInt(5));
				list.add(vo);
			}
		} 
		catch (Exception ex)
		{
			System.out.println(ex.getMessage());
		}
		finally
		{
			// 무조건 오라클을 닫는다
			disConnection();
		}
		return list;
	}
	// 3-1-1. 게시물 총 갯수 => 번호를 순서대로 출력
	public int boardRowCount()
	{
		int count=0;
		try 
		{
			getConnection();
			String sql="SELECT COUNT(*) FROM webBoard";
			ps=conn.prepareStatement(sql);
			ResultSet rs=ps.executeQuery();
			rs.next();
			count=rs.getInt(1);
			rs.close();
		} 
		catch (Exception ex) 
		{
			System.out.println(ex.getMessage());
		}
		return count;
	}
	// 3-2. 추가 => INSERT => 시퀀스 이용
	// 3-3. 수정 => UPDATE => SQL문장 2개 사용 1.비밀번호 확인, 2. 수정 하고 난 뒤 => 어디로 갈까? (흐름)
	// 3-4. 삭제 => DELETE => 비밀번호 확인
	// 3-5. 내용보기 => SQL(2개)
	public BoardVO boardDetailData(int no)
	{
		BoardVO vo=new BoardVO();
		try
		{
			getConnection();
			// 조회수 증가
			String sql="UPDATE webBoard SET "
					+"hit=hit+1 "
					+"WHERE no=?";
			ps=conn.prepareStatement(sql);
			// ?에 값을 채워준다 
			ps.setInt(1, no);
			// UPDATE를 실행
			ps.executeUpdate(); // COMMIT이 포함되어 있음 
			
			// 증가된 조회수를 포함해서 데이터 읽기
			sql="SELECT no, name, subject, content, regdate, hit "
					+"FROM webBoard "
					+"WHERE no=?";
			ps=conn.prepareStatement(sql);
			ps.setInt(1, no);
			ResultSet rs=ps.executeQuery();
			rs.next();
			vo.setNo(rs.getInt(1));
			vo.setName(rs.getString(2));
			vo.setSubject(rs.getString(3));
			vo.setContent(rs.getString(4));
			vo.setRegdate(rs.getDate(5));
			vo.setHit(rs.getInt(6));	
		}
		catch (Exception ex)
		{
			// TODO: handle exception
		}
		finally
		{
			disConnection();
		}
		return vo;
	}
	// 3-6. 찾기 => LIKE 
	
}

 역시 오라클 연결까지는 전부 동일하다. 어떤 기능을 구현 할 것인지에 따라 코드가 달라지는데, 먼저 전체 목록을 출력해주는 BoardListData를 만드는것이 가장 첫번째이다. 

 

페이지를 나눠줘야 하기 때문에 sql문장은 인라인뷰를 써서 데이터를 가져와 준다. 

String sql="SELECT no, subject, name, regdate, hit, num "
					+"FROM (SELECT no, subject, name, regdate, hit, rownum as num "
					+"FROM (SELECT no, subject, name, regdate, hit "
					+"FROM webBoard ORDER BY no DESC)) "
					+"WHERE num BETWEEN ? AND ?";

 가장 최근에 쓴 글이 맨 첫번째로 올라와야 하기 때문에 no의 값들을 DESC로 정렬을 해주고, rownum을 사용해서 num이라는 컬럼을 하나 만들어 준다. 이제 그 num 컬럼에 있는 값들을 가져와주면 최근 게시글 순으로 글들을 출력할 수 있다. 

 

금요일 수업에서는 상세보기 까지만 프로그램을 만들어 줬다. 

상세보기 프로그램을 만들기 위해서는 조회수를 먼저 증가시켜준 후에 목록이 출력될 수 있도록 해야한다.

 

// 조회수 증가
			String sql="UPDATE webBoard SET "
					+"hit=hit+1 "
					+"WHERE no=?";
			ps=conn.prepareStatement(sql);
			// ?에 값을 채워준다 
			ps.setInt(1, no);
			// UPDATE를 실행
			ps.executeUpdate(); // COMMIT이 포함되어 있음 

 조회수를 증가시켜 주고 나면 executeUpdate()를 통해 commit을 해준다. 

 

그리고 나서 조회수를 증가시킨 데이터를 출력해주는 코드를 짜면 된다. 

sql="SELECT no, name, subject, content, regdate, hit "
					+"FROM webBoard "
					+"WHERE no=?";
			ps=conn.prepareStatement(sql);
			ps.setInt(1, no);
			ResultSet rs=ps.executeQuery();
			rs.next();
			vo.setNo(rs.getInt(1));
			vo.setName(rs.getString(2));
			vo.setSubject(rs.getString(3));
			vo.setContent(rs.getString(4));
			vo.setRegdate(rs.getDate(5));
			vo.setHit(rs.getInt(6));	

 증가된 조회수까지 가져와주면 완성이 된다. 이 코드를 가지고 Servlet에서 실제 웹사이트에 출력만 해주면 된다. 

 

package com.sist.board;

import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;

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 java.util.*;
import com.sist.dao.*;
@WebServlet("/BoardListServlet")
public class BoardListServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//1. 서블릿 => 브라우저로 전송 (HTML,XML)
		response.setContentType("text/html;charset=EUC-KR");// text/xml;charset=EUC-KR
		//2. 어느 컴퓨터로 전송 할지 설정 
		PrintWriter out=response.getWriter();// 해당 클라이언트에 HTML을 전송
		/*
		 *   데이터 받기 
		 */
		//1. 데이터 => 사용자 요청한 페이지 받기 
		String page=request.getParameter("page");
		// 2. 처음에는 페이지 설정 (X) => 디폴트
		if(page==null)
			page="1";
		// 현재 페이지 저장 
		int curpage=Integer.parseInt(page);
		// 총페이지 저장 
		BoardDAO dao=new BoardDAO();
		int count=dao.boardRowCount();// 번호순서로 출력 
		int totalpage=(int)(Math.ceil(count/10.0));
		// 페이지별 데이터 읽기
		ArrayList<BoardVO> list=dao.boardListData(curpage);
		//3. 어떤 HTML 설정 
		out.println("<html>");
		out.println("<head>");
		out.println("<style type=text/css>");
		out.println("td,th{font-family:맑은 고딕;font-size:9pt;height:35px}");
		out.println(".table_main{border-collapse:collapse;");
		out.println("border-top-width: 2px;"
				+ "border-bottom-width: 1px;"
				+ "border-top-style: solid;"
				+ "border-bottom-style: solid;"
				+ "border-top-color: #333;"
				+ "border-bottom-color: #333;}");
		out.println(".table_main th{");
		out.println("background-color: #999;"
				+ "color: #fff;"
				+ "border-bottom-width: 1px;"
				+ "border-bottom-color: #333;}");
		out.println(".table_main td{");
		out.println("border-bottom-width: 1px;"
				+ "border-bottom-color: #666;"
				+ "border-bottom-style: dotted;}");
		out.println("a{color:black;text-decoration:none}");
		out.println("a:hover{color:green;text-decoration:underline}");
		out.println(".dataTr:HOVER {"
				+ "background-color: #FC6;"
				+ "cursor: pointer;"
				+ "cursor: hand;"
				+ "}");
		out.println("</style>");
		out.println("</head>");
		out.println("<body>");
		out.println("<center>");
		out.println("IP:"+request.getRemoteAddr());
		out.println("<h1>게시판</h1>");
		out.println("<table border=0 width=700>");
		out.println("<tr>");
		out.println("<td><a href=#>새글</a></td>");
		out.println("</tr>");
		out.println("</table>");
		
		out.println("<table width=700 class=table_main>");
		out.println("<tr id=head>");
		out.println("<th width=10%>번호</th>");
		out.println("<th width=45%>제목</th>");
		out.println("<th width=15%>이름</th>");
		out.println("<th width=20%>작성일</th>");
		out.println("<th width=10%>조회수</th>");
		out.println("</tr>");
		// 데이터를 출력하는 위치 
		for(BoardVO vo:list)
		{
			out.println("<tr class=dataTr>");
			out.println("<td width=10% align=center>"+vo.getNo()+"</td>");
			String today=new SimpleDateFormat("yyyy-MM-dd").format(new Date());
			String dbday=vo.getRegdate().toString();
			// YY/MM/DD => java => yyyy-MM-dd
			out.println("<td width=45%><a href=BoardDetailServlet?no="+vo.getNo()+">"+vo.getSubject()+"</a>");
			if(today.equals(dbday))
			{
				out.println("<sup><font color=red>new</font></sup>");
			}
			out.println("</td>");
			out.println("<td width=15% align=center>"+vo.getName()+"</td>");
			out.println("<td width=20% align=center>"+vo.getRegdate().toString()+"</td>");
			out.println("<td width=10% align=center>"+vo.getHit()+"</td>");
			out.println("</tr>");
		}
		out.println("</table>");
		// 하단
		out.println("<table width=700>");
		out.println("<tr>");
		out.println("<td align=left>");
		out.println("Search:");
		out.println("<select name=fs>");
		out.println("<option value=name>이름</option>");
		out.println("<option value=subject>제목</option>");
		out.println("<option value=content>내용</option>");
		out.println("</select>");
		out.println("<input type=text name=ss size=10>");
		out.println("<input type=submit value=검색>");
		out.println("</td>");
		out.println("<td align=right>");
		out.println("<a href=BoardListServlet?page="+(curpage>1?curpage-1:curpage)+">이전</a>&nbsp;");
		out.println(curpage+" page / "+totalpage+" pages&nbsp;");
		out.println("<a href=BoardListServlet?page="+(curpage<totalpage?curpage+1:curpage)+">다음</a>");
		out.println("</td>");
		out.println("</tr>");
		out.println("</table>");
		out.println("</center>");
		out.println("</bosy>");
		out.println("</html>");
		
	}

}

  테이블 형식으로 데이터를 출력해줄 것이기 때문에 먼저 테이블로 만들어서 그 이후에 for문을 사용해서 데이터를 반복해서 테이블에 찍어내주면 끝이 난다. 

 

 글 번호, 제목, 이름, 날짜, 조회수 순으로 출력해주는 테이블 형식을 만들어 준다. 

그리고 이제 각각 해당하는 값들을 채워넣어주면 끝난다. 

 

먼저 글 번호는 그냥 vo.getNO()를 써서 가져와주면 된다. 

제목 역시 vo.getTitle로 받아와주면 되는데, detailData로 연결 될 수 있도록 a태그를 사용해서 값을 가져와 준다

이때, 오늘날짜와 작성 날짜가 같다면 new글씨를 써주는 코드를 추가 시켜줄 수 있다. 

if(today.equals(dbday))
			{
				out.println("<sup><font color=red>new</font></sup>");
			}

 

그럼 제목을 눌러서 상세보기 페이지로 가면 내용을 출력해주는 코드를 짜면되는데, 이건 더욱 간단하다

 

package com.sist.board;

import java.io.*;
import java.util.ArrayList;

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 com.sist.dao.BoardDAO;
import com.sist.dao.BoardVO;

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

	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 1. 전송 타입 결정 (HTML)
		response.setContentType("text/html;charset=EUC-KR");
		PrintWriter out=response.getWriter(); // 요청한 사람의 브라우저로 전송
		
		String no=request.getParameter("no");
		// DAO 연결
		BoardDAO dao=new BoardDAO();
		BoardVO vo=dao.boardDetailData(Integer.parseInt(no));
	
		
	
		out.println("<html>");
		out.println("<head>");
		out.println("<style type=text/css>");
		out.println("td,th{font-family:맑은 고딕;font-size:9pt;height:35px}");
		out.println(".table_main{border-collapse:collapse;");
		out.println("border-top-width: 2px;"
				+ "border-bottom-width: 1px;"
				+ "border-top-style: solid;"
				+ "border-bottom-style: solid;"
				+ "border-top-color: #333;"
				+ "border-bottom-color: #333;}");
		out.println(".table_main th{");
		out.println("background-color: #999;"
				+ "color: #fff;"
				+ "border-bottom-width: 1px;"
				+ "border-bottom-color: #333;}");
		out.println(".table_main td{");
		out.println("border-bottom-width: 1px;"
				+ "border-bottom-color: #666;"
				+ "border-bottom-style: dotted;}");
		out.println("a{color:black;text-decoration:none}");
		out.println("a:hover{color:green;text-decoration:underline}");
		out.println(".dataTr:HOVER {"
				+ "background-color: #FC6;"
				+ "cursor: pointer;"
				+ "cursor: hand;"
				+ "}");
		out.println("</style>");
		out.println("</head>");
		out.println("<body>");
		out.println("<center>");
		
		out.println("<h1>내용보기</h1>");
		out.println("<table class=table_main width=600>");
		out.println("<tr>");
		out.println("<th width=20%>번호</th>");
		out.println("<td width=30% align=center>"+vo.getNo()+"</td>");
		out.println("<th width=20%>작성일</th>");
		out.println("<td width=30% align=center>"+vo.getRegdate().toString()+"</td>");
		out.println("</tr>");
		out.println("<tr>");
		out.println("<th width=20%>이름</th>");
		out.println("<td width=30% align=center>"+vo.getName()+"</td>");
		out.println("<th width=20%>조회수</th>");
		out.println("<td width=30% align=center>"+vo.getHit()+"</td>");
		out.println("</tr>");
		out.println("<tr>");
		out.println("<th width=20%>제목</th>");
		out.println("<td colspan=3>"+vo.getSubject()+"</td>");
		out.println("</tr>");
		
		out.println("<tr>");
		out.println("<td colspan=4 align=left valign=top style=\"height:200px\"><pre>"+vo.getContent()+"</pre></td>");
		out.println("</tr>");
		out.println("<tr>");
		out.println("<td colspan=4 align=right>");
		out.println("<a href=#>수정</a>&nbsp;");
		out.println("<a href=#>삭제</a>&nbsp;");
		out.println("<a href=BoardListServlet>목록</a>&nbsp;");
		out.println("</td>");
		out.println("</tr>");
		
		out.println("</table>");
		out.println("</body>");
		out.println("</center>");
		out.println("</html>");
	}

}

 테이블 형식에 맞춰 값들을 채워 넣어주면 되기 때문에 더욱 간단하게 데이터들을 출력해줄 수 있다.

 

아직 게시물 수정이나 삭제는 배우지 않아서 이제 다음시간에 마저 완성을 하면

진정한 CRUD 프로그램을 만들 수 있을것이다. 

728x90
반응형