게시글 수정 구현

DeadWhale·2022년 6월 7일
0

Servlet/JSP

목록 보기
21/22
post-thumbnail

게시글의 '수정' 기능을 구현해보았다.

이미 게시글 작성을 하기 위해 사용되는 BoardWriteForm을 활용해 조금은 편하게 만들었다.

이미 만들어져 있는 JSP 페이지에 forward 하기 전 게시글번호를 가지고 boardDetail JDBC 수행 후 value 옵션에 포함시킨다

이 때 value에 값이 없어도 js의 특성상 null이 아닌 ''공백이기 때문에 값의 변화에는 신경 쓰지 않아도 괜찮다.

update 요청의 경우

if (mode.equals("update")) {
int boardNo = Integer.parseInt(req.getParameter("no"));
BoardDetail detail = new BoardService().selectBoardDetail(boardNo);
// 개행 문자 처리 해제
detail.setBoardContent(detail.getBoardContent().replaceAll("<br>", "\n"));
req.setAttribute("detail", detail); // JSP에서 사용할 수 있도록 req에 값 세팅
}
  • BoardService . selectBoardDetail( 매개값 )으로 이미 만들어져있는 함수를 이용해 게시글을 가져온다.

  • 게시글을 조회해 올 때 개행 문자처리가 필요하다
    원래 서버에 insert boardContent 에 해당하는 textarea에 입력된 개행 문자 변환 처리를 하는데 다시 가져올때도 띄워쓰기에 해당하는 코드를 다시 개행문자로 변환해줘야 한다
    이건 계속 헷갈린다 나중에 한번 에러 나봐야 정신차릴듯

  • 그 다음 JSP 페이지로 Forward 하는데 Forward의 경우 req,resp 객체를 유지하는 장점을 가지고 있어 게시글 내용을 setAttribute해 JSP에서 기본 value로 활용 할 수 이다

detail 은 요청주소의 mode가 update일 때 boardDetail으로 게시글을 조회해와 value 기본값으로 집어넣는데 만약 그냥 작성이여도 그냥 공백이니 상관이 없다.

이 때 업로드 된 이미지도 같은 이유도 value가 아닌 src의 주소로 입력한다
이때 각 레벨에 맞는 이미지 주소를 등록하기 위해 각 레벨에 맞는 이미지가 있을 경우 변수를 생성에 변수의 이미지 주소를 저장해 준다

<h1 class="board-title">
<input type="text" name="boardTitle" placeholder="제목을 입력해주세요." autocomplete="off" value="${detail.boardTitle}">
</h1>

<%-- imageList에 존재하는 이미지 레벨을 이용해 변수 생성--%>
<c:forEach items="${detail.imageList}" var="boardImage">
    <c:choose>
        <c:when test="${boardImage.imageLevel == 0}">
            <%-- c:set 변수는 page-Scope가 기본값(이 페이지 내에서 계속 살아있음) --%>
                <c:set var="img0" value="${contextPath}${boardImage.imageReName}"/>
        </c:when>
        <c:when test="${boardImage.imageLevel == 1}">
                <c:set var="img1" value="${contextPath}${boardImage.imageReName}"/>
        </c:when>
        <c:when test="${boardImage.imageLevel == 2}">
                <c:set var="img2" value="${contextPath}${boardImage.imageReName}"/>
        </c:when>
        <c:when test="${boardImage.imageLevel == 3}">
                <c:set var="img3" value="${contextPath}${boardImage.imageReName}"/>
        </c:when>
        <c:when test="${boardImage.imageLevel == 4}">
                <c:set var="img4" value="${contextPath}${boardImage.imageReName}"/>
        </c:when>
    </c:choose>    
</c:forEach>

Controller

BoardWriteController ( post 요청 )

GET 방식으로 요청 받았을 때에는 게시글의 정보만 조회해 요청을 JSP로 위임한다. 그 후 내용을 수정 할 경우 form태그의 method에 따라 POST로 다시 요청온다


이 때 Insert와 동일하게 사용되는 값들은 이미 구성되어 있다

  • COS를 활용한 파일분리 / 파일외 자료 인코딩
  • type ( 게시글의 종류 )
  • detail 객체 이 때 공통적으로 넘어오는 제목 , 내용 , 번호는 객체에 세팅해준다.

그 후 parameter로 넘어오는 mode에 일치하는 if문을 수행한다
parameter값 가져오는건 req.parameter가 아닌
cos 만들어낸 mpReq객체로 GET해야 한다.

mode를 가져온 후 mode.equals("update") 일 경우
추가적으로 Parameter를 가져온다.

  1. 게시글의 번호 ( boardNo )
    (그냥 작성의 경우 게시글번호를 JDBC후 반환받지만
    이미 있는 게시글을 수정하는 것임으로 별다른 게시글 번호의 조회가 필요없다)
  2. cp( CurrntPage )
    (게시글을 새로 작성하게 되면 가장 첫 페이지에 위치하니 cp가 1로 고정이지만 수정의 경우 어느 페이지에 있는 글인지 확정할 수 없어 수정 받을때 가져와야 한다.)
  3. deleteList
    제목/내용을 수정하고 , 이미지를 삽입하는 경우도 있지만
    원래 있는 이미지를 삭제 하는 경우도 있다. 이 삭제하는 이미지들의 레벨을 배열형태로 가지고 있는 문자열(1,2,4) ,
    이를 이용해 BOARD_IMG테이블에서 WHERE IN 조건으로 사용한다

이렇게 되면 전달해야 할 매개값들이 많아 게시글 번호는 detail에 세팅해 가져간다.

mode = insert 의 경우 새로 삽입하는 경우라 어느 게시글인지 알기 위해
JDBC로 리턴을 게시글 번호로 받아오지만
mode = update의 경우 게시글 번호를 parameter로 이미 받아온 상태이기 때문에 그냥 int 변수 아무거나해서 받으면된다.

//detail,imageList,deleteList
int result = service.updateBoard(detail,imageList,deleteList);

String path = null;
String message = null;

if(result>0) { // 게시글 수정에 성공 했을 때.
	//detail?no , type , cp
	path = "detail?no="+boardNo+"&type="+boardCode+"&cp="+cp; //수정한 글의 상세주소 페이지
	message = "게시글이 수정되었습니다";
}else{ //수정에 실패했을 때.
	//수정화면으로 이동
	//상세조회 -> 수정화면 -> 수정  => (성공)상세조회 || (실패)수정화면
	path=req.getHeader("referer");
	//referer : HTTP Referer 요청 흔정( 들어온 요청의 바로 이전 페이지)
	message = "게시글 수정에 실패하였습니다.";
}

session.setAttribute("message", message);
	resp.sendRedirect(path);	
}

요청이 수행 완료되면 결과값에 따라 redirect할 주소와 전달할 메세지를 변수에 저장해 session에 저장하고 위치로 전달한다

이 때 수정에 실패할 경우 req가 기본적으로 가지고 있는 기능인 referer으로 바로 이전 페이지로 이동한다


😵‍💫이 때 위에서 mpReq으로 호출해놨지만 req의 기능도 그냥 사용 가능하다


Service

쓸 기력이 없기도 하고 Service의 경우 이미 알고있고 코드보면 왜 썻는지 아는 코드들도 많아 대략적으로만 작성한다

해야 될 것

  1. 게시글 부분 Update (제목/내용/마지막수정일(Sysdate))
    1.1 XSS 방지처리
    1.2 개행문자 처리
    1.3 DAO수항
  2. 게시글 부분이 정상적으로 수행되었을 경우 이미지 업로드
    2.1 for문을 반복해 DAO수행(Servlet의 한계)
    2.2 이 떄 0이 나오는 경우도 있음 DAO 수행구문이 UPDATE인대 원래 게시글이 없어 INSERT해야되는 경우도 있기 때문
    2.3 이럴 경우에는 이미 존재하는 InsertBoardImage를 호출
  3. 삭제된 이미지 DELETE DAO 수행

엄청 막 헷갈리는 부분은 없는데 imageList Delete의 경우 sql작성이 조금 독특했다.

PreparedStatement를 이용해 위치홀더로 값을 세팅할 경우
기본적으로 '' 홑따옴표가 감싸지에 되는데 이렇게 되면 ,으로 구분되어 있는 각각의 이미지 레벨이 '1,2,3'으로 하나의 묶음로 처리되 곤란해진다(수행할 수 없는 SQL)

해결방법은 단순하게 그냥 Statement를 사용했던것 처럼 위에 + 해 사용하면됬다.

String sql = prop.getProperty("deleteBoardImage")+deleteList+")";	

다시 생각하는 Forword / ReDirect 차이점

웃기게 나는 반대로 생각하고 있었다
forward의 요청 위임을 다른 JSP으로 위임한다고 생각하고
redirect의 재요청 요청한 기존 JSP로 다시 요청한다고 생각했다
왜 이렇게 생각했는지 기억이 안난다.

Servlet : JAVA에서 HTML 코드를 작성해 클라이언트에게 전달
매번 resp.getWriter() 난리칠 수 없어서
JSP(Java Server Page)가 나왔다

forward : 요청 위임

Servlet은 요청을 받아 벡엔드(Servlet , DB) 처리
-> 처리 결과를 JSP에게 위임해서 응답화면(HTML)으로 만들게 됨
--> Servlet의 req, resp를 그대로 JSP에게 넘겨줘야함.
forwoard 특징 :
1) req,resp 유지. == 파라미터.req.setAttribute() 으로 추가된 값을 JSP 그대로 사용 가능
2) Servlet -> JSP 두개의 페이지로 보이지만 실질적으로는 하나의 페이지 (협업같은 느낌 하나의 목적을 위해 같이 수행함)
-> Servlet에서 JSP 요청 위임을 해도 요청주소는 변하지 않는다.

redirect : 재요청

요청 처리 후 응답화면을 새롭게 만드는 것이 아닌 ( forward가 아니라 )
응답 화면을 만들어주는(forward) 요청 주소를 클라이언트에게 전달
->클라이언트가 해당 주소로 다시 요청하게 됨(Redirect)


클라이언트가 원하는 결과를 보여줄 수 있는 주소를 알려주어 이동하게 함
redirect 특징 :
1) req , resp가 새롭게 생성되서 기본 request scope에 세팅된 값(Parameter ,
req.setAttribute)가 다 사라짐.
대안책으로 Session Scope 활용
2) 다시 요청을 하기 때문에 주소가 변함.

0개의 댓글