Servlet 실습 : CURD 게시판 만들기

부트캠프(END)/-Web 실습|2022. 7. 14. 16:17

get을 보내면 get으로 받아야 하고

post를 보내면 post로 받아야 한다!

 

유일하게 번호가 안 넘어가는 것 = 검색/찾기 기능

회원가입, 회원탈퇴, 장바구니 추가/제거, 글 수정/삭제 다 번호가 넘어 간다.

 

MyBatis가 SQL과 자바 파일을 분리할 수 있도록 해줌.

나중에 자바코드는 servlet, html은 jsp에서 하도록 분리할 것임.

 

 

우선 게시판 VO를 만들어 준다.

→ 게시글 번호, 조회수, 작성자이름, 제목, 내용, 비밀번호, 작성일

BoardVO.java (Class)

package doodoo.vo;
import java.util.*;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class BoardVO {
	private int no, hit;
	private String name, subject, content, pwd;
	private Date regdate;

 

데이터베이스에 연결해서 CURD 기능을 구현하는 DAO를 생성한다.

BoardDAO.java (Class)

package doodoo.dao;
import java.sql.*;
import java.util.*;

import doodoo.vo.*;

public class BoardDAO {
  private Connection conn;
  private PreparedStatement ps;
  private final String URL = "jdbc:oracle:thin:@localhost:1521:XE";

  public BoardDAO() {
    try {
      Class.forName("oracle.jdbc.driver.OracleDriver");
    } catch (Exception ex) {}
  }

  public void getConnection() {
    try {
      conn = DriverManager.getConnection(URL, "user", "0000");
    } catch (Exception ex) {
      System.out.println("getConnection() 에러");
      ex.printStackTrace();
    }
  }

  public void disConnection() {
    try {
      if (ps != null) ps.close();
      if (conn != null) conn.close();
    } catch (Exception ex) {
      System.out.println("disConnection() 에러");
      ex.printStackTrace();
    }
  }

  public List < BoardVO > boardListData(int page) {
    List < BoardVO > list = new ArrayList < BoardVO > ();
    try {
      getConnection();
      //inline view
      //뒤에서부터(최신것부터) 차례로 10개씩 가져온다.
      String sql = "SELECT no, subject, name, regdate, hit, num " +
        "FROM (SELECT no, subject, name, regdate, hit, rownum as num " +
        "FROM (SELECT /*+ INDEX_DESC(freeboard fb_no_pk)*/no, 
      subject, name, regdate, hit " +
        "FROM freeboard)) " +
        "WHERE num BETWEEN ? AND ?";
      ps = conn.prepareStatement(sql);

      int rowSize = 10;
      int start = (page * rowSize) - (rowSize - 1);
      int end = page * rowSize;

      ps.setInt(1, start);
      ps.setInt(2, end);

      ResultSet rs = ps.executeQuery();
      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);
      }
      rs.close();

    } catch (Exception ex) {

    } finally {
      disConnection();
    }
    return list;
  }

  public int boardTotal() {
    int total = 0;
    try {
      getConnection();
      String sql = "SELECT CEIL(COUNT(*)/10.0) FROM freeboard";
      ResultSet rs = ps.executeQuery();
      rs.next();
      total = rs.getInt(1);
      rs.close();
    } catch (Exception ex) {
      System.out.println("boardTotal() 에러");
      ex.printStackTrace();
    } finally {
      disConnection();
    }

    return total;
  }

  //상세보기
  public BoardVO boardDetail(int no, int type) {
    BoardVO vo = new BoardVO();
    try {
      getConnection();
      //조회시 => 조회수 증가
      if (type == 1) {
        String sql = "UPDATE freeboard SET " +
          "hit = hit+1 " +
          "WHERE no=?";
        ps = conn.prepareStatement(sql);
        ps.setInt(1, no);
        ps.executeUpdate();
      }
      //수정시 => 조회수 증가하지 않음
      //실제 데이터 읽기 => UPDATE, DETAIL에서 다 씀
      String sql = "SELECT no, name, subject, content, regdate, hit " +
        "FROM freeboard " +
        "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));
      rs.close();

    } catch (Exception ex) {
      System.out.println("boardDetail() 에러");
      ex.printStackTrace();
    } finally {
      disConnection();
    }
    return vo;
  }
  //수정, 삭제
  public void boardUpdate(BoardVO vo) {
    try {
      getConnection();
      String sql = "UPDATE freeboard SET " +
        "name=?, subject=?, content=? " +
        "WHERE no=?";
      ps = conn.prepareStatement(sql);
      ps.setString(1, vo.getName());
      ps.setString(2, vo.getSubject());
      ps.setString(3, vo.getContent());
      ps.setInt(4, vo.getNo());

      ps.executeUpdate();

    } catch (Exception ex) {
      System.out.println("boardUpdate() 에러");
      ex.printStackTrace();
    } finally {
      disConnection();
    }
  }
  public void boardDelete(int no) {
    try {
      getConnection();
      String sql = "DELETE FROM freeboard " +
        "WHERE no=?";
      ps = conn.prepareStatement(sql);
      ps.setInt(1, no);
      ps.executeUpdate();
    } catch (Exception ex) {
      System.out.println("boardUpdate() 에러");
      ex.printStackTrace();
    } finally {
      disConnection();
    }
  }
  //새글
  public void boardInsert(BoardVO vo) {
    try {
      getConnection();
      String sql = "INSERT INTO freeboard(no, name, subject, content, pwd) " +
        "VALUES((SELECT NVL(MAX(no)+1,1) FROM freeboard), ?,?,?,?)";
      ps = conn.prepareStatement(sql);
      ps.setString(1, vo.getName());
      ps.setString(2, vo.getSubject());
      ps.setString(3, vo.getContent());
      ps.setString(4, vo.getPwd());

      ps.executeUpdate();
    } catch (Exception ex) {
      System.out.println("boardInsert() 에러");
      ex.printStackTrace();
    } finally {
      disConnection();
    }
  }
}

}

 

DAO를 통해 데이터를 읽어 오고, 그 데이터를 html코드와 함께 뿌려 주는 Servlet

BoardServlet.java (Servlet)

package doodoo.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 java.io.*;

import java.util.*;
import doodoo.dao.*;
import doodoo.vo.*;

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

  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //1. 변환(전송방법 선택) => HTML, XML, JSON
    response.setContentType("text/html; charset=UTF-8"); //HTML, 한글포함 텍스트로 보내겠습니다
    //2. 각 사용자별로 서버가 뿌려주고, 브라우저에서 읽어갈 위치의 메모리를 설정
    PrintWriter out = response.getWriter();
    //3. 데이터 읽기
    BoardDAO dao = new BoardDAO();
    List < BoardVO > list = dao.boardListData(1);

    //out 안에 HTML을 작성해 주면 된다
    out.println("<html>");
    out.println("<head>");
    //style
    out.println("<style type=text/css>");
    out.println("div{width:100%}");
    out.println("h1{margin-top:50px; text-align:center}");
    out.println("table{margin:0px auto;}"); //브라우저 가운데에 출력해라
    out.println("</style>");
    out.println("<link rel=stylesheet href=table.css"); //외부 css파일 불러오기
    out.println("</head>");
    //body
    out.println("<body>");
    out.println("<div>");
    out.println("<h1>자유게시판</h1>");
    out.println("<table width=700 class=table_content>");
    out.println("<tr>");
    out.println("<td><a href=BoardInsert>새 글</a></td>");
    out.println("</tr>");
    out.println("</table>");
    out.println("<table width=700 class=table_content>");
    out.println("<tr>");
    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>");
    //4. 데이터 출력
    for (BoardVO vo: list) {
      out.println("<tr class=dataTr>");
      out.println("<td width=10%>" + vo.getNo() + "</td>");
      out.println("<td width=45%><a href=BoardDetail?no=" +
        vo.getNo() + ">" + vo.getSubject() + "</a></td>");
      //상세보기를 들어갈 때 게시물 번호를 넘겨 주어야 한다. 
      //? 앞에 있는 BoardDetail이 no라는 값을 받아감.
      out.println("<td width=15%>" + vo.getName() + "</td>");
      out.println("<td width=20%>" + vo.getRegdate().toString() + "</td>");
      out.println("<td width=10%>" + vo.getHit() + "</td>");
      out.println("</tr>");
    }
    out.println("</table>");
    out.println("</div>");
    out.println("</body>");
    out.println("</html>");
  }

}

 

form 태그 내에 있는 데이터를 post 방식으로 전송하여 데이터베이스에 추가하는 Servlet

BoardInsert.java (Servlet)

package doodoo.servlet;

import java.io.*;
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 doodoo.dao.BoardDAO;
import doodoo.vo.BoardVO;

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

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//1. 변환(전송방법 선택) => HTML, XML, JSON
    	response.setContentType("text/html; charset=UTF-8"); //HTML, 한글포함 텍스트로 보내겠습니다
    	//2. 각 사용자별로 서버가 뿌려주고, 브라우저에서 읽어갈 위치의 메모리를 설정
    	PrintWriter out = response.getWriter();
    	
    	out.println("<html>");
    	out.println("<head>");
    	//style
    	out.println("<style type=text/css>");
    	out.println("div{width:100%}");
    	out.println("h1{margin-top:50px; text-align:center}");
    	out.println("table{margin:0px auto;}");//브라우저 가운데에 출력해라
    	out.println("</style>");
    	out.println("<link rel=stylesheet href=table.css"); //외부 css파일 불러오기
    	out.println("</head>");
    	//body
    	out.println("<body>");
    	out.println("<div>");
    	out.println("<h1>글쓰기</h1>");
    	out.println("<form method=post action=BoardInsert>");
    	//아래 내용을 한 번에 모아서 원하는 곳으로 전송할 수 있는 form태그
    	out.println("<table width=700 class=table_content>");
    	out.println("<tr>");
    	out.println("<th align=right width=15%>이름</th>");
    	out.println("<td width=85%><input type=text name=name size=15></td>");
    	out.println("</tr>");
    	out.println("<tr>");
    	out.println("<th align=right width=15%>제목</th>");
    	out.println("<td width=85%><input type=text name=subject size=45></td>");
    	out.println("</tr>");
    	out.println("<tr>");
    	out.println("<th align=right width=15%>내용</th>");
    	out.println("<td width=85%><textarea rows=10 cols=50 name=content></textarea></td>");
    	out.println("</tr>");
    	out.println("<tr>");
    	out.println("<th align=right width=15%>비밀번호</th>");
    	out.println("<td width=85%><input type=password name=pwd size=10></td>");
    	out.println("</tr>");
    	out.println("<tr>");
    	out.println("<td colspan=2 align-center>");
    	out.println("<input type=submit value=글쓰기>");
    	out.println("<input type=button value=취소 onclick=\"javascript:history.back()\">");
    	out.println("</td>");
    	out.println("</tr>");
    	out.println("</table>");
    	out.println("</form>");
    	out.println("</div>");
    	out.println("</body>");
    	out.println("</html>");
    	
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		//post방식으로 보낼 때 필요한 부분
		try {
			//한글이 깨질 수 있음. 변환 필요->디코딩
			req.setCharacterEncoding("UTF-8"); //POST 방식
			//get방식은 server.xml 63행 변경필요
			
			//전송할땐 byte[]로 인코딩, 받아올 땐 디코딩
		}catch(Exception ex){
			
		}
		//name을 notnull로 설정해 두었기 때문에 입력되지 않은채로 전송하려 하면 오류가 난다.
		//-> 그래서 유효성 검사를 하는 것
		String name=req.getParameter("name");
		String subject=req.getParameter("subject");
		String content=req.getParameter("content");
		String pwd=req.getParameter("pwd");
		
		BoardVO vo = new BoardVO();
		vo.setName(name);
		vo.setSubject(subject);
		vo.setContent(content);
		vo.setPwd(pwd);
		
		//DAO와 연결!
		BoardDAO dao = new BoardDAO();
		dao.boardInsert(vo);
		
		//화면 이동 -> BoardServlet
		resp.sendRedirect("BoardServlet");
	}
	
	
}

 

게시글 번호를 받아 해당 게시물의 상세 내용을 조회하는 Servlet

BoardDetail.java (Servlet)

package doodoo.servlet;

import java.io.*;
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 doodoo.dao.*;
import doodoo.vo.*;
@WebServlet("/BoardDetail")
//post방식은  form, ajax, axios 에서 많이 쓰인다.
public class BoardDetail extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//1. 변환(전송방법 선택) => HTML, XML, JSON
    	response.setContentType("text/html; charset=UTF-8"); //서버에서 실행결과를 HTML, 한글포함 텍스트로 보내겠습니다
    	//2. 각 사용자별로 서버가 뿌려주고, 브라우저에서 읽어갈 위치의 메모리를 설정(HTML 여기 저장할테니까 여기서 읽어 가라)
    	PrintWriter out = response.getWriter();
    	//3. 사용자가 보내준 데이터를 받는다 ?no=88 
    	//모든 데이터는 문자열로 받는다!!! getParameter는 리턴형이 String임.
    	String no = request.getParameter("no");
    	BoardDAO dao = new BoardDAO();
    	BoardVO vo = dao.boardDetail(Integer.parseInt(no),1); //no는 String이었으니까 int로 바꾼다.
    	out.println("<html>");
    	out.println("<head>");
    	//style
    	out.println("<style type=text/css>");
    	out.println("div{width:100%}");
    	out.println("h1{margin-top:50px; text-align:center}");
    	out.println("table{margin:0px auto;}");//브라우저 가운데에 출력해라
    	out.println("</style>");
    	out.println("<link rel=stylesheet href=table.css"); //외부 css파일 불러오기
    	out.println("</head>");
    	//body
    	out.println("<body>");
    	out.println("<div>");
    	out.println("<h1>내용보기</h1>");
    	out.println("<form method=post action=BoardInsert>");//아래 내용을 한 번에 모아서 원하는 곳으로 전송할 수 있는 form태그
    	out.println("<table width=700 class=table_content>");
    	out.println("<tr>");
    	out.println("<th width=25%>번호</th>");
    	out.println("<td width=30% align=center>"+vo.getNo()+"</td>");
    	out.println("<th width=25%>작성일</th>");
    	out.println("<td width=30% align=center>"+vo.getRegdate().toString()+"</td>");
    	out.println("</tr>");
    	out.println("<tr>");
    	out.println("<th width=25%>이름</th>");
    	out.println("<td width=30% align=center>"+vo.getName()+"</td>");
    	out.println("<th width=25%>조회수</th>");
    	out.println("<td width=30% align=center>"+vo.getHit()+"</td>");
    	out.println("</tr>");
    	out.println("<tr>");
    	out.println("<th width=25%>제목</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=200\">"+vo.getContent()+"</td>");
    	out.println("</tr>");
    	out.println("<tr>");
    	out.println("<td colspan=4 align=right >");
    	out.println("<a href=BoardUpdate?no="+vo.getNo()+">수정</a>");
    	out.println("<a href=BoardDelete?no="+vo.getNo()+">삭제</a>");
    	out.println("<a href=BoardServlet>목록</a>");
    	out.println("</td>");
    	out.println("</tr>");
    	out.println("</table>");
    	out.println("</body>");
    	out.println("</html>");
    	
	}

}

 

게시글 번호를 받아 내용을 불러와 미리 화면에 띄우고, 수정한 내용을 반영하는 Servlet

BoardUpdate.java (Servlet)

package doodoo.servlet;

import java.io.*;
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 doodoo.dao.*;
import doodoo.vo.*;

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

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//1. 변환(전송방법 선택) => HTML, XML, JSON
    	response.setContentType("text/html; charset=UTF-8"); 
    	//HTML, 한글포함 텍스트로 보내겠습니다
    	//2. 각 사용자별로 서버가 뿌려주고, 브라우저에서 읽어갈 위치의 메모리를 설정
    	PrintWriter out = response.getWriter();
    	
    	//수정할 데이터를 읽어 온다.
    	String no = request.getParameter("no");
    	BoardDAO dao = new BoardDAO();
    	BoardVO vo = dao.boardDetail(Integer.parseInt(no), 2);
    	out.println("<html>");
    	out.println("<head>");
    	//style
    	out.println("<style type=text/css>");
    	out.println("div{width:100%}");
    	out.println("h1{margin-top:50px; text-align:center}");
    	out.println("table{margin:0px auto;}");//브라우저 가운데에 출력해라
    	out.println("</style>");
    	out.println("<link rel=stylesheet href=table.css"); //외부 css파일 불러오기
    	out.println("</head>");
    	//body
    	out.println("<body>");
    	out.println("<div>");
    	out.println("<h1>수정</h1>");
    	out.println("<form method=post action=BoardUpdate>");
    	//아래 내용을 한 번에 모아서 원하는 곳으로 전송할 수 있는 form태그
    	out.println("<table width=700 class=table_content>");
    	out.println("<tr>");
    	out.println("<th align=right width=15%>이름</th>");
    	//수정을 위한 데이터는 input 내에 들어가야 하므로,
    	//tag 사이가 아니라 value로 주어야 한다. 
    	//단, value로 값을 줄 때는 공백을 포함한 글을 불러올 경우 꼭 따옴표(")로 감싸 주어야 한다.
    	out.println("<td width=85%><input type=text name=name size=15 value="+vo.getName()+">");
    	out.println("<input type=hidden name=no value="+vo.getNo()+">");//게시글 번호를 넘겨주는 부분(hidden!)
    	out.println("</td>");
    	out.println("</tr>");
    	out.println("<tr>");
    	out.println("<th align=right width=15%>제목</th>");
    	out.println("<td width=85%><input type=text name=subject size=45 value=\""+vo.getSubject()+"\"></td>");
    	out.println("</tr>");
    	out.println("<tr>");
    	out.println("<th align=right width=15%>내용</th>");
    	//textarea 태그의 경우에는 태그 사이에 넣어 준다.
    	out.println("<td width=85%><textarea rows=10 cols=50 name=content>"+vo.getContent()+"</textarea></td>");
    	out.println("</tr>");
    	out.println("<tr>");
    	out.println("<th align=right width=15%>비밀번호</th>");
    	out.println("<td width=85%><input type=password name=pwd size=10></td>");
    	out.println("</tr>");
    	out.println("<tr>");
    	out.println("<td colspan=2 align=center>");
    	out.println("<input type=submit value=수정>");
    	out.println("<input type=button value=취소 onclick=\"javascript:history.back()\">");
    	out.println("</td>");
    	out.println("</tr>");
    	out.println("</table>");
    	out.println("</form>");
    	out.println("</div>");
    	out.println("</body>");
    	out.println("</html>");
    	
		
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//post -> 요청 처리
		//submit으로 데이터를 전송할 경우 input창에서 입력된 데이터를 넘겨 준다.
		try {
			request.setCharacterEncoding("UTF-8"); // 한글깨짐방지
			
		}catch(Exception ex) {
			ex.printStackTrace();
		}
		//하지만, input창에서의 정보만으로는 몇 번 게시글을 수정해야하는지 정보를 받아오지 못하므로
		//게시글 번호를 따로 넘겨주어야 한다. -> hidden 타입 input태그를 하나 추가하여 거기서 게시글 번호를 넘겨 준다.
		String no = request.getParameter("no");
		String name=request.getParameter("name");
		String subject=request.getParameter("subject");
		String content=request.getParameter("content");
		String pwd=request.getParameter("pwd");
		
		BoardVO vo = new BoardVO();
		vo.setNo(Integer.parseInt(no));
		vo.setName(name);
		vo.setSubject(subject);
		vo.setContent(content);
		vo.setPwd(pwd);
		
		//Oracle에 연결
		BoardDAO dao = new BoardDAO();
		dao.boardUpdate(vo);
		//화면 이동 -> BoardDetail
		response.sendRedirect("BoardDetail?no="+Integer.parseInt(no));
	}

}

 

게시물 번호를 받아 해당 번호를 가진 게시물을 삭제하는 Servlet

BoardDelete.java (Servlet)

package doodoo.servlet;

import java.io.*;
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 doodoo.dao.*;
import doodoo.vo.*;

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

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String no = request.getParameter("no");
		BoardDAO dao = new BoardDAO();
		dao.boardDelete(Integer.parseInt(no));
		//삭제 후 화면 이동
		response.sendRedirect("BoardServlet");
	}
}

 

table.css

@charset "UTF-8";/*안넣어주면 한글깨짐*/
.table_content{
	border-collapse: collapse;/*테이블 테두리를 통합*/
	border-top-width: 2px;
	border-top-style: solid;/*라인 선의 종류. solid:일반 선, dot:점선, dash:쇄선...*/
	border-bottom-width: 1px;
	border-bottom-style: solid;
	border-top-color: #0080ff;
	border-bottom-color: #0080ff;
}
.table_content th{
	background-color: #999;
	color:white;
	height:33px;
}
.table_content td{
	height:33px;
	border-bottom-style:dotted;
	border-bottom-width:1px;
	border-bottom-color:#333;
}
.table_content th,td{
	font-family: "맑은 고딕";
	font-size: 9px;
}
.table_content .dataTr:hover{
	background-color: FC6;
	cursor: pointer;
}
a { /*a태그 파란색/줄처리 삭제*/
	text-decoration: none;
	color: black;
}
a:hover {
	text-decoration: underline;
	color: cyan;
}
input[type=button]
, input[type=submit]{
	border-radius : 50x;
	background-color: cyan;
}

댓글()