답글 등록 및 글 수정/삭제
Mapper
<!-- 답글 삽입 -->
<update id="bbsAnswerUpdate" parameterType="com.hwangduil.springbootbackend.dto.BbsDto">
UPDATE BBS
SET STEP = STEP + 1
WHERE REF = (SELECT * FROM (SELECT REF WHERE SEQ = #{seq}) AS BB)
AND STEP > (SELECT * FROM (SELECT STEP WHERE SEQ = #{seq}) AS BB2)
</update>
<insert id="bbsAnswer" parameterType="com.hwangduil.springbootbackend.dto.BbsDto">
INSERT INTO BBS (SEQ, ID, REF, STEP, DEPTH, TITLE, CONTENT, WDATE, DEL, READCOUNT)
VALUES (NEXTVAL('SEQ_BBS'),
#{id},
(SELECT REF FROM BBS AS BB3 WHERE SEQ = #{seq}),
(SELECT STEP FROM BBS AS BB4 WHERE SEQ = #{seq}) + 1,
(SELECT DEPTH FROM BBS AS BB5 WHERE SEQ = #{seq}) + 1,
#{title},
#{content},
SYSDATE(),
0,
0
)
</insert>
<!-- 게시글 수정 -->
<update id="bbsUpdate" parameterType="com.hwangduil.springbootbackend.dto.BbsDto">
UPDATE BBS
SET TITLE = #{title}, CONTENT = #{content}
WHERE SEQ = #{seq}
</update>
<!-- 게시글 삭제 : DEL 컬럼의 숫자를 1로 바꿔주고 DB에서는 삭제하지 않음. -->
<update id="bbsDelete" parameterType="com.hwangduil.springbootbackend.dto.BbsDto">
UPDATE BBS
SET DEL = 1
WHERE SEQ = #{seq}
</update>
MySQL
에서는 자기 테이블을 참조할 수 없기 때문에 ALIAS
를 붙여주어야 한다.
삭제 시 DEL 컬럼의 값을 1로 바꿔주어 DB에서 직접 삭제하지 않고 화면단에서만 보여주지 않게 처리할 것이다. 때문에 update를 사용하였다.
DAO
import com.hwangduil.springbootbackend.dto.BbsDto;
import com.hwangduil.springbootbackend.dto.BbsParam;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
@Repository
public interface BbsDao {
List<BbsDto> getBbsList();
void insertBbs(BbsDto dto);
BbsDto getBbsDetail(int seq);
void readcount(int seq);
List<BbsDto> getBbsListSearch(BbsParam param);
List<BbsDto> getBbsListSearchPage(BbsParam param);
int getBbsCount(BbsParam param);
void bbsAnswer(BbsDto dto); // 추가
int bbsAnswerUpdate(BbsDto dto); // 추가
void bbsUpdate(BbsDto dto); // 추가
int bbsDelete(BbsDto dto); // 추가
}
답글을 추가하는 기능과 추가시 REF
, STEP
, DEPTH
를 넣어주는 로직이 필요하다.
수정 및 삭제하는 메서드도 구현되어야 한다.
Service
import com.hwangduil.springbootbackend.dao.BbsDao;
import com.hwangduil.springbootbackend.dto.BbsDto;
import com.hwangduil.springbootbackend.dto.BbsParam;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional
@RequiredArgsConstructor
public class BbsService {
private final BbsDao dao;
public List<BbsDto> getBbsList() {
return dao.getBbsList();
}
public void insertBbs(BbsDto dto) {
dao.insertBbs(dto);
}
public BbsDto getBbsDetail(int seq) {
return dao.getBbsDetail(seq);
}
public void readcount(int seq) {
dao.readcount(seq);
}
public List<BbsDto> getBbsListSearch(BbsParam param) {
return dao.getBbsListSearch(param);
}
public List<BbsDto> getBbsListSearchPage(BbsParam param) {
return dao.getBbsListSearchPage(param);
}
public int getBbsCount(BbsParam param) {
return dao.getBbsCount(param);
}
public void bbsAnswer(BbsDto dto) { // 추가
dao.bbsAnswer(dto);
}
public int bbsAnswerUpdate(BbsDto dto) { // 추가
return dao.bbsAnswerUpdate(dto);
}
public void bbsUpdate(BbsDto dto) { // 추가
dao.bbsUpdate(dto);
}
public int bbsDelete(BbsDto dto) { // 추가
return dao.bbsDelete(dto);
}
}
서비스에서 DAO에 작성한 메소드와 동일한 이름으로 추가해주었다.
Controller
import com.hwangduil.springbootbackend.dto.BbsDto;
import com.hwangduil.springbootbackend.dto.BbsParam;
import com.hwangduil.springbootbackend.service.BbsService;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequiredArgsConstructor
public class BbsController {
public final Logger logger = LoggerFactory.getLogger(BbsController.class);
private final BbsService service;
@GetMapping("/getBbsList")
public List<BbsDto> getBbsList() {
logger.info("BbsController getBbsList");
return service.getBbsList();
}
@GetMapping("/insertBbs")
public void insertBbs(BbsDto dto) {
logger.info("BbsController insertBbs() ");
service.insertBbs(dto);
}
@GetMapping("/getBbsDetail")
public BbsDto getBbsDetail(int seq) {
logger.info("BbsController getBbsDetail()");
service.readcount(seq);
return service.getBbsDetail(seq);
}
@GetMapping("getBbsListSearch")
public List<BbsDto> getBbsListSearch(BbsParam param) {
logger.info("BbsController getBbsListSearch");
return service.getBbsListSearch(param);
}
@GetMapping("/getBbsListSearchPage")
public List<BbsDto> getBbsListSearchPage(BbsParam param) {
logger.info("BbsController getBbsListSearchPage");
// 페이지 설정
int sn = param.getPage(); // 현재 페이지
int start = sn * 10 + 1;
int end = (sn + 1) * 10;
param.setStart(start);
param.setEnd(end);
return service.getBbsListSearchPage(param);
}
@GetMapping("/getBbsCount")
public int getBbsCount(BbsParam param) {
logger.info("BbsController getBbsCount");
return service.getBbsCount(param);
}
@GetMapping("/bbsAnswerUpdate")
public String bbsAnswerUpdate(BbsDto dto) { // 추가
logger.info("seq = " + dto.getSeq());
logger.info("title = " + dto.getTitle());
logger.info("id = " + dto.getId());
logger.info("content = " + dto.getContent());
service.bbsAnswer(dto); // 추가
int result = service.bbsAnswerUpdate(dto);
if(result > 0) {
return "fail";
}
return "update";
}
@GetMapping("bbsUpdate")
public void bbsUpdate(BbsDto dto) { // 추가
logger.info("BbsController bbsUpdate()");
service.bbsUpdate(dto);
}
@GetMapping("bbsDelete")
public int bbsDelete(BbsDto dto) { // 추가
logger.info("BbsController bbsDelete()");
dto.setDel(1); // del의 값을 1로 조정
return service.bbsDelete(dto);
}
}
화면단 자바스크립트 구성
답글 추가
bbsAnswerUpdate
는 프론트엔드단으로부터 아래와 같은 값을 넘겨받는다.
부모글을 찾는 요소가 seq
이기 때문에 이 값을 넘겨주는 것이 중요하다.
$(document).ready(function() {
let dataStr = sessionStorage.getItem("login");
let data = JSON.parse(dataStr);
console.log(data);
const url = new URL(location.href);
const urlParams = url.searchParams;
let seq = urlParams.get("seq");
console.log(seq);
$("#writer").val(data.id);
$("#insertBtn").click(function() {
$.ajax({
url: "http://localhost:3000/bbsAnswerUpdate",
type: "GET",
data: {
seq: seq,
title: $("#title").val(),
id: $("#writer").val(),
content: $("#content").val()
},
success: function(msg) {
if(msg === "update") {
alert("등록되었습니다.");
location.href="boards.html";
} else {
alert("등록에 실패하였습니다");
}
},
error: function() {
alert("404 Error");
}
});
});
});
백엔드로부터 전달받은 값에 대해 조건문으로 등록여부를 알려준다.
글 수정
const url = new URL(location.href);
const urlParams = url.searchParams;
let seq = urlParams.get("seq");
$(document).ready(function() {
$.ajax({
url: "http://localhost:3000/getBbsDetail",
type: "GET",
data: { seq: seq },
success: function(data) {
console.log('good');
$("#writer").text(data.id);
$("#title").val(data.title);
$("#content").val(data.content)
},
error: function() {
console.log('bad');
}
});
$("#updateBtn").click(function() {
$.ajax({
url: "http://localhost:3000/bbsUpdate",
type: "GET",
data: {
seq: seq,
title: $("#title").val(),
content: $("#content").val()
},
success: function() {
console.log('success');
alert('수정되었습니다!');
location.href = "boards.html";
},
error: function() {
console.log('error');
}
});
});
})
seq
값을 날려서 게시글 데이터를 받아온 후 <input>
에 뿌려주어 글을 수정할 수 있는 모드로 만들어준다.
수정하기 버튼을 눌렀을 때 수정한 글과 seq
를 가지고 다시 컨트롤러로 가서 처리해준다.
삭제
$("#bbsdelete").click(function() {
$.ajax({
url: "http://localhost:3000/bbsDelete",
type: "GET",
data: { seq: seq },
success: function(data) {
let con = confirm('삭제하시겠습니까?');
if (con === true) {
location.href = "boards.html";
}
},
error: function() {
console.log(error);
}
})
});
여기서는 bbsDelete
패턴의 컨트롤러를 찾아 seq
를 전달하여 해당 글의 DEL 컬럼의 숫자를 1로 바꿔준다.
메인화면에서 리스트로 받아주는 함수에 다소 변화가 필요하다.
function getBbsList(page) {
let choice = $("#_choice").val();
let search = $("#_search").val();
$("#tbody").text("");
$.ajax({
url: "http://localhost:3000/getBbsListSearchPage",
type: "GET",
data: { choice: choice, search: search, page: page },
success: function(list) {
console.log(list);
$.each(list, function(index, list) { // index = 배열의 index
let str;
if(list.del === 0) {
str = `<tr>
<th>${index+1}</th>
<td>${getArrow(list.depth)} <a href="board-detail.html?seq=${list.seq}">${list.title}</a></td>
<td>${list.id}</td>
<td>${list.seq}</td>
</tr>`;
} else {
str = `<tr>
<th>${index+1}</th>
<td>삭제된 게시물 입니다.</td>
<td>${list.id}</td>
<td>${list.seq}</td>
</tr>`;
}
$("#tbody").append(str);
})
},
error: function() {
console.log("error");
}
})
}
여기에서 조건문을 걸어주었는데, 리스트로부터 받아온 del
변수의 값이 0일 때(초기값) 세부 글 보기를 할 수 있도록 보여주고, 그렇지 않은 경우 삭제된 게시물로 막아버리는 것이다.
답글의 답글에 화살표 및 공백 추가해주기
function getArrow(depth) {
let resource = "<img src='./img/arrow.png' width='20px' height='20px' />";
let nbsp = " ";
let str = "";
for(let i = 0; i < depth; i++) {
str += nbsp;
}
return depth === 0 ? "" : str+resource;
}
자세한 코드는 https://github.com/htwenty-1/spring-boot.git 에서 볼 수 있음.
'Study > Spring & Spring Boot' 카테고리의 다른 글
@Autowired 대신 @RequiredArgsConstructor (0) | 2022.03.11 |
---|---|
[Spring Boot] 게시판 기능 구현하기(2) (0) | 2022.02.24 |
[Spring Boot] 게시판 기능 구현하기(1) (0) | 2022.02.23 |
[Spring Boot] AJAX를 사용한 비동기 통신 (0) | 2022.02.22 |
[Spring Boot] DTO, DAO, Service, Controller (0) | 2022.02.21 |