⌦ 목표 개수 설정 페이지
☑︎ 운동의 종류를 선택하는 기능
- HTML
<input class="select squat" rel="squat" type="button" value="스쿼트
squat">
<input class="select lunge" rel="lunge" type="button" value="런지
lunge">
<input class="select plank" rel="pushUp" type="button" value="팔굽혀펴기
push up">
- CSS
body > .main > .form > .select-container > .select:hover,
body > .main > .form > .select-container > .select:focus,
body > .main > .form > .select-container > .select.selected {
background-color: rgb(30, 28, 28);
color: rgb(255, 255, 255);
font-weight: 500;
border: 0.2rem solid rgb(30, 28, 28);
}
- javaScript
const form = document.getElementById('form');
form.querySelectorAll('input.select').forEach(select => {
select.addEventListener('click', () => {
form.querySelectorAll('input.select').forEach(x => x.classList.remove('selected'));
select.classList.add('selected');
});
});
운동의 종류를 선택하면 input 태그 중 class = "select" 인 요소에 selected 라는 class 를 추가한다.
CSS 에 .select.selected 를 검정배경으로 설정하면, 운동의 종류를 선택했을 때 검정 배경으로 선택되었음을 표시할 수 있다.
중복선택이 불가능하게 하기 위해 , 클릭 시 forEach(x => x.classList.remove('selected')); 로 selected 클래스를 지우고 시작한다.
• 운동의 종류를 선택하지 않고 start 했을 때 "선택하세요!" 라는 알림이 뜬다.
- JavaScript
if (!squat.classList.contains("selected") && !lunge.classList.contains("selected") && !pushUp.classList.contains("selected")) {
form.querySelector('[rel="selectWarning"]').classList.add('visible');
return false;
}
body > .main > .form > .select-container > .warning {
display: none;
}
body > .main > .form > .select-container > .warning.visible {
display: block;
}
뭐라도 선택하면 class에 selected 가 추가되기 때문에 어디에도 selected class 가 없으면 아무 것도 선택되지 않은 것이다.
그래서 아무 것도 선택되지 않았을 때를 조건으로 걸고,
알림 말풍선의 class 에 visible 을 추가하여 display : none; 이었던 걸 display: block; 으로 바꾼다.
☑︎ 운동의 개수를 설정하는 기능
- Controller
@RequestMapping(value = "setting",
method = RequestMethod.GET)
public ModelAndView getSetting(@SessionAttribute(value = "user", required = false) UserEntity user) {
ModelAndView modelAndView;
if (user == null) {
modelAndView = new ModelAndView("redirect:/dios/login");
} else {
modelAndView = new ModelAndView("records/setting");
}
return modelAndView;
}
@RequestMapping(value = "setting",
method = RequestMethod.PATCH,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public String patchSetting(@SessionAttribute(value = "user", required = false) UserEntity user,
@RequestParam(value = "goalCount", required = false) Integer count) {
Enum<?> result = this.recordService.updateGoalCount(user, count);
JSONObject responseObject = new JSONObject();
responseObject.put("result", result.name().toLowerCase());
return responseObject.toString();
}
목표 개수 설정 페이지는 회원만 들어갈 수 있다. 그래서 @SessionAttribute로 user 를 받아와서 회원인지 확인해야 한다.
만약 user == null 이라면 페이지에 들어올 수 없고 login 페이지로 이동하도록 했다.
유저의 로그인 정보와 목표 개수를 매개변수로 받아온다.
✔️ @RequestParam
: @RequestParam 은 GET 요청 파라미터 전송 방식, HTML Form 전송 방식을 사용할 때에 조회할 수 있는 방법 중 하나이다.
(GET 방식은 요청 시 데이터를 message body에 담지 않고, query string(쿼리 스트링)에 담아서 전달하는 방법이다.)
여기서 목표 개수는 HTML Form 전송방식을 사용했기 때문에 RequestParam을 사용하여 value = "goalCount", required = false 로전달해 주었다. required = false 를 해주면 파라미터의 값이 전달되지 않는다면 null 값이 들어간다. 자료형 int 는 null 값을 담을 수 없기 때문에, Integer을 사용했다. 자바스크립트로 목표 개수를 입력하지 않았을 때 경고창이 뜨며 다음 화면으로 넘어갈 수 없게 하긴 했지만 required = false 도 사용했다.
recordService 의 updateGoalCount return 결과를 result에 담아 JSONObject에 lower case로 담는다.
✔️ JSON
: JSON 은 "키-값" 쌍으로 이루어진 데이터 오브젝트를 전달하기 위해 인간이 읽을 수 있는 텍스트를 사용하는 개방형 표준 포맷이다. 비동기 브라우저/서버 통신을 위해, 넓게는 xml을 대체하는 주요 대이터 포맷이다.
service의 updateGoalCount 의 return 값을 값으로, "result" 를 키로 넣기 위해 JSONObject 타입의 responseObject 변수를 만든다. responseObject.put("result", result.name().toLowerCase()); 의 형태로 키와 값 쌍을 변수에 넣어준다.
toString()은 JSONObject가 갖고 있는 데이터를 JSON 형식으로 출력한다.
- Service
public Enum<? extends IResult> updateGoalCount (UserEntity user, int count) {
UserEntity existingUser = this.memberMapper.selectUserByEmail(user.getEmail());
existingUser.setGoalCount(count);
return this.recordMapper.updateCount(existingUser) > 0
? CommonResult.SUCCESS
: CommonResult.FAILURE;
}
selectUserByEmail 은 user table 의 email 을 기준으로 select 하는 Mapper 이다. 이를 existingUser 변수에 담아 준 다음, existingUser 가 가진 goal_count 를 controller 의 매개변수로 받아온 count 로 set 해준다. 이 과정이 완료되었다면 SUCCESS 를 반환하고, 실패하면 FAILURE 를 반환하도록 했다.
- Mapper, xml
UserEntity selectUserByEmail(@Param(value = "email") String email);
int updateCount(UserEntity user);
<select id="selectUserByEmail"
resultType="com.blackgreen.dios.entities.member.UserEntity">
SELECT `email` AS `email`,
`goal_count` AS `goalCount`
FROM `dios_member`.`users`
WHERE BINARY `email` = #{email}
LIMIT 1
</select>
<update id="updateCount"
parameterType="com.blackgreen.dios.entities.member.UserEntity">
UPDATE `dios_member`.`users`
SET `goal_count` = #{goalCount}
WHERE BINARY `email` = #{email}
LIMIT 1;
</update>
user table 에는 goal_count column 이 default 0 으로 만들어져 있다. 회원가입할 때는 insert 되는 값이 없지만, 목표 개수 설정을 위해 만들어진 열이다.
목표 개수 설정 페이지에 들어있는 session인 사용자 email 을 기준으로 한 row를 select 해 주는 쿼리를 만들었다.
그리고 그 row의 goal_count 값을 목표 개수 설정 페이지 controller에서 받아 온 goalCount 로 update 해 주는 쿼리를 만들었다. email column 은 pk 이기 때문에 WHERE 조건으로 선택했다.
새로운 운동을 선택했을 때도 목표 개수를 변경할 수 있고, 운동을 하다가도 목표 개수를 변경할 수 있도록 만들기 위해 목표 개수를 insert 로 디비에 넣지 않고, update 로 넣도록 쿼리를 짰다.
- javaScript
form['submit'].addEventListener('click', () => {
const xhr = new XMLHttpRequest();
const formData = new FormData();
formData.append('goalCount', form['setting'].value);
xhr.open('PATCH', './setting');
xhr.onreadystatechange = () => {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status >= 200 && xhr.status < 300) {
const responseObject = JSON.parse(xhr.responseText);
switch (responseObject['result']) {
case 'success':
if (squat.classList.contains("selected")) {
window.location.href = 'squat';
} else if (lunge.classList.contains("selected")) {
window.location.href = 'lunge';
} else if (pushUp.classList.contains("selected")) {
window.location.href = 'pushUp';
}
break;
default:
alert('실패');
}
} else {
alert('알 수 없는 이유로 서버와 통신하지 못했습니다. 다시 시도해 주세요.');
}
}
}
xhr.send(formData);
});
start 버튼을 눌렀을 때, FormData 를 이용해서 'goalCount' (프론트에서 입력받은 값)를 받아온다.
✔️ formData.append(name, value) 함수를 이용해 데이터를 넣을시에 value는 문자열로만 입력 된다. 만일 문자열 이외의 데이터 타이을 넣으면 무시되고 문자열로 자동 변환 된다.
이렇게 보내진 걸 볼 수 있다.
✔️ XMLHttpRequest
: XMLHttpRequest 객체는 서버로부터 XML 데이터를 전송받아 처리하는 데 사용된다. 이 객체를 사용하면 웹 페이지가 전부 로딩된 후에도 서버에 데이터를 요청하거나 서버로부터 데이터를 전송받을 수 있다. 즉, 웹 페이지 전체를 다시 로딩하지 않고 일부분만을 갱신할 수 있게 된다.
✔️ readyState
: readyState 프로퍼티는 XMLHttpRequest 객체의 현재 상태를 나타낸다. 이 프로퍼티의 값은 객체의 현재 상태에 따라 다음과 같은 주기로 변화한다.
1. UNSENT (숫자 0) : XMLHttpRequest 객체 생성
2. OPENED (숫자 1) : open() 메소드 성공적 실행
3. HEADERS_RECEIVED (숫자 2) : 모든 요청에 대한 응답 도착
4. LOADING (숫자 3) : 요청한 데이터를 처리 중
5. DONE (숫자 4) : 요청한 데이터의 처리가 완료되어 응답할 준비 완료
✔️ status
: status 프로퍼티는 서버로부터 응답 받은 상태 및 리턴 메세지를 확인한다.
1. 200 ~ 201 : 요청이 성공적 상태
2. 그 외 상태 : 요청 실패
✔️ xhr.open
: 서버로 보낼 Ajax 요청의 형식을 설정
✔️ xhr.send
: Ajax 요청을 서버로 전달
controller 의 patchSetting 의 반환값이 "success" 면 디비 값이 입력한 목표 개수로 잘 update 되었다는 뜻이므로 selected 가 포함된 운동 화면으로 넘어가게 했다.
db 에 입력한 목표 개수가 잘 들어갔기 때문에, start 를 눌렀을 때 넘어가는 운동 화면에서 목표 개수가 잘 출력된다.
• 마찬가지로 운동의 개수를 설정하지 않고 start 했을 때는 "입력하세요!" 라는 알림이 뜬다.
'웹개발 > DIOS' 카테고리의 다른 글
[웹개발 - DIOS] 주문 페이지 (0) | 2023.02.25 |
---|---|
[웹개발 - DIOS] 장바구니 페이지 (2) (0) | 2023.02.25 |
[웹개발 - DIOS] 장바구니 페이지 (1) (0) | 2023.02.24 |
[웹개발 - DIOS] 기록장 페이지 (0) | 2023.02.23 |
[웹개발 - DIOS] Teachable Machine 를 이용한 운동 횟수 세는 페이지 / Teachable Machine / 티처블머신 / 머신러닝 (0) | 2023.02.23 |