전체 글 94

캡스톤 졸업 프로젝트 (2024.02~06) +앱스토어 138위로 차트인+_+

2월부터 시작해서 한학기동안 열심히 달린 학교 졸업 프로젝트가 끝났다...!그런데 팀원들과 마음이 너무 잘 맞아서 방학동안 UI 개선하고 2학기에 실제로 운영을 해보기로 해서, 회고록 겸 스스로를 격려하기 위한 목적으로 글을 작성한다! +_+ 어느 프로젝트든 그렇지만 팀원 잘 만나는게 정말 중요한데, 역대급으로 마음이 잘맞고 개발도 잘하는 팀원들을 만나서 팀장으로서 너무너무 감사한 한학기였다. 어떤 문제가 생겨도 항상 든든하게 같이 고민해주는 웅배오빠, 마르지않는 아이디어 뱅크 홍현이, 우리팀의 화기애애한 분위기 담당 동윤오빠한테 이글을 통해 함께해줘서 늘 고맙다는 말을 전하고싶다. 일단 우리 팀의 주제는 학과 중심 커뮤니티 서비스로, 전국의 대학생들이 학과별로 묶여서 소통할 수 있는 어플인데, 내 개인..

팀 프로젝트 2024.06.04

Springboot+JPA 사용중 발생한 N+1 문제 개선

개인프로젝트에서 만든 조회 api에 아주 심각한 성능 문제가 있었다. 바로 조회 한번에 select쿼리가 약 10개~15개가 나가는 것이다...... 문제의 쿼리 덩어리가 날아가는 부분을 찾기 위해 디버깅을 해보니 원인을 파악할 수 있었다. 현재 Member엔티티와 Post엔티티가 다대다여서 MemberPost라는 중간 객체를 두고 필요한 정보를 이 객체를 통해 조회하고있는데, 이를 불러오는 과정에서 문제가 발생하는 것 같았다. 아래는 개선 전 도메인 코드이다. @Entity @Getter @Setter public class Member { @Id @GeneratedValue @Column(name = "member_id") private Long id; private String nickname; p..

JPA 2024.03.14

Springboot + jwt + web socket(STOMP) 채팅 구현

스프링부트로 채팅을 구현하기 위해 STOMP 프로토콜을 사용해보기로 했다. 구현을 위해 공부하는 과정에서 헷갈렸던 부분이 있어 적어둔다. STOMP(Simple Text Oriented Messaging Protocol)란 http와 호환되는 양방향 통신을 제공하기 위한 프로토콜이다. @RequiredArgsConstructor @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { private final StompHandler stompHandler; @Override public void configureMessageBroker(Message..

Spring & SpringBoot 2024.02.12

Flutter에서 json 파일 사용하기 - dynamic to String

Flutter 프로젝트 내부에서 json 파일을 사용할 때 값이 String이 아닌 dynamic으로 들어가면서 생긴 오류가 있었다. { "01호선": [ "중동", "도화", "간석", "개봉", "방학", "금정", "동암", "오산", // 등등 ], "02호선": [ "이대", "홍대입구", "건대입구", "구로디지털단지", "용두", "합정", ], // 등등... } 내가 사용하고자 하는 json파일은 대충 이렇게 생겼다! String jsonString = await rootBundle.loadString('asset/jsons/subway_stations.json'); final Map lineAndStations = json.decode(jsonString); selectedLine = ..

Flutter 2024.02.08

토큰 재발급 요청이 중복으로 나가는 문제 - 요청 대기열 만들어 해결

개인 프로젝트를 위한 플러터 앱에서 Dio Interceptor를 사용해서 토큰 에러가 나면 토큰 재발급을 위한 api로 요청을 보내 토큰을 재발급받는 로직으로 처리하고 있었다. 그런데 앱을 테스트할 때, 프론트에서 토큰 재발급 요청이 중복으로 날아가 서버에서 SQLIntegrityConstraintViolationException 이 발생하였다. 새로 생성된 refreshToken이 저장되는 과정에서 Duplicate entry 문제가 발생한 것인데, 로그를 찍어보니 프론트 상에서 토큰이 필요한 api를 중복으로 보낼때 적절한 처리가 되어있지 않아서 발생한 문제 같았다. 만약 인증이 필요한 여러 api를 호출하였는데, accessToken이 만료된 경우, 이 각 호출들이 Interceptor에서 같은 ..

Flutter 2024.02.06

Postman environment에 Response값을 등록하는 방법

jwt등 토큰을 활용한 인증정보를 요청에 담아 보낼 때 헤더에 하나하나 담아 전달해도 되지만 더 편리한 방법이 있다. 바로 Postman environtment에 환경 변수를 등록해놓고 사용하는 것이다. 아래는 응답으로 들어온 토큰을 환경변수에 저장할 수 있게 해주는 Test scripts이다! 1. 토큰이 body에 담겨온 경우 pm.environment.set("accessToken", pm.response.json().accessToken); pm.environment.set("refreshToken", pm.response.json().refreshToken); 2. 토큰이 header에 담겨온 경우 pm.environment.set("accessToken", pm.response.headers...

기타 개발공부 2024.01.26

io.jsonwebtoken.MalformedJwtException: Invalid compact JWT string: Compact JWSs must contain exactly 2 period characters, and compact JWEs must contain exactly 4.

Spring security와 jwt를 이용해서 토큰 재발급 api를 구현하고 프론트엔드와 연동해서 테스트하던중 오류가 발생했다. 로그인 과정에서 첫 토큰 세트(accessToken + refreshToken)는 발행이 잘되는데 재발급이 안되는 것이다. 일단 내가 생각했던 토큰 발급 로직은 이렇다. - 첫번째 토큰 발급 1. 클라이언트가 아이디, 패스워드를 /login 으로 넘긴다. 2. 내가 사용하는 로그인 필터가 spring security의 UsernamePasswordAuthenticationFilter를 상속하므로 그 정의에 따라서 /login경로로 들어온 요청을 해당 필터에서 검증함. 3. 검증하고 문제가 없으면 accessToken, refreshToken을 발급해서 헤더에 담아 클라이언트에..

Spring & SpringBoot 2024.01.25

SpringBoot&JPA : CommandAcceptanceException

스프링부트 프로젝트에서 JPA 엔티티를 만들고 데이터베이스에 반영하려고 하는데 이런 오류가 났다. 로그를 보다보니 Caused by: java.sql.SQLSyntaxErrorException이라고도 하고.. 그래서 순간 sql 예약어가 있나 하는 생각이 쎄하게 들었고 찾아봤더니 이게 맞다고 한다... .. https://dev.mysql.com/doc/refman/8.0/en/keywords.html#keywords-8-0-detailed-U MySQL :: MySQL 8.0 Reference Manual :: 9.3 Keywords and Reserved Words 9.3 Keywords and Reserved Words Keywords are words that have significance in..

Spring & SpringBoot 2024.01.21

실전 스프링부트와 JPA활용2 - 조회 API 성능 최적화, OSIV

Order 엔티티를 보면 아래와 같이 Member, Delivery과는 to one관계를, OrderItem과는 to many관계를 맺고 있는 것을 확인할 수 있다. @Entity @Table(name = "orders") @Getter @Setter @NoArgsConstructor(access = AccessLevel.PROTECTED) //생성자 숨기기 public class Order { @Id @GeneratedValue @Column(name = "order_id") private Long id; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id") private Member member; @OneToMany(mappedBy =..

Spring & SpringBoot 2024.01.11

400에러 HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `jpabook.jpashop.api.

DTO를 만들어서 api 요청, 응답을 처리하던 중 PUT메소드를 테스트하다가 400에러가 발생했다. 원인은 DTO로 사용하는 객체에 디폴트 생성자가 없어서 발생한 문제였다. 스프링부트를 사용한다고 해서 기본생성자가 꼭 필요한 것은 아니지만, JPA 엔티티를 사용하면 리플렉션을 이용하기 때문에 기본생성자가 꼭 필요하다. 그리고 생성자가 없는 클래스는 클래스 파일을 컴파일하는 시점에 자바가 디폴트 생성자를 자동으로 생성해주지만, 임의로 작성한 생성자가 있을 경우, 자동으로 디폴트 생성자를 만들어주지 않는다. 나는 내 임의대로 생성자를 만들어뒀기때문에 기본 생성자가 생성되지 못했고 따라서 요청을 받아서 객체로 전환하는 JSON Serialize 과정에서 오류가 발생한 것 같다. 나는 대체 언제 이 의미없는..

Spring & SpringBoot 2024.01.09