우테코 레벨2 - 체스

현재 시각 새벽 5시 … 체스로 DB 전환이 이렇게 힘들었을 줄은.. 생각지도 못하였다..

난 얼마 안 걸릴 줄 알았으나.. 오산이었다.. ^^;

깨달은 것들

JQuery의 Ajax 요청이 생각보다 까다롭다

일반적인 js의 호출과 다르게 jquery 문법은 다소 다른게 있다

예를들어

  • dataType : Accept 이다. (서버 -> 클라이언트)
  • contentType : Content-Type 이다 (클라이언트 -> 서버)

그리고 dataType의 옵션 값으로

dataType: "json";

이 들어가는데

contentType은

contentType: "application/json";

이렇게 들어간다 (…)

또한 서버로 json을 보낼 때는

data: JSON.stringify(gameData);

위 처럼 보내주어야 한다 (…)

즉 .. 정리하면 아래와 같다

const gameData = {
  currentTeam: $("#current-team").text(),
  pieces: getPieces(),
};

$.ajax({
  url: "/save-game",
  method: "POST",
  data: JSON.stringify(gameData),
  contentType: "application/json",
})
  .done(function (data) {
    alert("저장 완료 !");
  })
  .fail(function (xhr, status, errorThrown) {
    console.log(xhr);
  });

그리고 서버에서 받을떄는.. 놀랍게도 사람들이 아는 것과는 다르게 Setter가 필요하다..

분명 리플렉션 등의 Util이 있기 때문에 필요 없었던 것으로 아는데.. 필요하다 !!

Exception Api 와 Interceptor 호출 순서

ExceptionResolver -> Interceptor.afterCom~ 순으로 실행이 된다. 즉 앞에서 예외를 잡아버리면 인터셉터에서 Exception Param 은 null 이 된다

안그러면 null 값이 들어온다… ㅠ

Session Store

쓰레드 로컬은 현재 쓰레드에만 해당되는 scope로 bean이 관리된다!! 즉, request 스코프에 대해서만 해당되므로 이 스코프가 아닌 웹 브라우저를 닫기 전의 Session 스코프가 적용되어 있어야 한다 !

그러나 스프링에서 관리하는 세션 스코프에도 한계가 있었다…

스프링에서 세션을 관리하다보니 이것의 초기화를 찾기 못해서 (즉 해당 세션에 대한 Bean을 강제 초기화해야한다) 그러나 이것을 하지 못해서 자바에서 강제로 SessionMap을 구현해서 이 방식으로 해당 세션에 대해 재 요청이 있을시 강제로 초기화하는 방법을 선택하였다!

@Repository
public class SessionToChessRepository {

    private static final int SESSION_REMOVE_MINUTE = 1;
    private Map<HttpSession, ChessBoard> sessionToChessBoard = new ConcurrentHashMap<>();

    public void add(HttpSession session, ChessBoard chessBoard) {
        sessionToChessBoard.put(session, chessBoard);
    }


    public ChessBoard get(HttpSession session) {
        return sessionToChessBoard.get(session);
    }

    @Scheduled(cron = "*/10 * * * * *")
    public void checkAndRemoveSessions() {
        for (HttpSession session : sessionToChessBoard.keySet()) {
            checkAndRemoveSession(session);
        }
    }

    private void checkAndRemoveSession(HttpSession session) {
        long currentTimeMillis = System.currentTimeMillis();
        long lastAccessedTime = session.getLastAccessedTime();

        long elapsedMinutes = Duration.ofMillis(currentTimeMillis - lastAccessedTime).toMinutes();

        if (SESSION_REMOVE_MINUTE == elapsedMinutes) {
            sessionToChessBoard.remove(session);
            System.out.println("remove it " + session);
        }
    }

    public void delete(HttpSession session) {
        sessionToChessBoard.remove(session);
    }
}

그러나 위 스케쥴링 기능은 Spring Boot에서 지원하는 글로벌 설정으로 바꾸게 된다.

server:
  servlet:
    session:
      timeout: 600

DDL 문을 작성할 수 있음 !

public class JdbcBoardPieceDao implements BoardPieceDao {
  public void setForeignKeyChecks(boolean isCheck) {
      if (isCheck) {
          jdbcTemplate.update(SET_FOREIGN_KEY_CHECKS_DDL + "1");
          return;
      }
      jdbcTemplate.update(SET_FOREIGN_KEY_CHECKS_DDL + "0");
  }
}

AppleDao -> BananaDao 처럼 참조관계가 있는 테이블을 테스트할 때

image image

위와 같이 테스트 가능하다

실험


  1. setter를 넣는다

image

  1. 호출한다

image

  1. 결과

image

… 소름이다 Setter를 호출한다…

utf8mb4_0900_ai_ci 보다는 utf8mb4_general_ci

정확한 한글(및 동아시아 언어, 일본어, 중국어) 검색을 처리하기 위해서는 utf8mb4_general_ci 로 설정해야 합니다.

참고
https://rastalion.me/mysql-8-0-1-%EB%B2%84%EC%A0%84%EB%B6%80%ED%84%B0-%EC%B1%84%ED%83%9D%EB%90%9C-utf8mb4_0900_ai_ci%EC%9D%98-%ED%95%9C%EA%B8%80-%EC%82%AC%EC%9A%A9%EC%97%90-%EB%8C%80%ED%95%9C-%EB%AC%B8%EC%A0%9C%EC%A0%90/

그 외


jQuery에서 method POST 지정하고 contentType 을 지정하지 않으면 기본적으로 x-xxx 로 날라가더라구요.. application/json 으로 보내야 하는데…


본래 의도 ! gameId 를 검색해서 가져오려고 했었다! 그러나… 계속 클라이언트가 favicon.ico를 호출한다 !

@GetMapping(“/{gameId}”) public 메서드명 (@PathVariable String gameId) {

}

localhost:8080/favicon.ico 이게 브라우저에 표시되는 아이콘

@GetMapping(“/game-id/{gameId}”)


queryForObject 이친구..

없거나 2개 이상이면 예외 터트림..

하나가 아니면 예외 터트림…!!


js 비동기를 몰라서

오찌/스컬이 30분 가까이 트러블 슈팅…

비동기…


jdbcTemplate과 관련해서

queryList() 는 컬럼이 하나인 곳에서만 사용할 수 있는 리스트 자료형이다

query() + rowMapper 를 사용해야 한다

그외 들은 것들

제이슨이 알려주었던 것

아래와 같은 TEST FW가 있다

restAssured.. web-test-client test-rest-template… mock-mvc…

이런 류의 테스트는 건 옵션 사항이라고 한다 !

connection 확인 및 안 끊기게 끔 요청을 할 떄 EXIST 쿼리를 사용한다 !

참고한 것들

★ REST-API 설계 https://server-engineer.tistory.com/886

getter를 사용해야 HttpMessageConverter 가 변환이 가능한 것으로 보인다
https://thinkground.studio/httpmessagenotwritableexception-no-converter-for-vo-class-with-preset-content-type-null/

string to boolean in js
https://stackoverflow.com/questions/263965/how-can-i-convert-a-string-to-boolean-in-javascript

query vs queryForList
https://stackoverflow.com/questions/33008205/incorrectresultsetcolumncountexception-incorrect-column-count-expected-1-actu

try-with-resources
https://hyoj.github.io/blog/java/basic/jdbc/jdbc-try-catch-tip.html#java-7-%EB%B6%80%ED%84%B0%EB%8A%94-try-with-resources-%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EC%9E%90

HTTP 설계 https://kyleyj.tistory.com/46

혜원님의 스프링 고분분투 테스트 ~! https://hyewoncc.github.io/2022/04/25/spring-study-1.html

AJAX Content Type In JQuery
https://mchch.tistory.com/181

JQuery 공식문서
https://api.jquery.com/jquery.ajax/

JQuery 옵션들
https://cofs.tistory.com/404

https://stackoverflow.com/questions/2253453/how-should-i-name-a-java-util-map map 이름 짓기 keyToValue 처럼 읽는 순서대로 짓는 것이 좋다는 의견

https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers HTTP URL 길이

https://rastalion.me/mysql-8-0-1-%EB%B2%84%EC%A0%84%EB%B6%80%ED%84%B0-%EC%B1%84%ED%83%9D%EB%90%9C-utf8mb4_0900_ai_ci%EC%9D%98-%ED%95%9C%EA%B8%80-%EC%82%AC%EC%9A%A9%EC%97%90-%EB%8C%80%ED%95%9C-%EB%AC%B8%EC%A0%9C%EC%A0%90/ utf8mb4_0900_ai_ci의 한글 사용에 대한 문제점

ArgumentResolver에서 예외를 핸들링하는 법? https://stackoverflow.com/questions/34762991/how-to-handle-exceptions-thrown-from-customized-handlermethodargumentresolver





© 2020.12. by 따라쟁이

Powered by philz