(24.12.04)
1. 한글 인코딩 문제로 인해 발생한 MySQL 다운로드 문제
[문제 상황]
MySQL을 설치하는 과정 중 계속 같은 단계에서 오류가 발생했다.
처음에는 버전 문제인가 싶었지만, 버전과 관계 없이 모종의 이유로 설치가 막혔다.
문제 화면을 캡쳐해두지는 못했지만 아래 빨간 박스로 표시해둔 단계를 넘어가지 못했다.
무엇이 문제인가 싶어서 튜터님과 함께 로그기록을 살펴보니 대략 어떤 파일을 찾을 수 없다는 문구가 나와있었다.
[해결 시도]
그 뒤로는 관리자 권한으로 설치 시도도 해보았고,
또 파일 설치 위치가 ProgramData로 되어있었는데, ProgramData는 숨겨진 파일이라 찾을 수 없다고 하는건가 싶어서 Program Files로 설치 경로를 바꿔보기도 했다.
하지만 무슨 짓을 해도 모두 같은 곳에서 실패! 로그 기록 역시 처음 문제 상태 그대로였다. (왜 계속 못 찾는거니...)🥹🥹🥹
[해결]
캡쳐는 못했지만.. 여튼 찾으려는 파일 경로에 이런 문자가 있었다. '/꿻뛜ㅎRO..' (대충 이런 느낌)
문득, 저렇게 글자가 깨지는 상태를 한글 인코딩 문제 때 봤던게 생각이 났다.
그리고 C 드라이브 파일 경로에는 한글이 없었지만, 내가 컴퓨터 이름을 '임Pro스터'라고 한글로 지어둔게 생각이 났고,
로그에 있던 영문 RO가 내 추측에 약간의 확신을 더해주었다. (Pro에서 RO만 남은거니..? 그것도 대문자로..?)
튜터님께서도 가능성이 있다고 하셔서, 설정에 들어가서 컴퓨터 이름을 영문으로 싹 변경해주었다.
그리고 다시 설치를 시도했더니... 된다!!!
결론적으로 설치 경로에 한글이 섞여들어간게 문제였던 것.
원래도 파일 경로에 한글이 있으면 오류가 생길 수 있다는 걸 알고는 있었지만,
설마 컴퓨터 이름이 영향을 줄거라고는 상상도 못했다...
+) 가슴 속에 새겨두자 파일 경로에는 한글 금지.
(1시간 넘게 문제 고민하고 해결해주신 튜터님 정말 감사합니다😭)
(24.12.06)
2. 예약어를 사용하지 않도록 주의하자
실제로 문제가 발생하지는 않았지만, 앞으로 문제가 될 수 있기에 알아두려한다.
인텔리제이에서 패키지를 만들 때 'scheduler'라는 이름을 사용했었다.
그랬더니 패키지 아이콘이 평소와는 다르게 번개 모양이 붙은채로 나왔다.
처음에는 별다른 생각 없이 넘어갔는데, 오늘 같은 팀원분께서 예약어에 대한 이야기를 해주셨다.
'scheduler'와 'user' 사용에 주의하라는 것.
특히 'user'의 경우 Jdbc에서는 괜찮았을지 몰라도 JPA에서는 오류가 생길 수 있다며 혹시라도 쿼리문에 'user'를 사용했을 경우 user를 대신해서 customer, consumer, member 등을 사용하는 것이 좋다고 하셨다.
찾아보니까 'user'는 H2의 예약어라고 한다.
나는 MySQL을 사용해서 괜찮지 않을까 싶기는 했지만.. 그래도 불안하니까 그냥 member로 싹 변경해주었다.
그리고 패키지명도 그냥 'schedules'로 변경해주었다. (불씨는 남겨두지말자)
예약어 참고:
https://zetawiki.com/wiki/MySQL_%EC%98%88%EC%95%BD%EC%96%B4
3. DB 연결 오류 문제
[문제 상황]
일정을 DB에 저장하는 POST API를 열심히 만들고 PostMan에서 실행 시켰는데, 500 Internal Server Error가 떴다.
일단 서버쪽 문제라서 혹시 코드가 잘못된 곳은 없나 자세히 살펴봤는데, 코드 자체의 문제는 아닌 것 같았다.
스스로 해결하기 어려운 문제라고 판단하고 곧장 튜터님께로 달려갔다.
튜터님과 함께 로그 기록을 살펴 보니 DB로 데이터를 넘기는 과정에서 'member_id'라는 애트리뷰트를 찾을 수 없다고 한다. 근데, 내 테이블에는 'member_id'라는 애트리뷰트가 없다.. (소름)
'member_id'는 내가 다른 프로젝트에서 만든 테이블에서 사용하던 애트리뷰트다.
근데 이게 왜 갑자기 엉뚱한 프로젝트에 나타나서 오류를 일으키는가..
[해결 시도]
일단, 코드 내부에서 테이블을 잘못 가리키고 있는 것은 아니다.
URL이 잘못 됐다거나 DB 연결이 잘못된 것도 아니다!
DB에 직접 접속해 살펴보니 스키마도 제대로 나눠져있다.
schedule이 현재 프로젝트에서 사용하는 스키마, schedulers가 문제의 'member_id' 애트리뷰트를 포함하는 스키마다.
어떤 컬럼을 사용할지 .usingColums( )를 사용해 직접 지정해줬더니 갑자기 잘 된다!..😦
왜 이럴까? 튜터님의 도움을 받으며 로그를 더 살펴보았다.
그러다 알게된 사실은 JDBC가 어째서인지 내가 연결해둔 DB가 아닌 다른 프로젝트의 DB를 참조하고 있는 것...
schedulers는 다른 프로젝트의 DB다. 그리고 schedulers역시 'schedule'이라는 테이블을 가진다.
그리고 schedulers의 'schedule' 테이블에는 'member_id'가 있다.
결론적으로,
JDBC가 내가 지정해준 scheduler의 'schedule'테이블을 가리키는게 아니라
엉뚱한 schedulers의 'schedule' 테이블을 가리키고 있던 것...
[해결]
왜 저런 일이 발생했는지 근본적인 원인은 알 수 없었다.
하지만 schedulers의 'schedule' 테이블을 삭제함으로써 문제를 해결할 수 있었다.
+) cmd에서 MySQL을 실행하는 명령어 'mysql -u root -p'를 배웠다.
(24.12.09)
4. 날짜 출력 형식 문제
[문제 상황]
Id를 사용해 일정을 조회하는 API를 완성한 후, 잘 동작하는지 확인을 위해 PostMan을 돌렸다.
작동은 잘 되는데 어째서인지 날짜 출력 형식이 이상하다.
341은 뭐고, 시간은 왜 24시간 단위가 아닐까?..
[해결 시도]
일단 데이터베이스에 문제는 없는지 확인부터 해보았다.
다행히 DB에는 날짜가 정확한 형식으로 저장되어있었다.
오늘도 튜터님의 도움을 받아 디버깅을 해보았다.
일단 DB에 저장되어있던 날짜를 ZonedDateTime 형식으로 변환하는 과정에서 문제가 있었던 것은 아닐까싶어서
의심이 되는 코드를 표시하고 디버깅을 했다.
일단 ZonedDateTime 형식으로 변환하는 과정에는 문제가 없어보인다.
이 외에도 날짜를 리턴 받는 모든 곳을 살펴본 후,
날짜 데이터를 JSON 형식으로 변환하는 과정에서 '날짜 형식 지정에 문제가 있다'라는 결론에 도달했다.
[해결]
일단 Schedule 클래스에서의 날짜 형식 지정은 문제가 없었다.
하지만 ScheduleResponseDto의 날짜 형식 지정에 문제가 있었다.
사건의 전말은 이렇다.
자바에서 날짜를 어떤 타입으로 받아야하는지 몰랐던 나는 검색을 통해 ZonedDateTime 타입을 사용하면 된다는 것을 배웠다. 그리고 날짜를 원하는 JSON 형식으로 설정하기 위해서는 @JsonFormat을 사용해야한다는 것을 알았는데,
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 이 pattern에 대소문자가 섞여있는게 마음에 들지 않았던 것.
그래서 뭣도 모르고 '연-월-일'은 대문자로, '시:분:초'는 소문자로 통일시켜버린게 문제가 됐던 것이다... 🥹
자바 공식 문서 'Class DateTimeFormatter'를 살펴보자.
살짝 아래로 내려서 'Patterns for Formatting and Parsing' 쪽을 살펴보면 이렇게 쓰여져있다.
'All letters 'A' to 'Z' and 'a' to 'z' are reserved as pattern letters.'
간단히 말해서 모든 알파벳은 패턴 문자로 예약되어있다는 뜻이다.
문자 'D'와 'h'에 대한 설명을 보니 숫자 341과, 시간이 24시간 단위가 아니었던 이유에 대한 의문이 풀렸다.
'D'는 특정 일자가 일년 중 몇 번째 날인지를 알려준다.
그래서 12월 06일은 1년(365일) 중 341번째 날이라는 의미로 341이 출력된 것이다.
'h'는 1부터 12까지의 시(hour)를 나타내며, 시간을 12시간 단위로 표시한다.
그래서 시간도 20시가 아닌 08시가 출력된 것이다.
문제의 원인을 바로 알고 난 후 @JsonFormat의 pattern을 수정하였다.
그리고 PostMan으로 다시 요청을 보내보면,
드디어 날짜가 정상적인 형식으로 출력된다..!!!!👏🏻
+) 비록 내 실수로 인해 발생한 문제였지만, 그래도 덕분에 문자에 예약어가 지정되어있다는 것도 새로 알게되었고,
어쩌면 실무에서 저지를 지도 모르는 실수가 하나 줄어든 느낌이라 다행이라는 생각도 들었다.
5. JSON > ZonedDateTime 역직렬화 문제
[문제 상황]
'수정일'을 기준으로 일정을 조회하는 API를 작성하고 있었다.
'yyyy-MM-dd' 형식의 날짜에 맞는 일정을 출력해야하기 때문에 쿼리문은 아래와 같이 작성했다.
select * from schedule where updated_date like ?%
수정일 검색을 위해 '?' 안에는 문자열이 들어가야한다고 생각했다.
그래서 원래 ZonedDateTime 타입인 updatedDate를 메서드를 사용해 String으로 포맷하려고 했다.
그후 PostMan으로 요청을 보냈더니 400 Bad Request가 떴다.
여기서 일단 요청 형식이 잘못됐다는 것을 알 수 있다.
또 다음과 같이 역직렬화가 안 된다는 에러 메세지도 확인할 수 있었다.
[해결 시도]
무슨 문제가 있는지는 알았는데, 어디서 이런 문제가 생기는지는 알 수가 없어서 튜터님께 여쭤보았다.
알고보니 ZonedDateTime 타입은 time zone에 대한 정보를 내포하고 있기 때문에 'yyyy-MM-dd' 형식으로는 역직렬화가 불가능했던 것이다.
'Format ZonedDateTime to String' 문서만 대충 보고 내가 원하는 형식의 문자열로 바꿀 수 있줄 알았는데 전혀 아니었다.
[해결]
굳이 찾아보면 ZonedDateTime을 'yyyy-MM-dd'형식의 문자열로 변환하는 방법이 있을 수도 있다고 하셨지만,
나는 'yyyy-MM-dd'형식의 문자열만 있으면 상관 없기 때문에 그냥 updatedDate의 타입을 LocalDate로 바꾸기로 하였다.
(String으로 받아도 상관은 없겠지만 나는 updatedDate가 날짜를 담는 변수인 것을 알리고 싶었다.)
[추가]
Controller에서 @GetMapping을 사용하는 findSchedule()에 @RequestBody를 사용했었는데,
튜터님께서 일반적으로 Get, Delete에는 Body를 사용하지 않는다고 알려주셨다.
또한, Spring에서는 Get에 Body를 사용하는 것을 허용하고 있으나 프론트엔드나 다른 쪽에서 문제가 될 수도 있기 때문에
@RequestParam 혹은 @PathVariable을 사용하는 것이 안전하다고 하셨다.
이에 findSchedule()을 아래와 같이 수정하였다.
6. null 값 처리 문제
[문제 상황]
'조건에 맞는 일정을 조회'하는 API를 작성하던 중 일어난 문제이다.
작성자명을 기준으로 일정을 찾으려고하면 어째서인지 아무런 값도 출력되지 않았다.
하지만 HttpStatus는 200 OK인 상황...
[해결 시도]
일단 로그를 천천히 살펴 보았고, 이상한 점을 발견할 수 있었다.
updatedDate가 null값이면 빨간 박스 안의 SQL문이 실행되도록 조건을 걸어놨는데,
실행 기록을 보니 노란 박스 안의 SQL 문이 실행되고 있었다.
그리고 [null%] 이라는 값도 처음에는 null 값이 저렇게 표시되는 것이라고 생각했는데,
다시 고민해보니 아무래도 String formattedDate=updatedDate+"%"; 가 실행된 결과인 것 같았다.
그렇다면 무엇이 문제인지는 몰라도 'updatedDate는 null이 아닌 어떤 문자열로 인식되고 있는 상태'라는 결론에 도달할 수 있었다.
[해결]
왜 updatedDate가 문자열로 인식되고 있을까? 아무런 값도 입력하지 않은 상태인데?
원인은 내가 updatedDate의 타입을 LocalDate에서 String으로 변환하는 과정에 있었다.
아래 코드와 같이 String.valueOf( )를 사용해서 updatedDate의 타입을 바꿔주었는데,
String.valueOf( )에 null 값이 들어가면 "null" 문자열이 된다는 것을 몰랐던 것이다..
그래서 아래와 같은 코드를 추가해주었다.
String formattedDate = updatedDate != null ? updatedDate.toString() : null;
updatedDate가 null인지 검사한 후, null이 아니면 toString() 메서드를 호출하여 문자열로 변환한다.
만약 updatedDate가 null일 경우, formattedDate는 "null" 문자열이 아닌 null 값이 되도록 하였다.
코드를 수정한 후 정상적으로 동작하는 것을 확인할 수 있었다.
'프로젝트 > 일정 관리 앱 만들기(개인)' 카테고리의 다른 글
[Trouble shooting] JPA를 활용한 일정 관리 앱 만들기 - 트러블 슈팅 (2) | 2024.12.19 |
---|