일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 세션
- jsp
- MVC
- jquery
- 대분류/중분류/소분류
- ajax
- jakarta.mail
- 로그인과 장바구니 구현
- 이메일로 인증코드 전송 구현
- Oracle
- jsp 프로젝트
- Level 1
- 다중 카테고리 구현
- java
- js
- Spring
- 자바
- 오라클
- 일단_해보는거야
- 스프링
- 프로그래머스
- SESSION
- Spring MVC
- MySQL
- json
- Sts
- 고객센터 구현
- 코딩
- 인증코드로 비밀번호 변경 구현
- 교보문고 따라하기
감 잃지말고 개발하기
[JSP] [MVC] [AJAX] [JS] [JSON] AJAX를 이용해 고객센터 페이지 구현하기 #6. FAQ 페이지 구현(마지막) 본문
[JSP] [MVC] [AJAX] [JS] [JSON] AJAX를 이용해 고객센터 페이지 구현하기 #6. FAQ 페이지 구현(마지막)
persii 2023. 4. 20. 05:25교보문고 고객센터 페이지를 모델로 하여 MVC패턴을 지키면서 ajax를 이용한 비동기 통신으로 DB에 저장된 데이터를 브라우저에 출력하는 로직을 기록하고자 한다.
지난 포스팅에서는 FAQ 페이지가 요청되는 두 가지 방식 두 번째 방식의 로직을 구현해 보았다.
이번 포스팅에서는 중분류 버튼을 클릭했을 때 해당 중분류에 따른 FAQ 데이터만 출력되는 로직을 구현해 보도록 하겠다. 전체적인 흐름은 이전 포스팅과 동일하다.
목표
♠ JSP에서 MVC 패턴을 지키면서 AJAX를 통해 데이터를 출력할 수 있다.
♠ 교보문고 고객센터 페이지를 구현할 수 있다.
로직 흐름
- FAQ 페이지에서 중분류 버튼을 클릭하면 ajax로 해당 대분류 코드(PK)와 중분류 코드(PK)가 서버에 넘어간다(faq.jsp).
- 해당 컨트롤러에서 URL을 받고, 해당 요청을 처리하는 클래스를 호출한다(AjaxFrontController.java).
- Action 클래스에서 비즈니스 로직을 처리하는 클래스를 호출하여 DB로부터 데이터를 가져오고, 가져온 데이터를 JSON 형태의 문자열로 만들어 response 객체에 담아 보낸다(CsCenterFkcodeFaqAction.java).
- Service 클래스에서 DAO클래스를 호출한다(BookCscenterFaqService.java).
- DAO 클래스에서 MySQL8.0 DB에 접근해 데이터를 가져온다(FaqDAO.java).
- 다시 FAQ 페이지로 돌아와 적절한 응답을 한다.
로직 흐름 코드 및 실행화면
1. FAQ 페이지(faq.jsp)
1-1. ▼ FAQ 페이지 중분류 영역
FAQ 페이지에서 중분류 버튼을 하나 클릭하면 스크립트 함수가 실행된다.
1-2. ▼ FAQ 페이지 중분류 영역 HTML
<button type="button" class="fkbtn" id="tab012"></button>
- class="fkbtn" : 중분류 버튼을 클릭했을 때 스크립트 함수를 편리하게 호출하기 위한 설정이다.
- id="tab012" : 중분류 링크를 클릭했을 때 중분류 코드(PK)를 서버로 넘기기 위해 PK값을 id="tab0" 뒤에 붙인다. 이 중분류 코드(PK) 값은 해당 대분류 링크를 클릭했을 때 AJAX로 가져오게끔 만들었다(이전 포스팅 참고).
- '전체' 버튼을 클릭할 경우, 0이 서버에 전달되도록 할 것이다.
<!-- faq.ok?fcode=n에 따른 데이터 출력되는 영역 -->
<section class="container mb-5 faqSection">
<div class="container-header faqTabArea" style="padding:10px 0;">
<h3><b>도서/상품정보/교과서</b></h3>
<div style="height: 50px;">
<ul class="nav h-100 faqkeywordUl">
<li class="nav-item my-2 mr-2">
<button type="button" class="fkbtn" id="tab00">
<span class="text-center">전체</span>
</button>
</li>
<li class="nav-item my-2 mr-2">
<button type="button" class="fkbtn" id="tab07">
<span class="text-center">정보/검색/알림기능</span>
</button>
</li>
<li class="nav-item my-2 mr-2">
<button type="button" class="fkbtn" id="tab08">
<span class="text-center">서양도서</span>
</button>
</li>
<li class="nav-item my-2 mr-2">
<button type="button" class="fkbtn" id="tab09">
<span class="text-center">일본도서</span>
</button>
</li>
<li class="nav-item my-2 mr-2">
<button type="button" class="fkbtn" id="tab010">
<span class="text-center">교과서/방송대교재</span>
</button>
</li>
<li class="nav-item my-2 mr-2">
<button type="button" class="fkbtn" id="tab011">
<span class="text-center">일본잡지정기구독</span>
</button>
</li>
<li class="nav-item my-2 mr-2">
<button type="button" class="fkbtn" id="tab012">
<span class="text-center">기프트</span>
</button>
</li>
</ul>
</div>
<hr class="my-3">
</div>
<div class="accordion faqCardList" id="accordionExample">
<!-- FAQ 데이터 출력(생략) -->
</div>
</section>
<!-- faq.ok?fcode=n에 따른 데이터 출력되는 영역 -->
1-3. ▼ FAQ 페이지 중분류 버튼 클릭 JS
중분류 버튼을 클릭했을 때 호출되는 스크립트 함수이다.
중분류 버튼은 AJAX로 생성된 HTML이기 때문에 $(document).on('click', '식별자', function() { });을 사용한다.
클릭하면 해당 중분류의 PK값과 대분류의 PK값이 서버에 넘어간다.
올바른 요청 및 응답이 이루어진 후의 액션은 이전 포스팅에서의 FAQ 데이터 출력 과정과 동일하다.
단, 여기서는 FAQ 데이터만 새로 붙일 것이기 때문에 <div class="faqCardList"> 아래에 붙인다.
<script type="text/javascript">
// 중분류 버튼 클릭 시
$(document).on('click', '.fkbtn', function() {
var fkbtnID = $(this).attr('id').substring(4);
var fc_code = $('#fc_code').val();
$.ajax({
url: '/cscenter/fkcode/faq.ax',
method: 'POST',
data: { "fk_code" : fkbtnID, "fc_code" : fc_code},
success: function(text) {
var toJsObj = JSON.parse(text);
var html = "";
// FAQ 출력
if(toJsObj["faqs"] === "no-faqs"){
// FAQ 데이터가 없는 경우
html += '<div>';
html += '<h4><b>등록된 문의가 없습니다.</b></h4>';
html += '</div>';
} else {
$.each(toJsObj["faqs"], function(index, value) {
html += '<div class="card">';
html += '<div class="card-header" id="heading"'+index+'" style="background-color:white !important;">';
html += '<h2 class="mb-0">';
html += '<button class="btn btn-link btn-block text-left" type="button" data-toggle="collapse"';
html += ' data-target="#collapse' + index + '" aria-expanded="true" aria-controls="collapse' + index + '"';
html += 'style="color:black !important;">';
html += '['+value.fk_value+']'+ value.f_title;
html += '</button>';
html += '</h2>';
html += '</div>';
html += '<div id="collapse'+index+'" class="collapse" aria-labelledby="heading'+index+'" data-parent="#accordionExample">';
html += '<div class="card-body" style="background-color:rgba(0,0,0,.03);">';
html += value.f_text;
html += '</div>';
html += '</div>';
html += '</div>';
});
}
// class="faqCardList" 아래에 붙이기
$(".faqCardList").html(html);
},
error: function(jqXHR, textStatus, errorThrown) {
console.error(errorThrown);
}
});
});
</script>
2. 컨트롤러(AjaxFrontController.java)
아래 코드만 기존 코드에 추가해준다.
// 중분류에 따른 Faq 처리 요청
else if (command.equals("/cscenter/fkcode/faq.ax")) {
action = new CsCenterFkcodeFaqAction();
try {
action.execute(req, resp);
} catch (Exception e) {
e.printStackTrace();
}
}
3. Action 클래스(CsCenterFkcodeFaqAction.java)
- ajax로 건너온 대분류 코드(fc_code)와 중분류 코드(fk_code)를 저장한다.
- Best 10에는 중분류 자체가 출력이 안되므로 fc_code에는 0이 저장될 수 없다.
- fk_code에는 0이 저장될 수 있다. 0의 경우, 전체 FAQ 데이터를 가져온다('전체' 버튼).
- DB에서 fc_code와 fk_code에 따른 FAQ 리스트를 가져온다.
- 가져온 데이터를 JSON 형태의 문자열로 저장한다.
- 만들 JSON 형태는 #2. 구현 틀 잡기 포스팅을 참고하길 바란다.
- 완성된 문자열을 response에 담아 보낸다.
보낼 JSON 형태는 아래와 같다.
{ "faqs" :
[
{"fk_code" : 1, "fk_value" : "회원가입/탈퇴", "f_id" : 1, "f_title" : "제목", "f_text" : "내용"},
{"fk_code" : 1, "fk_value" : "회원가입/탈퇴", "f_id" : 2, "f_title" : "제목", "f_text" : "내용"},
{"fk_code" : 2, "fk_value" : "본인성인인증", "f_id" : 3, "f_title" : "제목", "f_text" : "내용"}
]
}
package action;
import java.io.PrintWriter;
import java.util.ArrayList;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import svc.AjaxAction;
import svc.BookCscenterFaqService;
import vo.Faq;
/** fk_code에 따른 FAQ 요청을 처리하는 Action 클래스 */
public class CsCenterFkcodeFaqAction implements AjaxAction {
@SuppressWarnings("unchecked")
@Override
public void execute(HttpServletRequest req, HttpServletResponse resp) throws Exception {
/* 파라미터 저장 */
int fk_code = Integer.parseInt(req.getParameter("fk_code"));
int fc_code = Integer.parseInt(req.getParameter("fc_code"));
/* DB에서 fk_code에 따른 데이터 가져오기 */
BookCscenterFaqService service = new BookCscenterFaqService();
ArrayList<Faq> faqList = service.selectFaq(fc_code, fk_code);
String faqStr = null;
JSONArray faqsarr = new JSONArray();
JSONObject faqs = new JSONObject();
if(faqList != null) {
for(Faq faq : faqList) {
JSONObject faqObj = new JSONObject();
faqObj.put("fk_code", faq.getF_fk_code());
faqObj.put("fk_value", faq.getFk_value());
faqObj.put("f_id", faq.getF_id());
faqObj.put("f_title", faq.getF_title());
faqObj.put("f_text", faq.getF_text());
// 오브젝트 데이터를 JSONArray에 순서대로 저장
faqsarr.add(faqObj);
}
// 최종적으로 faqs 오브젝트에 JSON배열 저장
faqs.put("faqs", faqsarr);
} else {
faqs.put("faqs", "no-faqs");
}
// 파싱할 데이터 저장
faqStr = faqs.toJSONString();
resp.setCharacterEncoding("utf-8");
PrintWriter out = resp.getWriter();
out.print(faqStr);
out.close();
}
}
4. Service 클래스(BookCscenterFaqService.java)
기존 Service 클래스 안에 selectFaq(fc_code, fk_code) 메서드를 추가한다.
/** fc_code, fk_code에 따른 FAQ 데이터를 ArrayList 객체 타입으로 반환하는 메서드 */
public ArrayList<Faq> selectFaq(int fc_code, int fk_code) {
/* DB 처리 */
FaqDAO faqDAO = FaqDAO.getInstance();
Connection conn = getConnection();
faqDAO.setConnection(conn);
ArrayList<Faq> faqList = faqDAO.selectFaqList(fc_code, fk_code);
close(conn);
return faqList;
}
5. DAO 클래스(FaqDAO.java)
기존 FaqDAO 클래스 안에 selectFaqList(fc_code, fk_code) 메서드를 추가한다.
/** fc_code, fk_code에 따른 FAQ 데이터를 ArrayList 객체 타입으로 반환하는 메서드 */
public ArrayList<Faq> selectFaqList(int fc_code, int fk_code) {
PreparedStatement pstmt = null;
ResultSet rs = null;
ArrayList<Faq> faqList = null;
String sql = "select f.f_id, f.f_title, f.f_text, fk.fk_code, fk.fk_value "
+ "from faqkeyword fk join faq f "
+ "on f.f_fk_code = fk.fk_code ";
if(fk_code == 0) {
// 전체
sql += "and fk.fk_fc_code = " + fc_code + " "
+ "and f.f_use = 1 "
+ "order by f.f_id asc";
} else {
sql += "and fk.fk_fc_code = " + fc_code + " "
+ "and fk.fk_code = " + fk_code + " "
+ "and f.f_use = 1 "
+ "order by f.f_id asc";
}
try {
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
if (rs.next()) {
faqList = new ArrayList<Faq>();
do {
faqList.add(new Faq(rs.getInt(1),
rs.getInt(4),
rs.getString(2),
rs.getString(3),
rs.getString(5)));
} while (rs.next());
}
} catch (Exception e) {
System.out.println(" F.DAO : selectFaqList(fc_code, fk_code) ERROR : "+e);
} finally {
close(rs);
close(pstmt);
}
return faqList;
}
6. FAQ 페이지(faq.jsp)
ajax로 보낸 요청이 정상적으로 처리되고, 서버로부터 정상적인 응답이 이루어진 경우, 화면에 그에 따른 응답이 출력된다.
이렇게 중분류 버튼을 클릭했을 때 해당 중분류에 따른 FAQ 데이터만 출력되는 로직이 모두 구현되었다.
이로써 목표한 고객센터 페이지 구현이 완성되었다.
미흡한 부분이 있지만 본 포스팅을 끝으로 고객센터 페이지 구현을 마무리하도록 하겠다.