반응형
SettingsController
package com.demo.settings;
import javax.validation.Valid;
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.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.demo.account.AccountService;
import com.demo.account.CurrentUser;
import com.demo.domain.Account;
import lombok.RequiredArgsConstructor;
//프로필 수정 요청 처리
//패스워드 수정 요청 처리
@Controller
@RequiredArgsConstructor
public class SettingsController {
// @InitBinder를 이용해 대체
// passwordFormValidator.validate(passwordForm, errors);
// if (errors.hasErrors()) {
// return "account/sign-up";
// }
// -> 자동으로 PasswordForm 검증을 한다.
@InitBinder("passwordForm")
public void initBinder(WebDataBinder webDataBinder) {
webDataBinder.addValidators(new PasswordFormValidator());
}
// 자주 틀리는 오타는 변수를 만들어서 사용
// 프로필 변경 위한 뷰 네임, url
private static final String SETTINGS_PROFILE_VIEW_NAME = "settings/profile";
private static final String SETTINGS_PROFILE_URL = "/settings/profile";
// 패스워드 변경 위한 뷰 네임, url
private static final String SETTINGS_PASSWORD_VIEW_NAME = "settings/password";
private static final String SETTINGS_PASSWORD_URL = "/settings/password";
private final AccountService accountService;
// 패스워드 변경 요청 검증
@GetMapping(SETTINGS_PASSWORD_URL)
public String updatePasswordForm(@CurrentUser Account account, Model model) {
model.addAttribute(account);
model.addAttribute(new PasswordForm());
return SETTINGS_PASSWORD_VIEW_NAME;
}
// 패스워드 변경 검증 처리
@PostMapping(SETTINGS_PASSWORD_URL)
// 현재 업데이트하려는 사용자는 현재 사용자, valid를 통해 바인딩하고 검증, 바인딩을 담을 모델, 만약 에러발생시 에러 바인딩받는 객체,
// 잘 되었을 경우 메시지 전송
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;
}
}
PasswordForm
package com.demo.settings;
import org.hibernate.validator.constraints.Length;
import lombok.AccessLevel;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class PasswordForm {
@Length(min=8, max=50)
private String newPassword;
@Length(min=8, max=50)
private String newPasswordConfirm;
}
PasswordFormValidator
package com.demo.settings;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
//빈으로 만들 필요없이 new해서 만들면 된다.
//여러번 사용할 일이 없기 때문에
public class PasswordFormValidator implements Validator{
@Override
//어떤 타입의 폼 객체를 검증할것인가
public boolean supports(Class<?> clazz) {
// TODO Auto-generated method stub
return PasswordForm.class.isAssignableFrom(clazz);
//패스워드 폼의 객체
}
//할당 가능한 타입이면 검증
@Override
public void validate(Object target, Errors errors) {
// TODO Auto-generated method stub
PasswordForm passwordForm= (PasswordForm) target;
//패스워드폼으로 타겟을 변경
//같은지 검증
if(!passwordForm.getNewPassword().equals(passwordForm.getNewPasswordConfirm())) {
errors.rejectValue("newPassword", "wrong.value", "입력한 새 패스워드가 일치하지 않습니다.");
//새로운 패스워드가 잘못된 값으로 변경
}
}
}
fragments
<div th:fragment="settings-menu (currentMenu)" class="list-group">
<a class="list-group-item list-group-item-action" th:classappend="${currentMenu == 'profile'}? active" href="#" th:href="@{/settings/profile}">프로필</a>
<a class="list-group-item list-group-item-action" th:classappend="${currentMenu == 'password'}? active" href="#" th:href="@{/settings/password}">패스워드</a>
<a class="list-group-item list-group-item-action" th:classappend="${currentMenu == 'notifications'}? active" href="#" th:href="@{/settings/notifications}">알림</a>
<a class="list-group-item list-group-item-action" th:classappend="${currentMenu == 'tags'}? active" href="#" th:href="@{/settings/tags}">관심 주제</a>
<a class="list-group-item list-group-item-action" th:classappend="${currentMenu == 'zones'}? active" href="#" th:href="@{/settings/zones}">활동 지역</a>
<a class="list-group-item list-group-item-action list-group-item-danger" th:classappend="${currentMenu == 'account'}? active" href="#" th:href="@{/settings/account}">계정</a>
</div>
<!--needs-validation을 가지는 폼을 가져와 submit 이벤트 발생시 유효여부 검증, 유효하지 않으면, submit안되도록 처리 -->
<!--유효하면 was-validated에 추가 -> input의 required을 기반으로 처리-->
<script type="application/javascript" th:fragment="form-validation">
(function () {
'use strict';
window.addEventListener('load', function () {
// Fetch all the forms we want to apply custom Bootstrap validation styles to
var forms = document.getElementsByClassName('needs-validation');
// Loop over them and prevent submission
Array.prototype.filter.call(forms, function (form) {
form.addEventListener('submit', function (event) {
if (form.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
}
form.classList.add('was-validated')
}, false)
})
}, false)
}())
</script>
password
<!DOCTYPE html>
<!-- 프로필 수정 뷰 -> password form을 만들어야 한다. 닉네임 이메일 비밀번호-->
<!-- 타임리프 네임스페이스 설정-->
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<!-- replace를 이용해 교체-->
<head th:replace="fragments.html :: head">
</head>
<body class="bg-light">
<div th:replace="fragments.html :: main-nav"></div>
<!-- password html -> 그리드 시스템 이용 row를 column 12개로 나눈 상태-->
<div class="container">
<!-- top 마진 5만큼-->
<div class="row mt-5 justify-content-center">
<!-- 아바타-->
<div class="col-2">
<!--프로필, 패스워드, 알림, 관심주제, 활동지역 계정 메뉴 -> fragment 이용-->
<!-- 패스워드가 선택된 상태의 뷰 -->
<div
th:replace="fragments.html :: settings-menu(currentMenu='password')"></div>
</div>
<!-- 폼을 수정할 수 있는 프로필화면을 보면서 직접 작성 -->
<div class="col-8">
<div th:if="${message}"
class="alert alert-info alert-dismissible fade show mt-3"
role="alert">
<span th:text="${message}">메시지</span>
<button type="button" class="close" data-dismiss="alert"
aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<!-- row마다 설정 -->
<div class="row">
<h2 class="col-sm-12">패스워드 변경</h2>
</div>
<div class="row mt-3">
<form class="needs-validation col-12" action="#"
th:action="@{/settings/password}" th:object="${passwordForm}"
method="post" novalidate>
<div class="form-group">
<!-- 프론트엔드에서 미리 길이 체크를 하고 서버에서도 길이 체크를 한다-->
<label for="newPassword">새 패스워드</label> <input id="newPassword"
type="password" th:field="*{newPassword}" class="form-control"
aria-describedby="newPasswordHelp" required min="8" max="50">
<small id="newPasswordHelp" class="form-text text-muted">
새 패스워드를 입력하세요. </small> <small class="invalid-feedback">패스워드를
입력하세요.</small> <small class="form-text text-danger"
th:if="${#fields.hasErrors('newPassword')}"
th:errors="*{newPassword}">New Password Error</small>
</div>
<div class="form-group">
<label for="newPasswordConfirm">새 패스워드 확인</label> <input
id="newPasswordConfirm" type="password"
th:field="*{newPasswordConfirm}" class="form-control"
aria-describedby="newPasswordConfirmHelp" required min="8"
max="50"> <small id="newPasswordConfirmHelp"
class="form-text text-muted"> 새 패스워드를 다시 한번 입력하세요. </small> <small
class="invalid-feedback">새 패스워드를 다시 입력하세요.</small> <small
class="form-text text-danger"
th:if="${#fields.hasErrors('newPasswordConfirm')}"
th:errors="*{newPasswordConfirm}">New Password Confirm
Error</small>
</div>
<div class="form-group">
<button class="btn btn-outline-primary" type="submit"
aria-describedby="submitHelp">패스워드 변경하기</button>
</div>
</form>
</div>
</div>
</div>
</div>
<script th:replace="fragments.html :: form-validation"></script>
</body>
</html>
반응형
'Server Programming > Spring Boot Full-Stack Programming' 카테고리의 다른 글
[스프링 풀스택 클론 코딩 - 계정 설정] (2-8) ModelMapper 적용 (0) | 2022.09.05 |
---|---|
[스프링 풀스택 클론 코딩 - 계정 설정] (2-7) 알림 설정 (0) | 2022.09.05 |
[스프링 풀스택 클론 코딩 - 계정 설정] (2-4) 프로필 이미지 변경 (0) | 2022.09.02 |
[스프링 풀스택 클론 코딩] 엔티티 상태에 따른 DB 반영 (0) | 2022.09.01 |
[스프링 풀스택 클론 코딩 - 계정 설정] (2-2) 프로필 수정 처리 (0) | 2022.09.01 |