미니 프로젝트 : [Java로 쇼핑몰 만들기] - 게시판

까만호랭·2023년 8월 24일
1

🛒 지금까지 배운 Java를 사용하여 쇼핑몰의 게시판을 먼저 만들어보겠다.

🖥️ 게시판 기능

게시판의 형태는 밑의 그림처럼 만들것이다.

  • num : 댓글의 번호
  • title : 제목
  • gnum : title의 그룹을 번호로 매긴 것
  • onum : gnum에서 순서를 매긴 번호
  • nested : 댓글들에 대한 들여쓰기 수치
  • 위 사진의 게시판을 만들어보도록 하자.

    메인 게시판 구성

  • [메인으로] : main.html
  • [최근 목록] : boardlist.jsp
  • [새 글 작성] : boardwirte.jsp
  • [관리자용] : admin.jsp
  • 🔨 게시판 제작 순서

    1. MariaDB를 통한 Table 생성
    2. BoardBean과 BoardDto 생성
    3. 메인 게시판 기능을 하기 위한 JSP페이지 생성
    4. 댓글들에 대해 기능을 하기 위한 JSP페이지 생성

    1. MariaDB를 통한 Table 생성

    CREATE TABLE board (
        num INT(11) NOT NULL PRIMARY KEY,
        name VARCHAR(20) NOT NULL,
        pass VARCHAR(20) NOT NULL,
        mail VARCHAR(30),
        title VARCHAR(50),
        cont TEXT,
        bip VARCHAR(20),
        bdate VARCHAR(20),
        readcnt INT(11),
        gnum INT(11),
        onum INT(11),
        nested INT(11)
    );


    으로 DB에 board table을 생성하였다.

    2. BoardDto와 BoardBean 생성

    저는 setter,getter를 직접 만들지 않고 lombok을 사용하여 생성하였습니다.
    BoardDto

    import lombok.Data;
    
    @Data
    public class BoardDto {
    	private String name,pass,mail,title,cont,bip,bdate;
    	private int num,readcnt,gnum,onum,nested;
    }

    BoardBean 의 경우 등록일(작성일)을 위해 setDate() 메소드를 오버로딩을 추가로 하였다.

    
    import java.time.LocalDate;
    import lombok.Data;
    import lombok.Getter;
    import lombok.Setter;
    
    //@Getter
    //@Setter
    @Data
    public class BoardBean {  // ip, date는 키워드라 b를 앞에 붙임
    	private String name,pass,mail,title,cont,bip,bdate;
    	private int num,readcnt,gnum,onum,nested;
    	
    	public void setBdate() {
    		// 등록일(작성일)을 위해 오버로딩,, 결국 지금 setBdate()가 두개 있는 상태
    		LocalDate now = LocalDate.now();
    		int year = now.getYear();
    		int month = now.getMonthValue();
    		int day = now.getDayOfMonth();
    		this.bdate = year + "-" + month + "-" + day;
    	}
    	
    }

    자주 쓴 코드(DB와의 연동, useBean)

    📖 DB와의 연동

    	private Connection conn;
    	private PreparedStatement pstmt;
    	private ResultSet rs;
    	private DataSource ds;
    			  ...
    		try {
    			String sql = "select max(num) from board";
    			conn = ds.getConnection();
    			pstmt = conn.prepareStatement(sql);
    			rs = pstmt.executeQuery();
    			  ...
    		} catch (Exception e) {
    			System.out.println("메소드명 err : " + e.getMessage());
    		} finally {
    			try {
    				if(rs!=null) rs.close();
    				if(pstmt!=null) pstmt.close();
    				if(conn!=null) conn.close();
    			} catch (Exception e2) {
    				// TODO: handle exception
    			}
    		}
    		
    		return 리턴값;  
    	}

    은 위와 같은 코드들을 부분적인 메소드마다 연동시 비슷하게 사용하였으며 Connection, PreparedStatement, ResultSet, DataSource을 사용하여 JDBC를 구현하였다.

    🫘 useBean 사용

    <jsp:useBean id="bean" class="pack.board.BoardBean"/>
    <jsp:setProperty property="*" name="bean"/> <%-- 이 문장을 통해 set값을 해줌 --%>
    <jsp:useBean id="boardMgr" class="pack.board.BoardManager"/>

    3-1. 게시글 번호 매기기

    public int currentGetMaxNum() { // 새 글 번호 입력용
    		int cnt = 0;
    		try {
    			String sql = "select max(num) from board";
    			conn = ds.getConnection();
    			pstmt = conn.prepareStatement(sql);
    			rs = pstmt.executeQuery();
    			if(rs.next()) cnt=rs.getInt(1);  // 칼럼명인 max(num) 얘를 쓰던지 그냥 1번쨰를 뜻하는 1을 적든지 상관xx
    		} catch (Exception e) {
    			System.out.println("currentGetMaxNum err : " + e.getMessage());
    		} finally {
    			try {
    				if(rs!=null) rs.close();
    				if(pstmt!=null) pstmt.close();
    				if(conn!=null) conn.close();
    			} catch (Exception e2) {
    				// TODO: handle exception
    			}
    		}
    		
    		return cnt;  // 레코드 행이 비어있으면 0 return, 있으면 가장 큰 값을 return
    	}

    3-2. 하단의 페이징 처리하기

    페이지 수 당 글은 10개가 오도록 지정하였다.

    // paging 처리용
    	private int recTot; // 전체 레코드 수행
    	private int pList = 10; // 페이지 당 출력 행 수
    	private int pageSu;  //전체 페이지 수

    페이지 수는 전체 레코드 값(42) / 페이지 당 출력 행 수 (10)를 하여 몫이 4이므로 10개의 글로 가득 찬 4페이지와 2개의 글이 있는 1페이지로 총 5페이지를 구성하였다.

    public int getPageSu() {  // 총 페이지 수 반환
    		pageSu = recTot / pList;
    		if(recTot % pList > 0) pageSu++;  // 자투리(나머지 값)이 0보다 크면 pageSu에 1 더해줌
    		return pageSu;
    	}
    	
    	public void updateReadcnt(String num) {  // 글 상세보기 전 조휘수 증가 
    		try {
    			String sql = "update board set readcnt=readcnt + 1 where num=?";
    			conn = ds.getConnection();
    			pstmt = conn.prepareStatement(sql);
    			pstmt.setString(1, num);
    			pstmt.executeUpdate();
    		} catch (Exception e) {
    			System.out.println("updateReadcnt err : " + e.getMessage());
    		} finally {
    			try {
    				if(rs!=null) rs.close();
    				if(pstmt!=null) pstmt.close();
    				if(conn!=null) conn.close();
    			} catch (Exception e2) {
    				// TODO: handle exception
    			}
    		}
    	}

    3-3. 게시물 검색 구현하기

    public ArrayList<BoardDto> getDataAll(String stype, String sword, int page){  // 검색 결과도 반환 가능
    		//System.out.println(stype + " " + sword);
    		
    		ArrayList<BoardDto> list = new ArrayList<BoardDto>();
    		try {
    			//String sql = "select * from board order by gnum desc";
    			String sql = "select * from board"; // sql문장을 완성!!
    			
    			conn = ds.getConnection();
    			if(sword == null) { // sword==null은 검색을 안했을때를 의미함
    				sql += " order by gnum desc, onum asc";
    				pstmt = conn.prepareStatement(sql);
    			}else {
    				sql += " where " + stype + " like ?";
    				sql += " order by gnum desc, onum asc";
    				pstmt = conn.prepareStatement(sql);
    				pstmt.setString(1, "%" + sword + "%");
    			}
    			System.out.println(sql);  // 위 sql들이 잘 되는지 확인하려고 코드작성함
    			
    			rs = pstmt.executeQuery();
    			
    			for (int i = 0; i < (page - 1) * pList; i++) {
    				rs.next(); // 레코드 포인터 위치    
    				// 1 page : 0
    				// 2 page : 4
    				// 3 page : 9
    			}
    			
    			int k = 0;
    			while(rs.next() && k < pList) { // 0이면 포인터는 1부터 출발
    				BoardDto dto = new BoardDto();
    				dto.setNum(rs.getInt("num"));
    				dto.setName(rs.getString("name"));
    				dto.setTitle(rs.getString("title"));
    				dto.setBdate(rs.getString("bdate"));
    				dto.setReadcnt(rs.getInt("readcnt"));
    				dto.setNested(rs.getInt("nested"));
    				list.add(dto); // 이 코드들은 한 페이지에 5개의 
    				k++;
    			}
    		} catch (Exception e) {
    				System.out.println("getDataAll err : " + e.getMessage());
    			} finally {
    				try {
    					if(rs!=null) rs.close();
    					if(pstmt!=null) pstmt.close();
    					if(conn!=null) conn.close();
    				} catch (Exception e2) {
    					// TODO: handle exception
    				}
    			}
    		return list;
    	}

    3-4. 댓글에 대한 답변들 들여쓰기

    int num = bean.getNum();
    int gnum = bean.getGnum();
    int onum = bean.getOnum() + 1; // 댓글이므로 1 증가
    int nested = bean.getNested() + 1; // 들여쓰기 1 증가

    위 코드처럼 늘어난 onum에 맞게 nested도 1씩 증가하게 해주었다.



    사진의 우측에 있는 버튼들은 각각의 기능을 가지고 있다.

    Reply : 댓글에 대한 답변 달기
    Modify : 댓글 수정하기
    Delete : 댓글 삭제하기
    List : 목록으로 가기

    이 4개의 기능들을 가진 jsp을 구현해보도록 하자.


    4-1. 댓글에 대한 답변 달기 기능 ( reply.jsp )

    public BoardDto getReplyData(String num) { // 댓글용 원글 읽기
    		BoardDto dto = null;
    		try {
    			String sql = "select * from board where num=?";
    			conn = ds.getConnection();
    			pstmt = conn.prepareStatement(sql);
    			pstmt.setString(1, num);         
    			rs = pstmt.executeQuery();
    			if(rs.next()) {  // 행 읽으면서 자료 판단..
    				dto = new BoardDto();
    				dto.setTitle(rs.getString("title"));
    				dto.setGnum(rs.getInt("gnum"));
    				dto.setOnum(rs.getInt("onum"));
    				dto.setNested(rs.getInt("nested"));
    			} 
    		} catch (Exception e) {
    			System.out.println("getReplyData err : " + e.getMessage());
    		} finally {
    			try {
    				if(rs!=null) rs.close();
    				if(pstmt!=null) pstmt.close();
    				if(conn!=null) conn.close();
    			} catch (Exception e2) {
    				// TODO: handle exception
    			}
    		}
    		return dto;
    	}
        
        .......................
        public void saveReplyData(BoardBean bean) {  // 댓글 저장
    		try {
    			String sql = "insert into board values(?,?,?,?,?,?,?,?,?,?,?,?)";
    			conn = ds.getConnection();
    			pstmt = conn.prepareStatement(sql);
    			pstmt.setInt(1, bean.getNum());
    			pstmt.setString(2, bean.getName());
    			pstmt.setString(3, bean.getPass());
    			pstmt.setString(4, bean.getMail());
    			pstmt.setString(5, bean.getTitle());
    			pstmt.setString(6, bean.getCont());
    			pstmt.setString(7, bean.getBip());
    			pstmt.setString(8, bean.getBdate());
    			pstmt.setInt(9, 0);  // readcnt
    			pstmt.setInt(10, bean.getGnum());  // gnum
    			pstmt.setInt(11, bean.getOnum());   // onum
    			pstmt.setInt(12, bean.getNested());   // nested
    			pstmt.executeUpdate();
    		} catch (Exception e) {
    			System.out.println("saveReplyData err : " + e.getMessage());
    		} finally {
    			try {
    				if(rs!=null) rs.close();
    				if(pstmt!=null) pstmt.close();
    				if(conn!=null) conn.close();
    			} catch (Exception e2) {
    				// TODO: handle exception
    			}
    		}
    	}

    우선 getReplyDaya메소드를 사용하여 DB연동을 하였으며 댓글용 원글이 한 개만 조회하는 것이 목적이기 때문에 while이 아닌 if문을 사용하였다.


    4-2. 댓글 수정하기 ( edit.jsp )

    <%
    String spage = request.getParameter("page");
    
    boolean b = boardMgr.checkPass(bean.getNum(), bean.getPass()); // 비밀번호 비교하는거 시작
    
    if(b){
    	//out.print("비밀번호가 맞아요");
    	boardMgr.updateData(bean);
    	response.sendRedirect("boardlist.jsp?page=" + spage);
    }else{
    	//out.print("비밀번호가 틀려요");
    %>	
    	<script>
    	alert("비밀번호가 일치하지 않습니다.");
    	history.back();
    	</script>
    <%	
    }
    %>
    ..............................
    public void updateData(BoardBean bean) {
    		try {
    			String sql = "update board set name=?, title=?, mail=?, cont=? where num=?";
    			conn = ds.getConnection();
    			pstmt = conn.prepareStatement(sql);
    			pstmt.setString(1, bean.getName());
    			pstmt.setString(2, bean.getTitle());
    			pstmt.setString(3, bean.getMail());
    			pstmt.setString(4, bean.getCont());
    			pstmt.setInt(5, bean.getNum());
    			pstmt.executeUpdate();
    		} catch (Exception e) {
    			System.out.println("updateData err : " + e.getMessage());
    		} finally {
    			try {
    				if(rs!=null) rs.close();
    				if(pstmt!=null) pstmt.close();
    				if(conn!=null) conn.close();
    			} catch (Exception e2) {
    				// TODO: handle exception
    			}
    		}
    	}

    먼저 댓글을 수정할때 비밀번호를 입력하여 본인이 작성한 것이 맞는지를 확인하게 하고 암호가 맞다면 내용을 수정할 수 있게 하였다. 이때 비밀번호가 일치하지 않는다면 "비밀번호가 일치하지 않습니다." 가 나오게 구현하였다.


    4-3. 댓글 삭제 ( delete.jsp )

    <%
    String spage = request.getParameter("page");
    String num = request.getParameter("num"); 
    String pass = request.getParameter("pass");
    
    boolean b = boardMgr.checkPass(Integer.parseInt(num), pass); // 비밀번호 비교하는거 시작,, 숫자 num과 문자 pass 가져감
    
    if(b){
    	//out.print("비밀번호가 맞아요");
    	boardMgr.delData(num); 
    	response.sendRedirect("boardlist.jsp?page=" + spage);
    }else{
    	//out.print("비밀번호가 틀려요");
    %>	
    	<script>
    	alert("비밀번호가 일치하지 않습니다.");
    	history.back();
    	</script>
    <%	
    }
    %>
    
    ...............................
    public void delData(String num) {
    		try {
    			String sql = "delete from board where num=?";
    			conn = ds.getConnection();
    			pstmt = conn.prepareStatement(sql);
    			pstmt.setString(1, num);
    			pstmt.executeUpdate();
    		} catch (Exception e) {
    			System.out.println("delData err : " + e.getMessage());
    		} finally {
    			try {
    				if(rs!=null) rs.close();
    				if(pstmt!=null) pstmt.close();
    				if(conn!=null) conn.close();
    			} catch (Exception e2) {
    				// TODO: handle exception
    			}
    		}
    	}

    비밀번호 값을 입력하고 맞다면 "정말 삭제할까요?" 란 멘트가 나오면서 확인을 누르면 댓글이 삭제되도록 기능을 구현하였다.

    profile
    남들과 함께 발자국을 남기는 까만호랭

    0개의 댓글