본문 바로가기
수업자료

로그인, 로그아웃 기능 추가

by ^..^v 2023. 1. 11.
728x90
반응형

board_로그인,로그아웃기능추가.zip
1.09MB

 

 

테이블 생성 및 테스트 데이터 추가

MySQL Workbench를 이용해서 회원 정보를 저장할 테이블을 생성하고, 테스트 데이터를 추가합니다.

create table t_user (
    user_id         varchar(20)    not null, 
    user_password   varchar(200)   not null, 
    user_name       varchar(20)    not null, 
    user_email      varchar(100)   not null, 
    primary key (user_id)
);

insert into t_user (user_id, user_password, user_name, user_email) 
values ('gdhong', 'p@ssw0rd', '홍길동', 'hong@test.com'), 
       ('gdshin', 'p@ssw0rd', '신길동', 'shin@test.com'), 
       ('gdgo'  , 'p@ssw0rd', '고길동', 'go@test.com'  );

 

 

UserDto 클래스 생성

로그인한 사용자의 정보를 담을 UserDto 클래스를 생성합니다. 

package board.dto;

import lombok.Data;

@Data
public class UserDto {
	private String userId;
	private String userPassword;
	private String userName;
	private String userEmail;
}

 

 

LoginDto 클래스 생성

로그인 화면에서 사용자가 입력한 아이디와 패스워드를 전달할 LoginDto 클래스를 생성합니다.

package board.dto;

import lombok.Data;

@Data
public class LoginDto {
	private String userId;
	private String userPassword;
}

 

 

LoginController 클래스 생성

로그인 화면에 대한 요청, 로그인 요청, 로그아웃 요청을 처리할 LoginController 클래스를 생성합니다. 

package board.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

import board.dto.LoginDto;

@Controller
public class LoginController {
	// 로그인 화면에 대한 요청
	@GetMapping("/login.do")
	public String login() throws Exception {
		return "login.html";
	}
	
	// 로그인 처리에 대한 요청
	@PostMapping("/login.do")
	public String login(LoginDto loginDto) throws Exception {
		// TODO 로그인 로직 구현
		return "";
	}
}

 

 

login 페이지 생성

아이디와 패스워드를 입력받아 서버로 전달하는 페이지를 생성합니다.

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
	<meta charset="UTF-8">
	<title>로그인</title>
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
	<div class="container">
		<form action="/login.do" method="post">
			<div class="form-group">
				<label for="userId">ID</label>
				<input type="text" class="form-control" id="userId" name="userId" />
			</div>
			<div class="mt-2 form-group">
				<label for="userPassword">Password</label>
				<input type="password" class="form-control" id="userPassword" name="userPassword" />
			</div>
			<div class="mt-3">
				<input type="submit" value="Login" class="btn btn-primary" />
			</div>
		</form>
	</div>
	<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>	
</body>
</html>

 

 

LoginMapper 인터페이스 생성

사용자가 입력한 로그인 정보와 일치하는 사용자 정보를 조회해서 반환하는 메서드를 정의합니다.

package board.mapper;

import org.apache.ibatis.annotations.Mapper;

import board.dto.LoginDto;
import board.dto.UserDto;

@Mapper
public interface LoginMapper {
	public UserDto login(LoginDto loginDto) throws Exception;
}

 

 

sql-login.xml 파일 생성

로그인 로직을 구현할 쿼리를 저장할 sql-login.xml 파일을 생성합니다. 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="board.mapper.LoginMapper">
	<select id="login" parameterType="board.dto.LoginDto" resultType="board.dto.UserDto">
		select user_id, user_password, user_name, user_email 
		  from t_user 
		 where user_id = #{userId} and user_password = #{userPassword}
	</select>
</mapper>

 

 

LoginService 인터페이스 생성

package board.service;

import board.dto.LoginDto;
import board.dto.UserDto;

public interface LoginService {
	public UserDto login(LoginDto loginDto) throws Exception;
}

 

 

LoginServiceImpl 구현 클래스 추가

package board.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import board.dto.LoginDto;
import board.dto.UserDto;
import board.mapper.LoginMapper;

@Service 
public class LoginServiceImpl implements LoginService {
	@Autowired
	private LoginMapper loginMapper;
	
	@Override
	public UserDto login(LoginDto loginDto) throws Exception {
		return loginMapper.login(loginDto);
	}
}

 

 

LoginController 컨트롤러 메서드에 로그인 로직 추가

package board.controller;

import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

import board.dto.LoginDto;
import board.dto.UserDto;
import board.service.LoginService;

@Controller
public class LoginController {
	@Autowired
	private LoginService loginService;
	
	// 로그인 페이지를 반환합니다.    
	@GetMapping("/login.do")
	public String login(HttpSession session) throws Exception {
		if (session.getAttribute("user") == null) {
			return "login.html";
		} else {
			return "redirect:/board/openBoardList.do";
		}
	}
	
	// 일치하는 사용자가 존재하지 않는 경우 메시지와 함께 로그인 페이지로, 
	// 일치하는 사용자가 존재하는 경우 게시판 페이지로 이동합니다.
	@PostMapping("/login.do")
	public String login(LoginDto loginDto, HttpSession session) throws Exception {
		UserDto userDto = loginService.login(loginDto);
		if (userDto == null) {
			session.setAttribute("message", "일치하는 정보가 존재하지 않습니다.");
			return "redirect:login.do";
		} else {
			session.setAttribute("user", userDto);
			return "redirect:/board/openBoardList.do";
		}
	}
}

 

 

login 페이지에 메시지 처리

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
	<meta charset="UTF-8">
	<title>로그인</title>
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
	<div class="container">
		<form action="/login.do" method="post">
			<div class="form-group">
				<label for="userId">ID</label>
				<input type="text" class="form-control" id="userId" name="userId" />
			</div>
			<div class="mt-2 form-group">
				<label for="userPassword">Password</label>
				<input type="password" class="form-control" id="userPassword" name="userPassword" />
			</div>
			<div class="mt-3">
				<input type="submit" value="Login" class="btn btn-primary" />
			</div>
		</form>
	</div>
	<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
	<script>
		// 세션에 로그인 실패 메시지가 존재하는 경우, 메시지를 출력하고 세션에 있는 메시지를 삭제합니다.
		let message = "[[${session.message}]]";
		if (message) {
			alert(message);
			document.getElementById("userId").focus();
		}
	</script>	
	<th:block th:inline="text">[[${#session.removeAttribute('message')}]]</th:block>
</body>
</html>

 

 

게시판 페이지에 로그인 사용자 정보 출력 및 로그인, 로그아웃 버튼 추가

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
	<meta charset="UTF-8" />
	<title>게시판</title>
	<link rel="stylesheet" th:href="@{/css/style.css}" />	
</head>
<body>
	<div class="container">
		<!-- 로그인 전인 경우 로그인 버튼을 제공 -->     
		<div th:if="${#strings.isEmpty(session.user)}" style="text-align:right;">
			<a href="/login.do" class="btn">login</a>
		</div>
		<!-- 로그인 성공 시 로그인한 사용자 이름과 로그아웃 버튼을 출력 -->     
		<div th:unless="${#strings.isEmpty(session.user)}" style="text-align:right;">
			<b>[[${session.user.userName}]]</b>님 환영합니다. <a href="/logout.do" class="btn">logout</a>
		</div>
		<h2>게시판 목록</h2>
		<table class="board_list">
			<colgroup>
				<col width="15%" />
				<col width="*" />
				<col width="15%" />
				<col width="20%" />
			</colgroup>
			<thead>
				<tr>
					<th scope="col">글번호</th>
					<th scope="col">제목</th>
					<th scope="col">조회수</th>
					<th scope="col">작성일</th>
				</tr>
			</thead>
			<tbody>
				<tr th:if="${#lists.size(list)} > 0" th:each="board : ${list}">
					<td th:text="${board.boardIdx}"></td>
					<td class="title">
						<a href="/board/openBoardDetail.do?boardIdx=" 
							th:attrappend="href=${board.boardIdx}"
							th:text="${board.title}"></a>						
					</td>
					<td th:text="${board.hitCnt}"></td>
					<td th:text="${board.createdDt}"></td>
				</tr>
				<tr th:unless="${#lists.size(list)} > 0">
					<td colspan="4">조회된 결과가 없습니다.</td>
				</tr>
			</tbody>
		</table>
		<a href="/board/openBoardWrite.do" class="btn">글쓰기</a>
	</div>
</body>
</html>

 

 

LoginController 컨트롤러에 logout 메서드 추가

package board.controller;

import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

import board.dto.LoginDto;
import board.dto.UserDto;
import board.service.LoginService;

@Controller
public class LoginController {
	@Autowired
	private LoginService loginService;
	
	@GetMapping("/login.do")
	public String login(HttpSession session) throws Exception {
		if (session.getAttribute("user") == null) {
			return "login.html";
		} else {
			return "redirect:/board/openBoardList.do";
		}
	}
	
	@PostMapping("/login.do")
	public String login(LoginDto loginDto, HttpSession session) throws Exception {
		UserDto userDto = loginService.login(loginDto);
		if (userDto == null) {
			session.setAttribute("message", "일치하는 정보가 존재하지 않습니다.");
			return "redirect:login.do";
		} else {
			session.setAttribute("user", userDto);
			return "redirect:/board/openBoardList.do";
		}
	}
	
	// 세션에 user를 삭제하고, 세션을 무효화한 후 로그인 페이지로 이동합니다.
	@GetMapping("/logout.do")
	public String logout(HttpSession session) throws Exception {
		session.removeAttribute("user");
		session.invalidate();
		return "redirect:login.do";
	}
}

 

 

로그인 화면

 

 

로그인 실패 시 메시지 출력

 

 

로그인 성공 시 게시판 목록으로 이동

 

 

LoginCheckInterceptor 클래스 생성

로그인하지 않은 상태에서 게시판으로 접근하는 것을 막기 위해 인터셉터 클래스를 생성합니다. 

package board.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;

public class LoginCheckInterceptor implements HandlerInterceptor {
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		// 요청 주소에 /board가 포함된 경우, 세션에 user 정보가 존재하는지 체크
		// 포함되지 않은 경우 메시지와 함께 login 페이지로 이동
		if (request.getRequestURI().indexOf("/board") >= 0 && request.getSession().getAttribute("user") == null) {
			request.getSession().setAttribute("message", "로그인 후 사용하실 수 있습니다.");
			response.sendRedirect("/login.do");
			return false;
		} else {
			return true;
		}
	}
	
}

 

 

WebMvcConfiguration 클래스에 생성한 인터셉터 클래스를 등록

package board.configuration;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import board.interceptor.LoggerInterceptor;
import board.interceptor.LoginCheckInterceptor;

@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(new LoggerInterceptor());
		registry.addInterceptor(new LoginCheckInterceptor());
	}
}

 

 

로그인하지 않은 상태에서 게시판으로 접근

728x90
반응형

'수업자료' 카테고리의 다른 글

페이징 기능 추가  (0) 2023.01.17
세션으로부터 로그인한 사용자 정보를 가져와서 활용  (0) 2023.01.13
20230110 실습내용  (0) 2023.01.10
20230106 실습내용  (0) 2023.01.06
20230105 실습내용  (0) 2023.01.05

댓글