일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 영속성컨텍스트
- Argos
- BDDMockito
- 회고
- unique result
- 우아한테크코스
- 배포스크립트
- 우테코
- 우아한테크코스5기
- 벌크연산
- @Query
- ubuntu
- 스프링 롬복
- Mock
- 검색api
- 스프링부트배포
- 레벨인터뷰
- bomblab
- 밤랩
- jpa
- @Param
- clearAutomatically
- SpringDataJPA
- ubuntu이미지
- 우분투
- @Modifying
- 우아한테크코스 블랙잭
- NonUniqueResultException
- docker에 ubuntu
- 자바 롬복
- Today
- Total
목록Spring (9)
Jeomxon's Tech Note
기술적인 내용을 담은 글을 작성하는 것을 즐기는 편은 아닌데, OAuth로 카카오 소셜 로그인을 구현한 과정에서 배운 부분이 정말 많았다. 한번 정리해보고 싶기도 하고 팀원들에게 자료로써 공유하면 좋겠다라는 생각이 들어서 글로 남겨보았다. 방학 때 정리하지 않으면 바쁘다는 핑계로 작성하지 않을 것 같아서 며칠에 걸쳐서 한번 작성해봤다. 확실히 글로 정리해보니 내가 애매했던 부분을 인지하고 넘어갈 수 있다는 장점이 있다고 느꼈다. https://velog.io/@votogether2023/OAuth%EB%A1%9C-%EC%B9%B4%EC%B9%B4%EC%98%A4-%EC%86%8C%EC%85%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8..
문제 상황 팀 프로젝트를 진행하면서 OAuth를 이용한 회원가입 및 로그인 기능을 맡게 되었다. 거의 구현 막바지 무렵 자잘한 에러들을 고치고 있었는데, 개발서버에서는 발생하지 않았던 것으로 기억했는데 로컬에서 띄운 서버에서는 알 수 없는 에러로그가 찍히고 있었다. 토큰이 올바르지 않다고..? 토큰을 보낸 적이 없는데 이런 예외 메시지와 함께 에러로그가 찍히는 걸 확인할 수 있었다. 에러가 발생한 위치는 알았지만, 어느 시점에 해당 에러가 발생했는지 알기 위해서 위치를 파악해야했다. 일단 해당 로그로 확인할 수 있었던 사실은 filter에서 에러가 발생했기 때문에 요청의 시작 시점에 예외가 발생 해당 로그 이전에 회원 조회 쿼리문이 함께 나간 것을 확인했기에 두번째 요청에서 발생 그러면 결과적으로 내가 ..
컨트롤러 단을 테스트하면서 RestAssured를 사용하기도 하고, mockMvc도 사용을 해봤다. 각각의 미션마다 '이걸 사용하자!'라고 생각하고 사용하긴 했는데 막상 큰 이유는 없었던 것 같다. 어떤 상황에 어떤 걸 써야 잘 썼다고 할 수 있을까? 사실 정답은 없다고 생각한다. 적절한 상황에 맞춰서 잘 사용하면 된다는 것이 답이 될 것이다. 그런데 학습을 하고 있는 나의 입장에서는 적절한 상황이라는 말이 잘 와닿지 않았다. 그래서 나만의 기준을 세우고자 글을 써보면서 정리하려고 한다. 보통 RestAssured를 사용하는 경우는 @SpringBootTest가 붙은 테스트였다. 여기서 @SpringBootTest를 사용하면 실제 스프링부트 서버환경을 제공하게 되는데, 이는 당연히도 테스트가 무거워지게 ..
서비스는 어떻게 테스트할 수 있을까? 레벨2 첫 미션인 자동차 경주 미션은 요구사항이 많지 않았다. 그에 비해 공부해야할 양은 방대했다. 그 중 가장 시간을 많이 썼던 부분은 테스트였다. 특히나 서비스 계층에 대한 테스트를 작성할 때, 어디서부터 어떻게 작성해야할지 감이 오지 않았다. DAO에 의존이 걸린 Service를 대체 어떻게 테스트하면 좋을까? Mockito라이브러리를 사용해보자 class RacingGameServiceTest { private RacingGameService racingGameService; private PlayerDao playerDao; private RacingGameDao racingGameDao; @BeforeEach void setUp() { racingGameD..
javax.persistence.NonUniqueResultException: query did not return a unique result: 2 서비스 단에서 개발하고 테스트를 직접하던 도중 발생한 에러이다. 현재 db에는 값이 두개 이상이 있고, 동일한 조건으로 find를 통해서 조회를 하려고하면 발생하는 오류이다. 따라서 service단에서 사용한 find관련 메소드에서 이상이 없는지 먼저 확인하면 빠르게 해결할 수 있다. 에러에 대해서 풀어보자면 unique result, 즉 하나의 유일한 결과에 대해서 return하여 받아야하는데 2개 이상이 db에 들어있기 때문에 발생했던 것이었다.
spring-data-jpa에서 벌크연산을 처리할 때 주의해야할 사항은 꼭 알아둬야할 것 같아서 포스팅을 한다. @Modifying @Query("update Member m set m.age = m.age + 1 where m.age >= :age") int bulkAgePlus(@Param("age") int age); 위 코드에서 파라미터로 들어온 age보다 크거나 같은 age에 대해서는 1을 더하여 update쿼리를 날려주는 것을 알 수 있다. 첫번째 주의사항은 @Modifying을 써줘야한다는 것이다. @Modifying을 쓰지 않으니깐 이런 경고문이 뜬다. update 혹은 delete쿼리를 보낼 때는 반드시 필요한 어노테이션임을 알 수 있다. 두번째 주의사항은 벌크연산 후 영속성 컨텍스트를 ..
spring-data-jpa에서는 @Query 어노테이션을 통해 JPQL을 사용할 수 있도록 기능을 제공한다. @Query("select m from Member m where m.username = :username and m.age = :age") List findUser(@Param("username") String username, @Param("age") int age); 이런 식으로 사용할 수 있다. 여기서 얼핏보면 @Query에 있는 string으로 이루어진 쿼리문이 JPQL처럼 단순 스트링쿼리라고 생각이 들었는데 다른 점이 있었다. JPQL에서는 쿼리문에 문법 오류가 있으면 컴파일 타임에 에러를 잡아주지를 못한다. 따라서 런타임 시에 에러가 발생할 수 있는데 이는 치명적이다. 사용자가 특정..
java.lang.IllegalArgumentException: Parameter value [\] did not match expected type [java.lang.String (n/a)] 위와같은 오류가 검색 api에 발생했다. 이상하게도 첫번째 한번은 검색 api가 정상적으로 작동하는데 두번째 호출부터는 위와 같은 에러를 표출하면서 작동이 되지 않았다. 이유를 찾아보니 깃허브 spring-data-jpa 이슈 탭에서 발견할 수 있는 오류였다. https://github.com/spring-projects/spring-data-jpa/issues/2479 public interface FoodRepository extends JpaRepository { List findAllByFoodNameCo..
엔티티 클래스에서 사용하는 id(자동으로 증가되는 등의 시퀀스), 즉 들어가는 id에 대해서 Long타입으로 쓰는 이유가 뭘까? 처음에는 그냥 int타입을 쓰면 되지 않나?하고 생각했는데 전혀 아니었다. Wrapper Type인 Long을 쓰는 이유, 그것도 Integer가 아닌 굳이 Long을 쓰는 이유는 뭘까? 일단 int가 아니라 long을 쓰는 이유는 허용 범위가 더 크다는 점에서 추측을 할 수 있다. 하지만 왜 Wrapper Type을 사용하는지가 궁금했다. 일단 primitive Type에서는 기본 값이 0인데, 0이라는것이 실제로 id에 부여된 값이 0인지 아니면 값이 없다는 뜻인지 구분하기 어렵다. 하지만 Wrapper Type을 쓴다면 값이 없을 때는 null로 표시가 되기 때문에 pri..