๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Spring

Validation์œผ๋กœ ์š”์ฒญ ๊ฐ’ ๊ฒ€์ฆ

Validation์œผ๋กœ ์š”์ฒญ ๊ฐ’ ๊ฒ€์ฆ

ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์š”์ฒญ ๊ฐ’์„ ๋ณด๋‚ผ ๋•Œ, Validation์„ ์ด์šฉํ•˜์—ฌ ์„œ๋ฒ„์—์„œ ์˜ฌ๋ฐ”๋ฅธ ๊ฐ’์ธ์ง€ ๊ฒ€์ฆํ•ด๋ณด์ž.

์˜์กด์„ฑ ์ถ”๊ฐ€

gradle์„ ์ด์šฉํ•œ๋‹ค๋ฉด build.gradle์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•ด ์ค€๋‹ค.

    compile group: 'javax.validation', name: 'validation-api'
    compile group: 'org.hibernate', name: 'hibernate-validator', version: '6.1.0.Final'

Dto ์ž‘์„ฑ

ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ œ๊ณต๋ฐ›์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•  SignupDto๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•œ๋‹ค.

import lombok.*;
import org.hibernate.validator.constraints.Length;

import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;


@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class SignupDto {

    @NotBlank
    @Length(min=3, max = 20)
    @Pattern(regexp = "^[ใ„ฑ-ใ…Ž๊ฐ€-ํžฃa-zA-Z0-9_-]{3,20}$")
    private String nickname;

    @NotBlank
    @Length(min=8, max= 50)
    private String password;

    @Email
    @NotBlank
    private String email;
}

@NotBlank : ๊ณต๋ฐฑ์„ ๋ฐฉ์ง€ํ•˜๋Š” ์ฃผ์„์ด๋‹ค.

@Length(min=a, max = b) : ์ตœ์†Œ a, ์ตœ๋Œ€ b ๋ฒ”์œ„๋กœ ๊ธธ์ž ๊ธธ์ด๋ฅผ ์ œํ•œํ•œ๋‹ค.

@Pattern(regexp = "") : ์ •๊ทœ ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•˜์—ฌ ๋“ค์–ด์˜ฌ ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ž๋ฅผ ์ œํ•œํ•œ๋‹ค.

์œ„์˜ ์˜ˆ์ œ์—์„  ํ•œ๊ธ€, ์˜์–ด ๋Œ€์†Œ๋ฌธ์ž, ์ˆซ์ž, '_','-'๋ฅผ ํ—ˆ์šฉํ•œ๋‹ค.

@Email : String ํ˜•์‹์˜ ๋ฐ์ดํ„ฐ๊ฐ€ Email ํ˜•์‹์ธ์ง€ ํ™•์ธํ•œ๋‹ค.

์ปจํŠธ๋กค๋Ÿฌ์—์„œ ๊ฒ€์ฆ

ํด๋ผ์ด์–ธํŠธ๊ฐ€ "/sing-up" ๊ฒฝ๋กœ๋กœ Post ์š”์ฒญ์„ ํ†ตํ•ด form์˜ ์ •๋ณด๋ฅผ ๋ณด๋‚ด์ค€๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

    @PostMapping("/sign-up")
    public ResponseEntity<?> singUpRequest(@RequestBody @Valid SignupDto signupDto, Errors errors){
        return accountService.signUp(signupDto, errors);
    }

ํŒŒ๋ผ๋ฏธํ„ฐ์— @Valid๋ฅผ ์„ ์–ธํ•ด์„œ ์š”์ฒญ ๊ฐ’์„ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๊ณ , ๊ฒ€์ฆ ๊ฐ’์ด ์–ด๊ธ‹๋‚˜๋ฉด Errors errors๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

์œ„์˜ ์˜ˆ์ œ์—์„œ๋Š” ์„œ๋น„์Šค ๋ ˆ์ด์–ด์— Errors ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ–ˆ๋‹ค.

Iterator๋กœ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์ถ”์ถœ

์„œ๋น„์Šค์—์„œ ์ „๋‹ฌ๋ฐ›์€ Errors๋ฅผ ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋กœ ๋ฐ˜ํ™˜๋ฐ›์•„ ํ™•์ธํ•ด๋ณด์ž.

   private List<String> validCheck(SignupDto signupDto, Errors errors){
        List<String> errorList = new ArrayList<>();

        Iterator<ObjectError> it = errors.getAllErrors().iterator();
        while(it.hasNext()){
            errorList.add(it.next().getDefaultMessage());
        }

        return errorList;
    }

์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ํ™•์ธํ•ด๋ณด๊ธฐ

๋‹ค์Œ๊ณผ ๊ฐ™์ด Validation์— ์–ด๊ธ‹๋‚˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋ฉด ๊ฐ๊ฐ์˜ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๊ฐ€ ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

Test Code

JUnit5๋กœ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๋ณด์ž.

import com.cadi.team3.domain.Account;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@SpringBootTest
@AutoConfigureMockMvc
class AccountControllerTest {

    private Account createUser() {
        Account account = Account.builder()
                .nickname("testUser")
                .email("testUser@naver.com")
                .password("123456789")
                .role(Role.ROLE_USER)
                .emailVerified(false)
                .build();

        return account;
    }

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;

    @MockBean
    private JavaMailSender javaMailSender;

    @Autowired
    AccountRepository accountRepository;

    @BeforeEach
    public void tearDown() {
        accountRepository.deleteAll();
    }


    @DisplayName("๊ฐ€์ž… Valid ํ™•์ธ #1 - form ๊ฐ’์ด ์ž˜ ๋ชป ๋œ ๊ฒฝ์šฐ")
    @Test
    public void sign_up_form_test1() throws Exception {
        // given
        SignupDto signupDto = SignupDto.builder()
                .nickname("vividswan2131232131232131242145**")
                .password("1234")
                .email("vividswan")
                .build();

        // when
        final ResultActions perform = mockMvc.perform(post("/sign-up")
                .content(objectMapper.writeValueAsString(signupDto))
                .contentType(MediaType.APPLICATION_JSON));

        //then
        perform.andExpect(status().is4xxClientError());
    }

    @DisplayName("๊ฐ€์ž… Valid ํ™•์ธ #2 - ์˜ฌ๋ฐ”๋ฅธ form ๊ฐ’์ธ ๊ฒฝ์šฐ")
    @Test
    public void sign_up_form_test2() throws Exception {
        //given
        SignupDto signupDto = SignupDto.builder()
                .nickname("vividswan")
                .password("1234567890")
                .email("vividswan@naver.com")
                .build();

        //when
        final ResultActions perform = mockMvc.perform(post("/sign-up")
                .content(objectMapper.writeValueAsString(signupDto))
                .contentType(MediaType.APPLICATION_JSON));

        //then
        perform.andExpect(status().is2xxSuccessful());
    }
}


ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๊ฐ€ ํŒจ์Šค๋˜์—ˆ๋‹ค.