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 기능 수행 후

  1. login 성공 시 index로 돌아온다.
  2. 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 페이지에는 로그인 상태와 로그아웃 상태에 다른 버튼이 보여지도록 한 버튼의 내용이 빠귀도록 작성했다.

  1. 로그아웃 상태: 로그인 버튼이 보이고 로그아웃 버튼이 보이지 않는다.
  2. 로그인 상태: 로그인 버튼이 보이지 않고 로그아웃 버튼이 보인다.
<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 버튼이 보여지도록 한다.

 

[로그아웃상태]

[로그인상태]