| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- input
- string
- 배열
- CSS
- HashMap
- Visual Studio Code
- 자바문법
- Array
- list
- javascript
- ArrayList
- 정규식
- js
- junit5
- IntelliJ
- vscode
- 단위테스트
- 자바스크립트
- Eclipse
- math
- 인텔리제이
- 문자열
- 자바
- 테스트자동화
- junit
- html
- Java
- 스프링부트
- SpringBoot
- java테스트
- Today
- Total
목록SpringBoot (26)
어제 오늘 내일
혹시 아직도 배포할 때마다 이런 과정을 반복하고 계신가요? 로컬에서 ./gradlew build 실행 (한참 기다림) FTP나 SCP로 서버에 jar 파일 전송 서버 접속해서 기존 프로세스 죽이고(kill), 다시 실행(java -jar) 이 과정은 귀찮기도 하지만, 사람이 하기 때문에 반드시 실수가 발생합니다. 오늘은 이 과정을 로봇에게 맡기는 CI(Continuous Integration, 지속적 통합)를 GitHub Actions로 구현해 보겠습니다.1. CI/CD가 도대체 뭔가요?CI (Continuous Integration): "지속적 통합"개발자가 코드를 합칠(Merge) 때마다, 자동으로 빌드하고 테스트해서 "이 코드 문제없어!"라고 검증하는 과정입니다.CD (Continuous De..
"개발 끝났다!" 하고 좋아하기엔 이릅니다. 진짜 끝은 서버에서 돌아가는 것을 확인해야 끝이죠.Spring Boot가 혁명적인 이유는 바로 내장 톰캣(Embedded Tomcat) 덕분입니다. 서버를 설치하는 게 아니라, 서버를 내 코드 안에 넣어버리는 것이죠.이 모든 것을 가능하게 하는 실행 가능한 Jar(Executable Jar)의 비밀과 빌드 방법을 알아보겠습니다.1. 일반 Jar vs 실행 가능한 Jar (Fat Jar)우리가 평소에 라이브러리로 쓰는 Jar 파일과 Spring Boot가 만드는 Jar 파일은 다릅니다. 일반 Jar (Skinny Jar): 내가 짠 코드(.class)만 들어있습니다. 이것만으로는 실행 못 합니다. (의존성 라이브러리가 없으니까요) 실행 가능한 Jar (Fat..
여러분, 혹시 이런 코드를 짜보신 적 있나요?public void join(Member member) { long start = System.currentTimeMillis(); // 1. 시작 시간 측정 try { memberRepository.save(member); // 핵심 로직 (이거 하나만 진짜임!) } finally { long finish = System.currentTimeMillis(); // 2. 종료 시간 측정 long timeMs = finish - start; System.out.println("join = " + timeMs + "ms"); // 3. 로그 출력 }}회원 가입, 조회, 수정... 모든 메서드..
웹 개발을 하다 보면 "모든 요청에 대해 로그를 남겨라", "로그인 안 한 사용자는 튕겨내라" 같은 요구사항을 받게 됩니다.이걸 모든 컨트롤러 메서드에 복사-붙여넣기 하실 건가요? 절대 아니죠.스프링 부트에는 요청을 중간에 가로채서 처리하는 강력한 도구 두 가지가 있습니다. 바로 필터(Filter)와 인터셉터(Interceptor)입니다. 둘 다 비슷해 보이지만, 활동 구역과 권한이 완전히 다릅니다.1. 웹 컨테이너의 문지기: 필터 (Filter)필터는 스프링(Spring) 영역 밖, 즉 웹 컨테이너(Tomcat) 영역에서 동작합니다.위치: 요청이 DispatcherServlet에 도착하기도 전에 가장 먼저 실행됩니다.특징: 스프링과 무관한, 날것 그대로의 HTTP 요청/응답을 조작할 수 있습니다.주요 ..
안녕하세요! 개발자의 귀차니즘을 해결해 주는 IT 블로거입니다.API 문서는 개발자에게 계륵 같은 존재입니다. 없으면 협업이 불가능하고, 있으면 관리하기 너무 귀찮으니까요. 그래서 우리는 문서 자동화 도구를 사용합니다.스프링 부트 진영에는 두 가지 강력한 도구가 있습니다.Swagger (Springdoc): "쉽고 빠르고 예쁘다!" (Annotations 기반)Spring REST Docs: "테스트를 통과해야만 문서가 나온다!" (Test 기반)과연 우리 팀에는 무엇이 맞을까요?1. 쉽고 화려한: Swagger (Springdoc)가장 많이 쓰이는 도구입니다. 예전엔 springfox를 썼지만, 지금은 업데이트가 멈춰서 springdoc-openapi 라이브러리를 사용합니다.장점: 설정이 3분 컷!bu..
지난 시간에는 가짜 객체(Mock)를 써서 빠르게 로직만 검증하는 '단위 테스트'를 배웠습니다. 하지만 실무에서는 이런 일이 종종 발생합니다."테스트 코드는 다 통과했는데, 막상 서버 띄우니까 에러가 나요!" 😭이유는 간단합니다. SQL 쿼리가 틀렸거나, DB 연결 설정이 잘못되었기 때문입니다. 이런 문제는 Mock 객체로는 절대 찾을 수 없습니다.오늘은 스프링 컨테이너를 진짜로 띄워서 처음부터 끝까지 테스트하는 @SpringBootTest와, 테스트용 DB인 H2를 활용하는 방법을 알아보겠습니다. 1. 통합 테스트란?단위 테스트가 '부품 검사'라면, 통합 테스트는 '조립 검사'입니다.단위 테스트: MemberService만 떼어내서 테스트 (가짜 DB 사용) -> 빠르지만 실제 환경과 다름.통합 테..
DB를 다루는 애플리케이션에서 가장 중요한 것은 속도가 아니라 신뢰성입니다.A가 B에게 100만 원을 송금하는 로직을 짰다고 가정해 봅시다.A의 계좌에서 100만 원 차감 (UPDATE)(여기서 서버 전원 꺼짐 💥)B의 계좌에 100만 원 입금 (UPDATE)트랜잭션이 없다면 100만 원은 공중분해 됩니다. 이런 일을 막기 위해 "모두 성공하거나, 아니면 아예 없던 일로 하거나(All or Nothing)"를 보장해 주는 것이 바로 트랜잭션입니다. 1. 스프링은 어떻게 트랜잭션을 거나요? (AOP와 프록시)스프링에서 트랜잭션을 적용하는 방법은 너무나 간단합니다. 메서드나 클래스 위에 @Transactional만 붙이면 끝이죠.@Servicepublic class TransferService { ..
JPA를 쓰다 보면 로직은 완벽한데 페이지 로딩이 엄청 느릴 때가 있습니다.로그를 확인해 보니 SELECT 쿼리가 끝도 없이 실행되고 있다면? 축하합니다. 당신은 N+1 문제에 당첨되셨습니다.이것은 JPA가 너무 자동화를 잘해줘서 생기는 부작용인데요. 원리만 알면 아주 쉽게 잡을 수 있습니다. 1. N+1 문제가 뭔가요?쉽게 말해 "1번의 쿼리로 N개의 데이터를 가져왔는데, 그 N개의 데이터를 조회하기 위해 N번의 추가 쿼리가 나가는 현상"입니다.상황: 팀(Team)과 멤버(Member) 조회팀 10개를 조회하고, 각 팀에 소속된 멤버들의 이름을 출력한다고 가정해 봅시다.// 1. 팀 10개를 조회 (쿼리 1번)List teams = teamRepository.findAll();// 2. 루프를 돌며 ..
JPA를 쓰다 보면 Member를 저장했는데 Team에는 회원이 안 들어가 있거나, 반대로 Team을 저장했는데 Member의 외래 키가 null인 황당한 경우를 겪게 됩니다.이건 100% "연관관계의 주인"을 잘못 설정했기 때문입니다. 객체지향 설계와 데이터베이스 설계의 차이를 이해하면, 이 문제는 아주 쉽게 해결됩니다. 1. 객체 vs 테이블: 패러다임의 불일치가장 먼저 이 그림을 머릿속에 넣어야 합니다.테이블(DB): MEMBER 테이블에 있는 TEAM_ID (외래 키) 하나만 있으면, 멤버도 팀을 찾을 수 있고 팀도 멤버를 찾을 수 있습니다. (양방향 가능)객체(Java): Member 객체에 Team 필드가 있어야 팀을 찾을 수 있고, 반대로 Team 객체에도 List가 있어야 멤버를 찾을 수..
지난 포스팅에서 JPA가 SQL을 대신 짜준다고 했죠?하지만 EntityManager를 직접 다루려면 여전히 코드가 좀 깁니다.// 순수 JPA 코드 (좀 귀찮음)public void save(Member member) { em.persist(member);}public Member findOne(Long id) { return em.find(Member.class, id);}Spring Data JPA는 이 귀찮음마저 없애줍니다. "인터페이스만 정의하면, 스프링이 알아서 구현체를 만들어준다!" 이것이 핵심입니다. 1. 인터페이스 하나면 끝! (JpaRepository)사용법은 너무 간단해서 허무할 정도입니다.그냥 인터페이스를 하나 만들고 JpaRepository를 상속받으면 됩니다.publ..
