Spring

[Spring]Spring쇼핑몰 프로젝트 - Ajax를 활용하여 상품 문의 리스트 만들기 아코디언 리스트

issaac 2021. 12. 27. 12:11

판매자가 상품문의 리스트에서 할 수 있는 기능들은 아래와 같다.

  • 상품문의 확인
  • 답변 작성폼으로 이동
  • 작정한 답변 확인
  • 작성한 답변 수정 폼으로 이동
  • 작성한 답변 수정
  • 작성한 답변 삭제

해당 기능들 중 삭제를 제외한 기능들을 비동기로 처리하였다.

 

우선 리스트 출력시

리스트에서 상세보기 버튼을 통해서 문의내용을

아코디언 형식으로 출력하였고,

문의 내용을 출력할 때에는 답변을 작성한 경우와

작성하지 않은 경우로 나눠서

답변을 작성한 경우 - 문의내용과 답변을 출력하고,

답변을 작성하지 않은 경우 - 문의내용과 답변입력칸을 출력했다.

 

 


문의 리스트

1. 문의리스트.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<table border="1" id="goodsQnaTable" style="table-layout:fixed" width="800">
    <caption>문의 내역</caption>
    <tr>
        <th width="5%">번호</th>
        <th width="20%">상품명</th>
        <th width="25%">문의제목</th>
        <th width="20%">문의날짜</th>
        <th width="20%">상태</th>
        <th width="10%">액션</th>
    </tr>
    <c:set var="num" value="${listcount-(page-1)*10}"/> 
    <c:forEach var="gql" items="${sellergoodsQnaList}">
        <tr <c:if test="${gql.gdsqna_check == 0 }"> class="notcheck"</c:if> height=30px>
            <td style="text-align: center;"><!-- 번호 출력 부분 -->
                <input type="hidden" id="gdsqna_num" name="gdsqna_num" value="${gql.gdsqna_num}">
                <c:out value="${num}"/>            
                <c:set var="num" value="${num-1}"/>     
            </td>
            <td class="goodsQnaListName" title="${gql.gds_name}"><nobr>${gql.gds_name}</nobr></td>
            <td>${gql.gdsqna_title}</td>
            <td>
                <fmt:formatDate value="${gql.gdsqna_date}" pattern="yyyy-MM-dd HH:mm:ss"/> 
            </td>
            <td style="text-align: center;">
                <c:choose>
                    <c:when test="${gql.gdsqna_answer == 0}">
                        미답변
                    </c:when>
                    <c:when test="${gql.gdsqna_answer == 1}">
                        답변완료
                    </c:when>
                </c:choose>
            </td>
            <td style="text-align: center;">
                <button id="detailbtn" type="button" onclick="showquestiondetail(${gql.gdsqna_num})">상세보기</button>
            </td>
        </tr>
        <tr>
            <td colspan="6">
                <div id="questiondetail${gql.gdsqna_num}" class="hide"></div>
            </td>
        </tr>
    </c:forEach>
</table>
cs

forEach문으로 <tr> 2개식 출력하여

첫번째 tr은 리스트에서 보여줄 정보를 출력하고,

두번째 tr은 ajax의 결과값이 출력될 수 있도록  id와 class를 설정해준다.

id는 forEach로 여러 tr을 추가할 예정이기 때문에 

특정할 수 있도록 하기 위해 id값에 각 문의의 번호를 붙였고,

class는 ajax가 동작하기 전에는 보이지 않도록 hide로 설정한다.

 

미리보기 버튼은 onclick으로 ajax를 호출하고,

ajax를 호출할 때 각 문의의 번호를 가져간다.

 

2. 문의 리스트CSS

1
2
3
.hide {display:none;}
 
.show {display:table-row;}  
cs

class가 hide인 경우에는 display:none 으로 보이지 않게 하고,

show인 경우에는 display:table-row 로 tr 요소처럼 보이게 한다.

 

3. 문의 리스트 ajax.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function showquestiondetail(gdsqna_num) {
    // class가 hide인 경우
    if($("#questiondetail"+gdsqna_num).hasClass('hide')) { 
         $.ajax({
            url : '/showgoodsQnadetail'// 요청 할 주소
            type : 'post',
            dataType : 'text',
            data : {
                "gdsqna_num" : gdsqna_num,
            },
            success : function(data) { // 요청 완료 시
                $("#questiondetail"+gdsqna_num).html(data);
                $("#questiondetail"+gdsqna_num).removeClass('hide').addClass('show');  // class에 hide를 지우고, show를 추가한다.
            },
            error :function(xhr,status,error){
                        console.log("code:"+xhr.status+"\n"+"message:"+xhr.responseText+"\n"+"error:"+error);
                        alert(xhr.status);
            }
        });
    // class가 show인 경우 
    }else if($("#questiondetail"+gdsqna_num).hasClass('show')) {  
        $("#questiondetail"+gdsqna_num).empty();
        $("#questiondetail"+gdsqna_num).removeClass('show').addClass('hide');   // class에 show를 지우고, hide를 추가한다.
        
    }
}
cs

ajax 요청시 class가 hide라면 ajax를 요청한 뒤에 show로 변경하고,

class가 show면 해당 tr요소 내에 있는 데이터를 empty()로 비우고, hide로 변경해서

아코디언 형태로 view페이지를 출력한다.

 

4. 컨트롤러.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 판매자 문의 상세목록으로 이동
@RequestMapping(value = "/showgoodsQnadetail")
public String showgoodsQnadetail(@RequestParam("gdsqna_num"int gdsqna_num, Model model) throws Exception{
    
    // 답변이 달렸는지 확인하기
    int answer = goodsQnaService.getGoodsQnaAnswer(gdsqna_num);
    model.addAttribute("answer", answer);
    
    // 문의확인 업데이트
    goodsQnaService.updateCheckQna(gdsqna_num);
    
    // 문의 가져오기
    GoodsQnaVO goodsquestion = goodsQnaService.getGoodsQuestionDetail(gdsqna_num);
    model.addAttribute("goodsquestion", goodsquestion);
    
    // 답변이 있다면 답변 가져오기
    if(answer == 1) {
        GoodsQnaVO goodsanswer = goodsQnaService.getGoodsAnswerDetail(gdsqna_num);
        model.addAttribute("goodsanswer", goodsanswer);
    }
    
    return "seller/ajaxgoodsqnadetail";
}
cs

컨트롤러에서는 우선 해당 문의의 답변여부컬럼 (답변했으면 1, 안했으면0)

에 접근하여 

답변이 달렸는지 확인한 뒤에

답변이 달렸다면 문의와 답변을 같이 가져오고,

답변이 없다면 문의만 가져온다.

 

5. ajax 상세페이지.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<!-- 문의글 -->
    <table id="questionTable" border="1" style="table-layout:fixed" >
        <caption>문의</caption>
        <tr>
            <th width="100">상품 정보</th>
            <td style="border-right: none;" width="100">
                <img src="<%=request.getContextPath() %>/resources/images/thumbnailimage/${goodsquestion.gds_thumbnail}" height="100" width="100" />
            </td>
            <td style="border-left: none; white-space:nowrap; overflow: hidden;" width="500">
                ${goodsquestion.gds_name}
                <br><br>
                <div style="text-align: right"> <a href="goodsupdate?&gds_num=${goodsquestion.gds_num}">상품 수정하기</a></div>
            </td>
            <td width="100"    >
                <fmt:formatDate value="${goodsquestion.gdsqna_date}" pattern="yyyy-MM-dd HH:mm:ss"/> 
            </td>
        </tr>
        <tr>
            <th width="100">문의 제목</th>
            <td colspan="3">${goodsquestion.gdsqna_title}</td>
        </tr>
        <tr>
            <th width="100">문의 내용</th>
            <td colspan="3">
                <c:if test="${goodsquestion.fname ne null}">
                    <img src="<%=request.getContextPath() %>/resources/upload/goodsqna/${goodsquestion.fname}"/> <br><br>
                </c:if>
                <pre style="border: none; background: none;">${goodsquestion.gdsqna_content}</pre>
            </td>
        </tr>
    </table>
 
    <c:choose>
<!-- 답변이 있을 경우 -->
        <c:when test="${answer == 1 }">
        <div id="goodsQnaAnswer${goodsanswer.gdsqna_num}">
            <table border="1">
                    <caption>답변</caption>
                    <tr>
                        <th width="100">답변 제목</th>
                        <td>${goodsanswer.gdsqna_title}</td>
                        <th width="100">답변 등록일</th>
                        <td><fmt:formatDate value="${goodsanswer.gdsqna_date}" pattern="yyyy-MM-dd HH:mm:ss"/></td>
                    </tr>
                    <tr>
                        <th>문의내용</th>
                        <td colspan="3"><pre style="border: none; background: none;">${goodsanswer.gdsqna_content}</pre></td>
                    </tr>
                    <tr>
                        <td colspan="4" align="center">
                            <input type="button" onclick="updategoodsqnaanswer(${goodsanswer.gdsqna_num})" value="수정">
                            <input type="button" onclick="location='deletegoodsqnaanswer?gdsqna_num=${goodsanswer.gdsqna_num}'" value="삭제">
                        </td>
                    </tr>
                </table>
            </div>
        </c:when>
<!-- 답변이 없을 경우 -->
        <c:when test="${answer == 0 }">
            <form action="goodsqnaanswer" method="post">
            <input type="hidden" id="gdsqna_num" name="gdsqna_num" value="${goodsquestion.gdsqna_num}">
                <table border="1">
                    <caption>답변 등록</caption>
                    <tr>
                        <th width="100">답변 제목</th>
                        <td><input type="text" id="gdsqna_title" name="gdsqna_title" size="100"></td>
                    </tr>
                    <tr>
                        <th width="100">문의내용</th>
                        <td><textarea id="gdsqna_content" name="gdsqna_content" cols="102" rows="10"></textarea></td>
                    </tr>
                    <tr>
                        <td colspan="2" align="center">
                            <input type="submit" value="답변 등록">
                        </td>
                    </tr>
                </table>
            
            </form>
        </c:when>
    </c:choose>
    
cs

상세보기를 클릭하면 상품문의의 내용이 출력되고,

<c:choose> 태그를 활용하여

답변이 있는 경우 에는 답변 출력

답변이 없는 경우 - 답변 입력칸 출력

이 되도록 한다.

 

답변 수정의 경우 상세보기와 동일하게 onclick으로 ajax를 호출하며,

ajax를 호출할 때 각 문의의 번호를 가져간다.

 

답변영역의 경우 div로 감싸고, id값은 문의 리스트와

동일하게 특정할 수 있도록 문의 번호를 추가하여 설정해준다.

 

6. 수정 ajax.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function updategoodsqnaanswer(gdsqna_num) {
         $.ajax({
            url : '/updategoodsqnaanswerform',
            type : 'post'
            dataType : 'text',
            data : {
                "gdsqna_num" : gdsqna_num,
            },
            success : function(data) {
                $("#goodsQnaAnswer"+gdsqna_num).html(data);
            }, 
            error :function(xhr,status,error){
                        console.log("code:"+xhr.status+"\n"+"message:"+
xhr.responseText+"\n"+"error:"+error);
                        alert(xhr.status);
            }
        });
}
cs

 

7. 수정 controller.java

1
2
3
4
5
6
7
8
9
10
11
// 상품 문의 답변 수정 폼 
@RequestMapping(value = "/updategoodsqnaanswerform")
public String updategoodsqnaanswerform(@RequestParam(value = "gdsqna_num"int gdsqna_num,
                                    Model model) {    
    // 받아온 gdsqna_num으로 수정할 답변 정보 불러오기
    GoodsQnaVO answer =  goodsQnaService.getGoodsAnswer(gdsqna_num);
    
    model.addAttribute("answer", answer);
    
    return "seller/ajaxgoodsqnaanswerupdate";
}
cs

 

 

8. ajax 답변 수정.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<form action="<%=request.getContextPath()%>/updategoodsqnaanswer" method="post">
    <input type="hidden" id="gdsqna_num" name="gdsqna_num" value="${answer.gdsqna_num}">
    <table border="1" id="goodsQnaAnswer${answer.gdsqna_num}">
        <caption>답변 수정</caption>
        <tr>
            <th width="100">답변 제목</th>
            <td><input type="text" id="gdsqna_title" name="gdsqna_title" size="100" value="${answer.gdsqna_title }"></td>
        </tr>
        <tr>
            <th width="100">답변 내용</th>
            <td><textarea id="gdsqna_content" name="gdsqna_content" cols="102" rows="10">${answer.gdsqna_content }</textarea></td>
        </tr>
        <tr>
            <td colspan="4" align="center">
                <input type="submit" value="수정">
            </td>
        </tr>
    </table>
</form>
cs

 

 

 

9. 실행화면