본문 바로가기
카테고리 없음

24. 10. 10 상세조회 게시글 삭제하기, 수정하기

by 융기융 2024. 10. 10.
반응형

 

 

 

코드 전략

1) 기존에 이미지가 있음
-> BOARD_IMG 테이블 UPDATE


2) 기존에 이미지가 없음
-> BOARD_IMG 테이블 INSERT


3) 기존에 이미지가 있는데 그대로 둠(수정 X)
    -> file이 "선택된 파일없음" 제출
    -> 기존 이미지가 유지되도록 설정


4) 기존에 이미지가 있는데 X 버튼 눌러서 삭제
    -> file이 "선택된 파일없음" 제출
    -> DB에서 해당 이미지 삭제(DELETE)

 

 

@PostMapping("{boardCode}/{boardNo}/updateView")

public String updateView(

@PathVariable("boardCode") int boardCode,

@PathVariable("boardNo") int boardNo,

@SessionAttribute("loginMember")Member loginMember,

RedirectAttributes ra,

Model model) {

// boardCode, boardNo가 일치하는 글 조회

Map<String, Integer>map =

Map.of("boardCode", boardCode, "boardNo", boardNo);

Board board = boardService.selectDetail(map);

 

// 게시글이 존재하지 않는 경우

if(board == null) {

ra.addFlashAttribute("message",

"해당 게시글이 존재하지 않습니다.");

 

return "redirect:/board/" + boardCode; // 게시글 목록

}

// 게시글 작성자가 로그인한 회원이 아닌경우

if(board.getMemberNo() != loginMember.getMemberNo()) {

 

ra.addFlashAttribute("message",

"글 작성자만 수정 가능합니다");

 

return String.format("redirect:/board/%d%d",

boardCode, boardNo); // 상세조회

}

// 게시글이 존재하고

// 로그인한 회원이 작성한 글이 맞을경우

// 수정화면으로 forward

model.addAttribute("board", board);

return "board/boardUpdate";

}

 

boardCode : 게시판 종류
boardNo : 수정할 게시글 번호
loginMember : 로그인한 회원정보(session)
ra : redirect 시 request scope로 데이터 전달
model : forward시 request scope로 데이터 전달

게시글 수정 Controller

/** 게시글 수정

* @return

*/

@PostMapping("{boardCode:[0-9]+}/{boardNo:[0-9]+}/update")

public String boardUpdate(

@PathVariable("boardCode") int boardCode,

@PathVariable("boardNo") int boardNo,

@ModelAttribute Board inputBoard,

@SessionAttribute("loginMember") Member loginMember,

@RequestParam("images") List<MultipartFile> images,

@RequestParam(value="deleteOrderList", required = false)String deleteOrderList,

RedirectAttributes ra

) {

 

// 1. 커맨드객체 inputBoard에 로그인한 회원번호 추가

inputBoard.setMemberNo(loginMember.getMemberNo());

 

// inputBoard에 세팅된 값

// : boardCode, boardNo, boardTitle, boardContent, memberNo

 

// 게시글 수정 서비스 호출 후 결과반환

int result = service.boardUpdate(inputBoard, images, deleteOrderList);

 

String message = null;

if(result > 0) {

message = "게시글이 수정되었습니다";

} else {

message = "수정실패";

}

 

ra.addFlashAttribute("message", message);

 

return String.format("redirect:/board/%d/%d",

boardCode, boardNo); // 상세조회

}

 

게시글 수정 ServiceImpl

// 게시글 수정

@Override

public int boardUpdate(Board inputBoard, List<MultipartFile> images, String deleteOrderList) {

 

// 1. 게시글 부분(제목/내용) 수정

int result = mapper.boardUpdate(inputBoard);

if(result == 0) return 0; // 수정 실패 시

 

 

// 2. 기존에 존재했던 이미지 중

// deleteOrderList에 존재하는 순서의 이미지 DELETE

 

// deleteOrderList에 작성된 값이 있다면

if(deleteOrderList != null &&

deleteOrderList.equals("") == false) {

 

result = mapper.deleteImage(deleteOrderList, inputBoard.getBoardNo());

 

// 삭제된 행이 없을 경우 -> SQL 실패

// -> 예외를 발생시켜 전체 rollback

if(result == 0) {

throw new RuntimeException("이미지 삭제 실패");

// 사용자 정의 예외로 바꾸면 더 좋다!!

}

}

 

 

// 3. 업로드된 이미지가 있을 경우

// UPDATE 또는 INSERT + transferTo()

 

// 실제 업로드된 이미지만 모아두는 리스트 생성

List<BoardImg> uploadList = new ArrayList<>();

 

for(int i=0 ; i<images.size() ; i++) {

 

// i번째 요소에 업로든된 파일이 없으면 다음으로~

if(images.get(i).isEmpty()) continue;

 

 

// 업로드된 파일이 있으면

 

String originalName = images.get(i).getOriginalFilename();

String rename = FileUtil.rename(originalName);

 

// 필요한 모든 값을 저장한 DTO 생성

BoardImg img

= BoardImg.builder()

.imgOriginalName(originalName)

.imgRename(rename)

.imgPath(webPath)

.boardNo(inputBoard.getBoardNo())

.imgOrder(i)

.uploadFile(images.get(i))

.build();

 

 

// 1행씩 update 수행

result = mapper.updateImage(img);

 

// 수정이 실패 == 기존에 이미지가 없었다

// == 새로운 이미지가 새 order번째 자리에 추가되었다

// --> INSERT

if(result == 0) {

result = mapper.insertImage(img);

}

 

// 수정, 삭제가 모두 실패한 경우 --> 말도 안되는 상황

if(result == 0) {

throw new RuntimeException("이미지 DB 추가 실패");

}

 

uploadList.add(img); // 업로드된 파일리스트에 img 추가

 

} // for end

 

// 새로운 이미지가 없는경우

if(uploadList.isEmpty()) return result;

 

// 임시 저장된 이미지 파일을 지정된 경로로 이동(transferTo())

try {

for(BoardImg img : uploadList) {

img.getUploadFile()

.transferTo(new File(folderPath + img.getImgRename()));

}

 

}catch(Exception e) {

e.printStackTrace();

throw new FileUploadFailException();

}

return result;

}

 

게시글 삭제, 수정 editBoard-mapper.xml

<!--

동적 SQL 중 <foreach>

- Mybatis에서 제공하는 향상된 for문

 

- 특정 SQL 구문을 반복할 때 사용

 

- 반복 사이에 구분자(separator)를 추가할 수 있음

 

[지원하는 속성]

collection : 반복할 객체의 타입 작성(list, set, map...)

item : collection에서 순차적으로 꺼낸 하나의 요소를 저장하는 변수

index : 현재 반복 접근중인 인덱스 (0,1,2,3,4 ..)

 

open : 반복 전에 출력할 sql

close : 반복 종료 후에 출력한 sql

 

separator : 반복 사이사이 구분자

-->

 

<!-- 여러 이미지 한 번에 INSERT -->

<insert id="insertUploadList">

INSERT INTO "BOARD_IMG"

 

<foreach collection="list" item="img"

open="(" close=")" separator=" UNION ALL ">

 

SELECT

NEXT_IMG_NO(),

#{img.imgPath},

#{img.imgOriginalName},

#{img.imgRename},

#{img.imgOrder},

#{img.boardNo}

FROM DUAL

 

</foreach>

 

</insert>

 

<insert id="boardDelete">

UPDATE "BOARD"

SET

BOARD_DEL_FL = DECODE(BOARD_DEL_FL, 'Y', 'N', 'Y')

WHERE

"BOARD_NO" = #{boardNo}

</insert>

 

<!-- 게시글부분만 수정(제목/내용) -->

<update id="boardUpdate">

UPDATE

"BOARD"

SET

BOARD_TITLE = #{boardTitle},

BOARD_CONTENT = #{boardContent}

WHERE

BOARD_CODE = #{boardCode}

AND

BOARD_NO = #{boardNo}

AND

MEMBER_NO = #{memberNo}

</update>

 

<!--

[마이바티스 #, $의 의미]

 

# (PreparedStatement)

- {} 내 값을 SQL에 맞는 리터럴 표기법으로 변경해서 대입

ex) (int) 10 -> 10 (NUMBER(

(String) "apple" -> 'apple' (CHAR)

 

$ (Statement)

- {} 내 값을 있는 그대로 SQL에 대입 (SQL 코드로 인식)

ex) (int) 10 -> 10

(String) "apple" -> apple

 

* SQL Injection이 발생할 수 있기 때문에

권장하진 않음

 

-> 해당 SQL <forEach> 태그로 변경하면 좋음 -->

 

 

<!-- 기존에 존재하던 이미지 DB에서 삭제 -->

<delete id="deleteImage">

DELETE FROM "BOARD_IMG"

WHERE BOARD_NO = #{boardNo}

AND IMG_ORDER IN(${orders})

</delete>

 

<!-- 이미지 1행 수정 -->

<update id="updateImage">

UPDATE "BOARD_IMG"

SET

IMG_ORIGINAL_NAME = #{imgOriginalName},

IMG_RENAME = #{imgRename}

WHERE

BOARD_NO = #{boardNo}

AND

IMG_ORDER = #{imgOrder}

</update>

 

<!-- 새로운이미지 1행 삽입 -->

<insert id="insertImage">

INSERT INTO "BOARD_IMG"

VALUES(SEQ_IMG_NO.NEXTVAL,

#{imgPath},

#{imgOriginalName},

#{imgRename},

#{imgOrder},

#{boardNo} )

</insert>

반응형