패스워드 변경
새 패스워드를 두번 다 같은 것을 입력했는지 확인하자. 두개의 값을 가지고 있는 PassworForm을 만든다.
PassworForm.java
package com.goodmoim.settings;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
@Data
public class PasswordForm {
@Length(min = 8, max = 50)
private String newPassword;
@Length(min = 8, max = 50)
private String newPasswordConfirm;
}
이 폼을 Validation 할때 길이를 확인할 수 있게 끔 길이를 설정해준다.
validator 를 만들어보자. 두개의 값이 동일한지 확인해보도록 한다.
PasswordFormValidator.java
package com.goodmoim.settings;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
public class PasswordFormValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return PasswordForm.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
PasswordForm passwordForm = (PasswordForm)target;
if (!passwordForm.getNewPassword().equals(passwordForm.getNewPasswordConfirm())) {
errors.rejectValue("newPassword", "wrong.value", "입력한 새 패스워드가 일치하지 않습니다.");
}
}
}
Validator 를 implements 하면 두개의 메서드를 구현해야 한다.
Validator 는 빈으로 등록할 필요는 없다. 다른 빈을 사용할 게 없기 때문에!
@initBinder 란 Spring Validator를 사용 시 @Valid annotation으로 검증이 필요한 객체를 가져오기 전에 수행할 method를 지정해주는 annotation이다.
form Validation 할때 추가로 사용할 Validator를 어떻게 등록해야 할까? initBinder 를 사용해서 등록할 수 있다. (AccountController에 활용한 적이 있음. 내 머리속의 지우개 😅)
SettingsController.java
@InitBinder("passwordForm")
public void initBinder(WebDataBinder webDataBinder) {
webDataBinder.addValidators(new PasswordFormValidator());
}
passwordForm을 처리할 때 webDataBinder 에다가 넣어줄 수 있다.
SettingsController.java
@GetMapping(SETTINGS_PASSWORD_URL)
public String updatePasswordForm(@CurrentUser Account account, Model model) {
model.addAttribute(account);
model.addAttribute(new PasswordForm());
return SETTINGS_PASSWORD_VIEW_NAME;
}
PasswordForm을 넣어준다. 그리고 뷰를 리턴해준다. 그럼 form을 보여줄 수 있다.
@PostMapping(SETTINGS_PASSWORD_URL)
public String updatePassword(@CurrentUser Account account, @Valid PasswordForm passwordForm, Errors errors,
Model model, RedirectAttributes attributes) {
if (errors.hasErrors()) {
model.addAttribute(account);
return SETTINGS_PASSWORD_VIEW_NAME;
}
accountService.updatePassword(account, passwordForm.getNewPassword());
attributes.addFlashAttribute("message", "패스워드를 변경했습니다.");
return "redirect:" + SETTINGS_PASSWORD_URL;
}
현재 업데이트를 해야 하는 사용자, 현재 접속하고 있는 사용자의 비밀번호를 업데이트 하는 것이므로 현재 사용자를 가져와야 한다. 그 다음에 Valid를 사용해서 바인딩하고 Validation 하면서 바인딩 받은 모델 에트리뷰트를 파라미터로 등록해주고 발생하는 에러들을 받을 수 있는 errors가 필요하다. 잘 되지 않았다면 model 에다가 account를 다시 넣어주고 뷰를 넣어줘야 하므로 model이 있어야 한다. 그리고 잘 등록했으면 메시지를 보여줄 수 있도록 RedirectAttributes 를 사용한다.
public void updatePassword(Account account, String newPassword) {
account.setPassword(passwordEncoder.encode(newPassword));
accountRepository.save(account);
}
account.setPassword(newPassword);
를 사용하면 안된다. 인코딩되지 않은 password 자체가 저장될 것이다. (raw) 따라서 반드시 passwordEncoder로 인코더를 해줘야 한다. account에 있는 정보를 새로운 password로 변경해주는데, 이 객체는 detached 상태이다. 그래서 명시적으로 상태 변경을 해줘야 한다. (accountRepository.save(account);)
password.html
<script th:replace="fragments.html :: form-validation"></script>
needs-validation 사용하기
클라이언트에서 validation 한번 한 다음에, 서버사이드로 올 것이다. 서버 사이드에서도 validation 해야 한다. 클라이언트에 있는 validation은 최선의 노력일 뿐 .. 뚫릴 수 있는 값이므로 믿어선 안된다. 어디까지나 옵션이다.
출처 : 인프런 백기선님의 스프링과 JPA 기반 웹 애플리케이션 개발
https://mia-dahae.tistory.com/23