일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- SESSION
- 일단_해보는거야
- 프로그래머스
- ajax
- Spring
- json
- Spring MVC
- 대분류/중분류/소분류
- jsp
- 세션
- 로그인과 장바구니 구현
- js
- Sts
- jsp 프로젝트
- Oracle
- jakarta.mail
- 고객센터 구현
- 자바
- 다중 카테고리 구현
- java
- 코딩
- jquery
- MVC
- MySQL
- 교보문고 따라하기
- 오라클
- Level 1
- 스프링
- 이메일로 인증코드 전송 구현
- 인증코드로 비밀번호 변경 구현
감 잃지말고 개발하기
[JSP] [MVC] [AJAX] [JS] [JSON] AJAX를 이용해 고객센터 페이지 구현하기 #2. 구현 틀 잡기 본문
[JSP] [MVC] [AJAX] [JS] [JSON] AJAX를 이용해 고객센터 페이지 구현하기 #2. 구현 틀 잡기
persii 2023. 4. 18. 17:27교보문고 고객센터 페이지를 모델로 하여 MVC패턴을 지키면서 ajax를 이용한 비동기 통신으로 DB에 저장된 데이터를 브라우저에 출력하는 로직을 기록하고자 한다.
지난 포스팅에서는 교보문고 페이지를 살펴보면서 전체적인 구현 틀을 잡아보았다.
이번 포스팅에는 고객센터 페이지를 구현하기 위해 필요한 DB 테이블 생성 및 VO 클래스 생성과 ajax를 통해 서버에서 보낼 JSON 데이터 형식을 잡아보도록 하겠다.
목표
♠ 특정 페이지 구현을 위해 필요한 DB 테이블을 생성하고 설정할 수 있다.
♠ 특정 페이지 구현을 위해 필요한 VO 클래스를 생성할 수 있다.
DB 테이블 생성 및 설정
고객센터 페이지에서 생성한 테이블은 다음과 같다.
1. FAQ 대분류 테이블
대분류 테이블에 필요한 칼럼은 대분류 코드(PK), 대분류 코드명이다.
'Best 10'을 제외한 나머지 대분류 카테고리의 PK(fc_code)가 1씩 더해지며 테이블에 저장되게 할 것이다.
이 값으로 나중에 메인페이지에서 아래 대분류 버튼을 클릭했을 때 fcode 파라미터 값으로 전달되어 해당 데이터가 출력되게 할 것이다.
CREATE TABLE `faqcode` (
`fc_code` int NOT NULL AUTO_INCREMENT COMMENT 'faq 대분류코드',
`fc_value` varchar(30) NOT NULL COMMENT 'faq 대분류코드명',
PRIMARY KEY (`fc_code`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='고객센터 faq의 대분류'
2. FAQ 중분류 테이블
아래 이미지에서, '주문/결제'에 해당하는 중분류가 출력되고 있음을 볼 수 있다.
따라서 중분류 테이블에서 필요한 칼럼은 faq 대분류 코드, faq 중분류 코드, faq 중분류 코드명이며,
faq 대분류 코드 칼럼은 대분류 테이블의 대분류 코드 칼럼을 참조하게 할 것이다.
즉, 외래키인 대분류 코드 칼럼을 통해 대분류 테이블과 중분류 테이블이 서로 연결되게 만들 것이다.
'전체'를 제외한 나머지 중분류의 PK(fk_code)가 1씩 더해지며 테이블에 저장된다.
위 조건으로 테이블을 생성하면 아래와 같다.
CREATE TABLE `faqkeyword` (
`fk_code` int NOT NULL AUTO_INCREMENT COMMENT 'faq 중분류 코드',
`fk_fc_code` int NOT NULL COMMENT 'faq 대분류코드',
`fk_value` varchar(45) NOT NULL COMMENT 'faq 중분류코드명',
PRIMARY KEY (`fk_code`),
UNIQUE KEY `fk_value_UNIQUE` (`fk_value`),
KEY `fk_fk_fc_code_idx` (`fk_fc_code`),
CONSTRAINT `fk_fk_fc_code` FOREIGN KEY (`fk_fc_code`) REFERENCES `faqcode` (`fc_code`)
) ENGINE=InnoDB AUTO_INCREMENT=86 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='faq 중분류 테이블'
3. FAQ 테이블
아래 이미지는 [대분류] '주문/결제' - [중분류] '마일리지/예치금'에 해당하는 하나의 FAQ이다.
따라서 FAQ 테이블에 필요한 칼럼은 faq 아이디, faq 대분류 코드, faq 중분류 코드, faq 제목, faq 답변, faq 조회수 칼럼이다.
PK는 faq 아이디가 되고,
faq 대분류 코드 및 faq 중분류 코드 칼럼은 각각 중분류 테이블의 대분류 코드와 중분류 코드 칼럼을 참조하게 할 것이다.
위 조건으로 테이블을 생성하면 아래와 같다.
CREATE TABLE `faq` (
`f_id` int NOT NULL AUTO_INCREMENT COMMENT 'faq 아이디',
`f_fc_code` int NOT NULL COMMENT 'faq 대분류코드',
`f_fk_code` int NOT NULL COMMENT 'faq 중분류 코드',
`f_title` varchar(100) NOT NULL COMMENT 'faq 제목',
`f_text` text NOT NULL COMMENT 'faq 답변',
`f_use` int NOT NULL DEFAULT '1' COMMENT 'faq 사용유무 default 1 : 사용 / 0 : 만료',
`f_regdate` datetime NOT NULL COMMENT 'faq 등록날짜',
`f_readcnt` int NOT NULL DEFAULT '0' COMMENT 'faq 조회수',
PRIMARY KEY (`f_id`),
KEY `fk_f_fc_code_idx` (`f_fc_code`),
KEY `fk_f_fk_code_idx` (`f_fk_code`),
CONSTRAINT `fk_f_fc_code` FOREIGN KEY (`f_fc_code`) REFERENCES `faqkeyword` (`fk_fc_code`),
CONSTRAINT `fk_f_fk_code` FOREIGN KEY (`f_fk_code`) REFERENCES `faqkeyword` (`fk_code`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='고객센터 faq 테이블'
ERD
생성한 3개의 테이블의 관계도를 살펴보면 다음과 같다.
VO 클래스 설정
DB 테이블 생성과 설정이 끝났으니, 프로젝트에서 DB 테이블과 매핑될 VO 클래스를 생성해 보도록 하겠다.
나중에 쿼리문에서 두 개 이상의 테이블을 조인해 데이터를 가져올 것이기 때문에 FAQ 대분류 VO 클래스는 따로 생성하지 않았다.
1. FAQ 중분류 VO 클래스
package vo;
public class FaqKeyword {
private int fk_code;
private int fk_fc_code;
private String fk_value;
private String fc_value;
public FaqKeyword() {
super();
}
public FaqKeyword(String fc_value, int fk_fc_code) {
super();
this.fk_fc_code = fk_fc_code;
this.fc_value = fc_value;
}
public FaqKeyword(int fk_code, String fk_value) {
super();
this.fk_code = fk_code;
this.fk_value = fk_value;
}
public FaqKeyword(int fk_fc_code, String fc_value, int fk_code, String fk_value) {
super();
this.fk_code = fk_code;
this.fk_fc_code = fk_fc_code;
this.fk_value = fk_value;
this.fc_value = fc_value;
}
public int getFk_code() {
return fk_code;
}
public void setFk_code(int fk_code) {
this.fk_code = fk_code;
}
public int getFk_fc_code() {
return fk_fc_code;
}
public void setFk_fc_code(int fk_fc_code) {
this.fk_fc_code = fk_fc_code;
}
public String getFk_value() {
return fk_value;
}
public void setFk_value(String fk_value) {
this.fk_value = fk_value;
}
public String getFc_value() {
return fc_value;
}
public void setFc_value(String fc_value) {
this.fc_value = fc_value;
}
@Override
public String toString() {
return "FaqKeyword [fk_code=" + fk_code + ", fk_fc_code=" + fk_fc_code + ", fk_value=" + fk_value
+ ", fc_value=" + fc_value + "]";
}
}
2. FAQ VO 클래스
package vo;
import java.util.Date;
public class Faq {
private int f_id;
private int f_fc_code;
private int f_fk_code;
private String f_title;
private String f_text;
private int f_use;
private Date f_regdate;
private int f_readcnt;
private String fk_value;
public Faq() {
super();
}
public Faq(int f_id, int f_fk_code, String f_title, String f_text, String fk_value) {
super();
this.f_id = f_id;
this.f_fk_code = f_fk_code;
this.f_title = f_title;
this.f_text = f_text;
this.fk_value = fk_value;
}
// alt shift s r
public int getF_id() {
return f_id;
}
public void setF_id(int f_id) {
this.f_id = f_id;
}
public int getF_fk_code() {
return f_fk_code;
}
public void setF_fk_code(int f_fk_code) {
this.f_fk_code = f_fk_code;
}
public int getF_fc_code() {
return f_fc_code;
}
public void setF_fc_code(int f_fc_code) {
this.f_fc_code = f_fc_code;
}
public String getF_title() {
return f_title;
}
public void setF_title(String f_title) {
this.f_title = f_title;
}
public String getF_text() {
return f_text;
}
public void setF_text(String f_text) {
this.f_text = f_text;
}
public int getF_use() {
return f_use;
}
public void setF_use(int f_use) {
this.f_use = f_use;
}
public Date getF_regdate() {
return f_regdate;
}
public void setF_regdate(Date f_regdate) {
this.f_regdate = f_regdate;
}
public String getFk_value() {
return fk_value;
}
public void setFk_value(String fk_value) {
this.fk_value = fk_value;
}
public int getF_readcnt() {
return f_readcnt;
}
public void setF_readcnt(int f_readcnt) {
this.f_readcnt = f_readcnt;
}
// alt shift s s
@Override
public String toString() {
return "Faq [f_id=" + f_id + ", f_fc_code=" + f_fc_code + ", f_fk_code=" + f_fk_code + ", f_title=" + f_title
+ ", f_text=" + f_text + ", f_use=" + f_use + ", f_regdate=" + f_regdate + ", f_readcnt=" + f_readcnt
+ ", fc_value=" + fc_value + ", fk_value=" + fk_value + "]";
}
}
주고받을 데이터의 구조 설정(JSON)
데이터를 저장하는 설정이 끝났으니, 이젠 서버에서 웹 브라우저로 데이터가 넘어갈 때의 구조만 간단히 잡아보겠다.
이 구조를 잡아야 DB에서 데이터 유무에 따른 처리를 하기 편하다.
1. 대분류 코드에 따른 중분류 데이터와 FAQ 데이터가 존재하는 경우
{
"fc_code" : 1,
"fc_value" : "회원",
"fks" :
[ {"fk_code" : 1, "fk_value" : "회원가입/탈퇴"},
{"fk_code" : 2, "fk_value" : "본인성인인증"}
],
"faqs" :
[
{"fk_code" : 1, "fk_value" : "회원가입/탈퇴", "f_id" : 1, "f_title" : "제목", "f_text" : "내용"},
{"fk_code" : 1, "fk_value" : "회원가입/탈퇴", "f_id" : 2, "f_title" : "제목2", "f_text" : "내용2"},
{"fk_code" : 2, "fk_value" : "본인성인인증", "f_id" : 3, "f_title" : "제목3", "f_text" : "내용3"}
]
}
2. 대분류 코드에 따른 중분류 데이터는 존재하되 FAQ 데이터는 없는 경우
{
"fc_code" : 1,
"fc_value" : "회원",
"fks" :
[ {"fk_code" : 1, "fk_value" : "회원가입/탈퇴"},
{"fk_code" : 2, "fk_value" : "본인성인인증"}
],
"faqs" : "no-faqs"
}
3. 대분류에서 'Best 10' 을 클릭한 경우(중분류 데이터는 없지만 FAQ 데이터는 존재하는 경우)
{
"fc_code" : 0
"fc_value" : "Best10",
"fks" : "no-fks",
"faqs" :
[
{"fk_code" : 1, "fk_value" : "회원가입/탈퇴", "f_id" : 1, "f_title" : "제목", "f_text" : "내용"},
{"fk_code" : 1, "fk_value" : "회원가입/탈퇴", "f_id" : 2, "f_title" : "제목2", "f_text" : "내용2"},
{"fk_code" : 2, "fk_value" : "본인성인인증", "f_id" : 3, "f_title" : "제목3", "f_text" : "내용3"}
]
}
4. 중분류 코드를 클릭한 경우(중분류 코드에 따라 FAQ 데이터를 가져오는 경우)
{
"faqs" :
[
{"fk_code" : 1, "fk_value" : "회원가입/탈퇴", "f_id" : 1, "f_title" : "제목", "f_text" : "내용"},
{"fk_code" : 1, "fk_value" : "회원가입/탈퇴", "f_id" : 2, "f_title" : "제목2", "f_text" : "내용2"},
{"fk_code" : 2, "fk_value" : "본인성인인증", "f_id" : 3, "f_title" : "제목3", "f_text" : "내용3"}
]
}
2개의 포스팅을 거쳐 고객센터 페이지 구현의 설정이 끝났다.
다음 시간부턴 본격적인 내부 코드를 기록해 보겠다.