[Spring Boot] 7. Spring Boot Project (Bank v1)_3-2.Fuctions Design_Login & Logout
Mar 27, 2025
⚠ 로그인만 예외로 보안때문에 get이 아닌 post방식
application.properties
# utf-8
server.servlet.encoding.charset=utf-8
server.servlet.encoding.force=true
# DB
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:test
spring.datasource.username=sa
spring.datasource.password=
spring.h2.console.enabled=true
# JPA table create or none
spring.jpa.hibernate.ddl-auto=create
# query log
spring.jpa.show-sql=true
# dummy data
spring.sql.init.data-locations=classpath:db/data.sql
# create dummy data after ddl-auto create
spring.jpa.defer-datasource-initialization=true
# mustache request expose
spring.mustache.servlet.expose-request-attributes=true
# mustache session expose
spring.mustache.servlet.expose-session-attributes=true
# Sql formatter
spring.jpa.properties.hibernate.format_sql=true
header
조건문
- if → {{#값}}
- else → {{^값}}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Bank</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<nav class="navbar navbar-expand-sm bg-dark navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="/">Home</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#collapsibleNavbar">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="collapsibleNavbar">
<ul class="navbar-nav">
{{#sessionUser}}
<li class="nav-item">
<a class="nav-link" href="#">계좌목록</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">계좌생성</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">이체하기</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/logout">로그아웃</a>
</li>
{{/sessionUser}}
{{^sessionUser}}
<li class="nav-item">
<a class="nav-link" href="/join-form">회원가입</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/login-form">로그인</a>
</li>
{{/sessionUser}}
</ul>
</div>
</div>
</nav>
home
{{>layout/header}}
<!--마진 : mt,mr,ml,mb (1~5) ex) mt-5-->
<div class="container mt-2">
<div class="mt-4 p-5 bg-light text-dark rounded-4">
<h1>메타코딩 은행에 오신 것을 환영합니다</h1>
<h3>
{{#sessionUser}}
{{sessionUser.fullname}}님
{{/sessionUser}}
</h3>
</div>
</div>
{{>layout/footer}}
UserController
package com.metacoding.bankv1.user;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@RequiredArgsConstructor
@Controller
public class UserController {
private final UserService userService;
private final HttpSession session;
// 로그인만 조회 시에 예외로 Post
@PostMapping("/login")
public String login(UserRequest.LoginDTO loginDTO) {
User sessionUser = userService.로그인(loginDTO);
session.setAttribute("sessionUser", sessionUser); //statefull 스코프: 생명주기 session스코프 > request스코프
return "redirect:/";
}
@GetMapping("/login-form")
public String loginForm() {
return "user/login-form";
}
@GetMapping("/join-form")
public String joinForm() {
return "/user/join-form";
}
@PostMapping("/join")
public String join(UserRequest.JoinDTO joinDTO) {
userService.회원가입(joinDTO);
return "redirect:/login-form";
}
}
UserService
package com.metacoding.bankv1.user;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@RequiredArgsConstructor
@Service
public class UserService {
private final UserRepository userRepository;
@Transactional
public void 회원가입(UserRequest.JoinDTO joinDTO) {
// 1. 동일 username 있는지 검사 (조회)
User user = userRepository.findByUsername(joinDTO.getUsername());
// 2. 있으면 exception 터트리기
if (user != null) throw new RuntimeException("동일한 username이 존재합니다.");
// 3. 없으면 회원가입하기
userRepository.save(joinDTO.getUsername(), joinDTO.getPassword(), joinDTO.getUsername());
}
public User 로그인(UserRequest.LoginDTO loginDTO) {
// 1. 해당 username이 있는지
User user = userRepository.findByUsername(loginDTO.getUsername());
// 2. username, password가 불일치하는 것들을 Filtering
if (user == null) {
throw new RuntimeException("해당 username이 없습니다.");
}
if (!(user.getPassword().equals(loginDTO.getPassword()))) {
throw new RuntimeException("해당 password가 틀렸습니다.");
}
// 3. 인증
return user;
}
}
Login test
- 로그인 전 화면에는 회원가입과 로그인 메뉴만 나온다

⬆ 존재하는 user인 ‘ssar’ 로 로그인하면
⬇ 로그인되서 화면에 user의 fullname이 노출되고,
메뉴에 회원가입과 로그인은 나오지 않는다

Logout
UserController
package com.metacoding.bankv1.user;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@RequiredArgsConstructor
@Controller
public class UserController {
private final UserService userService;
private final HttpSession session;
@GetMapping("/logout")
public String logout() {
session.invalidate(); // 안에 있는 걸 전부 다 버림
return "redirect:/";
}
// 로그인만 조회 시에 예외로 Post
@PostMapping("/login")
public String login(UserRequest.LoginDTO loginDTO) {
User sessionUser = userService.로그인(loginDTO);
session.setAttribute("sessionUser", sessionUser); //statefull 스코프: 생명주기 session스코프 > request스코프
return "redirect:/";
}
@GetMapping("/login-form")
public String loginForm() {
return "user/login-form";
}
@GetMapping("/join-form")
public String joinForm() {
return "/user/join-form";
}
@PostMapping("/join")
public String join(UserRequest.JoinDTO joinDTO) {
userService.회원가입(joinDTO);
return "redirect:/login-form";
}
}
Login test
로그아웃
click

⬇ Redirection 되서 home 페이지로 이동하면서,
메뉴에 회원가입과 로그인만 확인된다

Share article