게시글 작성 + Image's' 업로드

DeadWhale·2022년 6월 30일
0

Spring

목록 보기
15/25
post-thumbnail

오전 수업을 게시글을 작성 후 업로드 하는 부분을 구현했다

JS 요청 주소 변경하기.

loginSession이 null이 아닐 경우 . 게시글 작성 버튼이 활성화 되는 코드를 작성했었다 하지만 연결된 버튼의 주소가 Servlet Project 당시와 좀 달라져 board.js의 즉시 실행 함수를 변경해줄 필요성이 생겼다.

// 서블릿 프로젝트 당시
프로젝트명/board/detail?no=249&cp=6
// Spring MVC 방식
프로젝트명/board/detail/1/496?cp=1

달라진점

  • 게시판 종류가 단순 정수로 변경 ( 1 : 공지 , 2: 자유 , 3: ~~)
  • 게시글의 번호로 Parameter가 아니라 단순 주소값으로 변경
  • cp만 파라미터로 전달하게 된다

이전 페이지에서 boardCode를 PathValue로 전달하게 되는데
PathValue는 자동적으로 Request Scope로 선언하게 된다
이 값을 이용해 해당 JSP 에서 전역변수로 만들어버려 사용하면 편하다.

<script>    
    const boardCode = "${boardCode}"; 
    //게시판 종류 번호를 전역변수로 생성해서 js파일에서도 쉽게 사용한다.
</script>

Controller

필요한 값

//게시글 작성 (삽입 / 수정)
@PostMapping("/write/{boardCode}")
public String boardWrite(BoardDetail detail 
					,@RequestParam(value="images" 
                    ,required = false)List<MultipartFile> imageList 
					,@PathVariable("boardCode") int boardCode
					,String mode
					,@ModelAttribute("loginMember")Member loginMember 
					,HttpServletRequest req
					,RedirectAttributes ra)throws Exception{

매개변수가 7개다...
이 때 전달되는 이미지'들'은 MultpartFile으로 자동적으로 변환되어 List객체에 저장된다.

step 1

로그인한 회원의 번호를 detail(게시글 상세정보VO)에 세팅해준다

detail.setMemberNo(loginMember.getMemberNo());

step 2

이미지를 저장할 경로 얻어오기( 2 가지 )
웹상에서 접근 가능한 경로인 webPath ( WEB-INF 기준? )

String webPath = "/resources/images/board/";

실제로 서버에 저장될 folderPath (실제 저장될 서버 경로)

//webPath값을 지정하면 해당경로까지의  realPath를 추출하는 코드
String folderPath = req.getSession().getServletContext().getRealPath(webPath); 

step 3

비지니스 로직 수행
INSERT에 필요한 VO(게시글 내용) , 이미지 목록 , 이미지를 저장할 경로값 두개를 가지고 로직 수행 후

삽입된 게시글 번호를 반환한다.

게시글 작성의 경우 Service 부분에서 상당히 많은 수행이 이뤄진다.

게시글 삽입

  • 이번에 작성할 게시글의 시퀀스를 먼저 조회 후
  • 그 시퀀스 값을 boardCode에 저장 후 반환한다.
    이 때 시퀀스 조회 + 삽입 과정은 동시에 이뤄진다
    myBatis의 장점 동적 SQL덕분에 (따로 글 작성 예정)
  • 여자저차해서 detail VO만 가지고 DAO한번 수행해 와 게시글번호를 전달받는다.

이미지 삽입

  • 만약 반환받은 boardNo가 0 이상일 경우
    게시글 삽입이 정상적으로 수행되었다는 의미임으로
    메모리에 적재되어있던 이미지들을 실제 서버에 업로드 하는 과정을 가진다.
if (boardNo > 0) {
	List<BoardImage> boardImageList = new ArrayList<BoardImage>();
	List<String> reNameList = new ArrayList<String>();
  • 이때 이미지들이 저장되어있는 imageList의 길이만큼 반복문을 수행하면서 삽입된 이미지들만 BoardImage으로 제네릭 설정된 List에 저장한다
for (int i = 0; i < imageList.size(); i++) {

	// i 번째 이미지는 업로드된 이미지가 있을 경우 없으면 0이기 때문
	if (imageList.get(i).getSize() > 0) {

		// 변경된 파일명 저장
		String rename = Util.fileRename(imageList.get(i).getOriginalFilename());
		reNameList.add(rename);

		// BoardImage 객체를 생성하여 값 세팅 후 boardImageList에 추가
		BoardImage img = new BoardImage();
		img.setBoardNo(boardNo); // 게시글 번호
		img.setImageLevel(i); // 이미지 순서
		img.setImageOriginal(imageList.get(i).getOriginalFilename()); // 원본 파일명
		img.setImageReName(webPath + rename); // 웹 경로 + 방금 만든 이름

		boardImageList.add(img);
	} // if문 끝

} // for문 끝
  • 만약 이 List가 비어있지 않다면 실제 DB에 삽입하는 IF문을 수행한다
if (!boardImageList.isEmpty()) {
//boardImageList ==  실제 삽입된 이미지 목록
  • 이 때 MultiPartFile 특성상 같은 name값들을 전부 가져오는데
    이미지들이 없는 경우도 있기 때문에 실제로 삽입된 이미지들이 있는지 분류하는 작업이 필요하다.

이미지 분류 작업.

if (!boardImageList.isEmpty()) {

	int result = dao.insertBoardImageList(boardImageList);
	if (boardImageList.size() == result) {
		for (int i = 0; i < boardImageList.size(); i++) {
			int index = boardImageList.get(i).getImageLevel();
			imageList.get(index).transferTo(new File(folderPath + reNameList.get(i)));
            }
		}else{
			throw new InsertFailException();
		}
	}

차근차근 읽어보면 단순한 로직이다

1 : 실제 삽입된 이미지만 DB에 저장되어야 한다

2 : 삽입 성공된 개수와 실제이미지 목록이 저장된 List의 길이가 동일하다면 정상적으로 삽입이 완료다는 의미이다

3: 실제 이미지들이 List의 길이 만큼 반복하면서 서버에 저장한다

단 ,반복을 수행하면서 단 한번의 에러라도 발생시 직접 정의한
파일 입력 실패 예외로 예외를 던진다.

0개의 댓글