Spring으로 OP.GG 클론 코딩해보기 -6 (마무리)
안녕하세요. 최근에 학교 개강도 하고 너무 바쁜 덕에 프로젝트 개발에대해서 크게 신경쓰지는 못했네요. 뭐 이번추석을 통해서 확실하게 마무리 지어서 너무 좋습니다.
여러분 이제 이 거대한 프로젝트도 어느정도 완성이 되었네요. 대략적으로 주요기능들은 잘 작동한 것 같아서 디자인이나 다른 요소들은 좀 나쁘더라도 여기까지 하는 걸로 맘을 먹었습니다.
기능 추가등의 일을 더 할 수 있지만, 추가하지않은 이유는 단순하게도 이건 Spring으로 만든 것이라는 생각이 잘 들지 않기 때문입니다. 학교를 다니면서도 꾸준히 부스트코스를 듣고 있는데 Spring 프레임워크를 재대로 사용하지 못했다는 생각이 너무 자주 들었습니다.
심지어는 이걸 다시 Spring으로 리펙토링하는 것은 엄청나게 시간을 들어야하고 수없이 많을 에러를 고칠생각을 하니까...
아무튼간에 아예 다시 처음부터 구상하는게 더 빠를 것 같아서 Spring으로 다시 짜는 걸 연습해보려고 합니다. 이번에는 순수하게 Spring에서 좋은 기능만 잘뽑아서 만들어보고 싶다는 생각도 많이 들구요.
아무튼 이번에는 여러가지 일들을 처리했습니다. 보면서 이야기 해보겠습니다.
이번에 구현했던 것들
- input값에서 띄어쓰기해도 문제없이 작동하게 하기.
- JDBC로 DB짜서 연동시키기.
- JDBC로 SearchLog만들어서 index페이지에 id 띄우고 바로 리다이렉트 해버리는 식으로 하기.
- searchlog만든거 검색창 누르면 튀어나오는 식으로 구성.
- Search로그 만들었을때는 Await나 AJAX를 통해서 바로 비동기 방식으로 처리하기. 단, jquery를 사용해도 좋으니 확인 꼭 해보기. (굳이 비동기식으로 처리 안해도 됨.)> search type 눌렀을때 뜨는 방식 구현하기.
- 5개나 10개단위로 짤라보기?
- versionCheck 만듬. 버전 변경되어도 최신화되어 키로 적용가능.
어떤 식으로 개발했는지에 대해서.
일단 순서대로 만들어보자면, DB연동부터 시작했습니다. (파란색이 구현한 대 주제입니다.)
저가 구현한 앱의 경우 DB를 구현할만한 꺼리를 딱히 생각해내기가 어려워서 가장 간단한 최근검색을 구현해보는게 어떨까라는 생각이 들어 바로 적용해보았습니다.
JDBC를 커넥션풀? namedTemplate등의 스프링에서 제공하는 기능을 사용해서 구현하려고 했는데, 예상보다 오류가 많고 정확하게 어떤식으로 돌아가는지를 파악하지 못해서 그냥 접고 가장 간단한 방식의 SearchLogDao를 만들었습니다.
mysql과 연동되고 거기에 맞는 기능들을 출력하는 식으로 진행했습니다. 만들건 한 두개정도로 DB추가화 DB보기정도가 있어서 둘다 만들어서 연동했습니다.
SearchLog는 결국에는 가장 최근에 검색한 걸 맨처음으로 나와야하니 정렬은 시간순(timestamp)를 통해서 진행했습니다.
그리고 추가는 검색을 한 순간에 그 DTO를 통해서 객체를 만든뒤에 그것과 같은 식의 DB 테이블 폼도 만들었고 그에 맞는 값도 집어넣었습니다.
문제점이 여기서 하나 발생합니다.
원래 Searchlog는 가장 최근에 검색한걸 맨처음으로 나와야하는데 이게 나오지 않는 겁니다. 검색한 순서만 시간순으로 정렬되있을뿐 같은걸 검색하면 전혀 최신화가 되지 않았죠.
에러는 :com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException : Duplicate entry '~~~~' for key 'PRIMARY'
대충 이런식.
왜그런가보면 중복키가 겹치는 경우 이걸 해결해주지 못하는 겁니다. 같은 검색을 하면 같은걸 검색하기때문에 Insert를 못해주는 거죠. 즉, 중복이면 Update를 해줘야하는 것인데요.
시도1
저는 메소드가 몇열을 넣었는지를 int값을 받고 그걸 리턴하기때문에 if문으로 처리하려고 했습니다. 변경되는게 없으면 update를 하는 방식으로 열삽입이 있으면 insert하는 방식을 택했습니다.
결과: 실패 > 중복에러는 예외로 처리되기때문에 리턴값이 재대로 전달이 안됬습니다.
시도2 및 시행착오
어떤식으로 해결해야할지 몰라서 블로그를 찾다보니 중복x시 INSERT 중복시 UPDATE해주는 쿼리문이 있다길래 후다닥 검색해보았죠.
http://jason-heo.github.io/mysql/2014/03/05/manage-dup-key2.html
https://til.songyunseop.com/mysql/some_case_insert_with_duplicated_key.html#on-duplicate-key-update
결론적으로는 ON DUPLICATE KEY UPDATE를 사용했는데 이게 마음처럼 잘 구현이 안됬습니다.
ON DUPLICATE KEY UPDATE searchdate = VALUES(searchdate);";
중복시 뒤에 업데이트 하는게 좀 많이 까다로운 편인데 코드만 적어서 바로 적용은 안됬는데, 제가 알아낸 방식은 이러합니다.
1. 일단 primary key든, unqiue키든 중복이 된순간 update 뒤의 구문이 바뀌게 된다.
2. 쿼리문상으로는 Searchdate가 열이고 values(searchdate) 값이라고 생각했는데 그게 아니라 value안에 들어가야하는 건 column명이다. (이건 제가 SQL문을 정확하게 배우지 않아서 values() 괄호안에 값을 넣어보면서 알아낸 경험적 지식입니다.)
3. 만약 바꿀 것이 시간이 아니라 이름변경이나 뭐 기타등등이라면 여러가지 쿼리를 넣는것도 가능하다. (즉, 이름변경, 시간변경을 같이도 할 수 있다는 것.)
이러면 중복된 아이디를 검색해도 검색시간 순서상 앞에 위치하게 됩니다.
이후에는 SearchLog에 아이디가 나오면 클릭하면 바로 그 아이디를 검색할 수 있게 해주는 코드를 작성해보았습니다. 단순하게 저는 A태그에 이름을 넣으면 될거라고 생각했는데. 이름이 연결이 안되기도 하고 그래서 뭔 방법이 있는가 찾아보니까
A태그에 onclick이벤트를 통해 함수를 물리는 방식을 이용해봤습니다.
http://amikhs.pe.kr/?c=1&uid=533
시행착오들들들..
물론 여기링크에 있던 것과는 좀 다르게 진행했지만
처음에는 뭐 이 태그안의 내용을 받아서 가져오는 방식으로 진행해보려고 했습니다. innerHTML이나 innerText를 써서 그 값을 받아온다음에 이걸 로케이션을 물려볼까 했는데 예상과는 다르게 innerText나 HTML을 쓰기가 너무 까다로워서
function idRedirect(name){
var replace = name.replace( /(\s*)/g, "");
document.location.href="/noxikaGG/search?title="+replace; // 선택한 페이지로
};
와 같은 함수를 만들어주고 아에 함수에 이름을 넣어서 진행해보려했습니다 > 실패
알고보니까 함수에 그냥 이름을 넣으면 > 오류 발생합니다. 즉, 'text'로 넣어서 ""나 ''을 통해서 넣어서 해결을 해야합니다.
그리고 난다음에 또 문제가 발생했는데, input과 같이 그냥 띄어쓰기 되있어도 자동처리해주는게 아닌 이건 띄어쓰기까지 인식을 해버리는 바람에 결과값이 오류가 나는 경우가 발생했습니다. 그래서 name.replace를 통한 띄어쓰기를 다 소거해준다음 넣는 방식을 취했습니다.
searchlog만든거 검색창 누르면 튀어나오는 식으로 구성과 5개씩 짤라서 나오는 방식을 구현.
일단 검색창이 튀어나오는 건 onclick 이벤트를 통해서 처리하는 방식을 택했습니다. 즉, input tag를 눌렀을때 display:none > display:table 과 같이 바꿔주면 됩니다.
function clickShowing(id){
var e = document.getElementById(id);
if(e.style.display == 'table')
e.style.display = 'none';
else
e.style.display = 'table';
}
function t(){
var form = document.getElementById("searchWindow");
var e = document.getElementById("log");
form.addEventListener("focusout", function( ) {
e.style.display = 'none';
}, true);
}
OP.GG의 경우 input태그를 누르면 밑의 search로그를 남겨주고 input태그의 포커스가 빠지면 사라지는 방식을 취하고 있어서 t함수는 같은 방식으로 구현해봤는데 그 아이디를 검색하기위해서 하이퍼링크를 누르는 행동도 focus out되는 행동이여서 ㅋㅋㅋㅋㅋㅋ 눌려지지 않기때문에 패스 정확하게 어떤식으로 구현해야할지 몰라 일단 남겨놓고 실제로 쓰지는 않음
5~7개씩 짜르는건 예상보다 쉬웠는데
<c:foreach>문을 그냥 end조건을 달아주면됨. 0부터시작이라는걸 감안하고 갯수 파악하면됨. 5면 6개나옴.
<c:forEach var="List" items="${idList}" varStatus="s" end="5">
versionCheck 만듬. 버전 변경되어도 최신화되어 키로 적용가능.
버전체크같은경우는 각 지역마다 DataDrangon의 json의 버전이 달라지기때문에 그 각 항목별 업데이트 버전을 따로 배포함.
"https://ddragon.leagueoflegends.com/realms/kr.json"
에서 Json을 직접 가져와서 각 항목별로 버전을 따로 때올 수 있는데, 그에 맞는 버전을 적용해서 URL을 적용하면됨.
저는 아예 자바파일을 만들고 여기서 아예 모든 버전정보를 여기서 관리하고 그에 맞는걸 객체에서 메소드를 실행한뒤에 그 값을 클래스에서 변수 가져와서 써버리면 된다고 생각해서 바로 적용함하면 됩니다.
참고로 나중에 포스팅할 예정인데 DataDragon 사용법에 대해서 이야기해볼까함.
그 외에도 자주 까먹거나 유용한 것들에 대해서 여기다 살짝 올려두면
1. 문자열 js,java에서 공백제거
java: str.replaceAll("\\p{Space}", "");
js: str.replace( /(\s*)/g, "");
2.update시 timestamp 최신화 시켜주는 기능 (그냥 테이블생성시부터 지정할 수 있음)
https://www.cikorea.net/bbs/view/tip?idx=8089
ALTER TABLE `테이블명` CHANGE `컬럼명` `컬럼명` TIMESTAMP ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
이미 테이블 생성한경우 수정하는 방식임.
마무리하면서...
이 프로젝트를 마무리하면서 확실히 코딩은 실제 프로젝트를 하면서 가장 많이 발전하게 되는것 같습니다. 그리고 이런식으로 내 기술에 대한 피드백은 모르겠고 꾸준한 기록은 나중에 도움이 될거라고 생각합니다. 어 비슷한 기능 저번에 썼는데... 아니면 이런 기능 여기서 썼는데.. 이런것들을 제 블로그에 한 곳에 모아두면 구글링에 구글링을 하면서 깨닳아가는 과정을 줄일 수 있을 겁니다.
참 많은 과정들이 있었고, 그런 과정을 걸치면서 8.24일부터 시작했었던 것이 거의 근 3주안에 끝났던걸 생각해보면(1주는 사실상 개발에 완전히 못쏟았으니까 한달로 안치고 싶당...) 점점 성장할수 있지 않을까라는 추측을 해보면서 이글을 마무리지어봅니다.
그리고 혹시 이 프로젝트의 실제 모습을 보시고 싶으신분들은
https://github.com/ventulus95/NoxikaGG
'프로젝트 > 개인프로젝트' 카테고리의 다른 글
리다이렉션을 처리하는 여러가지 방식 (0) | 2020.01.08 |
---|---|
User Agent를 통한 각 OS별 마켓으로 옮겨주는 리다이렉트 페이지 만들기 (0) | 2020.01.03 |
Spring으로 OP.GG 클론 코딩해보기 -5 (0) | 2019.09.01 |
Spring으로 OP.GG 클론 코딩해보기 -4 (0) | 2019.09.01 |
Spring으로 OP.GG 클론 코딩해보기 -3 (0) | 2019.08.24 |