package com.myapp.bbs.dao;
import java.util.List;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import com.myapp.bbs.model.User;
@Mapper
public interface UserMapper {
@Insert("insert into player values(#{email}, #{password}, #{name})")
public int insert(User user);
@Update("update player set password = #{password} where email = #{email}")
public int update(User user);
@Delete("delete from player where email = #{email}")
public int delete(String email);
@Select("select * from player")
public List<User> selectAll();
@Select("select * from player where email = #{email}")
public User selectByEmail(String email);
}
package com.myapp.bbs.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.myapp.bbs.dao.UserMapper;
import com.myapp.bbs.model.Login;
import com.myapp.bbs.model.User;
@Service
public class LoginService {
@Autowired
private UserMapper userMapper;
// 인증하기 메소드 : 실패할 경우 login객체에 에러메세지 입력됨
public void authenticate(Login login) {
// 이메일로 검색해서 유저찾기
User user = userMapper.selectByEmail(login.getEmail());
if(user == null) {
login.setError("이메일이 존재하지 않습니다.");
} else {
if (!user.getPassword().equals(login.getPassword())) {
login.setError("패스워드가 틀립니다.");
} else {
login.setError(null); // 에러없음 (인증됨)
}
}
}
// 유저 찾기 메소드 : 이메일로 유저찾기
public User findUserByEmail(String emali) {
User user = userMapper.selectByEmail(emali);
return user;
}
}
package com.myapp.bbs.controller;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.myapp.bbs.dao.UserMapper;
import com.myapp.bbs.model.User;
@Controller
public class UserController {
@Autowired
private UserMapper userMapper;
@GetMapping("/register")
public String getUsersView(@ModelAttribute User user) {
return "register";
}
@PostMapping("/register")
public String postUser(User user, Model model, HttpSession session, RedirectAttributes attr) {
// 클라이언트 단 또는 서버 단에서 데이터 유효성 체크를 적용하는 것을 권장한다.
User duplicatedUser = userMapper.selectByEmail(user.getEmail()); // 이메일이 같은 유저가 있는지 검색
if(duplicatedUser == null) {
// 이메일이 중복이 아니므로 가입처리
userMapper.insert(user);
attr.addFlashAttribute("message", "가입되었습니다.");
return "redirect:/login";
} else {
// 이메일이 중복됬으므로 메세지와 함께 다시 Redirect로 돌아감
attr.addFlashAttribute("message", "중복된 이메일입니다.");
return "redirect:/register";
}
}
}
package com.myapp.bbs.controller;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import com.myapp.bbs.model.Login;
import com.myapp.bbs.model.User;
import com.myapp.bbs.service.LoginService;
@Controller
public class LoginController {
@Autowired
private LoginService loginService;
@GetMapping("/login")
public String getLoginView(@ModelAttribute Login login) {
return "login";
}
@PostMapping("/login")
public String postLogin(Login login, Model model, HttpSession session ) {
loginService.authenticate(login); // 인증메소드 실행 (실패 시 에러메시지 입력됨)
if (login.getError() != null) {
model.addAttribute("message", login.getError());
return "login";
} else {
User user = loginService.findUserByEmail(login.getEmail());
session.setAttribute("user", user);
return "redirect:/board/list";
}
}
}
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/head :: 헤드"></head>
<style>
input:invalid:focus {
/* 유효성검사 통과 못할 시*/
background-image: linear-gradient(pink, skyblue) !important; /* !important는 가장 우선순위를 높게 설정하여 무조건 실행*/
}
</style>
<body class="g-sidenav-show bg-gray-200">
<aside th:replace="fragments/aside :: 어사이드"></aside>
<!-- 메인 컨텐트 시작 -->
<main class="main-content mt-0">
<section>
<div class="page-header min-vh-100">
<div class="container">
<div class="row">
<div class="col-6 d-lg-flex d-none h-100 my-auto pe-0 position-absolute top-0 start-0 text-center justify-content-center flex-column">
<div
class="position-relative bg-gradient-primary h-100 m-3 px-7 border-radius-lg d-flex flex-column justify-content-center"
style="background-image: url('../assets/img/illustrations/illustration-signup.jpg'); background-size: cover"
></div>
</div>
<div class="col-xl-4 col-lg-5 col-md-7 d-flex flex-column ms-auto me-auto ms-lg-auto me-lg-5">
<div class="card card-plain">
<div class="card-header">
<h4 class="font-weight-bolder">가입하기</h4>
<!-- 삼항연산자 ? true : false, 삼항연산자 ?: true(물음표 다음 : 띄우면 안됨)-->
<p class="mb-0" th:text="${message} ?: '가입양식을 작성해주세요'"></p>
</div>
<div class="card-body bg-white">
<form role="form" th:action="@{/register}" method="POST" th:object="${user}">
<div class="input-group input-group-outline mb-3">
<label class="form-label">Name</label>
<input type="text" class="form-control" th:field="*{name}" minlength="2" maxlength="5" required />
</div>
<div class="input-group input-group-outline mb-3">
<label class="form-label">Email</label>
<input type="email" class="form-control" th:field="*{email}" required />
</div>
<div class="input-group input-group-outline mb-3">
<label class="form-label">Password</label>
<input type="password" class="form-control" th:field="*{password}" minlength="4" maxlength="10" required />
</div>
<div class="form-check form-check-info text-start ps-0">
<input class="form-check-input" type="checkbox" value="" id="flexCheckDefault" checked />
<label class="form-check-label" for="flexCheckDefault"> I agree the <a href="javascript:;" class="text-dark font-weight-bolder">Terms and Conditions</a> </label>
</div>
<div class="text-center">
<button type="submit" class="btn btn-lg bg-gradient-primary btn-lg w-100 mt-4 mb-0">가입하기</button>
</div>
</form>
</div>
<div class="card-footer bg-white text-center pt-0 px-lg-2 px-1">
<p class="mb-2 text-sm mx-auto">
이미 계정이 있습니까?
<a th:href="@{/login}" class="text-primary text-gradient font-weight-bold">로그인</a>
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</main>
<jslink th:replace="fragments/jslink :: 링크"></jslink>
</body>
</html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/head :: 헤드"></head>
<style>
input:invalid:focus {
background-image: linear-gradient(red, blue) !important;
}
</style>
<body class="g-sidenav-show bg-gray-200">
<aside th:replace="fragments/aside :: 어사이드"></aside>
<!-- 메인 컨텐츠 시작 -->
<main class="main-content mt-0">
<div
class="page-header align-items-start min-vh-100"
style="background-image: url('https://images.unsplash.com/photo-1497294815431-9365093b7331?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1950&q=80')"
>
<span class="mask bg-gradient-dark opacity-6"></span>
<div class="container my-auto">
<div class="row">
<div class="col-lg-4 col-md-8 col-12 mx-auto">
<div class="card z-index-0 fadeIn3 fadeInBottom">
<div class="card-header p-0 position-relative mt-n4 mx-3 z-index-2">
<div class="bg-gradient-primary shadow-primary border-radius-lg py-3 pe-1">
<h4 class="text-white font-weight-bolder text-center mt-2 mb-0">로그인</h4>
<div class="row mt-3">
<div class="col-2 text-center ms-auto">
<a class="btn btn-link px-3" href="javascript:;">
<i class="fa fa-facebook text-white text-lg"></i>
</a>
</div>
<div class="col-2 text-center px-1">
<a class="btn btn-link px-3" href="javascript:;">
<i class="fa fa-github text-white text-lg"></i>
</a>
</div>
<div class="col-2 text-center me-auto">
<a class="btn btn-link px-3" href="javascript:;">
<i class="fa fa-google text-white text-lg"></i>
</a>
</div>
</div>
</div>
</div>
<div class="card-body">
<p class="text-primary" th:if="${message}" th:text="${message}"></p>
<form role="form" class="text-start" th:action="@{/login}" method="post" th:object="${login}">
<div class="input-group input-group-outline my-3">
<label class="form-label">Email</label>
<input type="email" class="form-control" th:field="*{email}" required />
</div>
<div class="input-group input-group-outline mb-3">
<label class="form-label">Password</label>
<input type="password" class="form-control" th:field="*{password}" minlength="4" maxlength="10" required />
</div>
<div class="form-check form-switch d-flex align-items-center mb-3">
<input class="form-check-input" type="checkbox" id="rememberMe" />
<label class="form-check-label mb-0 ms-2" for="rememberMe">Remember me</label>
</div>
<div class="text-center">
<button type="submit" class="btn bg-gradient-primary w-100 my-4 mb-2">로그인</button>
</div>
<p class="mt-4 text-sm text-center">
가입한 계정이 없다면?
<a th:href="@{/register}" class="text-primary text-gradient font-weight-bold">회원가입</a>
</p>
</form>
</div>
</div>
</div>
</div>
</div>
<footer class="footer position-absolute bottom-2 py-2 w-100">
<div class="container">
<div class="row align-items-center justify-content-lg-between">
<div class="col-12 col-md-6 my-auto">
<div class="copyright text-center text-sm text-white text-lg-start">
©
<script>
document.write(new Date().getFullYear());
</script>
, made with <i class="fa fa-heart" aria-hidden="true"></i> by
<a href="https://www.creative-tim.com" class="font-weight-bold text-white" target="_blank">Creative Tim</a>
for a better web.
</div>
</div>
<div class="col-12 col-md-6">
<ul class="nav nav-footer justify-content-center justify-content-lg-end">
<li class="nav-item">
<a href="https://www.creative-tim.com" class="nav-link text-white" target="_blank">Creative Tim</a>
</li>
<li class="nav-item">
<a href="https://www.creative-tim.com/presentation" class="nav-link text-white" target="_blank">About Us</a>
</li>
<li class="nav-item">
<a href="https://www.creative-tim.com/blog" class="nav-link text-white" target="_blank">Blog</a>
</li>
<li class="nav-item">
<a href="https://www.creative-tim.com/license" class="nav-link pe-0 text-white" target="_blank">License</a>
</li>
</ul>
</div>
</div>
</div>
</footer>
</div>
</main>
<jslink th:replace="fragments/jslink :: 링크"></jslink>
</body>
</html>
회원가입 화면
로그인 화면