๐Ÿš€chaper 4 ) ๊ณผ์ œ ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ… / TIL day 35

ํ•˜๋ฆฌ๋น„ยท2025๋…„ 4์›” 21์ผ
1

๐Ÿ“ TIL

๋ชฉ๋ก ๋ณด๊ธฐ
10/11
post-thumbnail

๐Ÿ“– ๊ณผ์ œ ๊ฐœ์š”


์ด๋ฒˆ ๊ฐœ์ธ ๊ณผ์ œ๋Š” ์˜ˆ์ œ๋ฅผ ๊ฐ€์ ธ์™€
์ฝ”๋“œ๋ฅผ ๊ฐœ์„ ํ•˜๊ณ , ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๋ณด๊ณ , ๋ฆฌํŒฉํ„ฐ๋ง ํ•ด๋ณด๋Š” ๊ณผ์ œ์˜€๋‹ค

โœ”๏ธ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ

  • Java: 17
  • JDK: 17.0.1
  • IDE: IntelliJ
  • Spring Frame Work : 3.4.4
  • API ํ…Œ์ŠคํŠธ ๋„๊ตฌ : postman

๐ŸŒŸ Git Hub ๋งํฌ



๐Ÿ“– ์ฝ”๋“œ ๋ฆฌ๋ทฐ


๐Ÿ“Œ [Lv 1] ์ฝ”๋“œ ๊ฐœ์„ ํ•˜๊ธฐ

โœ… 1. Early Return

    @Transactional
    public SignupResponse signup(SignupRequest signupRequest) {

       if (userRepository.existsByEmail(signupRequest.getEmail())) {
            throw new InvalidRequestException("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ์ด๋ฉ”์ผ์ž…๋‹ˆ๋‹ค.");
        } // ๐Ÿ’ก ์ˆ˜์ •ํ•œ ์œ„์น˜

        String encodedPassword = passwordEncoder.encode(signupRequest.getPassword());
      
        //if (userRepository.existsByEmail(signupRequest.getEmail())) {
        //   throw new InvalidRequestException("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ์ด๋ฉ”์ผ์ž…๋‹ˆ๋‹ค.");
        //} ๊ธฐ์กด ์œ„์น˜
       
        UserRole userRole = UserRole.of(signupRequest.getUserRole());

		...

โœ”๏ธ ๋ฐฐ์šด์ 

  • ๋ถˆํ•„์š”ํ•œ ๋กœ์ง ์‹คํ–‰์„ ์ค„์ด๊ณ , ์ฝ”๋“œ ๊ฐ€๋…์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค
  • ํŠนํžˆ passwordEncoder.encode()์™€ ๊ฐ™์€ ํฐ ์—ฐ์‚ฐ์„ ์ค„์ผ ์ˆ˜ ์žˆ์–ด ํšจ์œจ์ ์ด๋‹ค

โœ… 2. ๋ถˆํ•„์š”ํ•œ if-else๋ฌธ ์ค„์—ฌ ๋ฆฌํŒฉํ† ๋ง

if (!HttpStatus.OK.equals(responseEntity.getStatusCode())) {
    throw new ServerException("๋‚ ์”จ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š”๋ฐ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ์ƒํƒœ ์ฝ”๋“œ: " + responseEntity.getStatusCode());

if (weatherArray == null || weatherArray.length == 0) {
    throw new ServerException("๋‚ ์”จ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.");
    }
}

โœ”๏ธ ๋ฐฐ์šด์ 

  • ๋ถˆํ•„์š”ํ•œ else๋‚˜ ์ค‘์ฒฉ์„ ์ค„์ด์ž

โœ… 3. Validation

UserService ํด๋ž˜์Šค

if (userChangePasswordRequest.getNewPassword().length() < 8 ||
        !userChangePasswordRequest.getNewPassword().matches(".*\\d.*") ||
        !userChangePasswordRequest.getNewPassword().matches(".*[A-Z].*")) {
    throw new InvalidRequestException("์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” 8์ž ์ด์ƒ์ด์–ด์•ผ ํ•˜๊ณ , ์ˆซ์ž์™€ ๋Œ€๋ฌธ์ž๋ฅผ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.");
}

UserChangePasswordRequest ํด๋ž˜์Šค

 @NotBlank
    @Pattern(regexp = "^(?=.*[0-9])(?=.*[A-Z])[A-Za-z\\d]{9,}$", message = "์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” 8์ž ์ด์ƒ์ด์–ด์•ผ ํ•˜๊ณ , ์ˆซ์ž์™€ ๋Œ€๋ฌธ์ž๋ฅผ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.")
    private String newPassword;

โœ”๏ธ ๋ฐฐ์šด์ 

  • ์ •๊ทœ์‹ ์“ฐ๋Š” ๊ฒƒ์ด ์–ด๋ ค์› ๋‹ค. ๊ธฐ์กด์— ์žˆ๋Š” ํด๋ž˜์Šค,๋ฉ”์„œ๋“œ๋“ค์„ ์ž˜ ํ™œ์šฉํ•˜์ž


๐Ÿ“Œ [Lv 2] N+1 ๋ฌธ์ œ

โœ… N+1์„ ๋ฐฉ์ง€ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ฐพ๊ณ , @EntityGraph ๊ธฐ๋ฐ˜ ๊ตฌํ˜„์œผ๋กœ ์ˆ˜์ •

๊ธฐ์กดfetch join์„ ์‚ฌ์šฉํ•ด ์—ฐ๊ด€๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฆ‰์‹œ ๋กœ๋”ฉ
์ˆ˜์ •JPA์˜ @EntityGraph๋กœ ๋ฆฌํŒฉํ† ๋ง

๐Ÿ“Œ [Lv 3] ํ…Œ์ŠคํŠธ์ฝ”๋“œ ์—ฐ์Šต

โœ… 1. ์„ฑ๊ณต ์ผ€์ด์Šค

โœ”๏ธ ๋ฌธ์ œ


โœ”๏ธ ํ•ด๊ฒฐ

  • passwordEncoder.matches()
  • ํ•ด์‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋น„๊ตํ• ๋•Œ๋Š” ๋น„๊ต ๋Œ€์ƒ์ด ์•ž์—, ํ•ด์‹ฑ๋œ ์•”ํ˜ธ๊ฐ€ ๋’ค์— ์™€์•ผํ•œ๋‹ค

โœ… 2. ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์„ฑ๊ณต ์ผ€์ด์Šค

โœ”๏ธ ๋ฌธ์ œโœ”๏ธ ํ•ด๊ฒฐ
1
2
3
  • ์•Œ๋งž์€ Exception์œผ๋กœ ๋ณ€๊ฒฝํ•ด ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์‹คํ–‰์‹œ ์„ฑ๊ณตํ•˜๋„๋ก ์ˆ˜์ •ํ–ˆ๋‹ค

๐Ÿ“Œ Level 4. API ๋กœ๊น…

Interceptor์™€ AOP๋ฅผ ํ™œ์šฉํ•œ API ๋กœ๊น…

์–‘์ด ๋ฐฉ๋Œ€ํ•ด์„œ ๋”ฐ๋กœ ์ผ๋‹ค..๐Ÿคฏ

โœ… Interceptor ์‚ฌ์šฉ

  • Interceptor๋ฅผ ์‚ฌ์šฉํ•ด ์š”์ฒญ ์ •๋ณด ์‚ฌ์ „ ์ฒ˜๋ฆฌ
  • ์ธ์ฆ ์„ฑ๊ณต ์‹œ, ์š”์ฒญ ์‹œ๊ฐ๊ณผ URL์„ ๋กœ๊น…
  • ์–ด๋“œ๋ฏผ ์ธ์ฆ ์—ฌ๋ถ€ ํ™•์ธ

โœ”๏ธ ์ž‘์„ฑํ•œ ์ฝ”๋“œ


โœ… AOP ์‚ฌ์šฉ

  • @Around๋ฅผ ์‚ฌ์šฉํ•ด ์–ด๋“œ๋ฏผ API ์‹คํ–‰ ์ „ํ›„์— ๋กœ๊น…
  • ๋กœ๊น… ๋‚ด์šฉ: ์š”์ฒญํ•œ ์‚ฌ์šฉ์ž ID, API ์š”์ฒญ ์‹œ๊ฐ, ์š”์ฒญ URL, ์š”์ฒญ ๋ณธ๋ฌธ (RequestBody), ์‘๋‹ต ๋ณธ๋ฌธ (ResponseBody)
  • ์š”์ฒญ/์‘๋‹ต ๋ฐ”๋””๋Š” JSON ํ˜•ํƒœ๋กœ ๊ธฐ๋ก
  • Logger ํด๋ž˜์Šค ํ™œ์šฉ

โœ”๏ธ ์–ด๋ ค์› ๋˜์  + ๋ฐฐ์šด์ 

  1. ๋ณธ๋ฌธ์„ JSON์œผ๋กœ ๋ถˆ๋Ÿฌ์˜ฌ ๊ฒƒ
    • request.getInputStream() ๋“ฑ์œผ๋กœ๋Š” ํ•œ ๋ฒˆ๋งŒ ์ฝ์„ ์ˆ˜ ์žˆ์Œ
    • Tomcat์ด ๋จผ์ € ์ฝ์œผ๋ฉด ๋ฐ”๋””๋Š” null๋กœ ๋‚˜์˜ด
    • ํ•ด๊ฒฐ์ฑ…: ContentCachingRequestWrapper๋ฅผ ํ•„ํ„ฐ๋กœ ๊ฐ์‹ธ ์š”์ฒญ ๋ฐ”๋””๋ฅผ ์บ์‹ฑ
  1. ์™œ ํ•„ํ„ฐ๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋Š”๊ฐ€?
    • AOP๋‚˜ ์ผ๋ฐ˜ ํด๋ž˜์Šค์—์„œ๋Š” ์ด๋ฏธ Tomcat์ด ์ฝ์€ ๋’ค๋ผ ๊ฐ์‹ธ๋„ ๋ฌด์šฉ์ง€๋ฌผ
    • ํ•„ํ„ฐ๋กœ ๊ฐ€์žฅ ๋จผ์ € ์š”์ฒญ์„ ๊ฐ€๋กœ์ฑ„๊ณ  ๊ฐ์‹ธ์•ผ ์ดํ›„ AOP์—์„œ ๊บผ๋‚ด ์ฝ์„ ์ˆ˜ ์žˆ์Œ
    • ๊ทธ๋ž˜์„œ OncePerRequestFilter๋ฅผ ๊ตฌํ˜„ํ•œ ํ•„ํ„ฐ๋กœ ์ง์ ‘ ๊ฐ์Œˆ
  1. ์บ์‹ฑํ•ด์„œ ๊ฐ์‹ธ์ ธ ์žˆ๋Š”์ง€ instanceof๋กœ ํ™•์ธ
    • request๊ฐ€ ๋‚ด๊ฐ€ ๊ฐ์‹ผ ContentCachingRequestWrapper ๊ฐ์ฒด์ธ์ง€ ์ฒดํฌํ•ด์•ผ ํ•จ
    • ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด getContentAsByteArray() ํ˜ธ์ถœ ์ž์ฒด๊ฐ€ ๋ถˆ๊ฐ€๋Šฅ
    • instanceof ๊ฒ€์‚ฌ ํ›„ โ†’ ๋ฐ”์ดํŠธ ๋ฐฐ์—ด โ†’ ๋ฌธ์ž์—ด ๋ณ€ํ™˜ โ†’ ๋กœ๊น…

๐Ÿ“– ๋‚˜์˜ ํšŒ๊ณ 

  • ํ•„์ˆ˜๋‹จ๊ณ„๋งŒ ์ฐฉ์‹คํžˆ ํ•˜๋˜ ๋‚˜์—๊ฒŒ ์‰ฌ์–ด๊ฐ€๋Š” ๋А๋‚Œ์˜ ์ด๋ฒˆ ํ•„์ˆ˜ ๋‹จ๊ณ„๋“ค..
    ๋•๋ถ„์— ์‹œ๊ฐ„์ด ๋‚จ์•„์„œ ๋„์ „๋‹จ๊ณ„๊นŒ์ง€ ํ•ด๋ณด๊ฒŒ ๋˜์—ˆ๋Š”๋ฐ..! ์ •๋ง ์˜ค๋ž˜ ๊ฑธ๋ ธ๋‹ค..^^
  • ์ผ๋‹จ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋ฅผ ๋ณด๋Š”๊ฒŒ ์–ผ๋งˆ๋‚˜ ํž˜๋“ ์ง€ ๊นจ๋‹ฌ์•˜๋‹ค.
    ์ง€๊ธˆ ๊ฐ•์˜ ์ˆ˜์ค€์— ๋งž์ถฐ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋ฅผ ์ฃผ์‹ ๊ฑธ ํ…๋ฐ๋„ ๋‚ด๊ฐ€ ์ž‘์„ฑํ•œ๊ฒŒ ์•„๋‹ˆ๋‹ค๋ณด๋‹ˆ ์–ด๋ ค์› ๋‹ค
  • API ๋ช…์„ธ์„œ์˜ ์ค‘์š”์„ฑ์„ ๊นจ๋‹ฌ์•˜๋‹ค
    ๋ ˆ๋ฒจ 4 ๊ตฌํ˜„์„ ์œ„ํ•ด ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๊ฐ€ ์•„๋‹Œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด๋ฅผ ์‹คํ–‰ํ•˜๋Š”๋ฐ..
    ์š”์ฒญ์‹œ ๋ญ๊ฐ€ ๋“ค์–ด๊ฐ€์•ผํ•˜๋Š”์ง€ Path๊ฐ€ ๋ญ”์ง€ ์ปจํŠธ๋กค๋Ÿฌ DTO ๋‹ค ๋ˆŒ๋Ÿฌ๋ณด๊ณ  ํ•˜๋‚˜์”ฉ ํ™•์ธํ•˜๋ฉฐ ํ…Œ์ŠคํŠธํ–ˆ๋‹ค
    ๋‚˜๋„ ์ด๋Ÿฐ๋ฐ ์ •๋ง ์—”์ง€๋‹ˆ์–ด๊ฐ€ ์•„๋‹Œ ํŒ€๊ณผ ํ˜‘์—…ํ•ด์•ผ ํ•œ๋‹ค๋ฉด? API ๋ช…์„ธ์„œ๋Š” ์ƒ์„ธํ•  ์ˆ˜๋ก ์ข‹์€๊ฑฐ๊ตฌ๋‚˜~
  • AOP๋ฅผ ์•Œ๊ฒŒ๋˜๊ณ  ์žฌ๋ฐŒ์–ด์„œ(?) ํ™€๋ฆฐ ๋“ฏ ๋ธ”๋กœ๊ทธ๋ฅผ ๋’ค์ง€๋ฉฐ ๋”ฐ๋ผํ•ด๋ดค๋‹ค..
    ๋ชจ๋“ ๊ณณ์— ๊ณตํ†ต์œผ๋กœ ์ ์šฉํ•ด์•ผํ•  ์ž‘์—…์ด๋ผ๋˜์ง€ ์ด๋Ÿฐ ๋ถ€๋ถ„๋“ค์„ ๋‚ด๊ฐ€ ์ปค์Šคํ…€ํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค
  • ์ด๋ฒˆ์—๋„ ์‹œ๊ฐ„์„ ์ž˜ ๋ถ„๋ฐฐํ•˜์ง€ ๋ชปํ–ˆ๋‹ค. ๋‚ด๊ฐ€ ๊ฒŒ์œผ๋ฅด๊ณ  ๋А๋ฆฐ๊ฑธ๊นŒ ์•„๋‹˜ ํ• ์ผ์ด ๋„ˆ๋ฌด ๋งŽ์€๊ฑธ๊นŒ?
    ์—ฌ๊ธฐ๊นŒ์ง€ ์˜ค๋‹ˆ ์ค‘๊ฐ„์— ํ•˜์ฐจํ•˜์‹  ๋ถ„๋“ค์ด ๊ฝค ๋ณด์ด๋Š”๋ฐ.. ์ž ๊น์”ฉ ๋ถ€๋Ÿฝ๊ธฐ๋„ ํ–ˆ๋‹ค
    ์ด๋Ÿฐ ์ƒ๊ฐํ•˜์ง€ ์•Š๋„๋ก ๊พธ์ค€ํ•˜๊ฒŒ ์—ด์‹ฌํžˆ ํ•˜์ž !

1๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2025๋…„ 4์›” 21์ผ

๊ธ€์—์„œ ๋‹ค๊ธ‰ํ•จ์ด ๋А๊ปด์ง€๋„ค์š”

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ