https://magicmk.tistory.com/25
전편에 이은 회원 이메일 중복 체크 및 유효성 검사 편이다.
프로젝트를 완성하고 글을 작성하는 게 아니라 만들면서 까먹지 않도록 작성하는 거라
이전 편에 작성했던 코드들이 변경되는 것도 있고 밑에 코드를 추가할 때 너무 길어지지 않도록 기존에 작성한
코드는 제거할 거고 순서가 뒤죽박죽이지만 기록용이니 이해를 바란다. 😊
우선 유효성 검사를 위해 build.gradle에 라이브러리를 하나 추가한다.
🛑build.gradle
implementation 'org.springframework.boot:spring-boot-starter-validation'
spring boot 2.3 버전 이전까지는 spring-boot-starer-web 의존성 내부에 있던 녀석이 사라져 버려서
이제는 따로 추가해줘야 한다. 본인 spring boot 버전이 2.3 밑이라면 추가하지 않아도 된다.
그리고 유효성 검사를 위해 이전 시간에 작성했던 DTO를 변경했다.
🛑MemberSaveRequestDTO
package com.practice.board.dto;
import lombok.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MemberSaveRequestDTO {
@NotBlank(message="이메일을 입력해주세요.")
@Email(message = "올바른 이메일 주소를 입력해주세요.")
private String email;
@NotBlank(message = "닉네임을 입력해주세요.")
@Size(min = 2, max = 15, message = "닉네임은 2 ~ 15자 사이로 입력해주세요")
private String username;
@NotBlank(message = "비밀번호를 입력해주세요.")
private String password;
}
DTO 이름도 변경됐다.
validation을 이용하면 패턴을 등록하거나 다양한 설정을 할 수 있다.
그리고 repository에서 email의 존재 여부를 확인할 수 있도록
🛑MemberRepository
package com.practice.board.repository;
import com.practice.board.domain.Member;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface MemberRepository extends JpaRepository<Member, Long> {
/**
* 유효성 검사 - 중복 체크
* @param email 회원 이메일
* @return
*/
boolean existsByEmail(String email);
}
existsByEmail을 추가해주었다.
여기까지 진행했다면 이제 Validator를 직접 작성해야 한다.
🛑AbstractValidator
package com.practice.board.validator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
@Slf4j
public abstract class AbstractValidator<T> implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return true;
}
@SuppressWarnings("unchecked")
@Override
public void validate(Object target, Errors errors) {
try {
doValidate((T) target, errors);
} catch(RuntimeException e) {
log.error("중복 검증 에러", e);
throw e;
}
}
protected abstract void doValidate(final T dto, final Errors errors);
}
위 내용을 상속받는 CheckEmailValidator를 작성한다.
🛑CheckEmailValidator
package com.practice.board.validator;
import com.practice.board.dto.MemberSaveRequestDTO;
import com.practice.board.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
@Component
@RequiredArgsConstructor
public class CheckEmailValidator extends AbstractValidator<MemberSaveRequestDTO> {
private final MemberRepository memberRepository;
@Override
protected void doValidate(MemberSaveRequestDTO dto, Errors errors) {
if(memberRepository.existsByEmail(dto.getEmail())) {
errors.rejectValue("email", "이메일 중복 오류", "이미 사용중인 이메일 입니다.");
}
}
}
나는 이메일 중복 여부만 따질 것이기 때문에 이메일만 적용하였지만 원하는 분들은 다른 것들을 더 설정하면 좋다.
이제 Service와 Controller만 추가해주면 된다.
🛑MemberService
package com.practice.board.service;
import com.practice.board.dto.MemberSaveRequestDTO;
import com.practice.board.dto.MemberResponseDTO;
import org.springframework.validation.Errors;
import java.util.List;
import java.util.Map;
public interface MemberService {
/**
* 회원가입 시, 유효성 및 중복 검사
* @param errors
* @return
*/
Map<String, String> validateHandling(Errors errors);
}
🛑MemberServiceImpl
package com.practice.board.service.Impl;
import com.practice.board.domain.Member;
import com.practice.board.dto.MemberSaveRequestDTO;
import com.practice.board.dto.MemberResponseDTO;
import com.practice.board.repository.MemberRepository;
import com.practice.board.service.MemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
@RequiredArgsConstructor
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository;
private final PasswordEncoder passwordEncoder;
/* 회원가입 시, 유효성 및 중복 검사 */
@Transactional(readOnly = true)
@Override
public Map<String, String> validateHandling(Errors errors) {
Map<String, String> validatorResult = new HashMap<>();
/* 유효성 및 중복 검사에 실패한 필드 목록을 받음 */
for (FieldError error : errors.getFieldErrors()) {
String validKeyName = String.format("valid_%s", error.getField());
validatorResult.put(validKeyName, error.getDefaultMessage());
}
return validatorResult;
}
}
🛑MemberController
package com.practice.board.controller;
import com.practice.board.dto.MemberResponseDTO;
import com.practice.board.dto.MemberSaveRequestDTO;
import com.practice.board.service.MemberService;
import com.practice.board.validator.CheckEmailValidator;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PostMapping;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
@Controller
@RequiredArgsConstructor
@Slf4j
public class MemberController {
private final MemberService memberService;
private final CheckEmailValidator checkEmailValidator;
/* 유효성 검증 */
@InitBinder
public void validatorBinder(WebDataBinder binder) {
binder.addValidators(checkEmailValidator);
}
/**
* 회원 가입 post
* @param memberSaveRequestDTO 회원 정보
* @return 홈페이지
*/
@PostMapping("/members/new")
public String createMember(@Valid MemberSaveRequestDTO memberSaveRequestDTO, Errors errors, Model model) {
/* 검증 */
if (errors.hasErrors()) {
/* 회원가입 실패 시 입력 데이터 유지 */
model.addAttribute("dto", memberSaveRequestDTO);
/* 유효성 검사를 통과하지 못한 필드와 메세지 핸들링 */
Map<String, String> validatorResult = memberService.validateHandling(errors);
for (String key : validatorResult.keySet()) {
model.addAttribute(key, validatorResult.get(key));
}
/* 회원가입 페이지로 리턴 */
return "/members/createMemberForm";
}
Long memberId = memberService.join(memberSaveRequestDTO);
return "home";
}
}
현재 controller에 model.addAttribute를 통해 데이터를 전달하는데 HTML은 mustache나 thymeleaf나
원하는 템플릿을 사용해서 멋있게 출력하면 된다.
끝.
'Java > Spring Boot 게시판' 카테고리의 다른 글
spring boot 게시판 - 6 <bootstrap 적용하기> (0) | 2022.11.22 |
---|---|
spring boot 게시판 - 5 <thymeleaf layout 적용> (0) | 2022.11.21 |
spring boot 게시판 - 4 <spring security form login 구현> (0) | 2022.11.18 |
spring boot 게시판 - 3 <패스워드 암호화, 회원 목록 조회> (0) | 2022.11.11 |
Spring boot 게시판 - 1 < 간단 회원 가입 구현> (8) | 2022.11.10 |