JAVA/소박한그룹 프로젝트

[211004] @Validated로 Http 요청 파라미터 검증 작업을 거쳐주자

kth990303 2021. 10. 4. 20:03
반응형

오늘 검증 작업을 열심히 공부하여 아래 사진처럼 결과가 뜨게 작업해주는 하루를 보냈다.

예전에는 비밀번호를 아예 입력하지 않아도,

또는 아이디를 아예 입력하지 않아도 회원가입 버튼을 누르면 회원가입이 완료됐었다.

 

하지만 오늘 작업한 덕분에, 이제 위와 같이 입력폼에서 제대로 입력하지 않았을 경우, 이용자들에게 알림을 띄워주게 할 수 있었다.

 

또한, 아래 작업도 해주었다.

https://github.com/kth990303/BOJStudyList/issues/11

 

게시글 내용이 지나치게 길 경우, 에러가 발생합니다. · Issue #11 · kth990303/BOJStudyList

백준 코드를 복붙하거나, 노래 가사 전문을 입력할 경우 에러가 발생합니다. Data truncation: Data too long for column 'contents' at row 1 이 블로그를 참고하면 될 것 같습니다. https://theleast.tistory.com/42 다만,

github.com

이 내용은 비교적 간단하므로 맨 마지막에 포스팅하겠다.


@Validated를 이용해보자.

먼저, @Valid, @Validated 어떤 것을 이용해도 상관없다.

다만, @Validated는 스프링 전용 어노테이션, @Valid는 자바 표준 어노테이션이며,

@Validated에는 groups이 추가로 존재한다고 하나, 이번 포스팅에선 사용하지 않는다. 따라서 @Valid, @Validated 둘 중 어떤 것을 사용해도 결과는 똑같이 잘 나오므로 원하는 것을 사용하자. 난 @Validated를 사용했다.

 

Http 요청 파라미터 검증 작업이므로 컨트롤러에서 작업할 것이다.

먼저, DTO 형태를 보자.

MemberDTO

@Getter @Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class MemberDto {
    @NotEmpty(message = "이름은 필수입력 대상입니다.")
    private String name;
    @NotEmpty(message = "비밀번호는 필수입력 대상입니다.")
    @Size(min = 2, max = 16, message = "비밀번호는 2자 이상 16자 이하입니다.")
    private String password;
    @NotEmpty(message = "이메일은 필수입력 대상입니다.")
    @Email(message = "이메일 형식으로 입력해주세요.")
    private String email;
    private String tier;

    public MemberDto(String name, String tier, String email, String password){
        this.name=name;
        this.tier=tier;
        this.email=email;
        this.password=password;
    }
}

@NotEmpty: 공백입력, 또는 아무것도 입력하지 않았을 경우 검증

@Email: 이메일 형식이 맞는지 검증해줌. 좀 더 엄밀하게 검증을 원한다면 @Pattern을 이용한 정규식을 이용하자.

@Size(min, max): min자 이상, max자 이하인지 검증해줌. 영어든 한글이든 상관없다.

 

Entity 상에선 API 스펙 변경을 막기 위해 Validation 어노테이션을 붙이지 않았고,

DTO에 위와 같이 어노테이션을 붙여주었다.

 

MemberController

@Controller
@Slf4j
@RequiredArgsConstructor // lombok
public class MemberController {
    private final MemberService memberService;
    
    @PostMapping("/createMemberForm")
    public String create(@Validated @ModelAttribute("member") MemberDto memberDto,
                         BindingResult bindingResult){
        // 잘못된 입력폼 존재할 경우
        if (bindingResult.hasErrors()) {
            log.info("errors={}", bindingResult);
            return "createMemberForm";
        }
        Long memberId = memberService.join(memberDto);
        // 중복회원일 경우 아이디 -1L을 리턴 
        if(memberId==-1L)
            return "error/duplicateErrorPage";
        return "redirect:/";
    }

    @PostMapping("/edit/{id}")
    public String edit(@Validated @ModelAttribute("member") MemberDto memberDto,
                       BindingResult bindingResult, @PathVariable Long id
                       ){
        if(bindingResult.hasErrors()){
            log.info("errors={}", bindingResult);
            return "editMember";
        }
        log.info("MemberName: {}", memberDto.getName());
        memberService.edit(id, memberDto);
        return "redirect:/";
    }
}

변경된 코드만 입력해주었다.

 

bindingResult에 DTO의 검증 어노테이션에 해당되지 않는 입력들을 error로 담겨진다.

만약 잘못 입력된 폼이 여러개라면, 여러 개의 error들이 모두 담긴다.

  • bindingResult.hasErrors() {} 코드: 만약 검증 에러가 존재한다면 [입력폼이 존재하는 html파일]로 이동시킨다.

@Validated를 @ModelAttribute해주는 dto 왼쪽에 붙여주었다. 그리고 바로 오른쪽에 검증 작업을 실행해주는 Errors 인터페이스의 구현체 중 하나인 BindingResult를 붙여주었다.

순서가 굉장히 중요하다. @Validated 위치는 ModelAttribute 바로 왼쪽에, BindingResult는 ModelAttribute 오른쪽에 넣지 않으면 에러가 발생할 것이다.


위와 비슷하게 다른 도메인에 해당하는 DTO, Controller도 잘 바꿔주자.

이제 View에 해당하는 코드들을 고쳐보자.

 

index.css

/*잘못된 정보 입력시 빨간색으로 입력폼을 칠해준다.*/
.field-error {
    border-color: #dc3545;
    color: #dc3545;
}

스프링 김영한님 코드에서 가져왔다.

#dc3545는 빨간색을 의미한다.

즉, 잘못된 정보를 입력했을 경우, 빨간색 문구로 어떤 부분을 잘못 입력했는지, 그리고 잘못 입력한 폼을 빨갛게 칠해준다.

 

createMemberForm.html (일부분)

<tr>
	<td><label th:text="#{member.label.name}" th:for="name">백준 아이디</label></td>
	<td><input type="text" name="name" th:field="${member.name}" th:errorclass="field-error"
		placeholder="(필수)백준 아이디"></td>
	<div class="field-error" th:errors="${member.name}">
		아이디 오류
	</div>
</tr>

th:object, th:field를 이용해야 검증 작업을 thymeleaf로 받을 수 있다.

 

th:errorclass: error가 발생했을경우 지정한 class를 띄워준다. 여기서는 index.css에서 입력했던 빨간색으로 칠해주는 클래스가 뜰 것이다.

th:errors: 필드변수(여기선 member.name) 에러가 있을 경우 띄워준다. 어노테이션에서 지정해준 message가 따로 없거나, messages.properties 파일을 따로 만들어 지정해주지 않았다면 '아이디 오류' 라는 문구가 출력될 것이다.

 

아래 포스팅을 기억하는가? 

https://kth990303.tistory.com/156

 

[Thymeleaf] ERROR _ TemplateProcessingException: which is not valid: only variable expressions (${...}) are allowed in '{the:obj

오랜만에 스프링으로 소박한그룹 프로젝트 작업 중에 회원정보 수정 창에서 아래 화면이 발생했다. org.thymeleaf.exceptions.TemplateProcessingException: The expression used for object selection is..

kth990303.tistory.com

사실 글수정, 회원수정 등의 수정 폼에서 원래 데이터를 받아오는 역할도 있었지만, 검증 작업을 위해서 thymeleaf 코드를 수정한 이유가 컸다.

 

 

editMember.html (일부분)

<td><label th:text="#{member.label.name}" th:for="name">아이디</label></td>
<td><input type="text" name="name" th:value="${member.name}"
	th:field="${member.name}" th:errorclass="field-error" readonly></td>
<div class="field-error" th:errors="${member.name}">
	아이디 오류
</div>

주의할 점은, readonly를 이용해야 데이터가 직접적으로 넘겨진다.

만약 disabled를 이용한다면 데이터가 넘겨지지 않아 bindingresult에 에러가 담길 것이다.

disabled 색깔을 원한다면, th:class로 css를 따로 지정해주자.


Error: Data truncation: Data too long for column 'contents' at row 1 ?

검증 작업도 모두 잘 마쳤고, 한번 실행해보자.

그런데 게시글 입력 폼에 아래와 같이 긴 내용의 글을 입력하면 아래 에러가 뜰 것이다.

Data truncation: Data too long for column 'contents' at row 1

 

후....

사실 이건 예전에 발견한 에러인데 이제야 수정했다. 검증작업을 거칠 때 한번에 수정하려고 했기 때문이다.

https://github.com/kth990303/BOJStudyList/issues/11

 

게시글 내용이 지나치게 길 경우, 에러가 발생합니다. · Issue #11 · kth990303/BOJStudyList

백준 코드를 복붙하거나, 노래 가사 전문을 입력할 경우 에러가 발생합니다. Data truncation: Data too long for column 'contents' at row 1 이 블로그를 참고하면 될 것 같습니다. https://theleast.tistory.com/42 다만,

github.com

 

검증작업을 잘 거쳐도, DB에서 지정해준 타입의 최대 제한 사이즈를 넘어버린 경우이므로,

Entity를 수정해주어야 한다.

@Column(columnDefinition = "LONGTEXT")
private String contents;

위와 같이 LONGTEXT 형태로 수정해주면 65535자까지 끄떡없다고 한다

(다만 실제로는 20000자 정도까지가 한계라 하는데, 어차피 난 2000자로 제한해둘 것이기 때문에 지금은 크게 상관없을 듯하다.)


결과

프로젝트에 존재하는 게시글 입력 폼으로 테스트해보자.

사실 Controller 단에서 테스트하는 것이므로 MockMVC를 생성하고 테스트해야한다.

그러나, Slf4j로 bindingResult를 log.info하거나, 아래처럼 직접 돌려보는 것이 더 빠를 것 같아 직접 실행하면서 테스트해보았다.

 

createMemberForm.html 해당 코드 전체를 입력해보면 아래와 같이 결과가 뜬다.

 

또한, 아래와 같이 2000자는 넘지 않지만, text형 데이터의 제한사이즈는 넘어버리는 경우까지 잘 작동된다.

입력폼에 '볼빨간사춘기-썸탈꺼야' 가사 전체를 입력한 케이스이다.

잘 입력됐음을 확인할 수 있다.

이제 에러처리 페이지 이슈만 처리해주면 기능추가 이슈만 남는다~

열심히 공부하자.

 

프로젝트 github

https://github.com/kth990303/BOJStudyList

 

GitHub - kth990303/BOJStudyList: BOJ 그룹스터디 회원들의 공간을 만들자~

BOJ 그룹스터디 회원들의 공간을 만들자~. Contribute to kth990303/BOJStudyList development by creating an account on GitHub.

github.com

(BE: Spring Boot + JPA / FE: Thymeleaf)

반응형