Learned/Spring
Spring Boot ์ธ๋ถ API ํ ์คํธ ์ฝ๋๋ฅผ ์ง๋ณด์! [MockWebServer vs WireMock]
โ Mock ์๋ฒ๋ฅผ ์ฌ์ฉํ๋ ์ด์ Spring Boot Github ์์ ๋ก๊ทธ์ธ ๊ตฌํํ๊ธฐ [ RestTemplate · WebClient · FeignClient ๋ฅผ ๋น๊ตํด๋ณด์ ] Github OAuth ์ธ์ฆ ํ๋ฆ๊ณผ ์ฌ์ ์ค๋น Github ์ธ์ฆ ํ๋ฆ์ ๋ค์๊ณผ ๊ฐ๋ค. 1. https://github.com/login/oauth/authorize?client_id={๋ฐ๊ธ๋ฐ์ client_id} ๋ก ์ด๋ํ๋ ๋งํฌ๋ฅผ ์ฌ์ฉ์๊ฐ ํด๋ฆญํ๋ค. 2. ์ฌ์ฉ์๋ ์๋์ ๊ฐ์ ํ yinq.tistory.com REST API ์์ฒญ์ ํ ์ ์๋๋ก ํ๋ RestTemplate · WebClient · FeignClient ํด๋์ค๋ฅผ ํ์ฉํ์ฌ ์ธ๋ถ API ์์ฒญ์ ํตํด ๊ธฐ๋ฅ์ ๊ตฌํํ์๋ค. ํ ์คํธ ์ฝ๋๋ฅผ ์ง๊ธฐ ์ํ ๋ฐฉ๋ฒ์ ์ฐพ์๋ณด๋, ..
Spring Boot Github ์์ ๋ก๊ทธ์ธ ๊ตฌํํ๊ธฐ [ RestTemplate · WebClient · FeignClient ๋ฅผ ๋น๊ตํด๋ณด์ ]
Github OAuth ์ธ์ฆ ํ๋ฆ๊ณผ ์ฌ์ ์ค๋น Github ์ธ์ฆ ํ๋ฆ์ ๋ค์๊ณผ ๊ฐ๋ค. 1. https://github.com/login/oauth/authorize?client_id={๋ฐ๊ธ๋ฐ์ client_id} ๋ก ์ด๋ํ๋ ๋งํฌ๋ฅผ ์ฌ์ฉ์๊ฐ ํด๋ฆญํ๋ค. 2. ์ฌ์ฉ์๋ ์๋์ ๊ฐ์ ํ๋ฉด์ด ๋ํ๋๋ ํ๋ฉด์ผ๋ก ์ด๋ํ๊ณ , Github ์ธ์ฆ์ ํ๋ค. 3. ์ธ์ฆ์ ์ฑ๊ณตํ๋ฉด {์ค์ ํ ์ฝ๋ฐฑ URL}?code={์ธ์ฆ์ฝ๋} ๋ก code ๊ฐ์ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ ํํ๋ก ๋ณด๋ด์ค๋ค. 4. ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌ๋ code๋ฅผ ์๋ฒ์์ ๋ฐ๊ณ , https://github.com/login/oauth/access_token ์ผ๋ก {client_ID, client_Secret, code}๋ฅผ ๋ด์ POST ์์ฒญ์ ํ๋ค. 5. ๊นํ๋ธ ์ธก์์ acc..
Dispatcher Servlet์ ์ด๋ป๊ฒ ๋์ํ ๊น?
DispatcherServlet ์ Servlet ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ, HTTP ํ๋กํ ์ฝ๋ก ๋ค์ด์ค๋ ๋ชจ๋ ์์ฒญ์ ๋จผ์ ๋ฐ์ ์ฒ๋ฆฌํ๋ Front Controller ์ด๋ค. Servlet ์ด๋? Java ์ธ์ด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก, ํด๋ผ์ด์ธํธ๊ฐ ๋ณด๋ด๋ HTTP ์์ฒญ์ ์ฒ๋ฆฌํ๊ณ ์๋ตํ๋ ์ญํ ์ ๋ด๋นํ๋ ์ธํฐํ์ด์ค ์ด๋ค. public interface Servlet { void init(ServletConfig config) throws ServletException; ServletConfig getServletConfig(); void service(ServletRequest req, ServletResponse res) throws ServletException, IOException; String getServlet..
Swagger API ์ ์ฉ ์, Controller ์ฝ๋๊ฐ ๋๋ฌด ๋๋ฌ์์ง๋ค.. ๋ถ๋ฆฌํด๋ณด์
Swagger ๋ฅผ ์ฌ์ฉํ๋ฉด, API ๋ฌธ์๋ฅผ ์๋์ผ๋ก ๊ตฌ์ฑํด์ฃผ๋ฉฐ ์๋ํฌ์ธํธ๋ฅผ ํ ์คํธ ํ ์ ์๋ค๋ ์ฅ์ ์ด ์๋ค. @Tag , @Operation , @ApiResponses ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ๋ฉด ์ค์จ๊ฑฐ ๋ฌธ์์ ๋ถ๊ฐ์ ์ธ ์ค๋ช ์ ์ถ๊ฐ์ ์ผ๋ก ๋ฃ์ ์ ์์ด์ API ๋ฌธ์๋ฅผ ์ดํดํ๋๋ฐ ๋์์ ์ค ์ ์๋ค. @RestController @RequestMapping("/api/v1/posts") @RequiredArgsConstructor public class PostApiController { private final PostService postService; @Tag(name = "Post", description = "๊ฒ์๊ธ ๊ด๋ จ API") @Operation(summary = "๊ฒ์๊ธ ์กฐํ", descrip..
Dto Validation ์์ธ ์ฒ๋ฆฌ์ AOP๋ฅผ ์ ์ฉํด๋ณด์!
๊ธฐ์กด ๋ฐฉ์ implementation 'org.springframework.boot:spring-boot-starter-validation' ์ validation ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ฉด Controller ์์ @RequestBody ์ด๋ ธํ ์ด์ ์ผ๋ก ๋งคํํ๋ Request Dto ์ ํ๋ ์ ํจ์ฑ์ ๊ฒ์ฌํ ์ ์๋ค. public class UserCreateRequest { @Email(message = "์ฌ๋ฐ๋ฅธ ์ด๋ฉ์ผ ํ์์ด ์๋๋๋ค. '@' ๋ฅผ ํฌํจ์์ผ์ฃผ์ธ์.") private String email; @Length(min = 8,message = "๋น๋ฐ๋ฒํธ๋ ์ต์ 8์ ์ด์์ ๋๋ค.") private String password; } ์์ ๊ฐ์ด ๋งคํ๋๋ ํ๋์ validation์์ ์ ๊ณตํ๋ ์ด๋ ธํ ์ด์ ์..
ํ ์คํธ ์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง ๋ถ์ ๋๊ตฌ Jacoco๋ฅผ ์ ์ฉํด๋ณด์!
Jacoco ๋? Java Code Coverage ์ ์ค์๋ง๋ก, ์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง ๋ถ์์ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค. โ ์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง๋? ์ํํธ์จ์ด์ ํ ์คํธ ์ผ์ด์ค๊ฐ ์ผ๋ง๋ ์ถฉ์กฑ๋์๋์ง๋ฅผ ๋ํ๋ด๋ ์งํ ์ค ํ๋์ด๋ค. 1. ๋ผ์ธ ์ปค๋ฒ๋ฆฌ์ง : ์ฝ๋ ํ ์ค์ด ํ ๋ฒ ์ด์ ์คํ๋๋ค๋ฉด ์ถฉ์กฑ๋๋ค. 2. ๊ฒฐ์ ์ปค๋ฒ๋ฆฌ์ง : ๋ธ๋์น ์ปค๋ฒ๋ฆฌ์ง๋ผ๊ณ ๋ ๋ถ๋ฆฐ๋ค. ๋ชจ๋ ์กฐ๊ฑด์์ ๋ด๋ถ ์กฐ๊ฑด์ด true/ false ๋ฅผ ๊ฐ์ง๊ฒ ๋๋ฉด ์ถฉ์กฑํ๋ค. 3. ์กฐ๊ฑด ์ปค๋ฒ๋ฆฌ์ง : if ์กฐ๊ฑด๋ฌธ ์์ ๊ฐ๋ณ ์กฐ๊ฑด์์ด false ์ธ๊ฒฝ์ฐ์ true์ธ ๊ฒฝ์ฐ ๋ชจ๋ ์คํ๋์์ ๋ ์ถฉ์กฑํ๋ค. ๊ฒฐ์ ์ปค๋ฒ๋ฆฌ์ง๋ณด๋ค ๋ detailํ ์ปค๋ฒ๋ฆฌ์ง์ด๋ค. ์ ์ฉํด๋ณด์ ์ ์ฉ ์ build.gradle plugins { id 'java' id 'org.springframework.boot'..
@ControllerAdvice ๋ ์ด๋ป๊ฒ ๋์ํ๋ ๊ฒ์ผ๊น?
๐ ์์ธ ์ฒ๋ฆฌ ๋ฐฉ์ ํ๋ก์ ํธ๋ฅผ ์งํํ๋ฉด์, ๋ด๊ฐ ์ฃผ๋ก ํ๋ ์์ธ์ฒ๋ฆฌ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ๋ค. Enum ํ์ ์ ErrorCode ์ ์ @AllArgsConstructor @Getter public enum ErrorCode { DUPLICATE_USERNAME(HttpStatus.CONFLICT, "์ด๋ฏธ ์กด์ฌํ๋ ์ฌ์ฉ์๋ช ์ ๋๋ค."); private HttpStatus httpStatus; private String message; } Http ์ํ ์ฝ๋์ ์๋ฌ ๋ฐ์ ์ ์ ๋ฌํ ๋ฉ์ธ์ง ์ ๋ณด๊ฐ ๋ด๊ธด Enum ํ์ ์ ErrorCode ๋ฅผ ์ ์ํ๋ค. RuntimeException ์ ์์ํ๋ AppException์ ์ ์ @Getter public class AppException extends RuntimeExc..