[요리 후기 작성] 요리 후기 작성 기능 구현

    * 세미 프로젝트에서 구현한 기능들을 복습 겸 정리해보려고 합니다.

    당연한 이야기이지만, 제 코드가 정답은 아니기 때문에 감안하고 읽어주시면 감사하겠습니다.

     

     

    이번 포스팅은 요리 후기 작성 기능 구현입니다.

    요리 후기 조회 기능의 경우 아래의 포스팅을 참고해주시면 감사하겠습니다.

     

    [요리 후기 조회] Ajax로 요리 후기 조회 기능 구현

    * 세미 프로젝트에서 구현한 기능들을 복습 겸 정리해보려고 합니다. 당연한 이야기이지만, 제 코드가 정답은 아니기 때문에 감안하고 읽어주시면 감사하겠습니다. 이번 포스팅은 요리 후기 조

    seongeun-it.tistory.com


     

    대략적인 UI는 다음과 같습니다.

    * 별점 기능 구현 CSS와 JavaScript는 수정 중입니다 업데이트되는 대로 변경하겠습니다.

     

    왼쪽 : 기본 이미지, 오른쪽 : 미리보기 화면

     

     

    1. SQL

    	<entry key="insertReview">
    	INSERT INTO REVIEW
    	    (
    	        REVIEW_NO
    	        ,USER_NO
    	        ,RECIPE_NO
    	        ,REVIEW_CONTENT
    	        ,STAR
    	        ,IMG_NAME
    	    ) VALUES
    	    (
    	        SEQ_RVNO.NEXTVAL
    	        , ?
    	        , ?
    	        , ?
    	        , ?
    	        , ?
    	    )
    	    
    	</entry> 

    요리 후기 작성 시 필요한 정보는

    리뷰 번호 / 후기 작성자의 회원 번호 / 레시피 번호 / 리뷰 내용 / 별점 / 리뷰 이미지 경로입니다.

    이때, 리뷰 번호는 SEQ로 자동적으로 값이 입력되기 때문에 리뷰 번호를 제외한 총 5개의 정보들이 필요합니다.

     


    2. View

     

    *View단의 경우 코드 전체 복사가 아닌 우리가 필요한 정보들 ( 후기 작성자의 회원 번호 / 레시피 번호 / 리뷰 내용 / 별점 / 리뷰 이미지 경로 )만 요약해서 가져왔습니다.

     

    *또한 View단의 JavaScript 부분은 이어지는 포스팅을 참고해주시면 감사하겠습니다. 

    <form action="<%=contextPath%>/insertReview.recipe" method="post" id="enroll-form" enctype="multipart/form-data">
    
        <input type="hidden" name="userNo" value="<%=userNo%>">
        <input type="hidden" name="recipeNo" value="<%=recipeNo%>">
    
        <div>
        <br>
          <select name="starCount" id="starCount" >
            <option value="0.5">0.5</option>
            <option value="1">1</option>
            <option value="1.5">1.5</option>
            <option value="2">2</option>
            <option value="2.5">2.5</option>
            <option value="3" selected>3</option>
            <option value="3.5">3.5</option>
            <option value="4">4</option>
            <option value="4.5">4.5</option>
            <option value="5">5</option>
          </select>
        </div>
    
         <input type="file" id="reviewImg1" name="reviewUpfile" onchange="loadImg(this,1)" class="form-control-file border"  required>
    	 <textarea cols="55" rows="3" placeholder="자세한 리뷰는 다른 쉐프님들께 큰 도움이 될 거예요" style="font-size: 11px; resize: none; "  class="form-control form-control-sm" name="content" required></textarea>
         <button type="submit" class="btn btn-block" style="background-color: rgb(0, 153, 102); color:white" >완료</button>
    
    
    </form> 
    
    
    

     

    앞서 포스팅한 Ajax를 이용한 기능 구현들과  View단이 다른 점은 요리 후기 작성 기능은 form 태그 안에  enctype="multipart/form-data" 사용하여 첨부파일을 전송하는 방식이기 때문입니다. 

     

    각각의 name 속성과 value를 Controller단으로 넘겨줍니다.

     

     


    3. Controller

     1)
    		request.setCharacterEncoding("UTF-8");
    		
    		if(ServletFileUpload.isMultipartContent(request)) {
    			
    
    			int maxSize = 10*1024*1024;
    			String savePath = request.getSession().getServletContext().getRealPath("/resources/review_upfiles/");
    			MultipartRequest multiRequest = new MultipartRequest(request,savePath,maxSize,"UTF-8",new MyFileRenamePolicy());
    			
    2)
    			String reivewWriter = multiRequest.getParameter("userNo");
    			int recipeNo = Integer.parseInt(multiRequest.getParameter("recipeNo"));
    			String reviewContent = multiRequest.getParameter("content");
    			Double star = Double.parseDouble(multiRequest.getParameter("starCount"));
    			String reviewImg = multiRequest.getFilesystemName("reviewUpfile");
    			
    3)
    			Review rv = new Review();
    			
    			rv.setReviewWriter(reivewWriter);
    			rv.setRecipeNo(recipeNo);
    			rv.setReviewContent(reviewContent);
    			rv.setStar(star);								
    			rv.setReviewImg( "resources/review_upfiles/" + reviewImg);
    
    			int result = new RecipeService().insertReview(rv);
    				
    4)
    			// 요리 후기 작성시 별점 변경
    			int avgStar = new RecipeService().avgStarUpdate(recipeNo);
    			
    5)
    			if(result>0) {
    				
    				request.getSession().setAttribute("alertMsg", "요리후기 작성 성공 ! ");
    				response.sendRedirect(request.getContextPath()+"/detail.recipe?rno=" + recipeNo);
    				
    			}else {
    				
    				request.setAttribute("errorTitleMsg", "요리 후기 등록 실패");
    				request.getRequestDispatcher("views/member/login.jsp").forward(request, response);
    		
    			}
    	
    		}

    위의 구문을 총 6개의 부분으로 나누어 설명 드리겠습니다.

     

    1) View단에서 post 방식으로 요청되기 때문에 인코딩을 먼저 해줍니다. 조건 검사를 통해 첨부파일이 있을 경우, 아래의 코드가 실행되도록 했습니다. MutilpartRequest클래스는 파일 업로드를 직접적으로 담당하는 클래스입니다. 대략적으로 업로드될 경로와, 업로드 시 변경될 파일의 수정명 등을 기술합니다.

     

     

    2) View단에서 넘어온 5개의 값들을 parameter영역에서 가져와 각각의 변수에 담아줍니다. 회원 번호와 별점은 각각 int형, double형 변수에 담기기 때문에 파싱을 해줍니다. 여기서 주목해야 하는 부분은 String reviewImg = multiRequest.getFilesystemName("reviewUpfile"); 이 구문입니다. multiRequest 안에 있는 getFilesystemName메소드는 서버에 실제로 업로드된 파일명을 반환합니다. 그 값을 String reviewImg라는 변수에 담았습니다. 

     

     

    3) 5개의 값들을 하나의 VO 클래스에 담아 Service단으로 넘겨줍니다.  RecipeService안에 있는 insertReview에 3번에서 선언한 rv를 매개변수로 넘겨주었습니다.

     

     

    4) * 이 부분은 수정될 예정입니다. 

    후기 작성 시 레시피의 요리 후기 별점 값이 바뀌는 로직인데, 요리 후기를 작성 후 삭제해도 이전에 입력했던 별점이 출력됩니다.

    보완해서 업데이트하겠습니다.

     

     

    5) 

    Ajax와 차이점이 나타나는 부분입니다. 해당 구문에서는 요청 시 값을 보여주는 화면을 성공 시, 실패 시로 각각 설정했습니다.

    요리 후기 작성 시 alert로 메시지가 출력되고, 다시 레시피 상세보기 페이지로 넘어갑니다. 

    작성 실패 시 에러 페이지로 이동되며, 요리 후기 등록 실패라는 메시지가 보입니다.

     


    4. Service

    	public int insertReview(Review rv) {
    		
    		Connection conn = getConnection();
            
    		int result = new RecipeDao().insertReview(conn,rv);	
            
    		if(result>0) {
    			commit(conn);
    		} else {
    			rollback(conn);
    		}
    		close(conn);
            
    		return result;
    		
    	}

    service단은 Dao단으로 Connection 객체와 Review를 넘겨주며, 조회된 결과에 따라 성공 시에는 commit, 실패 시에는 rollback을 합니다.

     


    5. DAO

    	public int insertReview(Connection conn, Review rv) {
    		
    		int result = 0;
    		PreparedStatement pstmt = null;
    		String sql = prop.getProperty("insertReview");
    		
    		try {
    			pstmt = conn.prepareStatement(sql);
    			
    			pstmt.setString(1, rv.getReviewWriter());
    			pstmt.setInt(2, rv.getRecipeNo());
    			pstmt.setString(3, rv.getReviewContent());
    			pstmt.setDouble(4, rv.getStar());
    			pstmt.setString(5, rv.getReviewImg());
    			
    			result = pstmt.executeUpdate();
    			
    		} catch (SQLException e) {
    			e.printStackTrace();
    		}finally {
    			close(pstmt);
    		}
    		
    		return result;
    
    	}

    작성하기 기능임으로 sql에서  *행이 삽입되었습니다.라는 결과가 출력됩니다. int result에 처리된 행수를 담고,

    1번에서 기술한 미완성된 SQL문을 PreparedStatement에 담습니다. 5개의 ? 에 View단에서부터 가져온 값들을 대입합니다.

    result = pstmt.executeUpdate();문은 반드시 기술해야 SQL문이 실행됩니다. PreparedStatement 객체를 반납해줍니다.

     


    실행되는 결과는 다음과 같습니다.

     

     

     


    참고 블로그

     

     

    JSP / MultipartRequest 클래스

    *MultipartRequest MultipartRequset클래스는 COS라이브러리에서 가장 핵심적인 역할을 하는 클래스이다. 이 클래스는 파일 업로드를 직접적으로 담당하는 클래스이며, 파일업로드를 담당하는 생성자 및

    swdevelopment.tistory.com

     

    [Javascript] FileReader 객체로 파일 읽기

    FlieReader 객체를 이용하여 업로드된 파일을 읽을 수 있다. FileReader란? 웹 애플리케이션이 비동기적으로 데이터를 읽기 위하여 읽을 파일을 가리키는 File혹은 Blob객체를 이용해 파일의 내용을(혹

    developer-syubrofo.tistory.com

     

    728x90

    댓글