[Spring Boot] 11. Spring Boot Project (Blog v2 - jpa)_2.User - Login

김미숙's avatar
Jul 21, 2025
[Spring Boot] 11. Spring Boot Project (Blog v2 - jpa)_2.User - Login

UserRequest

package shop.mtcoding.blog.user; import lombok.Data; public class UserRequest { //insert 용도의 dto에는 toEntity 메서드를 만든다 @Data public static class JoinDTO { private String username; private String password; private String email; public User toEntity() { return User.builder() .username(username) .password(password) .email(email) .build(); } } @Data public static class LoginDTO { private String username; private String password; private String rememberMe; // check되면 on 안되면 null } }

UserController

package shop.mtcoding.blog.user; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletResponse; 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.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.ResponseBody; import shop.mtcoding.blog._core.Resp; import java.util.Map; @RequiredArgsConstructor @Controller public class UserController { private final UserService userService; private final HttpSession session; @GetMapping("/join-form") public String joinForm() { return "user/join-form"; } @PostMapping("/join") public String join(UserRequest.JoinDTO joinDTO) { userService.회원가입(joinDTO); return "redirect:/login-form"; } @GetMapping("/check-username-available/{username}") public @ResponseBody Resp<?> checkUsernameAvailable(@PathVariable("username") String username) { Map<String, Object> dto = userService.유저네임중복체크(username); return Resp.ok(dto); } @GetMapping("/login-form") public String loginForm() { return "user/login-form"; } @PostMapping("/login") public String login(UserRequest.LoginDTO loginDTO, HttpServletResponse response) { User sessionUser = userService.로그인(loginDTO); session.setAttribute("sessionUser", sessionUser); if (loginDTO.getRememberMe() == null) { Cookie cookie = new Cookie("username", null); cookie.setMaxAge(0); // 즉시 삭제 response.addCookie(cookie); } else { Cookie cookie = new Cookie("username", loginDTO.getUsername()); cookie.setMaxAge(60 * 60 * 24 * 7); // cookie 하루동안 유지 response.addCookie(cookie); } return "redirect:/"; } @GetMapping("/logout") public String logout() { session.invalidate(); return "redirect:/login-form"; } }

BoardController

package shop.mtcoding.blog.board; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @RequiredArgsConstructor @Controller public class BoardController { @GetMapping("/") public String home() { return "board/list"; } }

UserService

package shop.mtcoding.blog.user; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.HashMap; import java.util.Map; // 비즈니스 로직, 트랜잭션 처리, DTO 완료 @RequiredArgsConstructor @Service public class UserService { private final UserRepository userRepository; @Transactional public void 회원가입(UserRequest.JoinDTO joinDTO) { userRepository.save(joinDTO.toEntity()); } public User 로그인(UserRequest.LoginDTO loginDTO) { // username,password 검사 User user = userRepository.findByUsername(loginDTO.getUsername()); if (user == null) { throw new RuntimeException("해당 username이 없습니다"); } if (!(user.getPassword().equals(loginDTO.getPassword()))) { throw new RuntimeException("해당 passward가 일치하지 않습니다"); } // 로그인 return user; } public Map<String, Object> 유저네임중복체크(String username) { User user = userRepository.findByUsername(username); Map<String, Object> dto = new HashMap<>(); if (user == null) { dto.put("available", true); } else { dto.put("available", false); } return dto; } }

header

<!DOCTYPE html> <html lang="en"> <head> <title>Blog</title> <meta charset="utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1"/> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"/> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"> <style> .my-like-heart { font-size: 24px; color: gray; cursor: pointer; } .my-like-heart.liked { color: red; } </style> </head> <body> <nav class="navbar navbar-expand-sm bg-dark navbar-dark"> <div class="container-fluid"> <a class="navbar-brand" href="/">Metacoding</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="/board/save-form">글쓰기</a> </li> <li class="nav-item"> <a class="nav-link" href="/user/update-form">회원정보보기</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>

login-form

{{> layout/header}} <div class="container p-5"> <div class="card"> <div class="card-header"><b>로그인을 해주세요</b></div> <div class="card-body"> <form action="/login" method="post" enctype="application/x-www-form-urlencoded"> <div class="mb-3"> <input type="text" class="form-control" placeholder="Enter username" name="username" id="username"> </div> <div class="mb-3"> <input type="password" class="form-control" placeholder="Enter password" name="password" id="password"> </div> <!-- ✅ 공개 여부 체크박스 --> <div class="form-check mb-3"> <input class="form-check-input" type="checkbox" name="rememberMe" checked> <label class="form-check-label" for="isUsernameCheck"> 아이디를 기억하겠습니까? </label> </div> <button type="submit" class="btn btn-primary form-control">로그인</button> </form> </div> </div> </div> <script> let rememberUsername = getCookie("username"); if (rememberUsername != null) { document.querySelector("#username").value = rememberUsername; } function getCookie(name) { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop().split(';').shift(); return null; // return 안 하면 undefined } </script> {{> layout/footer}}
notion image
notion image
Share article

parangdajavous