일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 프로그래머스
- 스포티파이
- Spotify Api
- SWEA
- CS
- SECS/GEM
- Gem
- c
- programmers
- spring boot
- regression
- 자바
- 파이썬
- 백준
- SW Expert Academy
- linux
- SECS
- spotify
- Computer Science
- SECS-II
- Spring
- modern c++
- C++
- Spring JPA
- python
- Baekjoon
- 회귀
- MYSQL
- 회원가입
- java
- Today
- Total
비버놀로지
[Spring JPA] 1-4. 회원 가입 : 뷰 본문
회원가입을 위해 만들었던 sign-up.html을 수정합니다.
<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Sign-up Page</title>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css"
rel="stylesheet">
<style>
.container {
max-width: 100%;
}
</style>
</head>
<body class="bg-light">
<nav th:fragment="main-nav"
class="navbar navbar-expand-sm navbar-dark bg-dark">
<a class="navbar-brand" href="/" th:href="@{/}"> <img
src="/images/beaver.png" width="30" height="30">
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse"
data-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<form th:action="@{/search/study}" class="form-inline" method="get">
<input class="form-control mr-sm-2" name="keyword" type="search"
placeholder="스터디 찾기" aria-label="Search" />
</form>
</li>
</ul>
<ul class="navbar-nav justify-content-end">
<li class="nav-item" sec:authorize="!isAuthenticated()"><a
class="nav-link" th:href="@{/login}">로그인</a></li>
<li class="nav-item" sec:authorize="!isAuthenticated()"><a
class="nav-link" th:href="@{/sign-up}">가입</a></li>
<li class="nav-item" sec:authorize="isAuthenticated()"><a
class="nav-link" th:href="@{/notifications}"> <i
th:if="${!hasNotification}" class="fa fa-bell-o"
aria-hidden="true"></i> <span class="text-info"
th:if="${hasNotification}"><i class="fa fa-bell"
aria-hidden="true"></i></span>
</a></li>
<li class="nav-item" sec:authorize="isAuthenticated()"><a
class="nav-link btn btn-outline-primary" th:href="@{/new-study}">
<i class="fa fa-plus" aria-hidden="true"></i> 스터디 개설
</a></li>
<li class="nav-item dropdown" sec:authorize="isAuthenticated()">
<a class="nav-link dropdown-toggle" href="#" id="userDropdown"
role="button" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false"> <svg
th:if="${#strings.isEmpty(account?.profileImage)}"
th:data-jdenticon-value="${#authentication.name}" width="24"
height="24" class="rounded border bg-light"></svg> <img
th:if="${!#strings.isEmpty(account?.profileImage)}"
th:src="${account.profileImage}" width="24" height="24"
class="rounded border" />
</a>
<div class="dropdown-menu dropdown-menu-sm-right"
aria-labelledby="userDropdown">
<h6 class="dropdown-header">
<span sec:authentication="name">Username</span>
</h6>
<a class="dropdown-item"
th:href="@{'/profile/' + ${#authentication.name}}">프로필</a> <a
class="dropdown-item">스터디</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" th:href="@{'/settings/profile'}">설정</a>
<form class="form-inline my-2 my-lg-0" action="#"
th:action="@{/logout}" method="post">
<button class="dropdown-item" type="submit">로그아웃</button>
</form>
</div>
</li>
</ul>
</div>
</nav>
<div class="container">
<div class="py-5 text-center">
<h2>계정 만들기</h2>
</div>
<div class="row justify-content-center">
<form class="needs-validation col-sm-6" action="#"
th:action="@{/sign-up}" th:object="${signUpForm}" method="post"
novalidate>
<div class="form-group">
<label for="nickname">닉네임</label> <input id="nickname" type="text"
th:field="*{nickname}" class="form-control"
placeholder="whiteship" aria-describedby="nicknameHelp" required
minlength="3" maxlength="20"> <small id="nicknameHelp"
class="form-text text-muted"> 공백없이 문자와 숫자로만 3자 이상 20자 이내로
입력하세요. 가입후에 변경할 수 있습니다. </small> <small class="invalid-feedback">닉네임을
입력하세요.</small> <small class="form-text text-danger"
th:if="${#fields.hasErrors('nickname')}" th:errors="*{nickname}">Nickname
Error</small>
</div>
<div class="form-group">
<label for="email">이메일</label> <input id="email" type="email"
th:field="*{email}" class="form-control"
placeholder="your@email.com" aria-describedby="emailHelp" required>
<small id="emailHelp" class="form-text text-muted"> 스터디올래는
사용자의 이메일을 공개하지 않습니다. </small> <small class="invalid-feedback">이메일을
입력하세요.</small> <small class="form-text text-danger"
th:if="${#fields.hasErrors('email')}" th:errors="*{email}">Email
Error</small>
</div>
<div class="form-group">
<label for="password">패스워드</label> <input id="password"
type="password" th:field="*{password}" class="form-control"
aria-describedby="passwordHelp" required minlength="8"
maxlength="50"> <small id="passwordHelp"
class="form-text text-muted"> 8자 이상 50자 이내로 입력하세요. 영문자,
숫자, 특수기호를 사용할 수 있으며 공백은 사용할 수 없습니다. </small> <small
class="invalid-feedback">패스워드를 입력하세요.</small> <small
class="form-text text-danger"
th:if="${#fields.hasErrors('password')}" th:errors="*{password}">Password
Error</small>
</div>
<div class="form-group">
<button class="btn btn-primary btn-block" type="submit"
aria-describedby="submitHelp">가입하기</button>
<small id="submitHelp" class="form-text text-muted"> <a
href="#">약관</a>에 동의하시면 가입하기 버튼을 클릭하세요.
</small>
</div>
</form>
</div>
<footer th:fragment="footer">
<div class="row justify-content-center">
<small class="d-block mb-3 text-muted">© 2020</small>
</div>
</footer>
</div>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js"></script>
<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>
</body>
</html>
위의 코드를 통해 회원가입 뷰를 제작할 수 있다.
위의 코드를 제작하면서 th라는 타임 리프를 사용해 주었는데
<html lang="en" xmlns:th="https://www.thymeleaf.org">
위와 같은 코드를 추가해 주어야 타임리프를 사용할 수 있다.
그리고 위의 코드를 작성하고 실행을 해보면 아래와 같은 에러를 볼 수 있다.
이러한 에러가 발생하는 이유는 아직 SignUpForm이라는 컨트롤러가 만들어져 있지 않고, DTO도 만들어져 있지 않아서 이 두가지를 추가해 주어야 한다.
먼저, DTO에 SignUpForm을 추가해 준다.
위의 이미지는 현재까지의 구성이다.
그리고 아래와 같이 DTO를 추가해 준다.
package com.studyolle.repository.dto;
import lombok.Data;
@Data
public class SignUpForm {
private String nickname;
private String email;
private String password;
}
그리고 컨트롤러를 추가해 준다.
package com.studyolle.account.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import com.studyolle.repository.dto.SignUpForm;
@Controller
public class AccountController {
@GetMapping("sign-up")
public String signUpForm(Model model) {
model.addAttribute("signUpForm",new SignUpForm());
return "account/sign-up";
}
}
이전에 작성되어있는 코드에서 위와같이 변경을 해주고 다시 실행을 하게되면 문제없이 실행이 되는것을 확인할 수 있을 것이다.
위와 같이 실행이 되는 것을 확인할 수 있다.
하지만 위에 보면 이미지가 깨져서 나오는 것을 볼 수 있다.
네트워크에서 확인해 보면 이미지를 불러 올때 403 에러가 나는 것을 확인할 수 있다.
이러한 문제가 발생하는 이유는 SpringSecurity에서 로컬에 있는 이미지를 불러오는 것이 막아 불러올 수 없는 것이다. 그래서 SecurityConfig에 이러한 문제가 발생하지 않도록 예외 처리를 해주어야 한다.
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.mvcMatchers("/node_modules/**")
.requestMatchers(PathRequest.toStaticResources().atCommonLocations());
}
위와 같은 코드를 SecurityConfing.java에 상속을 시켜주면 위와 같은 에러를 막고 이미지를 불러오게 된다.
package com.studyolle.account.controller;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
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.test.web.servlet.MockMvc;
@SpringBootTest
@AutoConfigureMockMvc
public class AccountControllerTest {
@Autowired private MockMvc mockMvc;
@DisplayName("회원 가입 화면 보이는지 테스트")
@Test
void signUpForm() throws Exception {
mockMvc.perform(get("/sign-up"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(view().name("account/sign-up"))
.andExpect(model().attributeExists("signUpForm"));
}
}
위의 코드는 테스트코드이다. 위와같이 추가를 통해 테스트를 해볼 수 있다.
'LANGUAGE STUDY > Spring' 카테고리의 다른 글
[Spring JPA] 1-6. 회원 가입 폼 서브밋 처리 (0) | 2021.04.30 |
---|---|
[Spring JPA] 1-5. 회원 가입 폼 서브밋 검증 (0) | 2021.04.30 |
[Spring JPA] 1-3. 회원 가입 : 컨트롤러 (0) | 2021.04.27 |
[Spring JPA] 1-2. 계정 도메인 (0) | 2021.04.27 |
[Spring JPA] 1-1. 프로젝트 생성 (0) | 2021.04.26 |