1. 로그인 쿼리 만들기
먼저, UserRepository를 통해 사용자 이름과 비밀번호로 사용자를 조회하는 메서드를 만듭니다. 이 메서드는 JPQL을 사용하여 데이터베이스에서 사용자를 검색합니다.
package com.tenco.blog_v1.user;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
@RequiredArgsConstructor
@Repository // IoC
public class UserRepository {
private final EntityManager em;
/**
* 사용자 이름과 비밀번호로 사용자 조회
* @param username
* @param password
* @return 조회된 User 엔티티, null
*/
public User findByUsernameAndPassword(String username, String password) {
TypedQuery<User> jpql =
em.createQuery("SELECT u FROM User u WHERE u.username = :username AND u.password = :password", User.class);
jpql.setParameter("username", username);
jpql.setParameter("password", password);
return jpql.getSingleResult();
}
}
LoginDTO 만들기
로그인 요청을 처리하기 위해 Data Transfer Object (DTO)를 만듭니다. 이는 클라이언트로부터 전달받은 데이터를 안전하게 관리하는 데 사용됩니다.
package com.tenco.blog_v1.user;
import lombok.Data;
@Data
public class UserDTO {
// 정적 내부 클래로 모우자
@Data
public static class LoginDTO {
private String username;
private String password;
}
// 정적 내부 클래로 모우자
@Data
public static class JoinDTO {
private String username;
private String password;
private String email;
}
}
UserController 구현
UserController를 구현하여 로그인 및 로그아웃 요청을 처리합니다. 이 컨트롤러는 사용자의 로그인 정보를 검증하고, 세션을 관리합니다.
로그인 로그아웃 기능 추가
package com.tenco.blog_v1.user;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@RequiredArgsConstructor
@Slf4j
@Controller
public class UserController {
// DI 처리
private final UserRepository userRepository;
private final HttpSession session;
/**
* 자원에 요청은 GET 방식이지만 보안에 이유로 예외 !
* 로그인 처리 메서드
* 요청 주소 POST : http://localhost:8080/login
* @param reqDto
* @return
*/
@PostMapping("/login")
public String login(UserDTO.LoginDTO reqDto) {
try {
User sessionUser = userRepository.findByUsernameAndPassword(reqDto.getUsername(), reqDto.getPassword());
session.setAttribute("sessionUser", sessionUser);
return "redirect:/";
} catch (Exception e) {
// 로그인 실패
return "redirect:/login-form?error";
}
}
@GetMapping("/logout")
public String logout() {
session.invalidate(); // 세션을 무효화 (로그아웃)
return "redirect:/";
}
/**
* 회원가입 페이지 요청
* 주소설계 : http://localhost:8080/join-form
*
* @param model
* @return 문자열
* 반환되는 문자열을 뷰 리졸버가 처리하며
* 머스태치 템플릿 엔진을 통해서 뷰 파일을 렌더링 합니다.
*/
@GetMapping("/join-form")
public String joinForm(Model model) {
log.info("회원가입 페이지");
model.addAttribute("name", "회원가입 페이지");
return "user/join-form"; // 템플릿 경로 : user/join-form.mustache
}
/**
* 로그인 페이지 요청
* 주소설계 : http://localhost:8080/login-form
*
* @param model
* @return 문자열
* 반환되는 문자열을 뷰 리졸버가 처리하며
* 머스태치 템플릿 엔진을 통해서 뷰 파일을 렌더링 합니다.
*/
@GetMapping("/login-form")
public String loginForm(Model model) {
log.info("로그인 페이지");
model.addAttribute("name", "로그인 페이지");
return "user/login-form"; // 템플릿 경로 : user/join-form.mustache
}
/**
* 회원 정보 수정 페이지 요청
* 주소설계 : http://localhost:8080/user/update-form
*
* @param model
* @return 문자열
* 반환되는 문자열을 뷰 리졸버가 처리하며
* 머스태치 템플릿 엔진을 통해서 뷰 파일을 렌더링 합니다.
*/
@GetMapping("/user/update-form")
public String updateForm(Model model) {
log.info("회원 수정 페이지");
model.addAttribute("name", "회원 수정 페이지");
return "user/update-form"; // 템플릿 경로 : user/join-form.mustache
}
}
header.mustache 코드 수정
<!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">
</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>
설정 확인
spring:
mustache:
servlet:
expose-session-attributes: true # Mustache ????? ?? ??? ??? ? ??? ??
expose-request-attributes: true # Mustache ????? ?? ??? ??? ? ??? ??
'Spring boot > 개념 공부' 카테고리의 다른 글
게시글 삭제 (1) | 2024.10.20 |
---|---|
게시글 쓰기 (0) | 2024.10.20 |
게시글 목록보기 (Post List View) (0) | 2024.10.20 |
Mustache 란 뭘까? (0) | 2024.10.07 |
템플릿 엔진이란 뭘까? (0) | 2024.10.07 |