해당 페이지에선 MySQL
의 주요 기능별로 기록한다.
MySQL
문을 작성하면서 DBeaver
라는 데이터베이스 관리도구를 이용해 편리하게 관리했다. 해당 페이지에서 나오는 이미지들은 DBeaver
라는 관리도구의 모습이다.
회원가입에 대한 SQL문을 작성하기 전에 알맞은 column
과 함께 사용자 계정 관리 테이블을 생성해준다. 해당 프로젝트의 사용자 계정 관리 테이블은 다음과 같이 생성했다.
다음은 회원가입에 대한 MySQL
전체코드이다.
// index.js
app.post('/join', (request, response) => {
const { id, password, nickname } = request.body
connection.query(
`select * from user where user_id='${id}'`,
(error, results) => {
if (results.length >= 1) {
response.status(403).json({
code: 1,
message: '중복된 아이디'
})
return
}
connection.query(
`SELECT * FROM user WHERE nickname='${nickname}'`,
(error, results) => {
if (results.length >= 1) {
response.status(403).json({
code: 2,
message: '중복된 닉네임'
})
return
}
connection.query(
`INSERT INTO user (user_id, password, nickname)
VALUES ("${id}", SHA2("${password}", 512), "${nickname}")`,
(error, results) => {
if (error) {
console.log(error)
response.status(403).json({
message: '서비스 처리 불가'
})
return
}
response.status(200).json(results)
})
}
)
}
)
})
회원가입을 함에 있어서 SELECT
를 이용해 중복된 아이디가 있는지, 중복된 닉네임이 있는지부터 확인을 하고 없다면 INSERT
를 이용해 회원가입 테이블에 id
, password
, nickname
을 삽입해주는 방식이다.
다음은 클라이언트에서 axios
를 이용해 백엔드와 연동하기 위한 코드이다.
// src/view/JoinMemberShip/index.js
const [profile, setProfile] = useState({
id: '',
password: '',
repassword: '',
nickname: ''
})
const onJoinMembershipClick = useCallback(() => {
axios.post('http://localhost:65100/join', profile)
.then(() => {
alert("회원가입이 완료되었습니다.")
history.push('/')
})
.catch((error) => {
const { code } = error.response.data
if (code === 1){
setCode(code)
}
if (code === 2){
setCode(code)
}
})
}, [profile])
먼저, 클라이언트에서 axios
를 이용해서 /join
이라는 주소에 profile
변수를 보내고, 백엔드에선 request.body
를 통해 각 변수를 구조분해 할당으로 받는다. 그 후에 다음과 같은 SELECT
문으로 id
가 중복된 데이터를 반환해준다.
connection.query(
`SELECT * FROM user WHERE nickname='${nickname}'`,
(error, results) => {
if (results.length >= 1) {
response.status(403).json({
code: 2,
message: '중복된 닉네임'
})
return
}
}
)
SELECT
를 통해 중복된 아이디와 닉네임이 없다면 테이블에 데이터를 INSERT
를 이용해 삽입해준다.
connection.query(
`INSERT INTO user (user_id, password, nickname)
VALUES ("${id}", SHA2("${password}", 512), "${nickname}")`,
(error, results) => {
if (error) {
console.log(error)
response.status(403).json({
message: '서비스 처리 불가'
})
return
}
response.status(200).json(results)
})
패스워드에 대해 해시저장을 다음과 같이 해줌으로써 비밀번호에 대해 암호화해준다.
SHA512
으로 암호화해줘야 한다.SHA2("${password}", 512)
회원가입할 때 사용자 계정 관리 테이블을 생성했는데, 이때 사용자가 입력한 계정 정보를 조회해주면 되기 때문에 별도의 테이블은 생성하지 않았다.
다음은 로그인에 대한 MySQL
의 전체코드이다.
// index.js
app.post('/auth', (request, response) => {
const { id, password } = request.body
console.log(request.body)
connection.query(`SELECT * FROM user WHERE user_id="${id}" and password=SHA2("${password}", 512)`,
(error, results) => {
if (error) {
response.status(500).json({
message: '서비스 처리 불가'
})
return
}
if (results <= 0){
response.status(403).json({
code: 4,
message: '아이디를 다시 확인해주세요.'
})
return
}
response.status(200).json(results[0])
})
})
사용자 계정 정보를 SELECT
를 이용해 조회하면서 알맞은 아이디와 비밀번호를 입력했다면 로그인이 되고 그 결과를 클라이언트에 보내주는 형식이다.
다음은 클라이언트에서 axios
를 이용해 백엔드와 연동하기 위한 코드이다.
// src/view/Home/index.js
const onLoginClick = useCallback(async () => {
await axios.post('http://localhost:65100/auth', profile).then((response) => {
alert('로그인을 성공하셨습니다.')
setGlobalCookie(`${response.data.id}`, `${response.data.nickname}`)
goGameStart()
}).catch((error) => {
const {code, message} = error.response.data
if(code === 3) {
setCode(code)
}
if(code === 4) {
setCode(code)
}
})
}, [profile])
사용자가 게임에 입장하면서 게임기록 등에 대한 데이터를 보관하기 위해 게임 기록 관리 테이블을 생성했어야 했다. 해당 프로젝트의 게임 기록 관리 테이블은 다음과 같이 생성했다.
다음은 게임티켓 발행에 대한 MySQL
의 전체코드이다.
// index.js
app.post('/ticket', (request, response) => {
const { id, nickname } = request.body
connection.query(
`INSERT INTO
game_round (user_id, user_nickname)
VALUES ("${id}", "${nickname}")
`,
(error, results) => {
if (error) {
response.status(500).json({
message: error
})
return
}
response.status(200).json(results)
})
})
게임에 입장하면 (해당 프로젝트에선 게임 버튼을 클릭했을 때) 티켓을 발행해주는 것이기 때문에 게임에 입장할 때 클라이언트에서 요청을 보내준다.
// src/view/Home/index.js
const onGameStartButtonClick = useCallback(() => {
axios.post('http://localhost:65100/ticket', {id: cookies.data.id, nickname: cookies.data.nickname})
setLevelOfDifficult(inputStatus)
}, [inputStatus])
게임 기록 관리 테이블을 생성했는데, 해당 테이블에 게임종료 시간, 정답 등의 데이터를 삽입해줌으로써 게임기록확인시에 사용자가 얼마나 게임을 진행했는지 알수 있도록 했다.
다음은 게임티켓 업데이트에 대한 MySQL
의 전체코드이다.
app.post('/gameEnd', (request, response) => {
const { id, scoreSum, answer } = request.body
connection.query(
`UPDATE
game_round
SET
termniated_at = NOW(),
score = ${scoreSum},
answer = ${answer}
WHERE 1 = 1
AND user_id = ${id}
ORDER BY created_at DESC
LIMIT 1
`,
(error, results) => {
if (error) {
response.status(500).json({
message: error
})
return
}
response.status(200).json(results)
})
})
사용자가 정답을 맞췄을 때 게임티켓을 업데이트 해줘야 하기 때문에 정답을 맞췄을때 클라이언트에서 요청을 다음과 같이 보내준다.
// src/view/Game/index.js
useEffect(() => {
if (strike === level) {
axios.post('http://localhost:65100/gameEnd', {
id: cookies.data?.id,
scoreSum: scoreSum,
answer: answer,
})
alert("정답입니다!!!")
history.push({
pathname: '/End',
state: {
answer: answer,
scoreSum: scoreSum,
},
nickname: cookies.data?.nickname
})
}
}, [life])
해당게임의 정답과 사용자가 정답을 시도했던 기록들 그리고 그 시도에 따른 결과들을 데이터베이스에서 관리해줌으로써 사용자가 게임을 끝냈을때 볼수 있도록하였다. 때문에 테이블을 생성해주었다.
다음은 게임 히스토리에 대한 MySQL
의 전체코드이다.
// index.js
app.post('/game', (request, response) => {
const { id, answer, guess } = request.body;
const getScore = (guess, answer) => {
let strike = 0, ball = 0, out = 0
for (let answerIndex = 0; answerIndex < answer.length; answerIndex++) {
if (answer[answerIndex] === guess[answerIndex]) {
strike += 1
}
else if (guess.includes(answer[answerIndex])) {
ball += 1
}
else {
out += 1
}
}
return { strike, ball, out }
}
const { strike, ball, out } = getScore(guess, answer)
connection.query(
`
SELECT
id FROM game_round
WHERE user_id="${id}"
ORDER BY created_at DESC LIMIT 1
`,
(error, result) => {
if (error) {
console.log(error)
return
}
connection.query(
`INSERT INTO game_history (gameticket_id, user_id, guess, strike, ball, out_count)
VALUES ('${result[0].id}', '${id}', '${guess}', '${strike}', '${ball}', '${out}')`,
(error, result) => {
if(error) {
console.log(error)
return
}
}
)
}
)
})
사용자가 정답을 시도할때마다 게임히스토리 테이블에 데이터가 저장될거기 때문에 UserPanel
컴포넌트에서 요청을 보내준다.
// src/view/Game/UserPanel/index.js
if (checkIfDuplicateValue && checkIsProperLengthValue) {
axios.post('http://localhost:65100/game', {
id: cookies.data?.id,
guess: guess,
answer: answer,
})
}
백엔드에서도 strike
, ball
, out
의 값을 다루는 getScore
함수를 가지고 있으면서 return
된 값들을 게임 히스토리 테이블에 INSERT
를 해주면된다.
게임점수에 따라 사용자의 닉네임을 나열해서 저장하고, 또한 상위 10명에 대해 명예의 전당에 올리기도 해주기 때문에 명예의전당 테이블을 생성해 관리해 주었다.
다음은 명예의 전당에 대한 MySQL
의 전체코드이다.
app.post('/rank', (request, response) => {
connection.query(
`SELECT distinct user_nickname, score
FROM game_round
WHERE 1 = 1
and score = score ORDER BY score DESC`,
(error, results) => {
if (error) {
response.status(500).json({
message: '서비스 처리 불가'
})
return
}
response.status(200).json(results)
}
)
})
distinct
를 이용해서 중복된 값들을 제외하고 단일의 데이터만을 조회했다.
명예의 전당은 게임이 종료된 후 /End
페이지가 렌더링 되면서 클라이언트가 요청해서 그 명단을 페이지에 보여줘야하기떄문에 useEffect
로 요청해준다.
// src/view/End/index.js
useEffect(() => {
axios.post('http://localhost:65100/rank')
.then((response) => {
setScoreArray(response.data)
})
}, [])
사용자가 게임을 어떻게 플레이 하였는지 게임시간을 얼마나 진행했는지 데이터를 뿌려주기 위해 게임을 진행하면서 기록했던 테이블을 이용했다.
다음은 게임히스토리 데이터 조회에 대한 MySQL
의 전체 코드이다.
// index.js
app.post('/gameHistory', (request, response) => {
const { id } = request.body;
connection.query(
`SELECT
id FROM game_round
WHERE user_id="${id}"
ORDER BY created_at DESC LIMIT 1`,
(error, result) => {
if(error) {
console.log(error)
return
}
connection.query(
`
SELECT guess, strike, ball FROM game_history
WHERE 1 = 1
AND gameticket_id = "${result[0].id}"
ORDER BY id ASC
`,
(error, result) => {
if(error) {
console.log(error)
return
}
response.status(200).json(result)
}
)
}
)
})
app.post('/playTime', (request, response) => {
const { id } = request.body;
connection.query(
`SELECT RUN_TIME FROM (SELECT *, TIME_TO_SEC(TIMEDIFF(termniated_at, created_at)) AS RUN_TIME
FROM game_round) AS GAME_TICKET_WITH_RUN_TIME WHERE 1 = 1 AND user_id = "${id}" ORDER BY created_at DESC LIMIT 1`,
(error, result) => {
if (error) {
console.log(error)
return
}
response.status(200).json(result)
}
)
})
다음과 같이 클라이언트에서 요청했다
// src/view/End/index.js
useEffect(() => {
axios.post('http://localhost:65100/gameHistory', {id: cookies.data.id})
.then((response) => {
setHistoryArray(response.data)
})
}, [])
useEffect(() => {
axios.post('http://localhost:65100/playTime', {id: cookies.data.id})
.then((response) => {
setplayTime(response.data[0].RUN_TIME)
})
}, [])