▸JSP & Servlet/기본 문법

MVC 패턴의 게시판 만들기_글작성 로직 [4/5]

코데방 2020. 3. 3.
728x90

로그인 페이지 만들기에 이어 이번에는 MVC 패턴을 적용한 웹 어플리케이션에서 게시판을 만들어봅니다. Spring 없이 순수 JSP와 서블릿으로 구성되며, 기존 로그인과 회원가입, 정보조회를 만들었던 웹페이지에 기능을 붙여서 구현합니다. 

 

[· JSP & Servlet/- 부트스트랩] - 부트스트랩으로 게시판 만들기_리스트 화면 [1/3]

[· JSP & Servlet/- 부트스트랩] - 부트스트랩으로 게시판 만들기_글쓰기 화면 [2/3]

[· JSP & Servlet/- 부트스트랩] - 부트스트랩으로 게시판 만들기_게시물 보기 화면 [3/3]

[· JSP & Servlet/- 기본 문법] - MVC 패턴의 게시판 만들기_계층형 게시판 로직 설계 [1/5]

[· JSP & Servlet/- 기본 문법] - MVC 패턴의 게시판 만들기_페이징 처리(오라클DB) [2/5]

[· JSP & Servlet/- 기본 문법] - MVC 패턴의 게시판 만들기_리스트 출력 로직 [3/5]

[· JSP & Servlet/- 기본 문법] - MVC 패턴의 게시판 만들기_글작성 로직 [4/5]

[· JSP & Servlet/- 기본 문법] - MVC 패턴의 게시판 만들기_게시물 보기 로직 [5/5]

 

 

전체 코드는 깃허브에 있습니다. 커밋 시점은 "add board" 입니다. 

https://github.com/codevang/hssweb

 

 

 


 

 

게시물에 대한 정보를 뷰에서 받아 DTO에 넣어줍니다. 새글과 답글에 대한 정보는 모두 뷰(View) 단에서 처리해서 넘겨주고, DAO에서는 전달된 데이터 값을 DB에 넣어주는 역할만 합니다.

 

게시물 번호는 고유번호이므로 무조건 DB의 시퀀스를 넣어주면 됩니다. 하지만 그룹 번호의 경우 새 글은 시퀀스로, 답글은 새 글의 번호를 넣어줘야 하기 때문에 쿼리가 두 가지로 나눠져야 합니다.

 

오라클 DB에서 시퀀스를 사용하는 방법은 "시퀀스.nextval" 입니다. 언뜻 보면 문자열같지만 홑따옴표가 붙지 않습니다. setString()으로 넣어주면 자동으로 홑따옴표가 붙기 때문에 쿼리에서 오류가 납니다. 넣어줄 데이터가 많기 때문에 preparedStatement 객체를 사용해야하는데, 이럴 경우 약간 난감한 것 같습니다. 조금 더 효율적인 방법을 찾지 못해 아래와 같이 쿼리문을 경우에 따라 두 개로 나누고 최대한 중복 코드가 들어가지 않도록 처리했습니다.

 

또한 로직 설계 글에서 다뤘듯이, 답글 작성의 경우 해당 그룹에서 새로운 답글의 순서와 같거나 큰 게시물들의 순서를 1씩 증가시켜줘야 합니다. 

 

/* 글쓰기 */
	public int writeBoard(BoardDTO dto) {

		try {
			dbConnect(); // DB 연결

			String query;
			// 새글쓰기일 경우, 그룹넘버는 시퀀스로 처리
			if (dto.getBdGroup() < 0) {
				query = "insert into board_chat "
						+ "(bdnum, bdorder, bdindent, bdtitle, "
						+ "bdcontent, bduserid, bdviewcount,bdgroup) "
						+ "values (BDNUM_SEQ.nextval,?,?,?,?,?,?,BDGROUP_SEQ.nextval)";
				preStmt = conn.prepareStatement(query);

				// 답글쓰기일 경우, 그룹넘버는 dto에서 지정된 숫자로 처리
			} else {
				query = "insert into board_chat "
						+ "(bdnum, bdorder, bdindent, bdtitle, "
						+ "bdcontent, bduserid, bdviewcount,bdgroup) "
						+ "values (BDNUM_SEQ.nextval,?,?,?,?,?,?,?) ";
				preStmt = conn.prepareStatement(query);
				preStmt.setInt(7, dto.getBdGroup()); // 그룹넘버

				// 답글달기의 경우 먼저 같은 그룹의 나머지 글들의 순서를 1씩 증가시킴
				stmt = conn.createStatement();
				query = "update board_chat set bdorder = bdorder + 1 "
						+ "where bdgroup = " + dto.getBdGroup()
						+ "and bdorder >= " + dto.getBdOrder();
				stmt.executeUpdate(query);

			}

			// 그룹넘버 외에는 공통적으로 처리
			preStmt.setInt(1, dto.getBdOrder());
			preStmt.setInt(2, dto.getBdIndent());
			preStmt.setString(3, dto.getBdTitle());
			preStmt.setString(4, dto.getBdContent());
			preStmt.setString(5, dto.getBdUserID());
			preStmt.setInt(6, 0); // 글 작성시 조회수는 0

			// 입력 쿼리 실행
			preStmt.executeUpdate();

 

 


 

 

업데이트 쿼리이고, 심지어 두 번이나 업데이트가 이뤄지기 때문에 자동 커밋은 위험할 수 있습니다. 따라서 안전하게 커넥션 객체 생성 시에 자동 커밋을 해제한 뒤 직접 커밋과 롤백을 수행해주는 것이 좋습니다. 커넥션 객체에서 자동 커밋을 해제하는 방법은 setAutoCommit() 메소드에서 매개변수를 false로 주면 됩니다. 

 

	/* DB 연결 (Spring 전환 시 별도 클래스 분리 필요) */
	private void dbConnect() throws Exception {

		context = new InitialContext();
		datasource = (DataSource) context
				.lookup("java:comp/env/jdbc/Oracle11g");
		conn = datasource.getConnection();
		conn.setAutoCommit(false); // 오토커밋 해제
	}

 

 

모든 업데이트 작업을 완료한 뒤 마지막에 한번에 커밋해줍니다. 그리고 만약 쿼리 작업에서 예외가 발생했을 때 롤백처리를 해주면 됩니다.

			// 커밋
			conn.commit();
			return Ctrl.TRUE;

			// 예외 시 쿼리 롤백
		} catch (

		Exception e) {
			try {
				conn.rollback();
			} catch (Exception rollbackEx) {
				System.out.println("BoardWriter rollbakcEx");
				rollbackEx.printStackTrace();
			}

			System.out.println("boardWriter DB Working Ex");
			e.printStackTrace();

			// 자원 해제
		} finally {
			dbClose();
		}

 

 


 

 

[ db.boardDAO.java - 글쓰기 로직 전체 코드 ]

 

	/* 글쓰기 */
	public int writeBoard(BoardDTO dto) {

		try {
			dbConnect(); // DB 연결

			String query;
			// 새글쓰기일 경우, 그룹넘버는 시퀀스로 처리
			if (dto.getBdGroup() < 0) {
				query = "insert into board_chat "
						+ "(bdnum, bdorder, bdindent, bdtitle, "
						+ "bdcontent, bduserid, bdviewcount,bdgroup) "
						+ "values (BDNUM_SEQ.nextval,?,?,?,?,?,?,BDGROUP_SEQ.nextval)";
				preStmt = conn.prepareStatement(query);

				// 답글쓰기일 경우, 그룹넘버는 dto에서 지정된 숫자로 처리
			} else {
				query = "insert into board_chat "
						+ "(bdnum, bdorder, bdindent, bdtitle, "
						+ "bdcontent, bduserid, bdviewcount,bdgroup) "
						+ "values (BDNUM_SEQ.nextval,?,?,?,?,?,?,?) ";
				preStmt = conn.prepareStatement(query);
				preStmt.setInt(7, dto.getBdGroup()); // 그룹넘버

				// 답글달기의 경우 먼저 같은 그룹의 나머지 글들의 순서를 1씩 증가시킴
				stmt = conn.createStatement();
				query = "update board_chat set bdorder = bdorder + 1 "
						+ "where bdgroup = " + dto.getBdGroup()
						+ "and bdorder >= " + dto.getBdOrder();
				stmt.executeUpdate(query);

			}

			// 그룹넘버 외에는 공통적으로 처리
			preStmt.setInt(1, dto.getBdOrder());
			preStmt.setInt(2, dto.getBdIndent());
			preStmt.setString(3, dto.getBdTitle());
			preStmt.setString(4, dto.getBdContent());
			preStmt.setString(5, dto.getBdUserID());
			preStmt.setInt(6, 0); // 글 작성시 조회수는 0

			// 입력 쿼리 실행
			preStmt.executeUpdate();

			// 커밋
			conn.commit();
			return Ctrl.TRUE;

			// 예외 시 쿼리 롤백
		} catch (

		Exception e) {
			try {
				conn.rollback();
			} catch (Exception rollbackEx) {
				System.out.println("BoardWriter rollbakcEx");
				rollbackEx.printStackTrace();
			}

			System.out.println("boardWriter DB Working Ex");
			e.printStackTrace();

			// 자원 해제
		} finally {
			dbClose();
		}

		return Ctrl.EXCEPT;
	}
728x90

댓글

💲 추천 글