드디어 오라클을 연동해서 글을 쓰고, 삭제하고, 수정하고 지울 수 있는 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> ");
out.println(curpage+" page / "+totalpage+" pages ");
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> ");
out.println("<a href=#>삭제</a> ");
out.println("<a href=BoardListServlet>목록</a> ");
out.println("</td>");
out.println("</tr>");
out.println("</table>");
out.println("</body>");
out.println("</center>");
out.println("</html>");
}
}
테이블 형식에 맞춰 값들을 채워 넣어주면 되기 때문에 더욱 간단하게 데이터들을 출력해줄 수 있다.
아직 게시물 수정이나 삭제는 배우지 않아서 이제 다음시간에 마저 완성을 하면
진정한 CRUD 프로그램을 만들 수 있을것이다.
'programming > Gukbi' 카테고리의 다른 글
국비 교육 46일차 - 로그인 프로그램, CSS, 형상관리 프로그램(Git) (0) | 2021.03.03 |
---|---|
국비 교육 45일차 - 오라클 연동 (게시판 마무리), CSS (0) | 2021.03.02 |
국비 교육 43일차 - 오라클 연결 웹 프로젝트, servlet, HTML (input, attribute) (0) | 2021.02.25 |
국비 교육 42일차 - PL/SQL, HTML(table, img tag.. etc) (0) | 2021.02.25 |
국비 교육 41일차 - 서브쿼리, html, 팀프로젝트 회의 (0) | 2021.02.23 |