๐Ÿ”™ Backend

    Spring Boot :: @FeignClient ๋กœ ์™ธ๋ถ€ REST API ๊ฐ„ํŽธ ํ˜ธ์ถœ

    Spring Boot :: @FeignClient ๋กœ ์™ธ๋ถ€ REST API ๊ฐ„ํŽธ ํ˜ธ์ถœ

    ๋“ค์–ด๊ฐ€๋ฉด์„œ ์นด์นด์˜ค ๋ฐ ์• ํ”Œ ๋กœ๊ทธ์ธ์„ ๊ตฌํ˜„ํ•˜๋ฉด์„œ ์™ธ๋ถ€ API ์„œ๋ฒ„์— ์ ‘๊ทผํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์™€์•ผ ํ•˜๋Š” ์ผ์ด ๋งŽ์•„์กŒ๊ณ , API ์ฃผ์†Œ๋ฅผ ์„ค์ •ํŒŒ์ผ์— ์ €์žฅํ•œ ํ›„ ์ง์ ‘ HttpURLConnection ์„ ์ƒ์„ฑํ•ด์„œ ์—ฐ๊ฒฐํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ์ค‘๋ณต๋˜๊ฒŒ ๋˜์—ˆ๋‹ค. ๋˜ ์ง์ ‘ HttpURLConnection ์„ ์—ฐ๊ฒฐํ•ด ์™ธ๋ถ€ API ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋ฉด ๋ฐ›์•„์˜จ JSON ์„ ์ง์ ‘ ํŒŒ์‹ฑํ•ด์•ผ ํ•˜๋Š” ๋ถˆํŽธํ•จ๋„ ์กด์žฌํ–ˆ๋‹ค. ์ •๋ฆฌํ•˜์ž๋ฉด, ์™ธ๋ถ€ API ๋ฅผ ๊ฐ„ํŽธํ•˜๊ฒŒ ํ˜ธ์ถœํ•˜๊ณ  ์‹ถ์–ด์„œ ํ˜ธ์ถœ ๊ฒฐ๊ณผ๋ฅผ ์ง์ ‘ ํŒŒ์‹ฑํ•˜๋Š” ๊ณผ์ •์ด ๋ฒˆ๊ฑฐ๋กœ์›Œ์„œ FeignClient ๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. ์•„๋ž˜ ์„ค๋ช…์—์„œ๋Š” ๋งŽ์ด ์˜ˆ์‹œ๋ฅผ ๋“œ๋Š” Github API ๋ฅผ ์ด์šฉํ•ด์„œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๋ณด์•˜๋‹ค. FeinClient Feign ์€ Netflix ์—์„œ ๊ฐœ๋ฐœํ•œ REST Client ์ด๋‹ค. ๊ธฐ์กด์— Rest..

    EC2 :: Ubuntu Swap ๋ฉ”๋ชจ๋ฆฌ ์„ค์ •

    EC2 :: Ubuntu Swap ๋ฉ”๋ชจ๋ฆฌ ์„ค์ •

    EC2 ํ”„๋ฆฌํ‹ฐ์–ด ์„œ๋ฒ„๋กœ ์Šคํ”„๋ง์„ ๋„์šฐ๊ณ , CI/CD ๋ฅผ ์„ธํŒ…ํ•˜๊ณ  ํ•˜๋‹ค๋ณด๋ฉด ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๋ถ€์กฑํ•œ ๊ฒฝ์šฐ๊ฐ€ ์ข…์ข… ์žˆ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋Š˜๋ฆฌ๋ ค๋ฉด ๊ณผ๊ธˆ์„ ํ•ด์•ผํ•˜๊ณ .. ๊ฐ„๋‹จํ•œ ์‹ค์Šต์ด๋‚˜ ๊ฐœ๋ฐœ์šฉ ํ™˜๊ฒฝ ์„ธํŒ…์ด๋ผ๋ฉด ์‚ฌ์–‘์„ ์˜ฌ๋ฆฌ๊ธฐ๋ณด๋‹ค Swap ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ด์šฉํ•ด ์ด๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค. Swap ํŒŒ์ผ ๋˜๋Š” ํŒŒํ‹ฐ์…˜ ํ™•์ธ sudo free -m Swap ์˜์—ญ์ด 0 ์ด๋‹ˆ ์„ค์ •์„ ํ•ด์ฃผ์ž Swap ํŒŒ์ผ ์ƒ์„ฑ sudo fallocate -l 2G /swapfile ์šฉ๋Ÿ‰์ด 2G ์ธ swapfile ์ด๋ž€ ์ด๋ฆ„์˜ ํŒŒ์ผ์„ ์ƒ์„ฑํ–ˆ๋‹ค. ์œ„ ํŒŒ์ผ์„ ์Šค์™‘ํŒŒ์ผ๋กœ ์„ค์ •ํ•˜์ž. sudo mkswap /swapfile 600์˜ permission ์„ ๊ถŒ์žฅํ•œ๋‹ค๊ณ  ํ•˜๋‹ˆ ๋ฐ”๊ฟ”์ฃผ์ž. sudo chmod 600 /swapfile Swap ํ™œ์„ฑํ™” sudo swapon /swapfil..

    JUnit :: ParameterizedTest ๋กœ ๊ฒฝ๊ณ„๊ฐ’ ํ…Œ์ŠคํŠธํ•˜๊ธฐ

    JUnit :: ParameterizedTest ๋กœ ๊ฒฝ๊ณ„๊ฐ’ ํ…Œ์ŠคํŠธํ•˜๊ธฐ

    ๊ฒฝ๊ณ„๊ฐ’์—์„œ ์žฅ์• ๊ฐ€ ๋งŽ์ด ์ผ์–ด๋‚œ๋‹ค ํ…Œ์ŠคํŠธํ•  ๋•Œ๋Š” input ๊ฐ’์˜ ๊ฒฝ๊ณ„๊ฐ’์— ๋Œ€ํ•ด์„œ ํ•ญ์ƒ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•ด์•ผ ํ•œ๋‹ค ๊ทธ๋Ÿฌ๊ธฐ ์œ„ํ•ด ParameterizedTest ๋ฅผ ์ด์šฉํ•˜๋ฉด ์—ฌ๋Ÿฌ ๋ฐ์ดํ„ฐ ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. build.gradle ์ˆ˜์ • junit-jupiter-params ์ถ”๊ฐ€ testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.2' ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์•„๋ž˜ ๋งํฌ ์ฐธ์กฐ https://www.petrikainulainen.net/programming/testing/junit-5-tutorial-writing-parameterized-tests/ ์‹ค์Šต ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ ๊ฐ’ ๊ฒ€์ฆ ํ…Œ์ŠคํŠธ ์š”๊ตฌ์‚ฌํ•ญ ๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ์ตœ์†Œ 8์ž ์ด์ƒ 12์ž ์ดํ•˜์—ฌ์•ผ ํ•œ๋‹ค. ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ 8์ž ๋ฏธ..

    JPA :: ๋ฒŒํฌ์„ฑ ์ˆ˜์ • ์ฟผ๋ฆฌ

    JPA :: ๋ฒŒํฌ์„ฑ ์ˆ˜์ • ์ฟผ๋ฆฌ

    ๋ฒŒํฌ ์—ฐ์‚ฐ ์—ฌ๋Ÿฌ ๊ฑด์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ๋ฒˆ์— ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œ ์กฐ๊ฑด์— ๋งž๋Š” ๊ฐ์ฒด๋ฅผ ๋‹ค ๊ฐ€์ง€๊ณ  ์™€์„œ ์ˆ˜์ •ํ•  ํ•„์š” ์—†์ด DB ์ฟผ๋ฆฌ๋กœ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ. JPA Bulk ์˜ˆ์ œ ์ฝ”๋“œ : ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์€ ๋‚˜์ด๋ณด๋‹ค ๋งŽ์€ ํšŒ์›๋“ค์˜ ๋‚˜์ด๋ฅผ +1 ์‹œํ‚จ๋‹ค. public int bulkAgePlus(int age) { return em.createQuery( "update Member m set m.age = m.age + 1" + " where m.age >= :age") .setParameter("age", age) .executeUpdate(); } ํ…Œ์ŠคํŠธ ์ฝ”๋“œ @Test public void bulkUpdate() { //given memberJpaRepository.save(new Member("member1", 10)); m..

    JPA :: ํŽ˜์ด์ง•๊ณผ ์ •๋ ฌ

    JPA :: ํŽ˜์ด์ง•๊ณผ ์ •๋ ฌ

    ๊ธฐ์กด JPA ํŽ˜์ด์ง•๊ณผ ์ •๋ ฌ public List findByPage(int age, int offset, int limit) { return em.createQuery("select m from Member m where m.age = :age order by m.username desc") .setParameter("age", age) .setFirstResult(offset) .setMaxResults(limit) .getResultList(); } public long totalCount(int age) { return em.createQuery("select count(m) from Member m where m.age = :age", Long.class) .setParameter("age", a..

    JPA :: Query Method ๊ธฐ๋Šฅ

    JPA :: Query Method ๊ธฐ๋Šฅ

    ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๋งˆ๋ฒ•๊ฐ™์€ ๊ธฐ๋Šฅ์ด ์žˆ๋‹ค. ๋ฐ”๋กœ โ€œ์ฟผ๋ฆฌ ๋ฉ”์†Œ๋“œโ€ ๊ธฐ๋Šฅ์ธ๋ฐ, ๊ฒฐ๋ก ๋ถ€ํ„ฐ ๋งํ•˜๋ฉด 3๊ฐ€์ง€ ๊ธฐ๋Šฅ์ด ์žˆ๋‹ค. ๋ฉ”์†Œ๋“œ ์ด๋ฆ„์œผ๋กœ ์ฟผ๋ฆฌ ์ƒ์„ฑ ๋ฉ”์†Œ๋“œ ์ด๋ฆ„์œผ๋กœ JPA NamedQuery ํ˜ธ์ถœ @Query ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด์„œ Repository interface ์— ์ฟผ๋ฆฌ ์ง์ ‘ ์ •์˜ Method ์ด๋ฆ„์œผ๋กœ Query ์ƒ์„ฑ ๋ฉ”์†Œ๋“œ ์ด๋ฆ„์„ ๋ถ„์„ํ•ด์„œ JPQL ์ฟผ๋ฆฌ ์‹คํ–‰ ์˜ˆ) ์ด๋ฆ„๊ณผ ๋‚˜์ด๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํšŒ์›์„ ์กฐํšŒํ•˜๋ ค๋ฉด ? // ์ˆœ์ˆ˜ JPA Repository public List findByUsernameAndAgeGreaterThan(String username, int age) { return em.createQuery("select m from Member m where m.username = :us..

    Spring Boot :: Spring Data ํŒจํ‚ค์ง€ ๊ตฌ์กฐ

    Spring Boot :: Spring Data ํŒจํ‚ค์ง€ ๊ตฌ์กฐ

    Spring Data JPA ๋ฅผ ํ™œ์šฉํ•ด์„œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ JpaRepository ๋ฅผ ์ƒ์†๋ฐ›์•„์„œ ์‚ฌ์šฉํ•œ๋‹ค. ์ด JpaRepository ์•ˆ์— ๋“ค์–ด๊ฐ€๋ฉด ๋˜ ๋‹ค๋ฅธ Repository ๋ฅผ ์ƒ์†๋ฐ›๊ณ  ๋˜ ์ƒ์†๋ฐ›๊ณ  ,, ์ด ๊ตฌ์กฐ์— ๋Œ€ํ•ด์„œ ๊ธฐ๋กํ•ด๋‘๊ณ ์ž ํ•œ๋‹ค. ์ธํ„ฐํŽ˜์ด์Šค ์‚ดํŽด๋ณด๊ธฐ ๋จผ์ € MemberRepository ๋ผ๋Š” ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์•˜๋‹ค. public interface MemberRepository extends JpaRepository { } ์—ฌ๊ธฐ์„œ JpaRepository ์•ˆ์— ๋“ค์–ด๊ฐ€๋ณด์ž. ํŒจํ‚ค์ง€ ์œ„์น˜๋Š” org.springframework.data.jpa.repository ์ด๋‹ค. JpaRepository ๋Š” PagingAndSortingRepository ๋ฅผ ์ƒ์†๋ฐ›๊ณ  ์žˆ๊ณ , PagingAndSort..

    Spring Boot :: Spring Data JPA

    Spring Boot :: Spring Data JPA

    ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ์ •์˜ํ•ด๋„ CRUD ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค ? ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด์„œ CRUD ๊ธฐ๋Šฅ์ด ๋™์ž‘ํ•˜๋Š”์ง€ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ…Œ์ŠคํŠธํ•ด๋ณด์ž. ํ…Œ์ŠคํŠธ ์ˆœ์„œ Entity ์ƒ์„ฑ ์ˆœ์ˆ˜ JPA Repository ์ƒ์„ฑ ํ›„ ํ…Œ์ŠคํŠธ Data JPA Repository ์ƒ์„ฑ ํ›„ ํ…Œ์ŠคํŠธ Entity ์ƒ์„ฑ ๋จผ์ € Member Entity ๋ฅผ ๋งŒ๋“ค์ž. @Entity @Getter @Setter @NoArgsConstructor(access = AccessLevel.PROTECTED) @ToString(of = {"id", "username"}) public class Member { @Id @GeneratedValue @Column(name = "member_id") private Long id; private String usernam..