Spring/Spring 프로젝트(dsBBS)
Login 기능 구현
snorlax1106
2022. 8. 4. 14:46
[Mapper XML 작성, DTO 작성, DAO 작성] - Register 기능 구현에 작성
2022.08.02 - [Spring 프로젝트(dsBBS)] - Register 기능 구현
Register 기능 구현
먼저 mysql에서 작성한 DB 데이터를 dataSource bean에 가져오기 위해 다음 코드를 root-context.xml에 추가하였다. 또한 dataSource를 사용하기 사용하기 위해 sqlSessionFactory bean 객체를 mybatis-config.xml..
snorlax1106.tistory.com
[Service 작성 & 테스트]
< UserServiceImpl.java > - 추가
@Transactional(rollbackFor = Exception.class)
public UserDto login(String id, String pwd) throws Exception {
UserDto userDto = null;
try {
userDto = userDao.select(id);
// password가 일치하지 않으면 "Incorrect pwd" 예외 발생
if(userDto.getPwd().equals(pwd)==false)
throw new Exception("Incorrect pwd");
return userDao.select(id);
} catch (Exception e) {
e.printStackTrace();
throw new Exception("LOG_ERR");
}
}
id를 통해 select로 user 정보를 얻어와 password가 다르다면 Incorrect pwd 예외를 던진다.
< UserServiceImplTest.java > - 추가
@Test
public void loginTest() throws Exception {
userDao.deleteAll("18011742");
UserDto userDto = new UserDto("18011111", "990101", "홍길동", "학생","aaa@aaa.com");
assertTrue(userDao.insert(userDto)==1);
System.out.println("userService.login(\"18011111\",\"991101\") = " + userService.login("18011111","990101"));
userDto = new UserDto("18011112", "990102", "홍길덩", "교수","bbb@bbb.com");
assertTrue(userDao.insert(userDto)==1);
System.out.println("userService.login(\"18011112\",\"990102\") = " + userService.login("18011112","990102"));
userDto = new UserDto("18011113", "990103", "test_name","학생","abc@abc.com");
assertTrue(userDao.insert(userDto)==1);
// System.out.println("userService.login(\"18011113\", \"990112\") = " + userService.login("18011113", "990112")); // 일부러 예외 발생
assertTrue(userDao.deleteAll("18011742")==3);
}
[컨트롤러 작성 & 테스트]
< LoginController.java >
package com.sju.dsBBS.controller;
import com.sju.dsBBS.dao.UserDao;
import com.sju.dsBBS.service.UserService;
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 org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Controller
@RequestMapping("/login")
public class LoginController {
@Autowired
private UserService userService;
@GetMapping("/login")
public String login(){
return "login";
}
@PostMapping("/login")
public String login(String id, String pwd, boolean rememberMe, RedirectAttributes rattr,
HttpServletRequest request) throws Exception {
try {
// 아이디와 패스워드 확인
userService.login(id, pwd);
// 아이디와 패스워드가 일치하면 세션 객체를 얻어와서 id 저장
HttpSession session = request.getSession();
session.setAttribute("id", id);
// rememberMe가 체크면 session 일주일 설정
if(rememberMe)
System.out.println(rememberMe);
session.setMaxInactiveInterval(60*60*24*7);
return "index";
} catch (Exception e) {
e.printStackTrace();
rattr.addFlashAttribute("msg", "LOG_ERR");
return "redirect:/login/login";
}
}
@GetMapping("/logout")
public String logout(HttpSession session) {
// 1. 세션을 종료
session.invalidate();
// 2. 홈으로 이동
return "redirect:/";
}
}
GetMapping을 통해 login.jsp로 이동
PostMapping을 통해 login 기능 수행 후
- login 성공 시 index로 돌아온다.
- login 실패 시 RedirectAttributes 객체에 msg이름의 LOG_ERR의 value를 담아서 /login/login에게 요청을 넘긴다.
[뷰(UI) 작성 & 테스트]
< login.jsp >
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page import="java.net.URLDecoder"%>
<%@ page session="false" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>SB Admin 2 - Login</title>
<!-- Custom fonts for this template-->
<link href="${pageContext.request.contextPath}/vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<link
href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i"
rel="stylesheet">
<!-- Custom styles for this template-->
<link href="${pageContext.request.contextPath}/css/sb-admin-2.min.css" rel="stylesheet">
</head>
<body class="bg-gradient-primary">
<script>
let msg="${msg}";
if(msg=="LOG_ERR") alert("로그인 실패");
</script>
<div class="container">
<!-- Outer Row -->
<div class="row justify-content-center">
<div class="col-xl-10 col-lg-12 col-md-9">
<div class="card o-hidden border-0 shadow-lg my-5">
<div class="card-body p-0">
<!-- Nested Row within Card Body -->
<div class="row">
<div class="col-lg-6 d-none d-lg-block bg-login-image"></div>
<div class="col-lg-6">
<div class="p-5">
<div class="text-center">
<h1 class="h4 text-gray-900 mb-4">Welcome Back!</h1>
</div>
<form action="<c:url value="/login/login"/>" method="POST" class="user">
<div class="form-group">
<input type="text" name="id" id="id" placeholder="Id"
class="form-control form-control-user" aria-describedby="emailHelp">
</div>
<div class="form-group">
<input type="password" name="pwd" id="pwd" placeholder="Password"
class="form-control form-control-user">
</div>
<div class="form-group">
<div class="custom-control custom-checkbox small">
<input type="checkbox" class="custom-control-input" id="customCheck" name="rememberMe">
<label class="custom-control-label" for="customCheck">Remember
Me</label>
</div>
</div>
<button class="btn btn-primary btn-user btn-block">
Login
</button>
<%-- <hr>--%>
<%-- <a href="index.jsp" class="btn btn-google btn-user btn-block">--%>
<%-- <i class="fab fa-google fa-fw"></i> Login with Google--%>
<%-- </a>--%>
<%-- <a href="index.jsp" class="btn btn-facebook btn-user btn-block">--%>
<%-- <i class="fab fa-facebook-f fa-fw"></i> Login with Facebook--%>
<%-- </a>--%>
</form>
<hr>
<div class="text-center">
<a class="small" href="forgot-password.html">Forgot Password?</a>
</div>
<div class="text-center">
<a class="small" href="register.jsp">Create an Account!</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Bootstrap core JavaScript-->
<script src="${pageContext.request.contextPath}/vendor/jquery/jquery.min.js"></script>
<script src="${pageContext.request.contextPath}/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Core plugin JavaScript-->
<script src="${pageContext.request.contextPath}/vendor/jquery-easing/jquery.easing.min.js"></script>
<!-- Custom scripts for all pages-->
<script src="${pageContext.request.contextPath}/js/sb-admin-2.min.js"></script>
</body>
</html>

해당 페이지에 보이는 Remember Me와 Login의 구현은 차후에 구현 계획이다.
index 페이지에는 로그인 상태와 로그아웃 상태에 다른 버튼이 보여지도록 한 버튼의 내용이 빠귀도록 작성했다.
- 로그아웃 상태: 로그인 버튼이 보이고 로그아웃 버튼이 보이지 않는다.
- 로그인 상태: 로그인 버튼이 보이지 않고 로그아웃 버튼이 보인다.
<c:set var="loginId" value="${pageContext.request.getSession(false)==null ? '' : pageContext.request.session.getAttribute('id')}"/>
<c:set var="loginOutLink" value="${loginId=='' ? '/login/login' : '/login/logout'}"/>
<c:set var="loginOutBtn" value="${loginId=='' ? 'Login' : 'Logout'}"/>
c:set 코드를 통해 각 변수를 설정해 준다.
<a class="collapse-item" href="<c:url value='${loginOutLink}'/>">${loginOutBtn}</a>
login 버튼과 logout 버튼을 하나로 묶어서 loginOut 버튼으로 만들어 각 session이 있을 경우 logout 버튼이 보여지고, session이 없을 경우 login 버튼이 보여지도록 한다.
[로그아웃상태]

[로그인상태]
