JAVA

스프링부트 블로그 만들기 – 6강 로그인, 로그아웃

blog app

스프링부트 블로그 만들기 – 6강 로그인, 로그아웃

로그인

1.로그인 페이지에서 데이터를 넘겨줄 수 있게 만들어준다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>

<%@ include file="../layout/header.jsp"%>

<div class="container p-4 w-25 bg-light rounded shadow">
  <h5 style="font-family: 'IBM Plex Sans KR', sans-serif; margin-bottom: 30px;">로그인</h5>
  <form action="/login" method="post">
    <div class="form-group">
      <input type="text" name="username" class="form-control" placeholder="Enter username" required="required">
    </div>
    <div class="form-group">
      <input type="password" class="form-control" name="password" placeholder="Enter password" id="pwd" >
    </div> 
    <button type="submit" class="btn btn-primary col-md-4" style="margin-top: 30px;">로그인</button>
  </form>
</div>
<%@ include file="../layout/footer.jsp"%>
2.로그인 DTO(Data Transfer Oject) 를 만들어준다.

DTO(Data Transfer Object)란 통신을 위한 오브젝트로 변수를 적는 대신 함수로 만들어 재사용할 수 있게 만든다. jsp 파일의 form 태그에서 name으로 데이터를 받아올 때 일반 변수로 받으면 MINE Type으로 데이터를 받아오는데 이렇게 만들면 validation 타입으로 받을 수 없어지기 때문에 Dto를 사용하여 타입에 상관없이 받을 수 있게 만드는 것이다.

방법1. 개인 프로젝트

package com.cos.blogapp.web.dto;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class LoginReqDto {
  
  @Size(min = 2, max = 20)
  @NotBlank 
  private String username;
  
  @Size(min = 4, max = 20)
  @NotBlank 
  private String password;
  
  
}
join 메서드를 실행할 때 DTO에서 toEntity라는 함수로 만들어 사용하면 호출시 코드가 깔끔해지고 재사용에 용이해집니다.

방법2. 회사 실무

package com.cos.blogapp2.web.dto;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

@AllArgsConstructor
@Setter
@Getter
public class LoginReqDto {
  private String username;
  private String password;
}
3.UserRepository에서 아이디/비밀번호를 셀렉트하기 위한 네이티브 쿼리를 만들어준다.
package com.cos.blogapp.domain.user;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

public interface UserRepository extends JpaRepository<User, Integer>{
  
  @Query(value = "SELECT * FROM user WHERE username = :username AND password = :password", nativeQuery = true)
  User mLogin(String username, String password);
}
기본적으로 가지고 있는 함수 crud 중에 save(), findById(), findAll(), deleteById()가 있는데 로그인과 패스워드로 select하는 함수는 없으므로 네이티브쿼리를 따로 만들어줄 수 있습니다. 내가 만든 쿼리 이름에는 ‘m’을 붙여 구분해주세요.
interface는 메모리에 뜨지 않기 때문에 @Repository를 붙여줘야하지만 JpaRepository 내부에 이미 포함되어 있기때문에 이를 상속받는 UserRepository는 따로 적어주지 않아도 됩니다.
4.UserController.java에서 로그인 메서드를 만들어준다.
private final HttpSession session;

@PostMapping("/login")
  public String login(LoginReqDto dto) {
    
    String encPassword = SHA.encrypt(dto.getPassword());
    User principal =  userRepository.mLogin(dto.getUsername(), encPassword);
    
    if(principal == null) {
      return "redirect:/loginForm";
    }else {
      session.setAttribute("principal", principal);
      return "redirect:/";
    }
  }
방법2를 선택한 경우 다음과 같은 오류가 뜬다.
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.orm.jpa.JpaSystemException: No default constructor for entity:  : com.cos.blogapp2.domain.user.User; nested exception is org.hibernate.InstantiationException: No default constructor for entity:  : com.cos.blogapp2.domain.user.User] with root cause

원인 : 디폴트 생성자의 부재

해결 방법
User.java 파일에서 디폴트 생성자를 만들어주는
@NoArgsConstructor 어노테이션 추가

5.로그인 완료 후 헤더 메뉴가 바뀌도록 만들어준다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Blog</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet"
  href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<script
  src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script
  src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script
  src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<link
  href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote.min.css"
  rel="stylesheet">
<script
  src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote.min.js"></script>
</head>

<body>

  <!-- 네브바 시작 -->
  <nav class="navbar navbar-expand-md bg-dark navbar-dark">
    <a class="navbar-brand" href="/">블로그</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse"
      data-target="#collapsibleNavbar">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="collapsibleNavbar">
      <ul class="navbar-nav">

        <c:choose>
          <c:when test="${empty sessionScope.principal}">
            <li class="nav-item"><a class="nav-link" href="/loginForm">로그인</a>
            </li>
            <li class="nav-item"><a class="nav-link" href="/joinForm">회원가입</a>
            </li>
          </c:when>
          <c:otherwise>
            <li class="nav-item"><a class="nav-link" href="/board/saveForm">글쓰기</a>
            </li>
            <li class="nav-item"><a class="nav-link" href="/user/${sessionScope.principal.id}">회원정보</a>
            </li>
            <li class="nav-item"><a class="nav-link" href="/logout">로그아웃</a>
            </li>
          </c:otherwise>
        </c:choose>



      </ul>
    </div>
  </nav>
  <br>
  <!-- 네브바 끝 -->

로그아웃

세션 값을 무효화하고 메인페이지로 이동
@GetMapping("/logout")
  public String logout() {
    session.invalidate();
    return "redirect:/";
  }

 

로그인 부가기능

blog app
스프링부트 블로그 만들기 - 유효성 검사프로그램을 만들 때 핵심기능을 만들기 전후로 부가기능을 추가해줘야 한다. 핵심기능을 부가기능과 분리시켜 함수로 만들어 재사용하면 아주 편하게 코딩을 할 수 있다. 하지만 함수로 만들기 위한 공통 로직을 찾는 것은 결코 쉬운 일이 아니다....
blog app
스프링부트 블로그 만들기 - 사용자 경험프로그램을 만들 때 핵심기능을 만들기 전후로 부가기능을 추가해줘야 한다. 핵심기능을 부가기능과 분리시켜 함수로 만들어 재사용하면 아주 편하게 코딩을 할 수 있다. 하지만 함수로 만들기 위한 공통 로직을 찾는 것은 결코 쉬운 일이 아니다....
최신글